Forums

Atmega8 Sleep mode doesn't work with USART

Started by Unknown July 20, 2005
Hi.

I'd like to use sleep operation with USART but when I use USART with
sleep operation, the system was crashed.

my code like this.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>

void Uart_Put_Char(unsigned char data)
{
	while ( !( UCSRA & (1<<UDRE)) );
	UDR = data;
}

void Hardware_Init(void)
{
	MCUCR = 0xb0;
	UBRRL = 16;
	UCSRA = 0x00;
	UCSRB = 0x18;

}

void main(void)
{
	Hardware_Init();

	while(1)
	{
		Uart_Put_Char('A');
		__asm volatile ("sleep");
	}
}

but when I comment like this

// __asm volatile ("sleep");

my code works fine.

I really wanna use sleep with USART.
Could you tellme why ?

thx.

<ilovecpp@gmail.com> wrote in message
news:1121840504.024790.82650@g14g2000cwa.googlegroups.com...
> Hi. > > I'd like to use sleep operation with USART but when I use USART with > sleep operation, the system was crashed.
If you go to sleep mode, something has to happen to make the AVR wake up from sleep mode. This is usually a reset or an interrupt. In your code, you don't use interrupts on the UART, so when you enter sleep mode, the AVR stays there. Meindert
Thank you Meindert Sprang.

But It's a little bit different. In my case, I fix code like below.

void main(void)
{
        Hardware_Init();

        while(1)
        {
                Uart_Put_Char('A');
                __asm volatile ("sleep");
                Uart_Put_Char('B');
        }
}

and My system doesn't print even "A".

I think something wrong. 
Do you know why ?

<ilovecpp@gmail.com> wrote in message
news:1121844978.458057.302820@g43g2000cwa.googlegroups.com...
> Thank you Meindert Sprang. > > But It's a little bit different. In my case, I fix code like below. > > void main(void) > { > Hardware_Init(); > > while(1) > { > Uart_Put_Char('A'); > __asm volatile ("sleep"); > Uart_Put_Char('B'); > } > } > > and My system doesn't print even "A".
That is most likely because you put the AVR to sleep before the "A" has left the UART. Your Uart_Put_Char() first checks the UDRE bit, then it loads a new byte in the UDR register. If you then call "sleep", the AVR goes to sleep before the UART has finished shifting the byte out. Checking for UDRE *after* the write to UDR doesn't help either because the UART is double buffered. UDRE flags the state of the UDR register and not the shift register. To test this, insert while ( !( UCSRA & (1<<TXC)) ); before the "sleep" instruction. This will test if the shifter is really empty and thus you have seen the "A" appear. Meindert
Meindert Sprang wrote:
> <ilovecpp@gmail.com> wrote in message > news:1121844978.458057.302820@g43g2000cwa.googlegroups.com... > >>Thank you Meindert Sprang. >> >>But It's a little bit different. In my case, I fix code like below. >> >>void main(void) >>{ >> Hardware_Init(); >> >> while(1) >> { >> Uart_Put_Char('A'); >> __asm volatile ("sleep"); >> Uart_Put_Char('B'); >> } >>} >> >>and My system doesn't print even "A". > > > That is most likely because you put the AVR to sleep before the "A" has left > the UART. Your Uart_Put_Char() first checks the UDRE bit, then it loads a > new byte in the UDR register. If you then call "sleep", the AVR goes to > sleep before the UART has finished shifting the byte out. Checking for UDRE > *after* the write to UDR doesn't help either because the UART is double > buffered. UDRE flags the state of the UDR register and not the shift > register. To test this, insert > > while ( !( UCSRA & (1<<TXC)) ); > > before the "sleep" instruction. This will test if the shifter is really > empty and thus you have seen the "A" appear. > > Meindert > > >
If his uart transmit routine were interrupt driven then the avr might go to sleep and wake up in the transmit routine. Note that there are different sleep modes you can specify, and some of them will NOT allow the uart to run, there is a mode that WILL allow the uart to receive data while the cpu is asleep and you need to use that mode to wake up on a character received. Of course the power savings isn't as great with this mode..... BTW, I'm working on a project with a mega128 avr using external ram. In putting this one to sleep I first disabled external memory mode so the chip select of the ram (wired to A15) would go high to save the current pulled by the selected ram chip (dropped about 30ma!). But to do this I first had to relocate the stack to internal ram (I'll leave the reason for this as an excerise for the reader!). The stack is restored after the cpu wakes up. The cpu is put to sleep in mainline code, ANY interrupt will wake up the cpu, and after returning from interrupt we are at the instruction AFTER the sleep instruction. NOTE that the interrupt code must NOT access any data in external ram! (think of all the fun I am having with this!)
You have to wait for the characyter to lkeave the uart --- then goto sleep.
I use ATMEGA128 with UART and also with external 32KHz xtal on
timer 0 for power save modes.  So far I'm down to 35uA.  Be careful
with external pull-ups, make sure ports are configured for input lest the
chew up power while in sleep.  Shut everything else off --- including
JTAG debug interface, analog comparator, and watchdog timer
(can be done in software), otherwise you will not get anywhere near
10's of uA.

David Howard

"Ken Scharf" <wa2mzeNOTTHIS@bellsouth.net> wrote in message
news:oRY3f.18754$Yl.4065@bignews4.bellsouth.net...
> Meindert Sprang wrote: > > <ilovecpp@gmail.com> wrote in message > > news:1121844978.458057.302820@g43g2000cwa.googlegroups.com... > > > >>Thank you Meindert Sprang. > >> > >>But It's a little bit different. In my case, I fix code like below. > >> > >>void main(void) > >>{ > >> Hardware_Init(); > >> > >> while(1) > >> { > >> Uart_Put_Char('A'); > >> __asm volatile ("sleep"); > >> Uart_Put_Char('B'); > >> } > >>} > >> > >>and My system doesn't print even "A". > > > > > > That is most likely because you put the AVR to sleep before the "A" has
left
> > the UART. Your Uart_Put_Char() first checks the UDRE bit, then it loads
a
> > new byte in the UDR register. If you then call "sleep", the AVR goes to > > sleep before the UART has finished shifting the byte out. Checking for
UDRE
> > *after* the write to UDR doesn't help either because the UART is double > > buffered. UDRE flags the state of the UDR register and not the shift > > register. To test this, insert > > > > while ( !( UCSRA & (1<<TXC)) ); > > > > before the "sleep" instruction. This will test if the shifter is really > > empty and thus you have seen the "A" appear. > > > > Meindert > > > > > > > If his uart transmit routine were interrupt driven then the avr > might go to sleep and wake up in the transmit routine. Note that > there are different sleep modes you can specify, and some of them > will NOT allow the uart to run, there is a mode that WILL allow the > uart to receive data while the cpu is asleep and you need to use > that mode to wake up on a character received. Of course the power > savings isn't as great with this mode..... > > BTW, I'm working on a project with a mega128 avr using external > ram. In putting this one to sleep I first disabled external memory > mode so the chip select of the ram (wired to A15) would go high to > save the current pulled by the selected ram chip (dropped about > 30ma!). But to do this I first had to relocate the stack to internal > ram (I'll leave the reason for this as an excerise for the reader!). > The stack is restored after the cpu wakes up. The cpu is put to sleep > in mainline code, ANY interrupt will wake up the cpu, and after > returning from interrupt we are at the instruction AFTER the sleep > instruction. NOTE that the interrupt code must NOT access any data > in external ram! (think of all the fun I am having with this!)