EmbDev.net

Forum: ARM programming with GCC/GNU tools Resetting the entire processor


von Jim K. (ancaritha)


Rate this post
useful
not useful
I'm trying to get a power down mode to work on the SAM7A3.  Right now I
have it enter a power down state, where I configure all of the pins
controllable by the PIO, and then I set a bunch of them to certain
positions, configure the pull-ups on them, etc.  I turn of the AIC, PMC
etc etc.  I then configure the AIC to fire an interrupt on a level
change (when I push an external button) so that it will turn back on.
Lastly, I lower the clock frequency to 500 Hz, switch the master clock
to slow clock, then I disable the PLL, the Main Osciallator and then the
Processor Clock.  All of this seems to work as its supposed to.

The issue arrises when I try to turn everything back on.  I successfully
fire the interrupt, I'm able to turn the clock back on (or so the power
jump implies, as does the fact that the external oscillator starts
churning out 3.6 MHz again), but then my program just seems to kind of
hang...  So I figured since I've screwed with all the PIO stuff and all
the peripherals, the best option to get everything back into shape is to
simply reset the entire damn board.  Sounds easy right?  Well, the reset
controller didn't seem to do jack, so I decided to try to jump to vector
0x0 and cause a reset.

Shouldn't this cause it to branch to 0x0, causing a reset?
__asm("mov r0, #0");
__asm("bx r0")


Here is all of my on/off code.


void hwSleep(void)
{
// Configure all pins as PIO controlled
  AT91C_BASE_PIOA->PIO_PER = 0xFFFFFFFF;
  AT91C_BASE_PIOB->PIO_PER = 0xFFFFFFFF;

  // Disable USART RX, TX and it
  AT91F_US_DisableRx(AT91C_BASE_US0);
  AT91F_US_DisableTx(AT91C_BASE_US0);
  AT91F_US_Close(AT91C_BASE_US0);

  // Set LED pins to input with no pull-ups
  AT91F_PIO_CfgInput(AT91C_BASE_PIOA, LED_PINS);
  AT91C_BASE_PIOA->PIO_PPUDR = LED_PINS;

  // Drive PA1 low, PA0 high  (both high works better)
  AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA0 | AT91C_PIO_PA1);
  AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA0 | AT91C_PIO_PA1);
  AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PIO_PA0 | AT91C_PIO_PA1;

  // SPI stuff
  AT91F_SPI_Disable(AT91C_BASE_SPI0);
  AT91F_SPI_Close(AT91C_BASE_SPI0);

  U32 nPins = AT91C_PIO_PA11 | AT91C_PIO_PA12 | AT91C_PIO_PA13 |
AT91C_PIO_PA14 |
    AT91C_PIO_PA15 | AT91C_PIO_PA16 | AT91C_PIO_PA17;

  // Set PA11-17 to inputs (no pull-ups)
  AT91F_PIO_CfgInput(AT91C_BASE_PIOA, nPins);
  AT91C_BASE_PIOA->PIO_PPUDR = nPins;

  // Set PB25 to input (no pull-up)
  AT91F_PIO_CfgInput(AT91C_BASE_PIOB, AT91C_PIO_PB25);
  AT91C_BASE_PIOB->PIO_PPUDR = AT91C_PIO_PB25;

  nPins = AT91C_PIO_PB0 | AT91C_PIO_PB1 | AT91C_PIO_PB2 | AT91C_PIO_PB3
| AT91C_PIO_PB4 | AT91C_PIO_PB5 |
     AT91C_PIO_PB6 | AT91C_PIO_PB7 | AT91C_PIO_PB8 | AT91C_PIO_PB9 |
AT91C_PIO_PB10 | AT91C_PIO_PB11 |
     AT91C_PIO_PB12 | AT91C_PIO_PB13 | AT91C_PIO_PB14 | AT91C_PIO_PB15 |
AT91C_PIO_PB16;

  // Set PB0-16 to input (no pull-up)
  AT91F_PIO_CfgInput(AT91C_BASE_PIOB, nPins);
  AT91C_BASE_PIOB->PIO_PPUDR = nPins;


  // Set PB17-23 to input with (pull-up ENABLED)
  AT91F_PIO_CfgInput(AT91C_BASE_PIOB, BTN_PINS);
  AT91C_BASE_PIOB->PIO_PPUER = BTN_PINS;


  // Enable the USB, then disable it.  It helps
  AT91C_BASE_PMC->PMC_PCER= AT91C_ID_UDP;
    AT91C_BASE_PMC->PMC_PCDR= AT91C_ID_UDP;

  // Disable all interrupts
  AT91F_AIC_DisableIt(AT91C_BASE_AIC, 0xFFFFFFFF);

  // Disable entire PMC except for GPIOB so we can be woken up
    AT91C_BASE_PMC->PMC_PCDR = 0xFFFFFFF7;
    AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_PIOB);

  // Drive PB24 High (MUST BE LAST)
  AT91F_PIO_CfgOutput(AT91C_BASE_PIOB, AT91C_PIO_PB24);
  AT91F_PIO_SetOutput(AT91C_BASE_PIOB, AT91C_PIO_PB24);


  // Configure the AIC to fire off an interrupt on PB17 (active low)
  AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_PIOB,
