|
|
View previous topic :: View next topic |
Author |
Message |
JamesW
Joined: 23 Apr 2007 Posts: 91 Location: Rochester, England
|
[SOLVED] Uart Lagging 4 Characters PIC24FJ64GA202-I/SP RS232 |
Posted: Wed Mar 08, 2017 4:51 am |
|
|
Hi Folks,
I am seeing something really strange on a new project where I am using PIC24FJ64GA202-I/SP.
I am getting a receive interrupt on every character, however the character that is retrieved from uart is lagging 4 characters from what is entered.
For example if I send 12345 from power up, the data I receive on my VT100 terminal is (code below, the NI and NO are positions of the head and tail of the buffer in the isr):
NI:0 NO:0
NI:0 NO:0
NI:0 NO:0
[00]0 NO:0
[00]1 NO:1
ΓΏ[ff] NO:2
1[31] NO:3
NI:4 NO:4
NI:4 NO:4
NI:4 NO:4
So on the first character when I press '1', the ISR obtains a 0x00 from the uart, when I press '2' I also get 0x00, when I press '3' I get 0xFF, when I press '4' I get the '1' and so forth. Every incoming character from that point, returns the character that entered the uart 3 characters previously.
I know this PIC has a 4 byte FIFO, and it almost seems like that this is being used, but not handled by the normal CCS RS232 code.
Can anyone point me in the right direction of what I am missing please?
I have defined the uart as normal with :
Code: |
/* UART DEFINITIONS - DEBUG */
#pin_select U2TX=PIN_B1
#pin_select U2RX=PIN_B14
#use rs232(UART2, baud=38400, errors, stream=DEBUG_PORT)
|
My ISR is pretty much the CCS example of how to handle serial interrupts (which I've used for years and years without a problem).
Code: |
void DRV_VT100_UartInt()
{
UI_8 t;
DEBUG_buffer[DEBUG_next_in]=fgetc(DEBUG_PORT);
t = DEBUG_next_in;
if (++DEBUG_next_in == DEBUG_BUFFER_SIZE)
{
DEBUG_next_in = 0;
}
if(DEBUG_next_in==DEBUG_next_out)
{
/* BUFFER FULL */
DEBUG_next_in=t;
}
}
|
And my main loop has been cut down to the absolute minimum, just to try and resolve this
Code: |
while (TRUE)
{
LoopCount++;
if (LoopCount >= 70000)
{
fprintf(DEBUG_PORT, "\r NI:%u NO:%u", DEBUG_next_in, DEBUG_next_out);
LoopCount= 0;
}
if (_DEBUG_kbhit)
{
/* READ IN THE SENT BYTE AND SAVE IT IN THE BUFFER */
NewChar = Debug_bgetc();
ConsoleGotoXY(1,25);
fprintf(DEBUG_PORT,"%c[%02x]",NewChar,NewChar);
}
}
|
Any suggestions would be gratefully received.
Thanks
James
Last edited by JamesW on Wed Mar 08, 2017 9:38 am; edited 1 time in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Mar 08, 2017 6:09 am |
|
|
Sure sounds like a 'buffer' problem but I don't use that PIC..sigh too mny PICs ,too little time.
What REALLY impresses me is that you've got a working VT100 terminal !! I used to fix them in my 'day job',40 YEARS ago...like 2/3rds of my lifetime.
Sad thing is I got rid of all my DEC stuff 2 decades ago....kinda wish I'd kept the ASR33 though.
Jay |
|
|
JamesW
Joined: 23 Apr 2007 Posts: 91 Location: Rochester, England
|
|
Posted: Wed Mar 08, 2017 6:12 am |
|
|
Well - hyperterminal in VT100 mode actually.
It still has its place, and is incredibly useful debugging, displaying, and changing stuff cheaply when you don't have a display.
Cheers
James |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Mar 08, 2017 9:11 am |
|
|
Add the following to the interrupt handler:
Code: |
void DRV_VT100_UartInt(void)
{
UI_8 t;
do
{
DEBUG_buffer[DEBUG_next_in]=fgetc(DEBUG_PORT);
t = DEBUG_next_in;
if (++DEBUG_next_in == DEBUG_BUFFER_SIZE)
{
DEBUG_next_in = 0;
}
if(DEBUG_next_in==DEBUG_next_out)
{
/* BUFFER FULL */
DEBUG_next_in=t;
}
} while (kbhit(DEBUG_PORT));
}
|
What is happening is that the UART is receiving some zeros as garbage during the boot. So has four zeros in it's hardware buffer, when you start the interrupt. Each time you get an interrupt, since you only retrieve one character, you never catch up at all.
So it interrupts straight away when you enable it, and you then get a zero. A character arrives, triggering the interrupt again, but you then retrieve the 'old' zero that is already there. etc. etc..
On PIC's with larger buffers it is always worth looping if there is more than one character waiting (as shown). The other thing to do is to flush the buffer before enabling the interrupt. So:
Code: |
while (kbhit(DEBUG_PORT))
dummy=fgetc(DEBUG_PORT);
clear_interrupts(INT_RDAxxxx); //for this UART
enable_interrupts(INT_RDAxxxx);
|
This is worth doing even on standard PIC's, where it is common to find one garbage character on boot. |
|
|
JamesW
Joined: 23 Apr 2007 Posts: 91 Location: Rochester, England
|
|
Posted: Wed Mar 08, 2017 9:37 am |
|
|
Problem solved.
We thought that was what it must be what the problem was, but couldn't see any mention in the help files as to how uarts with FIFO's need to be handled.
So that's how you clear the buffer!
Thanks for that - it had us completely stumped, we were hunting through the datasheet looking for a register setting we could check.
Crate of virtual internet beer heading your way!
James |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Mar 08, 2017 11:46 am |
|
|
It has been mentioned here before, but not for quite a while. Unfortunately the CCS examples don't really cover this.
Glad you have it sorted. Also more efficient anyway, if something delays the serial ISR being serviced, it'll now grab all characters that are waiting. |
|
|
|
|
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
|