View previous topic :: View next topic |
Author |
Message |
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
PIC18LF47K42 doesn't awake when receives data by UART. |
Posted: Fri Oct 30, 2020 5:34 am |
|
|
I use PIC18LF47K42 for the first time.
I'm not able to awake the PIC when it receives a character by the UART1 using interrupts once it is asleep.
I'm forgetting something...
...This PIC has two UART but previous PIC's I've been used had EUART with 'E'?
...fuses?
The same code works fine with other PICs like PIC18LF47K40.
Could someone help me?
Thank you in advance!
Code: |
// MPLABX version: 5.40
// CCS version: 5.096
#CASE // Case sensetive compiler
#include <18LF47K42.h>
#FUSES NOBROWNOUT
#use delay(clock = 16MHZ, internal)
#pin_select U1TX = PIN_C6
#pin_select U1RX = PIN_C7
//The PIN_SELECT stuff must be before you use the UART
#use rs232 (UART1, baud = 9600)
#define LED PIN_C4 // OUT high = led on
#INT_RDA
void serial_isr()
{
putc(getc());
}
void main(void)
{
output_high(LED); // Led on
delay_ms(300);
output_toggle(LED); // Led off
delay_ms(300);
output_toggle(LED); // Led on
delay_ms(300);
output_toggle(LED); // Led off
output_low(PIN_A0);
output_low(PIN_A1);
output_low(PIN_A2);
output_low(PIN_A3);
output_high(PIN_A4);
output_low(PIN_A5);
output_low(PIN_A6);
output_low(PIN_A7);
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B5);
output_low(PIN_B6);
output_low(PIN_B7);
output_low(PIN_C0);
output_low(PIN_C1);
output_low(PIN_C2);
output_low(PIN_C3);
output_low(PIN_C4);
output_low(PIN_C5);
//output_high(PIN_C6); // TX pin 44
//output_high(PIN_C7); // RX pin 1
output_low(PIN_D0);
output_low(PIN_D1);
output_low(PIN_D2);
output_low(PIN_D3);
output_low(PIN_D4);
output_low(PIN_D5);
output_low(PIN_D6);
output_low(PIN_D7);
output_low(PIN_E0);
output_low(PIN_E1);
output_high(PIN_E2);
output_high(PIN_E3);
putc('>');
delay_ms(1);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
// while(TRUE) // With this loop at VDD=3.0V current consumption is 3000uA. Receives RX data OK.
// {
// }
// while(TRUE) // With this loop at VDD=3.0V current consumption is 0.3uA. Doesn't receive any RX data. Is OK.
// {
// sleep();
// delay_cycles(1);
// }
while(TRUE) // Whith this loop I'm not able to awake the PIC to receive data! Help needed here!
{ // With this loop at VDD=3.0V current consumption is 0.3uA.
setup_uart(UART_WAKEUP_ON_RDA);
sleep();
delay_cycles(1);
}
}
|
|
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
Posted: Fri Oct 30, 2020 5:55 am |
|
|
I have done more tests without success.
Code: |
while(TRUE) // Whith this loop I'm able to awake the PIC to receive data but with a lot of errors!
{ // With this loop at VDD=3.0V current consumption is very high, 1900uA.
setup_uart(UART_WAKEUP_ON_RDA);
sleep(SLEEP_IDLE); // #define SLEEP_IDLE 1 // Clock and peripherals don't stop
delay_cycles(1);
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Fri Oct 30, 2020 6:36 am |
|
|
Ok, I don't consider 1900ua (1.9ma) to be 'very high' but then I'm a dinosaur that had 40AMP, +5 PSUs for my equipment.
To reduce power consumption, you need to disable any/all internal peripherals that you're not using. Items like ADC, comparators, etc. I don't use that PIC, but modern PICs have a LOT of peripherals and most will be enabled by default.
As for the 'errors', what are they ? If data, do you buffer the incoming data, have you 'errors' in the #use RS232(...options...). What is the other RS232 'device', what baudrate ? Is it 3 volt device. What level translators are you using? Cable type, length, etc. Proper ground between PIC and 'device' ?
If the PIC is NOT asleep, is the data 100% ?
At 3 volts, are you using a battery ?
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Fri Oct 30, 2020 8:42 am |
|
|
You do understand you can't receive the character that wakes you?.
You also have to send a 'break' character to wake the chip.
The chip does not receive this, just wakes.
So the sequence is 'send break', pause for a moment, then send the
characters you want received. The PIC has to stay awake once the break
is seen till the packet is complete.
So you won't wake on any old character being received, and even if you
did, the actual character that wakes you is never received. |
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
Posted: Tue Nov 03, 2020 7:18 am |
|
|
Thanks for your answer temtronic.
I need an average consumption current of 100uA. I want the two AA (Vdd 3.0V...1.8V) batteries last more than 2 years.
With all peripherals disabled I have consumption less than 1uA.
I don't used 'errors' in the #use RS232(...options...).
The rs232 communicates with a Bluetooth module at 9600. No need level translators.
When the PIC is not asleep the data is OK. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Tue Nov 03, 2020 7:30 am |
|
|
You need to add 'ERRORS'. Without it, if the PIC receives 3 or more characters and you don't read the UART buffer, the UART will shutdown due to 'overrun'. Like having a mailbox and NOT getting your mail, the box gets 'stuffed' and you're in trouble !
As it's a battery powered device, remember that batteries do NOT like getting cold ! Their energy output is greatly reduced. |
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
Posted: Tue Nov 03, 2020 7:31 am |
|
|
Thanks for your answer Ttelmah.
You are right again.
Sorry for asking a question that I know that you are answering almost every day during more than a decade.
Once I have studied and understood the AUTO-WAKE-UP ON BREAK (PIC18LF47K42 31.17.3 AUTO-WAKE-UP ON BREAK pag.496) I will make a test code and I will post it.
If the PIC doesn’t go to sleep a UART works in 5 minutes but if you need low consumption (sleep) things are more complicated. |
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
Posted: Tue Nov 17, 2020 2:15 am |
|
|
PIC consumes < 1uA.
Receives a 5 bytes order plus a heading break byte.
The PIC starts consuming 2500uA while receiving the order and transmitting the answer.
PIC goes to sleep again consuming < 1uA.
How can I improve this code with ",timeout" ",errors" in "#use rs232 ()" ?
Code: |
// AUTO-WAKE-UP ON BREAK
//
// TX: 00 01 02 03 04 05 => RX 01 02 03 04 05 (0x00 = break)
//
// TX: ff 01 02 03 04 05 => RX 01 02 03 04 05 (0xff = break)
//
// 0 1 2 3 4 0 1 2 3 4
// order to receive: 00(brk) 01 02 03 04 05 from PC terminal to RX PIC
// order resend 01 02 03 04 05 from PIC TX to PC terminal
// PIC _____sleep______> <awake-------------------------awake> <___sleep___
// <1uA 2500uA <1uA
//
// MPLABX version: 5.40
// CCS version: 5.096
#CASE // Case sensetive compiler
#include <18LF47K42.h>
#FUSES NOBROWNOUT
#FUSES NOWDT
#use delay(clock = 16MHZ, internal)
#pin_select U1TX = PIN_C6 // U1RXPPS portC 0x3ae5 = 0x17
#pin_select U1RX = PIN_C7
#use rs232 (UART1, baud = 9600) // The PIN_SELECT stuff must be before you use the UART
// ,timeout ???
// ,errors ???
#define NO 0
#define YES 1
#define LED PIN_C4 // OUT high = led on
#byte U1ERRIR = 0x3DF9
#bit TXMTIF = U1ERRIR.7
#byte U1UIR = 0x3DF8
#bit WUIF = U1UIR.7
#byte U1FIFO = 0x3df7
#bit RXIDL = U1FIFO.3
#byte U1CON2 = 0x3DF4
#byte U1CON1 = 0x3df3
#bit WUE = U1CON1.4
#byte INTCON0 = 0x3FD2
#bit GIE = INTCON0.7
#byte U1CON0 = 0x3DF2
#byte U1TXB = 0x3dea; // 0x3dea U1TXB: UART TRANSMIT REGISTER
#byte U1RXB = 0x3de8; // 0x3de8 U1RXB: UART RECEIVE REGISTER
#byte PIR3 = 0x39A3
#bit U1RXIF = PIR3.3 // UART1 Receive Interrupt Flag bit.
#byte PIE3 = 0x3993
#bit U1IE = PIE3.6
#bit U1RXIE = PIE3.3
int8 rxIndex = 0;
int1 goToSleep = YES;
int1 orderReceived = NO;
int8 rxBuffer[5] = {0xff, 0xff, 0xff, 0xff, 0xff};
#INT_RDA
// When the wake-up event ocours the UART module generates a U1UIR.WUIF interrupt (0x3DF8.7).
void serial_isr(void)
{
rxBuffer[rxIndex++] = getc();
if (rxIndex >= 5)
{
rxIndex = 0;
orderReceived = YES;
}
WUIF = 0; // U1UIR.WUIF 0x3DF8.7 Wake-up Interrupt bit. The interrupt condition is cleared here by software.
// U1UIR: UART GENERAL INTERRUPT REGISTER
// bit 7 WUIF: Wake-up Interrupt bit
// 1 = Idle to non-idle transition on RX line detected when WUE is set. Also sets U1IF. (WUIF must be cleared by software to clear U1IF)
// 0 = WUE not enabled by software or no transition detected
// PIR3.U1RXIF 0x39a3.3 bit cleared by compiler.
// PIR3: PERIPHERAL INTERRUPT REGISTER 3
// bit 3 U1RXIF: UART1 Receive Interrupt Flag bit
// 1 = Interrupt has occurred
// 0 = Interrupt event has not occurred
}
void main(void)
{
int8 i;
output_high(LED); // Led on
delay_ms(300);
output_toggle(LED); // Led off
delay_ms(300);
output_toggle(LED); // Led on
delay_ms(300);
output_toggle(LED); // Led off
output_low(PIN_A0);
output_low(PIN_A1);
output_low(PIN_A2);
output_low(PIN_A3);
output_low(PIN_A4);
output_low(PIN_A5);
output_low(PIN_A6);
output_low(PIN_A7);
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B5);
output_low(PIN_B6);
output_low(PIN_B7);
output_low(PIN_C0);
output_low(PIN_C1);
output_low(PIN_C2);
output_low(PIN_C3);
output_low(PIN_C4); // LED low = off
output_low(PIN_C5);
//output_high(PIN_C6); // TX pin 44 output
//output_high(PIN_C7); // RX pin 1 input
output_low(PIN_D0);
output_low(PIN_D1);
output_low(PIN_D2);
output_low(PIN_D3);
output_low(PIN_D4);
output_low(PIN_D5);
output_low(PIN_D6);
output_low(PIN_D7);
output_low(PIN_E0);
output_low(PIN_E1);
output_low(PIN_E2);
output_high(PIN_E3); // MCLR
putc('>');
delay_ms(1);
U1IE = 1; // PIE3.U1IE, 0x3993.6 = 1. PERIPHERAL INTERRUPT ENABLE REGISTER 3.
// bit 6 U1IE: UART1 Interrupt Enable bit
// 1 = Enabled
// 0 = Disabled
enable_interrupts(INT_RDA); // PIE3.U1RXIE, 0x3993.3 = 1. PERIPHERAL INTERRUPT ENABLE REGISTER 3.
// bit 3 U1RXIE: UART1 Receive Interrupt Enable bit
// 1 = Enabled
/// 0 = Disabled
enable_interrupts(GLOBAL); // 0x3df2 | 0b11000000 INTCON0: INTERRUPT CONTROL REGISTER 0
// bit 7 GIE/GIEH: Global Interrupt Enable bits
// bit 6 GIEL: Global Low Priority Interrupt Enable bit
while (TRUE)
{
output_toggle(LED);
output_toggle(LED);
if (goToSleep == YES)
{
setup_uart(UART_WAKEUP_ON_RDA); // U1CON1.WUE, 0x3DF3.4 = 1. U1CON1: UART CONTROL REGISTER 1
// bit 4 WUE: Wake-up Enable bit
// 1 = Receiver is waiting for falling RX input edge which will set the UxIF bit. Cleared by hardware on wake event. Also requires UxIE
// 0 = Receiver operates normally
sleep();
delay_cycles(1);
goToSleep = NO;
}
else
{
if (orderReceived == YES)
{
orderReceived = NO;
for (i = 0; i < 5; i++)
putc(rxBuffer[i]);
while(TXMTIF == 0); // 3DF9h.7 U1ERRIR.TXMTIF: Transmit Shift Register Empty Interrupt Flag bit
// 1 = Transmit shift register is empty (Set at end of Stop bits)
// 0 = Transmit shift register is actively shifting data
goToSleep = YES; // Entering sleep with last 2 characters sent correctly.
}
}
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Tue Nov 17, 2020 3:34 am |
|
|
'ERRORS' should always be used with a hardware UART. It really should
be made the default by CCS. Without this if a character does get missed,
the UART can become completely hung.
TIMEOUT, would not do anything for you. You never sit 'waiting' on the
UART, so no effect from this. TIMEOUT doesn't generate an interrupt.
If you want a timeout, you are going to have to write it yourself. So
(for example), start a timer when you wake from the break, and when this
expires, if you have not received a complete 'packet', throw away what you
have received and go back to sleep. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Tue Nov 17, 2020 6:25 am |
|
|
If 'improve' means use less power, consider a faster baudrate. while doubling it( 9600> 19200) won't reduce power by 1/2, there will be a slight reduction. Same holds true with the PIC 'clock'. Running it faster for a shorter time, will reduce power.
Microchip had an 'appnote' very early ( AN606 ???, it's OLD...) that had charts and numbers about batteries/clocks/tricks to reduce power . It's only 10-15 pages long but well worth the effort to find and read it.
Also
instead of...
Quote: |
output_low(PIN_A0);
output_low(PIN_A1);
output_low(PIN_A2);
output_low(PIN_A3);
output_low(PIN_A4);
output_low(PIN_A5);
output_low(PIN_A6);
output_low(PIN_A7); |
try...
Code: | output_A(0b00000000); |
It makes for shorter and faster code, even if some bits have to be '1's. Instead of 16 lines of code, only 2 or 3.
I know, it only gets executed once BUT it's a 'tweak' that does reduce overall power consumption.
Adding a small 'supercap' in parallel to the battery could help.
When using 'batteries only', EVERY trick or tweak, has to be tested. |
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Nov 18, 2020 5:40 am |
|
|
Thank you ! for taking the time, finding it and posting a 'link' to it !! I used to have the real databooks here on the shelf for quick reference, sigh, that was a long, long time ago.... Kind interesting that I remember the apnote number, bet there's a 'few' more added since then.
Another 'fun' read are the 'Tips & Tricks' books. Though code is in assembler, they can easily be adapted to C.
Jay aka Temtronic |
|
|
Josep Robert
Joined: 27 Mar 2018 Posts: 25
|
|
|
|