View previous topic :: View next topic |
Author |
Message |
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
RS232 missing characters |
Posted: Thu Oct 12, 2017 3:14 am |
|
|
I am working on a motor controller using a PIC24EP256MC204.
The controller uses I2C to communicate with another board, SPI for the control of local ADCs and UART via an FDTI UART to USB chip (FT232RL) to communicate with a PC.
We are seeing problems with occasional missing characters on the USB connection. I originally thought that this was a scheduling/interrupt problem between the various buses, however, if I distil the problem down to a single bus it still happens.
The attached code basically fills the buffer with ‘This is data %counter%’ where counter is a 16 bit value that increments after every write. When the buffer exceeds 50% full, the programme writes the buffer level and allows the buffer to empty to below 10 characters using delays. The buffer then starts to fill again.
The missing characters seem occur in the first 40 characters after the buffer starts to refill. The position of the error is not constant and sometimes two individual characters are missed, but not contiguous characters.
The output below is typical.
This is data 19013
This is data 19014
This is data 19015
Buffer full 19016 520
This is data 1016
This is data 19017
This is data 19018
Anyone any ideas?
Code: |
#include <24EP256MC204.h>
#FUSES NOWDT
#fuses XT
#FUSES NOJTAG //JTAG disabled
#FUSES NOALTI2C1 //I2C1 mapped to SDA1/SCL1 pins
#fuses PR_PLL
#FUSES PLLWAIT
#fuses ICSP1 //Clock switch to PLL will wait until the PLL lock signal is valid
#FUSES IESO //Internal External Switch Over mode enabled
#include <float.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#use delay(clock=80000000)
#pin_select U1RX=PIN_B12 //ccs needs this to force use of the hardware uart
#pin_select U1TX=PIN_B11
#use rs232( UART1, baud=460800, RECEIVE_BUFFER=1024, TRANSMIT_BUFFER=1024,stream=RS232, TXISR)
//#use spi(MASTER, force_HW, SPI1,baud=100000, BITS=32, stream=ADS)
//#use i2c(SLAVE, I2C1,ADDRESS=0x10,STREAM=i2ccomms,FORCE_HW)
#word osccon=0x0742
#word clkdiv=0x0744
#word plldiv=0x0746
int16 nnn;
void main (void)
{
osccon=0x3000;
clkdiv=0x0000; //PLLPRE and PLLPOST=0
plldiv=0x003E;//003E+2=0x40 or 64 Fosc=5*64/4Mhz=80MHz
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1, 0);
setup_timer4(TMR_INTERNAL | TMR_DIV_BY_1, 50000);//1ms timer
while(TRUE)
{
fprintf(rs232, "This is data %lu \n\r",nnn);
nnn++;
if (tx_buffer_bytes()>512)
{
fprintf(rs232, "Buffer full %lu %lu\n\r", nnn, tx_buffer_bytes());
while (tx_buffer_bytes()>=10)
{
delay_ms(1);
}
}
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Thu Oct 12, 2017 5:33 am |
|
|
It might not be PIC problem, rather the PC !
What's running on the PC? Which OS, How many 'in the background ' programs are running (like ap updates)? How is the USB driver configured for the link to the PIC? What 'terminal program' is being used ? There's dozens of reasons why the PC side will display 'bad' or 'random' data.
For test purposes, grab an old PC, format a small hard drive, install W98 and use a terminal program. Be sure NOTHING else is running or installed except USBView. That's nice to see how the USB link is configured. I've seen some real head pulling problems that were caused by the PC side of the wires.
Jay |
|
|
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Oct 12, 2017 5:47 am |
|
|
That is a fair point. I have tried 2 different PCs with Hyperterm, Teraterm and an in house terminal emulator and they all see the same.
I am going to splice into the UART output with a signal analyser and write some code to trigger a capture of the last few milliseconds of data when an unexpected character is received. That should give better insight into what is going on |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Thu Oct 12, 2017 6:00 am |
|
|
I saw your baudrate is, well, pretty darn fast, but one option may be to program a 2nd PIC with a VGA interface (for speed). Use this to receive the data and display on a monitor. Poor man's analyzer.
Obviously an LCD module ain't going to work....way too slow.
I had 'some program' on a PC change the USB power settings mysteriously over a weekend. That killed the USB<>PIC communications (aka garbage). For 5 days it'd worked flawlessly. Hmm, I can only assume it was some 'auto update' to some program and for some reason edited the USB power register in thedriver. I never did waste more time on that, reformatted the HD, installed a true minimal system (no internet access, etc.) and my new 'test PC' has run fine for 2-3 years. 'Windows' is a mystery...case in point Win7 'locks' the PS2 mouse from my KVM that goes through a PS2> USB dongle. Randomly of course.
This is why you have to consider the PC side of the wire.
Jay |
|
|
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
|
Posted: Thu Oct 12, 2017 7:40 am |
|
|
Yeah, the baud rate is high. Reducing it even to 4k doesn't eliminate the problem, but does make it less frequent. Unfortunately, I have a lot of stuff going on with this card so I need the fast clock and baud rate. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Thu Oct 12, 2017 11:08 am |
|
|
You need to be using flow control.
Problem is that USB does not guarantee a data rate. It depends on the rate at which Windows polls the hardware, and what else is happening on the bus. From the FTDI knowledgebase:
Quote: |
It is strongly encouraged that flow control is used because it is impossible to ensure that the FTDI driver will always be scheduled. The chip can buffer up to 384 bytes of data. Windows can 'starve' the driver program of time if it is doing other things. The most obvious example of this is moving an application around the screen with the mouse by grabbing its task bar. This will result in a lot of graphics activity and data loss will occur if receiving data at 115200 baud (as an example) with no handshaking. If the data rate is low or data loss is acceptable then flow control may be omitted.
|
Given they are talking about this happening at only 1/4 the rate you are dealing with, you really do need to have flow control.... |
|
|
turpin62
Joined: 19 Mar 2008 Posts: 11 Location: UK
|
Update |
Posted: Tue Oct 17, 2017 9:26 am |
|
|
OK so I set up two laptops one monitoring the PIC UART and one monitoring the RS232 output from the FDTI serial port
This is data 3651
This is data3652
his is data 3653
This is data 3654
RS232 via FDTI
This is data 3651
This is data3652
his is data 3653
This is data 3654
TTL from PIC UART
I also changed the while loop in the original programme to the below as I wondered if reading the buffer size was having an effect. The 10 data are at worse 200 bytes or 1800 bits (8 data 1 stop). They should clear the buffer in 3.9ms hence the delay.
The fact that the same error is seen on both streams must mean it is a compiler/chip issue, unless anyone has any other ideas!
Code: |
while(TRUE)
{
for (loop=0; loop<=9; loop++)
{
fprintf(rs232, "This is data %lu \n\r",nnn);
nnn++;
}
delay_ms(4);
}
|
|
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Tue Oct 17, 2017 12:41 pm |
|
|
Out of curiosity, have you tried using the supplied example Transmit ISR buffer instead of the one used by the #use RS232() call?
It's in the examples folder located in your install directory. I forget the exact name. I remember the receive buffer example was ex_sisr.c. The transmit one had a similar name but I forget the exact name.
EDIT: based on forum searching, it sounds like the file is named
ex_stisr.c
I would be curious to see if you get the same issue using a manually managed serial buffer versus the compiler supplied one. The compiler supplied ones have various problems (like when they fill, the buffer is flagged as empty), so the ones from the example files are generally better. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Tue Oct 17, 2017 2:02 pm |
|
|
It'd be nice if you could grab a PC with W98 and REAL RS232 comports and run your test. I never, ever had any problems sending data at 115K200 to that system config.
USB is a nightmare...bloated and NOT interrupt driven. Any OS after W98 and you lose DIRECT access to the comports. Sigh, another 'layer' of code to deal with, with 'something' altering 'things' at every layer.
You should (will?) get better PC performance if you can cut Delphi code. It's 'self contained' so it doesn't use any Win DLLs, etc. Perhaps that can be an option ??
Guess I'm getting(?) old and cranky but it was a lot more fun 20 years ago....
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 17, 2017 6:09 pm |
|
|
Quote: | #use rs232( UART1, baud=460800, RECEIVE_BUFFER=1024, TRANSMIT_BUFFER=1024,stream=RS232, TXISR) |
My first thought is the same as Jeremiah's. Get rid of the CCS buffer stuff.
That's the first thing I would suspect.
Also there is this errata:
http://ww1.microchip.com/downloads/en/DeviceDoc/80000533M.pdf
Quote: |
5.Module:UART
When using UTXISEL<1:0> = 01 (interrupt when last character is shifted
out of the Transmit Shift Register) and the final character is being shifted
out through the Transmit Shift Register (TSR), the Transmit (TX) interrupt
may occur before the final bit is shifted out.
Work around
If it is critical that the interrupt processing occurs only when all transmit
operations are complete. Hold off the interrupt routine processing by
adding a loop at the beginning of the routine that polls the Transmit Shift
Register Empty bit (TRMT) before processing the rest of the interrupt.
Affected Families and Silicon Revisions:
dsPIC33/PIC24EP256 devices
A3, A8, A9 |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Oct 18, 2017 1:09 am |
|
|
If you are using the CCS buffer stuff, you need to make sure there is space in the buffer _before_ trying to send. You need 'tx_buffer_available' to be at least one characters more than the data you are going to send.
The transmit buffer will silently drop characters if you overflow.
Look at the example for this in the manual. |
|
|
|