Using USART to wake ATMEAG 328P-PU from SleepMode

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm working on a new version of my hardware bus monitor program which reads a 16 bit address bus, 8 bit data bus and 7 bit signals bus from an attached 65C02 board.

My previous version works with a 20x4 LCD, but this one is going to be command line control by (and results displayed back to) PuTTY on my PC via RS232C.

Things are working well so far and I've got info printing out in PuTTY and input dropping in via USART interrupt.

A slightly irritating issue is that in between character inputs and when the AVR has nothing to do, I'm putting it into sleep mode. However, I cannot seem to wake the AVR backup using interrupts if I use anything other than SLEEP_MODE_IDLE. I know it will have issues with SLEEP_MODE_PWR_DOWN, but I'd have thought that the rest would work...

 

Here's my part of my main() code which contains the sleep instructions:


int main(void)
{
	// set things up	
	PortSetup();
	_delay_ms(100);
	Serial0_Init();

	// Enable USART interrupt
	UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
	
	// Turn on global interrupts
	sei();

	int keyscount = 0;
	char keys[32]= {0};
	
	set_sleep_mode(SLEEP_MODE_IDLE);

	while(1)
	{
		// sleep the AVR until a USART interrupt wakes it up
		sleep_mode();

 

 

 

Here's my interrupt (ISR) code:

 

ISR(USART_RX_vect)
{
	// grab the incoming character from USART UDR0 register and put it in rawkey
	// rawkey is picked up by the main while() loop in main(void)
	rawkey = UDR0;
}

 

Sleep modes:

  1.      *     SLEEP_MODE_ADC

  2.      *     SLEEP_MODE_PWR_SAVE

  3.      *     SLEEP_MODE_STANDBY

  4.      *     SLEEP_MODE_PWR_DOWN

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There I as chart in the "Power Management and Sleep Modes" section that shows what will wake the CPU in each mode. Unfortunately there is nothing in that chart that shows explicitly whether or not a USART interrupt will wake the CPU. Presumably it is included in "other". This is supported by the fact that USART is mentioned in "idle" mode but not in any other mode.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:

There I as chart in the "Power Management and Sleep Modes" section that shows what will wake the CPU in each mode. Unfortunately there is nothing in that chart that shows explicitly whether or not a USART interrupt will wake the CPU. Presumably it is included in "other". This is supported by the fact that USART is mentioned in "idle" mode but not in any other mode.

Thanks, Koshchi. I was hoping to keep the power usage down.

Currently, the breadboard circuit takes approx 21mA (30mA when in buffer read mode) for a 7805, 4x SN74AC245N buffers, the AVR, a MAX232E and a power LED (3mA). Not too bad, I suppose.

 

Thanks again.

Last Edited: Tue. Sep 29, 2015 - 07:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was hoping to keep the power usage down.

Currently, the breadboard circuit takes approx 21mA (30mA when in buffer read mode) for a 7805, 4x SN74AC245N buffers, the AVR, a MAX232E and a power LED (3mA). Not too bad, I suppose.

 

Hmmm--"keep power usage down", eh?

 

What you describe, 20mA-30mA, isn't what I think of for a "low power" AVR8 app.  That is 3AH per week...not really battery-friendly.

 

And if not battery powered, what difference does it make whether the draw is 20mA or 25mA?

 

Using a regulator, especially a plain-old '7805, isn't a recipe for lowest power.

 

Consider feathering or chopping or similar to keep your "power LED" down to a mA or so.  (You can even call it a feature -- solid on when active; dim/chopping when idle.

 

If you really need a MAX232 or similar transceiver, consider using one with an idle/wakeup mode.

 

But anyway, all is not lost.  Atmel has addressed your situation with the [nearly] drop-in PB series...

 

Now, when you can actually get your hands on a Mega328PB is another matter. ;)  Some Mega168PB are around--but they don't come in DIP, if that's what your breadboard setup uses.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Tue. Sep 29, 2015 - 08:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW, why isn't IDLE good enough?  It takes active current from ~5mA to ~1.5mA (8MHz, 5V).  1mA is a spit in the ocean when your status LED alone is 3mA.

 

If you want to play games, you could slow your AVR way down when going to IDLE, changing UBRR accordingly.  Then ACTIVE is about 1mA and IDLE is ~0.15mA.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, if aiming at POWERDOWN, tell more about your AVR's clock source.  A crystal takes some milliseconds to wake up and I'd speculate that USART reception will not be reliable during that warmup time.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi theusch

 

Thanks for the information.

This project doesn't have to but super low power, but as I'm a new comer to electronics and AVRs I thought I'd try my hand at keeping the power low.

 

Clock source-wise, I am  using the inbuilt oscillator running at 8MHz. I may choose to drop this to 1MHz.

 

One thing I have run into which is really causing me issues (sorry to side track slightly): I'm trying to use USART interrupts and a Timer at the same time. The USART seems to fire all the time when I enable the Timer. Here's my code:

 

void Serial0_Init(void)
{
	// Set baud rate
	UBRR0H = (uint8_t)(UBRR_VALUE>>8);
	UBRR0L = (uint8_t)UBRR_VALUE;
	// Set frame format to 8 data bits, no parity, 1 stop bit
	UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
	//enable transmission and reception
	UCSR0B |= (1<<RXEN0) |(1<<TXEN0);
}

 


void SetClock(int mode)
{
	 //PB0 = PHI2/clock out (output)
	 //PB1 = Single cycle clock in (input)

	
	TIMSK2 |= (1 << TOIE2); // Enable overflow interrupt
	sei();
	TCCR2B |= (1 << CS11); // Start timer at Fcpu/8

}

ISR(TIMER2_OVF_vect)
{
	bit_flip(PORTB, BIT(0));
}

 

I have tried swapping from Timer 1 to Timer 2, but this doesn't help and I know it's not the Timer ISR contents as I've tried commenting that out.

The only thing which stops the constant USART interrupts is commenting out

TCCR2B |= (1 << CS11); 

 which stops the timer being started.

 

I'm looking at the interrupts in the datasheet at the moment, but this is all new to me. Are USART and Timer interrupts known to conflict?

Last Edited: Tue. Sep 29, 2015 - 09:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
	//enable transmission and reception
	UCSR0B |= (1<<RXEN0) |(1<<TXEN0);
}
TIMSK2 |= (1 << TOIE2); // Enable overflow interrupt
	sei();
	TCCR2B |= (1 << CS11); // Start timer at Fcpu/8

 

Please, oh please, tell me why |= is so attractive in the lines above?  What about a good-old = just so we don't need to speculate about what the previous contents of the I/O registers are?  It is slower.  It is bigger.  Desired operation depends on knowing what the previous contents are.

 

Show a complete test program that exhibits your symptoms.  That is obviously needed as your "symptom" is constantly firing USART interrupts but the posted code has none enabled, nor a catching ISR.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Tue. Sep 29, 2015 - 11:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A common problem is a wrongly named interrupt vector. The compiler will usually give a warning.
Since you've posted only part of the code, i'd suggest running it in the atmel studio simulator and see step by step where it goes wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Kartman

 

I didn't get anny warnings about the vectors bing wrong.

I'm not at home at the moment so will post my complete project (with War Games quotes included :)) now and both swap the |= for = and also try and simulate it as well when I get home.

 

Thank you for your patience and help with this.

Attachment(s): 

Last Edited: Wed. Sep 30, 2015 - 01:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, yes, sometimes we need to wade through the complete project.  But what I'd really like is a stripped-down minimal yet complete program that demonstrates the symptoms.

 

Often (usually?) the process of stripping-down and testing after each "strip" uncovers the problem area.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, the interrupt is not continually firing.  "rawkey" is used but never cleared. 

 

"rawkey" must be volatile.

 

I don't know if lib_USART.c is seeing the correct F_CPU value, so your delays will be way off.

 

If using interrupt-driven serial communications, then use a circular buffer and associated "peek"/"fetch".  I'd also strongly suggest it for transmit to avoid hard delays between characters -- your "bus monitor" is going to miss a lot.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Like a FIFO buffer? I can do that. I haven't noticed any missed characters thus far, though - data being transmitted/received is simply display from the monitor to the PC and keyboard input form the PC to the monitor. That's slow and not really a problem to deal with.

Normally I have the AVR in sleep mode and so rawkey shouldn't be processed unless the USART interrupt fires. I commented these out as part of a test run above.

To test that this is the USART interrupt firing, I added in a command to display an '!' in the USART ISR. As a result of this I get a continuous set of '!'. Without this, then the the KEYS[] char string fills up until 30 characters have been stored then sounds chr(7) (bell) and refuses to store any more. In fact, this acts as a buffer although controlled by the main routine and not the ISR.

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. What was happening was that the timer was bringing the AVR out of sleep mode. As soon as it did this the main program loop would carry on and act as if it had received a input from the USART.

I've put a 'rawkey=0' line at the end of the main program loop and qualified the key buffering so that it'll ignore '0'.  Given that the timer has to run at 0.5Hz, 1Hz, 2Hz and 4Hz (selectable) I can't see that there's another way around this -at least until I look into it further.

 

[edit]

 

I've modified the main while() loop so that a rawkey = 0 jumps to the beginning of the loop and the AVR will go to sleep.

 

	sei();
	set_sleep_mode(SLEEP_MODE_IDLE);


	while(1)
	{
		sleep_mode();
		if (rawkey==0) continue;

 

Last Edited: Wed. Sep 30, 2015 - 09:51 PM