View previous topic :: View next topic |
Author |
Message |
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
PCD (PIC24F) UART receive ISR question |
Posted: Sat Mar 12, 2016 4:28 pm |
|
|
Hi guys.
Is this an effective way to handle the 4 deep FIFO receive data buffer ISR on a PIC24F? I know about URXISL <1:0>but even set to 00 more than one byte can be in the receive buffer (I believe.) PCD compiler version is 5.027 and my PIC is a 24FJ256GA106.
Thank you!
Code: | #use rs232(uart4,stream=bluetooth_stream,baud=19200,parity=n,bits=8,rcv=serin_rn4020,xmit=serout_rn4020,errors)
#int_rda4 // Receive Data Available (UART #4)
void serial_ISR_RN4020()
{
byte c;
// the PIC24F may have up to 4 bytes in the UART buffer
do
{
c = fgetc( bluetooth_stream );
// rest of code...
}
while ( kbhit( bluetooth_stream ) );
} // serial_isr() |
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Mar 12, 2016 4:55 pm |
|
|
so long as you are OK with variable C having only the LAST char of up to 4 chars received - it's fine - but otherwise it kinda sucks - losing so many possible chars
BUT that said -
if the ISR was not called until the FIFO was full - the code would be an even bigger disaster. read the example EX_SISR in the ccs driver folder
to see how to handle the data correctly on receive.
SERIOUSLY even with the glaring flaw in your code
so long as you save c somewhere FAST and prevent its over write -
you might squeak by because of this in the data sheet--
its about the timing of when the data_available ISR flag is set
Quote: |
A receive interrupt will be generated when one
or more data characters have been received, as
per interrupt control bit, URXISELx.
4. Read the OERR bit to determine if an overrun |
|
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Sat Mar 12, 2016 9:55 pm |
|
|
Thanks the quick reply asmboy. I completely understand what you are saying and trust me I've never pulled more than one char at a time from int_rda in my PIC18F products but the way I interpret the dsPIC33/PIC24 Family Reference Manual "If URXISEL<1:0> = 00 or 01, an interrupt is generated each time a data word is transferred from the UARTx Receive Shift Register (UxRSR) to the receive buffer. THERE MAY BE ONE OR MORE CHARACTERS IN THE RECEIVE BUFFER." I am indeed seeing more than one character is in the UART buffer sometimes when the ISR fires which is the reason for the do while. It appears when I don't process the extra characters then the int_rda does not fire again for them. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Sun Mar 13, 2016 5:46 pm |
|
|
Thanks PCM programmer for the link. It looks like I'm handing the ISR correctly. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Mar 14, 2016 4:41 am |
|
|
Except possibly how much time you might be spending in the code after reading the byte. If you start doing too much here, then things could get messy...
Also (of course) how the interrupt is configured. Remember that if you set it to only interrupt when four bytes have been received, then nothing will happen if you get two (for example). Unless the data is certain to be arriving regularly (and even then, what happens if communications get interrupted), you may need to consider having a 'timeout', that triggers the serial interrupt, if the processing code has not been called for a period. |
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Mon Mar 14, 2016 7:51 am |
|
|
Hey Ttelmah thanks to you and everyone for the feedback. I confirmed that the ISR fires after every received byte (this is the default). My ISR code is very quick. All it does is update a rolling buffer and handle the wrap. But to be honest I have a big problem that is VERY strange so I am consolidating the code now to post. In a nutshell the UART ISR is running fine (with the extra code of course to process the extra bytes that may be in the receive buffer). My app is working great but for kicks when I change the main line code to do nothing but an endless loop of eating the rolling received buffer chars and sprintf a float32 into a string then the PIC resets. If I change the sprint to do an int32 then the PIC never resets! And the reset will only occur once serial data starts to come into the UART. No buffer overruns on the sprintf and no watchdog timer is running. I’ll post the code if anyone would be gracious enough to take a quick look and tell me I’m doing something really stupid. Thanks! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Mar 14, 2016 8:11 am |
|
|
Almost certainly stack overflow.
On these later PIC's, the stack is used for temporary storage inside the routines, as well as just for return addresses (the smaller PIC's don't support this). Printing, and things like FP maths can easily overflow the stack.
The real way to diagnose this 'properly', is to test the restart cause, or even more sophisticated generate an error trap on the overflow, and then the return address can be used to find out where in the code it happens. On complex code this can be really helpful.
However I'd be 99% confident on guessing this is the cause, and that you need to enlarge the stack. Actually depends on your compiler version (historically older compilers defaulted to a smaller stack size than the current ones).
Add:
#build (STACK=512)
Just before your fuses. |
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Mon Mar 14, 2016 6:08 pm |
|
|
Ttelmah you were 100% correct that it was a stack overflow issue. The problem went away when I increased the stack size. It’s interesting that one sprintf and a simple UART receive ISR function could cause a 256 byte stack to overflow but you explained why above. Thank you so very much! |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Tue Mar 15, 2016 10:31 am |
|
|
From your earlier post, you were mentioning floats, which are not so trivial. I would guess some included libraries or float routines were related to the stack problem? |
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Tue Mar 15, 2016 1:26 pm |
|
|
Hi jeremiah. I was just doing a sprintf of a float (32 bits) to a string along with some very simple URT ISR receiver code. Increasing the stack from 256 to 512 bytes fixed the problem. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Mar 15, 2016 3:07 pm |
|
|
Printf uses a lot of stack space for floats.
You will find the default was 128 for that compiler version. Look at the top of the list file. |
|
|
Oesterling
Joined: 07 Mar 2016 Posts: 13
|
|
Posted: Tue Mar 15, 2016 8:24 pm |
|
|
Your are correct (again) Ttelmah. My default stack size was only 128 bytes.
I got the 256 byte size idea from the CCS docs: "STACK configures the range (start and end locations) used for the stack, if not specified the compiler uses the last 256 bytes."
I should have looked at the list file.
Thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Mar 16, 2016 1:11 pm |
|
|
Good.
If you think about it, you are calling the printf, then this is calling FP division. Then the whole lot is calling the serial out. Even the integer version nearly uses all the available space, The FP one takes it over the edge. |
|
|
|