void deepSleep(void){
pGCLK->GENCTRL=0x00290300; // turn on GEN0 and drive it from OSC32ULP
pGCLK->GENCTRL=0x00290303; // turn on GEN3 and drive it from OSC32ULP (needed for timer)
pSysCtrl->XOSC = 0xAB44; // turn off XOSC
pSysCtrl->OSC8M = 0x880e0380; // turn off OSC8M
*pSCR |= 0x4; // DEEEP SLEEP!
asm volatile("WFI");
}
void wakeUp(void){
volatile uint32_t testResult;
pSysCtrl->OSC8M = 0x880e0382; // turn on OSC8M
while(1){ // wait until OSC8M is ready...
testResult = pSysCtrl->INTFLAG&0x08;
if(0!=testResult)
break;
}
pPort->DIRSET = 0xFFFFFFFF; // set to OUTPUT
pPort->OUTCLR = 0xFFFFFFFF; // turn all the outputs to 0 - try and reduce current/power
pPort->OUTSET = (1 << 10);
/*
pPort->PINCFG[10]=0x01; // setup the pin to be multiplexed.
pPort->PMUX[5]=0x77; // set PA10 and PA11 to be muxed to peripheral H
pPort->PINCFG[6]=0x01;
pPort->PMUX[3]=0x22; // set PA06 (SERCOMPAD0) to output and mux it.
*/
pSysCtrl->XOSC = 0xAB46; // turn on XOSC
while(1){ // wait until XOSC is ready...
testResult = pSysCtrl->INTFLAG&0x01;
if(0!=testResult)
break;
}
pGCLK->GENCTRL=0x00290001; // turn on GEN1 and drive it from XOSC
pGCLK->GENCTRL=0x00090204; // now drive GEN4 from GEN1
pGCLK->GENCTRL=0x00290600; // turn on GEN0 and drive it from GCLK1 (OSC8M for now, again)
// pGCLK->GENDIV =0x00000A00; // divide by 10 for 1.356MHz operation
pGCLK->GENCTRL=0x00290303; // turn on GEN3 and drive it from OSC32ULP (needed for timer)
pPM->APBCMASK = 0x84;
setupTimer(65535-350);
/*
pGCLK->CLKCTRL = 0x400E; // route the clock to the core.
pCOM->CTRLA = 0x40120004; // setup the serial port
pCOM->BAUD = 64793; // 9600 bps
pCOM->CTRLA = 0x40120006; // setup the serial port
pCOM->CTRLB = 0x00010000; // turn on the transmitter
*/
}
void setupTimer(uint16_t count){
//route clock.
pGCLK->GENCTRL = 0x00290303; // route the 32kHz ULP osc to GEN3. Run while in standby
pGCLK->CLKCTRL = 0x4312; // route Gen3 to TC2 (for some reason there is no tie-in to TC1?)
pPM->APBCMASK = 0x84; // enable the clock on the power map
// now setup the timer, but don't turn it on
pTC2->CTRLA = 0x0F00; // just a simple counter. 32,000Hz / 1024 = 31.25Hz / 32mS tick
pTC2->INTFLAG = 0x01; // make sure the flag is cleared.
pTC2->INTENSET=0x01; // enable "OVERFLOW INTERRUPT"
pTC2->COUNT = count; // load up the value
pNVIC->NVIC_ISER = (1 << 14); // set the interrupt for timer 14
resetCount = count;
}
void startTimer(void)
{
pTC2->CTRLA = 0x0F02; // turn on the timer.
}
void resetTimer(void){
//route clock.
pGCLK->GENCTRL = 0x00290303; // route the 32kHz ULP osc to GEN3. Run while in standby
pGCLK->CLKCTRL = 0x4312; // route Gen3 to TC2 (for some reason there is no tie-in to TC1?)
pPM->APBCMASK = 0x84; // enable the clock on the power map
// now setup the timer, but don't turn it on
pTC2->INTFLAG = 0x39; // make sure the flag is cleared.
pTC2->INTENSET=0x01; // enable "OVERFLOW INTERRUPT"
pTC2->COUNT = resetCount; // load up the value
pTC2->CTRLA = 0x0F02; // just a simple counter. 32,000Hz / 1024 = 31.25Hz / 32mS tick
pTC2->COUNT = resetCount; // load up the value
// turn it on
}
void __attribute__((interrupt(14))) TC2_Handler(void) {
// do nothing!
pTC2->INTFLAG = 0x01;
wakeUp();
for(uint32_t x=0;x<10;x++){
pPort->OUTTGL=(1<<10);
for(uint32_t q=0;q<100;q++);
}
resetTimer();
deepSleep();
}
int main(void)
{
wakeUp();
startTimer(); // trigger it.
while (1)
{
deepSleep();
}
}
Please, use defines from header files. It is impossible to read this code with all those magic numbers.
And where this "__attribute__((interrupt(14))) " even come from? This is nonsense for ARM, and compiler should probably complain about this.
You can't (or should not) call deepSleep() from the IRQ handler itself. Let it exit the interrupt normally and your main while (1) loop will take care of the sleep.
Now your code blocks because the same interrupt handler can't be called twice without extra messing around.
The main problem is that you are calling issuing WFI from within the interrupt handler.
Attribute stuff is not need on Cortex devices, it all works with plain C.
/* Cortex-M0+ core handlers */
void NMI_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
void SVC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
void PendSV_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
void SysTick_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
They are standard CMSIS headers (made by Atmel, obviously, who else will make them?). If you refuse to use them, then I personally won't be able to help you, sorry.
As mentioned, I no longer need to call WFI within the handler, and it still fails, so it follows that WFI from within the handler is not the problem.
Omitting the __attribute__ factor, as used in Atmel's own code produces the following error:
Just for completeness' sake, here is an excerpt from the startup_samd09.c as generated by Atmel:
I'm not even understanding what or where your complaint is and by the discrepancies above, I too do not think your efforts will be purposeful as well.
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC1_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);
Then you should probably post up to date code. It is hard to guess what changes you have made.
void __attribute__((interrupt(14))) TC2_Handler(void) {
// do nothing!
pTC2->INTFLAG = 0x01; // clear the ISR
wakeUp(); // Restore all of the clock configurations.
for(uint32_t x=0;x<10;x++){
pPort->OUTTGL=(1<<10); // perform a simple toggle
for(uint32_t q=0;q<100;q++); // perform a bit of time delay
}
resetTimer(); // stuff the timer with appropriate reset information and start it
pGCLK->GENCTRL=0x00290300; // turn on GEN0 and drive it from OSC32ULP
pGCLK->GENCTRL=0x00290303; // turn on GEN3 and drive it from OSC32ULP (needed for timer)
pSysCtrl->XOSC = 0xAB44; // turn off XOSC
pSysCtrl->OSC8M = 0x880e0380; // turn off OSC8M
}
andvoid deepSleep(void){
pGCLK->GENCTRL=0x00290300; // turn on GEN0 and drive it from OSC32ULP
pGCLK->GENCTRL=0x00290303; // turn on GEN3 and drive it from OSC32ULP (needed for timer)
pSysCtrl->XOSC = 0xAB44; // turn off XOSC
pSysCtrl->OSC8M = 0x880e0380; // turn off OSC8M
*pSCR |= 0x06; // DEEEP SLEEP, but now use SLEEPONEXIT. When an ISR finishes,
// the uC will resume sleeping rather than continuing with the
// program
asm volatile("WFI");
}
void TC2_Handler(void) {
This attribute is meaningless on ARM.
There is no need to enable/disable clocks, just configure them once and let the MCU handle the rest. If you don't want some clocks to run when MCU is sleeping, just don't set RUNSTDBY bit.
If for whatever reason you need to do clock control manually, you have to wait for synchronization before going to sleep (or exiting the IRQ handler in this case).
But I do suspect that the problems come from this manual clock management without waiting for synchronization or any of the status bits.
And just useCode: [Select]void TC2_Handler(void) {
This attribute is meaningless on ARM.
pTC2->INTENSET=0x01; // enable "OVERFLOW INTERRUPT"
pTC2->CTRLA = 0x0F02; // just a simple counter. 32,000Hz / 1024 = 31.25Hz / 32mS tick
pTC2->INTENSET= TC_INTENSET_OVF; // enable "OVERFLOW INTERRUPT"
pTC2->CTRLA = TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_RUNSTDNY | TC_CTRLA_MODE_COUNT16 | TC_CTRLA_ENABLE;
Code: [Select]pTC2->INTENSET=0x01; // enable "OVERFLOW INTERRUPT"
pTC2->CTRLA = 0x0F02; // just a simple counter. 32,000Hz / 1024 = 31.25Hz / 32mS tick
We want that to look like:Code: [Select]pTC2->INTENSET= TC_INTENSET_OVF; // enable "OVERFLOW INTERRUPT"
pTC2->CTRLA = TC_CTRLA_PRESCALER_DIV1024 | TC_CTRLA_RUNSTDNY | TC_CTRLA_MODE_COUNT16 | TC_CTRLA_ENABLE;
Otherwise we have to open up the datasheet and stare a long time to see if your constants really do what your comment says they do (at least, you DID have comments!)
without a reliable and consistent source book to derive this kind of context from
As such, would it be a reasonable compromise to then do up a mess of #defines, so it might not be "TC_CTRLA_PRESCALAR_DIV1024" but would be "PRESCALARDIV1024"?
TC_CTRLA_PRESCALAR_DIV1024
xx Peripheral type
xxxxx Register name
xxxxxxxxx Field name
xxxxxxx Value
(Those names are all exactly as they are documented in the datasheet.)#define TC_DIV1024 0x0700
#define TC_RUNSTDBY 0x0800
#define TC_16BIT 0x0000
#define TC_RUN 0x0002
pTC2->CTRLA = TC_DIV1024 | TC_RUNSTDBY | TC_16BIT | TC_RUN;