328P ignoring sleep/waking up unexpectedly - Page 1
Forum section: electronics / general

author: gobo207
author_rank: Contributor
timestamp: October 27, 2019, 06:25:56 am
content: Hi all,I'm having issues with a 328P sleep modes. I have a 328P running at 3.7-4.2v, 8Mhz with Timer2 connected to a 32k watch crystal. I have a loop that has some basic function in it that is run each time the Timer2 overflows (1 sec). Problem is that when I try go back to sleep, it either ignores the command or wakes straight back up for the first ~60uS.Here is my troubleshooting code:Code:# define F_CPU 8000000UL#include <stdio.h>#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>#include <avr/sleep.h>#define PPS_OUT1void timer_Init(void);/********************************************************************************Main********************************************************************************/int main(void){timer_Init();set_sleep_mode(SLEEP_MODE_PWR_SAVE);DDRC |= (1<<PORTC3);sei();sleep_enable();while(1){PORTC = (1<<PORTC3);while( (ASSR & 0x1F) );// Make sure any Timer2 registers have finished updatingsleep_cpu();PORTC = (0<<PORTC3);}}ISR(TIMER2_OVF_vect){//_delay_us(20);return;}ISR(BADISR_vect){sleep_disable();TCCR2A &= ~(1<<COM2A1) | ~(1<<COM2A0);while( (ASSR & 0x1F) );//Do something obvious to detect a bad isrwhile(1){PORTC ^= (1<<PORTC3);}return;}void timer_Init(void){//Setup timer 2 with watch crystalASSR |= (1<<AS2);//Enable 32Khz crystal as clockwhile( (ASSR & 0x1F) );TCNT2 = 0x00;TCCR2A = 0x00;TCCR2B = 0x00;TIMSK2 = 0x00;OCR2A = 255;OCR2B = 255;while( (ASSR & 0x1F) );TCCR2A |= (0<<WGM21) | (0<<WGM20);//Normal modeTCCR2B |= (0<<WGM22) | (1<<CS22) | (0<<CS21) | (1<<CS20);//Normal mode, 128 clock pre scalewhile( (ASSR & 0x1F) );#if PPS_OUT//Toggle OC2A on compare with OCR2ATCCR2A |= (0<<COM2A1) | (1<<COM2A0);DDRB |= (1<<DDB3);while( (ASSR & 0x1F) );#endifTIMSK2 |= (1<<TOIE2);}If I put in a delay of 20uS in the ISR, you can see it loop for ~10uS through the sleep_cpu() function, then finally sleep properly. If I don't put any delay in the ISR, you can see it loop through the sleep_cpu() function for ~30uS. (see attachments)In the attached pictures, I'm triggering off the Timer2 overflow (yellow) so you can see when the loop gets executed (green).So my question now is, is there a minimum amount of time you need to wait after waking up, before you can sleep the micro again? Or is this related to the fact I'm waking of an asynchronous clock?Thank you.

author: cv007
author_rank: Frequent Contributor
timestamp: October 27, 2019, 11:56:47 am
content: 30us = 1/32768, 60us = 2/32768You are dealing with the async nature of things- waveform out is async, other things need synchronization. The datasheet has a page or so about timer2 async issues, and the first 30us are probably easily explained, the second 30us I'm not sure. I would wiggle a pin in the isr for more info, although it doesn't look like the isr is firing inside those main loop pin wiggles (~16 instructions is about enough time for the main loop only).You can look at this code as an example-https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en591232Just need to write to a t2 register that requires sync, check for sync, sleep (so you know you are not still in the first tosc1 cycle after wakeup).

author: gobo207
author_rank: Contributor
timestamp: October 27, 2019, 01:13:22 pm
content: Absolutely! What I first wrote the app, I was using their ASSR busy flag method in the loop, but not for this reason. It was stopping the issue from appearing. Then when I removed it to speed things up (ASSR takes about 60uS) I hit this issue.I think I found the issue. The datasheet does talk about async wake ups using Timer2, but only says it's an issue in Power-Save and ADC noise reduce. This is all in IDLE. Potentially an undocumented case? Bit weird how they would specifically mention 2 modes and leave the others out, surely it was for a reason...The stranger thing is that if I put that code back into my full app, it executes the interrupt multiple times, where in this isolated case, it does not.... My solution was to start a timer for 35uS and not go to sleep unless it's expired.Code:If TC2 is used to wake the device up from Power-Save or ADC Noise Reduction mode, precautionsmust be taken if the user wants to re-enter one of these modes: If re-entering sleep mode within theTOSC1 cycle, the interrupt will immediately occur and the device wakes up again. The result ismultiple interrupts and wake-ups within one TOSC1 cycle from the first interrupt. If the user is indoubt whether the time before re-entering Power-save or ADC Noise Reduction mode is sufficient,the following algorithm can be used to ensure that one TOSC1 cycle has elapsed:1. Write a value to TCCR2x, TCNT2, or OCR2x.2. Wait until the corresponding update busy flag in ASSR returns to zero.3. Enter Power-Save or ADC Noise Reduction mode.

author: cv007
author_rank: Frequent Contributor
timestamp: October 27, 2019, 01:57:38 pm
content: >This is all in IDLE.your example is not using idle-set_sleep_mode(SLEEP_MODE_PWR_SAVE);>Then when I removed it to speed things up (ASSR takes about 60uS) I hit this issueYou may be looking at 60us in any case from power save mode- 30us to wake, 30us to get out of the first tosc1 cycle.>The stranger thing is that if I put that code back into my full app, it executes the interrupt multiple timesMaybe you are using idle mode there, where the wakeup time is not delayed for 30us, but in its place you get the continual interrupt firing because the timer can be seen when it is 0 and appears to be an overflow every time timer2 syncs internally (as opposed to power save, where by the time you are awake, the timer already went to 1). I'm not sure if this actually explains things if this was true, but probably does not matter much. You have to solutions to prevent the problem, so implement them and move on.

author: gobo207
author_rank: Contributor
timestamp: October 27, 2019, 09:56:59 pm
content: Ah yes, my mistake. I was switching between IDLE and PWR_SAVE for testing. Pasted the code without changing....One thing left to try will be writing to the timer in the ISR and seeing how long it takes once I get back into the main loop. I'm thinking it takes 60uS when you write to it because it'll use 1 cycle to take it from the buffer, then another to clear the flag?