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.
> > 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
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 :)
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
Log in with Google account
No account? Register here.