|
|
View previous topic :: View next topic |
Author |
Message |
srtgumbee
Joined: 15 Dec 2018 Posts: 5
|
Clearing UART overflow flag PIC18F47K42 |
Posted: Tue Dec 03, 2019 9:18 pm |
|
|
I have a project that is sometimes locking up the UART1 (eg once a day) and only being saved by a WDT. While investigating the cause I questioned why the lockup wasn't being cleared/reset in the UART error handling.
The RXFOIF bit (of the the U1ERRIR reg) is getting set indicating an FIFO overflow has occurred. From the CCS documents, it seems adding 'ERRORS' to #use_RS232 should clear the RXFOIF. From the datasheet it seems reading the FIFO should also clear the bit.
I made some sample code to cause an overflow by leaving interrupts disabled and made attempts to clear the RXFOIF but no luck. I'm missing something here....any ideas would be appreciated!
PIC18F47K42
CCSC Compiler 5.083
Code: |
#include <18F47K42.h>
#fuses RSTOSC_HFINTRC_1MHZ,NOCLKOUT,BORV24,NOMCLR,NOFCMEN,PUT_64MS,NOPROTECT,NOWRTB,NOXINST
#byte porta = 0x3fca
#byte portb = 0x3fcb
#byte portc = 0x3fcc
#byte porte = 0x3fce
#bit GPS_power_switch = porte.0
#define TRIS_B_VALUE 0b10001011
#define TRIS_C_VALUE 0b10010000
#define TRIS_E_VALUE 0b11111110
#byte U1RXB = 0x3de8 //Recieve register
#byte U1ERRIR = 0x3df9 //error register
#bit TXMTIF1 = U1ERRIR.7 //TX active 1 when finished
#bit FERIF1 = U1ERRIR.3 //Framing error 1 = error
#bit RXBKIF1 = U1ERRIR.2 //Break detected = 1
#bit RXF0IF1 = U1ERRIR.1 //Overflow detected = 1
#byte U1CON0 = 0x3df2
#bit RXEN1 = U1CON0.4 //1 is enabled
#byte U1CON2 = 0x3df4 //new code to add
#bit RUNOVF1 = U1CON2.7 //new code to add
#byte U1ERRIE = 0x3dfa //new code to add
#bit FERIE1 = U1ERRIE.3 //new code to add
#byte U1FIFO = 0x3dfc
#bit RXBE = U1FIFO.1
#bit TXBE = U1FIFO.5
#INT_RDA
void receive_data_isr()
{
int rda1i,character1;
if( FERIF1 || RXBKIF1 || RXF0IF1)
{
RXEN1 = 0;rda1i = U1RXB;rda1i = U1RXB;rda1i = U1RXB;RXEN1 = 1;
}
else
{
character1 = U1RXB;
}
}
void main()
{
setup_oscillator( OSC_HFINTRC_1MHZ );
#use delay( clock = 1000000 )
set_tris_b( TRIS_B_VALUE );
set_tris_c( TRIS_C_VALUE );
set_tris_e( TRIS_E_VALUE );
#PIN_SELECT TX2=PIN_B2
#PIN_SELECT RX2=PIN_B3
#use rs232 (BAUD=9600,RCV=PIN_B3,XMIT=PIN_B2,STREAM=bt, ERRORS)
#PIN_SELECT RX1=PIN_C7
#PIN_SELECT TX1=PIN_C6
#use rs232 (BAUD=9600,RCV=PIN_C7,XMIT=PIN_C6,STREAM=gi, ERRORS)
//enable_interrupts( INT_RDA ); // disable interrupts so incoming data will cause uart overflow
//enable_interrupts( GLOBAL );
int error,temp_data;
error = U1ERRIR;
fprintf(bt," \r\n Error before GPS on = %u \r\n",error); // check error before data comes in (result 128 or b10000000)
GPS_power_switch = true; // turn on GPS for 2 sec to get NMEA data
delay_ms(2000);
GPS_power_switch = false; // turn off GPS to stop incoming data
error = U1ERRIR;
fprintf(bt," Error after GPS on = %u \r\n",error); // check error before data comes in (result 130 or b10000010)
RXEN1 = 0; // disable uart1
temp_data=U1RXB; // Read UART
temp_data=U1RXB; // Read UART
temp_data=U1RXB; // Read UART
RXEN1 = 1; // enable uart1
error = U1ERRIR;
fprintf(bt," Error after clearing FIFO = %u \r\n",error); // check error after clearing and result is still 130 or b10000010
while(1){}
}//end main |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Wed Dec 04, 2019 1:20 am |
|
|
On a normal UART, the error bits are in the RXSTA register. It is these
that 'ERRORS' handles.
On your chip the UART instead generates an _interrupt_ on overflow,
This generates an overrun interrupt. This can be cleared using
clear_interrupt.
Or you can have an overrun error interrupt handler. It this is called
the handler will clear the interrupt.
However understand you cannot clear the interrupt while the UART
buffer is overflowed, So you have to read at least one byte before the
interrupt can be cleared. |
|
|
srtgumbee
Joined: 15 Dec 2018 Posts: 5
|
|
Posted: Wed Dec 04, 2019 4:36 pm |
|
|
Thank you very much! I did not realize that 'ERRORS' only uses the RXSTA register.
On the 18F47K42 if an error has been seen in the #INT_RDA then disabling the UART, reading the UART, clearing the interrupt flag in the U1ERRIE register and enabling the UART has fixed my problem of the UART locking up. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Thu Dec 05, 2019 12:30 am |
|
|
Good. Glad to help. |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Thu Dec 05, 2019 3:38 pm |
|
|
Hi All,
Does this unique UART behavior exist in the 18F44K22 as well?
I ask because I too am having occasional lock-ups of the UART that seem to to be unresolved with the use of the 'errors' directive in the #use rs232 statement.
The lockups occurs very rarely - every few weeks at most - but when I disable serial reception from the GPS in the code they stop all together.
While I generally understand the concept of resolving this potential issue, I'm not at all sure of the actual mechanics. Do I need to simply execute a 'clear_interrupt(int_rda);' instruction after retrieving each character? Doesn't the interrupt handler do this already? Can I define a 'handler' where the code will branch when an overflow is encountered? Or, do I simple need to test a particular register inside int_rda??
BTW, I'm using all 'built-in' CCS serial functions, while the OP seems to be 'rolling his own'.....
Thanks,
Jack |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Thu Dec 05, 2019 4:01 pm |
|
|
re:
Quote: |
The lockups occurs very rarely - every few weeks at most - but when I disable serial reception from the GPS in the code they stop all together. |
So you've run your 'disabledGPS' code for several weeks fine ? Disabled, how? Cut the etch between TXD and RXD ? or software? IF software, does the GPS and PIC still do everything except serial communications ?
Whenever I read 'random' acts of lockup I first think of a hardware issue. Nearby EMI, local cell phone, neighbours welder, etc.
This kind of stuff requires a 'timestamp' of the failure.
In one case, my remote energy system would ONLY fail, between 3 and 4 AM on sundays. We finally traced it to 'crosstalk' on a 100 pair cable we leased. The 'crosstalk' was a bank computer being updated.
The key point is you need to somehow find out WHEN the failure occours.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Thu Dec 05, 2019 11:26 pm |
|
|
The receive interrupt handler clears the receive interrupt.
It is the receive overflow interrupt that has to be cleared if an overflow
has occurred (unless you have a separate overflow interrupt handler).
This applies to all chips that have an overflow interrupt.
In fact there is an error in the way CCS are handling this.
If you execute 'clear_interrupt(INT_U1E);' which is the code to clear the
'ERROR' interrupt, it attempts to clear the U1E bit. However the data sheet
says this bit is 'read only', and can only be cleared by clearing the bits in the
U1ERR register. So currently you need to be clearing these bits yourself.
I have reported this to CCS, so hopefully the next compiler update will
correct this. |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Fri Dec 06, 2019 3:31 pm |
|
|
Hi All,
The 18F44K22 datasheet says this about UART overrun error:
Quote: | 16.1.2.6 Receive Overrun Error
The receive FIFO buffer can hold two characters. An
overrun error will be generated if a third character, in its
entirety, is received before the FIFO is accessed. When
this happens the OERR bit of the RCSTAx register is
set. The characters already in the FIFO buffer can be
read but no additional characters will be received until
the error is cleared. The error must be cleared by either
clearing the CREN bit of the RCSTAx register or by
resetting the EUSART by clearing the SPEN bit of the
RCSTAx register.
|
So, I added this to the top of my code:
Code: | //-----< UART1 Registers/Control Bits >-----
//When an overflow occures on UART1, bit 1 (OERR) of the RCSTA1 status register is set. To clear
//the overflow, bit 4 (CREN) of this status register must be cleared.
#byte RCSTA1_reg = getenv("SFR:RCSTA1")
#bit OERR_bit=RCSTA1_reg.1
#bit CREN_bit=RCSTA1_reg.4
|
I then have this code to test for an overflow, and clear the error:
Code: |
//Here we test for an overflow of UART1. If the UART has overflowed, then the OERR bit will be set in the RCSTA1 register. If this bit
//is set, then we need to clear it by clearing the CREN bit in the RCSTA1 register.
if (OERR_bit) //a UART1 overflow has occured...
CREN_bit = False;
|
At the moment, I'm just not 100% sure where I need to place this code? Does it go in my main while() loop that sits there fetching characters from the circular Rx buffer, or does it go in the #int rda interrupt handler?
When an Rx overflow occurs, I assume that means the PIC is still running, but no longer servicing the Rx interrupt, correct? So, I guess that means it needs to be outside the ISR?
Am I on the 'right' track here?
Thanks,
Jack |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Fri Dec 06, 2019 11:23 pm |
|
|
ERRORS does that.
It does it when you read the character.
It is only chips that don't have the OERR bits like this that ERRORS
doesn't handle.
The RDA interrupt is set when the overrun occurs.
The UART is locked when the error bit sets.
You have to clear CREN, the set it again or the UART doesn't restart. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|