Forum: Mikrocontroller und Digitale Elektronik Corex M4 neu starten ohne Reset


von S. C. (samc)


Lesenswert?

Hi,

ich bin grad am suchen, wie ich einen Cortex M4 neu starten kann ohne 
den reset auszuführen. Es geht um einen LPC4330. Problem ist, dass bei 
einem normalen Reset der ROM Bootloader durchlaufen wird und das führt 
manchmal du einer Situation wo die CPU in einer Endlosschleife hängt 
bevor überhaupt mein Code ausgeführt wird.

Ich will/muss aus einer beliebigen Stelle, auch zB aus dem harfault IRQ 
meinen code neu bei 0x00 starten.

Das ist nicht so einfach, weil die CPU ja im Handler mode sein könnte 
und die Stackpointer resetet werden müssen.

Weiss jemand wie ich im hardfault handler zurück in den Thread mode 
schalten kann und was ich sonst dabei beachten muss?

Danke,
Simon

von cfgardiner (Gast)


Lesenswert?

Hi,

Bin mir nicht sicher, ob wir das gleich meinen, aber ich es so gelöst in 
einer Applikation. Ergebnis ist ein Warm-Start ohne Power-Cycle. War 
allerdings ein M3


if (lpcImgInfo->prodID == 583) {
   spImage  = (uint32_t*) 0x14020000;
   }
else {
   spImage  = (uint32_t*) 0x14010000;
   }

NVIC_SetVTOR((uint32_t)spImage);
__set_MSP(*spImage);       /* Load stack pointer of the selected image 
*/
__enable_irq();

      // Call the first function in the Vector Table
      // (this is the reset vector at offset 0x4)
bootAddr = spImage + 1;
((void (*)())(*bootAddr))();

  // never get to here, diverted by boot
while (1);

von S. C. (samc)


Lesenswert?

Hi,

Super, das hilft mir mit dem stack pointer!

ich vermute, du rufst das nie aus einem IRQ, geschweige denn fault IRQ 
auf, weil dann wäre die CPU nicht im thread mode und einige oder alle 
IRQs wären weithin geblockt.

Hast du dazu eine Idee?

danke,
Simon

von Christian J. (Gast)


Lesenswert?

cfgardiner schrieb:

> ((void (*)())(*bootAddr))();

Darum hasse ich C manchmal. Was ist denn das für ein Konstrukt?

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

*bootAddr zeigt auf eine Adresse, die main() Routine
das ganze drum herum macht aus der Adresse einen Funktionszeiger und 
ruft den auf. Es ist somit der main(); Aufruf, bzw. der Einsprungpunkt 
in den ersten Befehl, der die CPU ausführt.

Man könnte auch die Adresse *bootAddr in den PC (ProgrammCounter) 
schreiben, ist das gleiche.

von cfgardiner (Gast)


Lesenswert?

Stimmt.

Aus den Exceptions heraus hatte ich es anders gelöst. Das ist allerdings 
NXP spezifisch(aber das hast Du ja). Mit den aktuellen lpcopen 2.12 ist 
der Aufruf leider etwas anders, glaube ich (muesste ich noch suchen). 
Das unten stehende kann man aber auch einfach zu Fuss programmieren:

Applikation
===========
z.B.
void BusFault_Handler(void) {
   RGU_SoftReset(RGU_SIG_CORE);
   }

NXP hat RGU_SoftReset so definiert:
===================================

typedef enum
{
  RGU_SIG_CORE  = 0,          /**< Core reset signal       */
  RGU_SIG_PERIPH,            /**< Peripheral reset signal  */
  RGU_SIG_MASTER,            /**< Master reset signal    */
  . . . . . . .
  RGU_SIG_SPIFI,            /**< SPIFI reset signal      */
  RGU_SIG_CAN = 55          /**< CAN reset signal      */
}RGU_SIG;


void RGU_SoftReset(RGU_SIG ResetSignal)
{
  if(ResetSignal < 32){
    LPC_RGU->RESET_CTRL0 = 1 << ResetSignal;
    LPC_RGU->RESET_CTRL0 = 0;
  }else{
    LPC_RGU->RESET_CTRL1 = 1 << (ResetSignal - 32);
    LPC_RGU->RESET_CTRL1 = 0;
  }
}

von cfgardiner (Gast)


Lesenswert?

Habe ich doch gefunden.

mit lpcopen heisst es
void Chip_RGU_TriggerReset(CHIP_RGU_RST_T ResetNumber);

ist aber das gleich in grün:
lpcopen/software/lpc_core/lpc_chip/chip_18xx_43xx/rgu_18xx_43xx.c


/* Trigger a peripheral reset for the selected peripheral */
void Chip_RGU_TriggerReset(CHIP_RGU_RST_T ResetNumber)
{
        volatile uint32_t *p;

        /* To trigger reset- write RESET_CTRLx with a 1 bit */
        p = (volatile uint32_t *) &(LPC_RGU->RESET_CTRL0);

        /* higher numbers are in RESET_CTRL1, RESET_CTRL2, etc. */
        p += ResetNumber / 32;

        /* On the LPC18xx and LPC43xx, most of the reset bits 
automatically clear
           after 1 clock cycle, so set the bit and return */
        *p = (1 << (ResetNumber % 32));
}