INTERRUPT_PRIORITY_SEVEN, AT91C_AIC_SRCTYPE_EXT_LOW_LEVEL,
hwWakeUpInterrupt);
  AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_PIOB);

  // Read the Status Register to clear all pending interrupts
  nPins = AT91C_BASE_PIOB->PIO_ISR;

  // Enable the PIO Interrupt
  AT91C_BASE_PIOB->PIO_IER = AT91C_PIO_PB17;

  // Reduce the MCK Frequency Down to 500 Hz
    nTemp = 0;
    nTemp |= AT91C_PMC_PRES_CLK_64;
    AT91C_BASE_PMC->PMC_MCKR = nTemp ;
    while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  // Switch the Master Clock (MCK) to Slow Clock
  nTemp =  0;
    AT91C_BASE_PMC->PMC_MCKR = nTemp ;
    while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

  // Enable the Shutdown pin
  AT91C_BASE_SHDWC->SHDWC_SHCR = AT91C_SHDWC_KEY | AT91C_SHDWC_SHDW;
  AT91C_BASE_SHDWC->SHDWC_SHMR = AT91C_SHDWC_WKMODE0_NONE |
AT91C_SHDWC_WKMODE1_NONE;

  // Disable the PLL
  AT91C_BASE_PMC->PMC_PLLR = 0x0;

  // Disable the Main Oscillator
  AT91C_BASE_PMC->PMC_MOR = 0x0;

  // Disable Processor Clock and USB clock
  AT91C_BASE_PMC->PMC_SCDR = 0xFFFF;
}


void hwWakeUpInterrupt(void)
{

  // Read the Status Register to clear all pending interrupts
  U32 nTemp = AT91C_BASE_PIOB->PIO_ISR;
  nTemp = 0;

  // Disable the PIO Interrupt
  AT91C_BASE_PIOB->PIO_IDR = AT91C_PIO_PB17;

  __asm("mov  r0, #0");
  __asm("bx  r0");

  // Turn all the clocks back on;
  AT91F_LowLevelInit();

  // Acknowledge the interrupt
    AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
}


Note:  The LowLevelInit file is the file that configures the clock and
default interrupt handler vectors that the assembly file calls.

von Jonathan D. (dumarjo)


Rate this post
useful
not useful
>
> Shouldn't this cause it to branch to 0x0, causing a reset?

The only way we found to reset the cpu is to use the watchdog.

I have seen a discussion about this on at91.com in the forum

here the link

http://www.at91.com/phpbb/viewtopic.php?t=2589

Jonathan

von Jim K. (ancaritha)


Rate this post
useful
not useful
Jonathan Dumarjo wrote:
>>
>> Shouldn't this cause it to branch to 0x0, causing a reset?
>
> The only way we found to reset the cpu is to use the watchdog.
>
> I have seen a discussion about this on at91.com in the forum
>
> here the link
>
> http://www.at91.com/phpbb/viewtopic.php?t=2589
>
> Jonathan

Yea, thats what I ended up doing.  Nothing like a good old fashioned
while(1) until the watchdog fires :)

von Clifford S. (clifford)


Rate this post
useful
not useful
Jim Kaz wrote:
> Yea, thats what I ended up doing.  Nothing like a good old fashioned
> while(1) until the watchdog fires :)


That is in fact the the 'correct' method. You had it the wrong way
arround before - a jump-to-zero will not cause a hardware reset. Rather
a hardware reset causes a jump-to-zero; which is a different thing
altogether.

Jump-to-zero can may possibly be used to implement a 'warm-start', but
it will not reset the hardware registers and peripherals, or the MMU for
devices that have one, to a 'known' reset state. On some ARM
architectures it may cause a problem if the memory map is not as
expected - that is  zero may not even be the correct reset vector any
longer, you would have to engineer it to be so, and usually have
specific code to distinguise a warm from a cold start and behave
appropriately.

Clifford

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.