View previous topic :: View next topic |
Author |
Message |
ktallevi
Joined: 17 Dec 2005 Posts: 58
|
UART rx during sleep mode problem |
Posted: Wed Jul 04, 2007 11:46 am |
|
|
I am attempting to capture a single character from a serial device while the PIC18LF8722 is in sleep mode. Everything works fine if I sit in 'idle' mode, but that consumes too much power. I am using a 10Mhz crystal as my main running clock, although I shut that down while in sleep using setup_oscillator(OSC_31250); The circuit draws 60uA in sleep mode, which I am happy with.
I have wired the receive pin to both UART1 and EXT1. my idea is that the high-to-low transition will trigger EXT1 and wake up the PIC, the first instruction will be a getc() ... or a timed getc routine.
So far my logic is correct, but the character is not being read properly, I keep getting 255 back. The character I'm expecting is 165. Again, the problem only occurs in sleep mode, not idle mode.
My assumption is that upon EXT1 being triggered, the PIC switches from 31khz to the 10mhz external crystal. The delay period of the PIC waking up and the 10mhz crystal stabilizing is too long for the character to be properly read.
Without pasting the entire code , which is not really necessary, here are the relevant portions...
Code: |
#FUSES HS
#use delay(clock=10000000) // 10Mhz
char rx_char;
#int_EXT1
void EXT1_isr(void) {
disable_interrupts(INT_EXT1);
enable_interrupts(GLOBAL);
rx_char=timed_getc();
}
/* code extracted from CCS example file */
char timed_getc() {
long timeout;
char retval;
timeout=0;
while(!kbhit() && (++timeout< (KEYHIT_DELAY*100)))
delay_us(10);
if(kbhit())
retval = getc();
else
retval = 0;
return(retval);
}
void main(void) {
setup_oscillator(OSC_31250);
sleep();
fprintf(SerialPortOne,"Received: %U\n\r",rx_char);
}
|
any ideas? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jul 04, 2007 12:10 pm |
|
|
Quote: |
My assumption is that upon EXT1 being triggered, the PIC switches from 31khz to the 10mhz external crystal. | Don't assume. Most likely this is your problem.
Code: | #int_EXT1
void EXT1_isr(void) {
disable_interrupts(INT_EXT1);
enable_interrupts(GLOBAL);
rx_char=timed_getc();
} | NEVER activate the global interrupt enable flag inside an interrupt handler. This can cause nested interrupts, a feature not supported by the hardware with program crashes as a result. Most likely you intended to disable the global interrupt flag but this is not going to work as the hardware will restore the flag on exiting the interrupt handler. |
|
|
ktallevi
Joined: 17 Dec 2005 Posts: 58
|
UART rx during sleep mode problem |
Posted: Wed Jul 04, 2007 12:36 pm |
|
|
So any ideas as to capturing the character upon waking up? The character is being received at 9600bps, so I would need to power up before the start of the first data bit (100usec or so). Is there a way to keep that single hardware UART active while the device is in sleep mode, without using idle mode of course.
I'm open to any other ideas of course.
thanks |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 05, 2007 3:23 am |
|
|
The problem is that the UART, is clocked by the processor clock, and cannot work without a clock.
What you can do, is have the command to switch the clock to a slow rate (but still running), and then a new #use delay statement, and #use RS232 statement, for this clock rate. Then the UART is running and clocked at the slower rate, to receive the first character.
Unfortunately though, the 32K clock, is not fast enough to operate the UART for 9600bps reception. The UART will trigger a 'wake' on the first edge of the start bit, but cannot then clock the data in, till the main oscillator has woken.
The normal way to deal with this, is to send a dummy 'wake up' character, in front of the actua data, with enough delay, for the oscillator to have started, before the main data is sent.
Unfortunately, this is hardware limitation.
Best Wishes |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu Jul 05, 2007 7:32 am |
|
|
Why are you sleeping at 32kHz? If it is just something readily available and slow enough to save power without being stopped, but accuracy is not too important, you might try a faster sleep clock, like a 200kHz resonator. It might be slow enough to save power, but fast enough to run your UART. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Thu Jul 05, 2007 10:13 pm |
|
|
I think it's worth mentioning that a crystal speed of 38400 will allow you to run in low power mode and still receive at 9600 baud with no error using only the low speed crystal. It will use about the same power that a clock crystal would use but operating a real time clock becomes more complicated. Also, you may be able to go much lower than 60uA in low power mode. |
|
|
ktallevi
Joined: 17 Dec 2005 Posts: 58
|
|
Posted: Thu Nov 29, 2007 10:35 am |
|
|
so the best course of action should be enable sleep mode, but use a faster crystal. I'll have to calculate the lowest possible crystal value that allows for 9600 reception, but still provides good power saving. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Thu Nov 29, 2007 12:08 pm |
|
|
ktallevi wrote: | so the best course of action should be enable sleep mode, but use a faster crystal. I'll have to calculate the lowest possible crystal value that allows for 9600 reception, but still provides good power saving. |
lowest crystal speed for a given baud rate is 4 * baud rate.
While in sleep mode the crystal does not oscillate, there is no clock and no instructions are executed.
Switching from a 10Mhz crystal to a 38.4Khz crystal will cause power use to drop from about 10mA to about 40uA. Instructions will continue to execute.
So to reduce power use, configure USART for slower crystal then switch crystals to the lower crystal speed. You don't need to enter sleep mode. |
|
|
ktallevi
Joined: 17 Dec 2005 Posts: 58
|
|
Posted: Thu Nov 29, 2007 1:44 pm |
|
|
I still need the 10Mhz crystal for other purposes, so could I put the 38.4khz crystal on RC0/RC1 and use setup_oscillator(OSC_TIMER1)?
This way the PIC could run off the 38.4khz until it gets the data from the 9600 bps device (instead of sleeping), read the data, then switch back to the 10Mhz crystal again for full operation.
thanks |
|
|
|