von S. C. (samc)


Lesenswert?

Hi,

danke für die Mühe, aber das führt wieder dazu dass der ROM Bootloader 
durchlaufen wird :-)

Problem ist, dass der dann den ISP pin prüft, und ggf in den ISP Mode 
wechselt.

Dieser Pin ist gleichzeitig eine Adressleitung vom SDRAM. Und das SDRAM 
musste ich abschaltbar machen um Strom zu sparen.
Es ist so verschaltet, dass der SDRAM mit Strom versorgt wird sobald die 
IOs in den reset-state gehen, aber offenbar ist das Timing nicht immer 
ausreichend. Ganz ganz selten wird dann doch der ISP aufgerufen...
Hab das schon auf alle erdenkliche Arten versucht, Timing stimmt jetzt 
perfekt, trotzdem passierts manchmal.

==> deshalb würde ich den ROM Bootloader gerne nie durchlaufen, brauch 
ihn ja auch nicht.

Ich hatte zwischenzeitlich noch eine Idee, aber noch nicht versucht.
Evtl. würde es ja gehen, zuerst mit PRIMASK und BASEMASK alle IRQs zu 
deaktivieren. Dann alle pending löschen und nur den ResetISR pending 
setzen.
Vector table auf den bootloader setzen.

Dann Stack und evtl CONTROL passend setzen, und die IRQs wieder 
aktiveren.

Fault Handler mit return verlassen.

Dann müsste doch eigentlich der ResetHandler im bootloader angesprungen 
werden und alles müsste passen, oder?

Naja, ich denk grad noch drüber nach...

Grüße,
Simon

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Der STM32 hat ein Register in dem drin steht wer den Reset ausgelöst 
hat. Wenn man ein Soft-Reset über die Befehle macht springt der zwar in 
Bootloader, aber der kann dieses Register auslesen und so direkt zu 
Applikation springen.
Das müsste es beim LPC auch geben.

: Bearbeitet durch User
von Jens (Gast)


Lesenswert?

S. C. schrieb:
> Es ist so verschaltet, dass der SDRAM mit Strom versorgt wird sobald die
> IOs in den reset-state gehen, aber offenbar ist das Timing nicht immer
> ausreichend.
Evtl. bringt es was, hier noch einen hochohmigen Pullup/Pulldown 
unterzubringen, um geordnete Verhätlnisse zu schaffen.

von Jim M. (turboj)


Lesenswert?

Hast Du mal versucht, CRP auf "NO_ISP" zu setzen? Siehe Kapitel 6.6 im 
UM10503.pdf Manual. Dann sollte der Pegel auf P2.7 beim Reset egal sein.

von S. C. (samc)


Lesenswert?

Hi,

- Register gibts, aber der ROM bootloader ist von NXP, den kann ich 
nicht beeinflussen

- Pullup ist schon da, kann aber nur gegen die Versorgungsspannung vom 
SDRAM gehen, sonst würde er ja das ganze SDRAM versorgen wenn es 
abgeschaltet ist.
Vor dem Reset setze ich auch mit Gewalt die Pegel, aber auch das hilft 
nicht 100%ig

- CRP wäre eine super Idee, aber der 4330 hat kein Flash sondern bootet 
vom externen SPIFI. Laut Flußdiagram wird der ISP pin nur dann nicht 
abgefragt wenn die CPU AES kann und auch eine Key programmiert ist. 
Die CPU kann aber kein AES...blöde Konstellation.

Danke,
Simon

von Gerd E. (robberknight)


Lesenswert?

S. C. schrieb:
> - Pullup ist schon da, kann aber nur gegen die Versorgungsspannung vom
> SDRAM gehen, sonst würde er ja das ganze SDRAM versorgen wenn es
> abgeschaltet ist.
> Vor dem Reset setze ich auch mit Gewalt die Pegel, aber auch das hilft
> nicht 100%ig

wie wäre es an der stelle mit einem kleinen puffer zwischen µC und 
SDRAM? Z.B. so ein 74lvc2g17. Der erlaubt am Input 0-5V auch bei 
ausgeschalteter eigener Stromversorgung. Den 74lvc2g17 versorgst Du mit 
der selben Stromversorgung wie den SDRAM und erst wenn die angeht, gibt 
er einen Pegel aus.

Damit kannst Du dann einen sauberen Pullup an die Stromversorgung des 
µCs realisieren.

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

S. C. schrieb:
> Ich will/muss aus einer beliebigen Stelle, auch zB aus dem harfault IRQ
> meinen code neu bei 0x00 starten.
>
> Das ist nicht so einfach, weil die CPU ja im Handler mode sein könnte
> und die Stackpointer resetet werden müssen.

Genau dafür kann man doch 2 Stacks einrichten: R13_PSP für Thread und 
R13_MSP für Handler.

The Stack Pointer (SP) is register R13. In Thread mode, bit[1] of the 
CONTROL register indicates the stack pointer to use:

    0 = Main Stack Pointer (MSP). This is the reset value.

    1 = Process Stack Pointer (PSP).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.