none
Received incorrect two bytes in serial communication RRS feed

  • Question

  • I have a simple loop back setting of transmitting from portA to PortB, then Port B back to port A. The program doesn't use event detection, but rely on the known timing it takes from one port to the other. The configuration works well 99.99%, but occasionally it sees two incorrect first two bytes. A bit more details and questions:

    - The 16-byte transmit and receive FIFOs in the 16C550 are they enabled or disabled by default in window? The manufacture of the chip default is off, but I see some documentation that it is on in window? If it is on, what is the default trigger level on receive FIFO?

    - I'm using Visual Studio 2008. The transfer byte is 18-byte long at 19200bits/sec. The wait between write on one port and read from the other port is 15ms.

    - The program runs on win7. The same program on XP has bigger problem. It has to receive twice for each transfer as the first read/receive doesn't get full 18-bytes.

    Wednesday, September 12, 2012 3:25 PM

All replies

  • Microsoft doesn't know how to impliment the 16C550 hardware interupt.  I've been having this problem since I tried to read a 80C50 on a first generation PC (8086) using XBasic.  Don't laugh.  It is true.  I'm an expert with UARTs and programming them on PC since the beginning of time.

    Most people write their own driver to read and write UART because the drivers in windows use buffering instead of hardware interupts.  The buffering is runs off the PC timer tick and at high transfer rates may not get back to read data quick enough because of other processes running on the PC.

    Are you using hardware or software controls?  Enabling hardware control on the interface will allow the UART to stop data before an overflow occurs.  You may want to read the overflow bit in the uart to help determine if the problem is in the Uart itself or other buffers in the Net Library (actually part of windows) the is dropping the data.  I've seen problems in windows that occured after the data was read out of the UART.


    jdweng

    Wednesday, September 12, 2012 9:32 PM
  • Thank you so much for the reply.

    I'm using two serial COM ports off Syba's SD-PCI-4S card which uses standard ST16C550 UART chip. I think I'm using the driver in the window 7. I tried to find more documentation off the web on Window's driver on IO board. If you know any that may also help

    Thanks.

    Thursday, September 13, 2012 3:35 PM
  • "Enabling hardware control on the interface will allow the UART to stop data before an overflow occurs."

    No, it will not - simply because 16C550 does not have any hardware flow control (except for UART's from Texas Instruments).

    The so called hardware flow control actually takes place in software, which may be too slow! When CTS goes low, the transmitter will transmit all 16 bytes in the FIFO plus any additional bytes loaded until the software stops loading.

    If you want to use hardware flow control, you need a better UART. I have tried 16C950, but all types from 16C650 to 16C950 will do. You can also use an EXAR USB-serial converter such as XR21B1411. With that converter I have used SerialPort to 5 Mbit/s (!) and it has the very great advantage that it has a wide-mode where 2 bytes are transferred for every byte received so that the status flags are not lost. Microsoft is so "clever" to take 11 bits from the UART, use the 3 status bits to fire events and then throw these important bits away before the result is stored in a 16-bit stream, which could easily have contained all 11 bits! I agree with Joel. The implementation is horrible, but this is obviously the best the worlds biggest software company is able to do.

    Why do you use a timer driven system? It is much better to make it event driven.

     


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Thursday, September 13, 2012 3:58 PM
  • My boss used to call these devices "The UARTs from hell" because it took a Phd in UARTS to get them working properly.  The part has two UARTs with a common clock divider circuit.  We were using on UART at 9600 Async to operate a modem (1980's) and the second one at 16K sync.  Two different software engineers were involved.  One would change the configuration to get their code working and would break the other engineers code.  This went on for over 6 months.  Finally I fiured out what was wrong.  I had to add a wire from one pin of the device to another to bring out an route an internal clock to the external clock input clock pin. It was impossible to get both UARTs working at the same time using the internal connections.

    jdweng

    Thursday, September 13, 2012 5:01 PM
  • Thank you both for the responses!

    I tried the Xon/Xoff and it's not working. I inherited the code which is a test code and performance is not a concern at the moment, so the flow control wasn't implemented, and instead a timer is used to ensure sufficient time has passed before receive. The issue came when readfile() occasionally misread two bytes which seems to match the fact that I'm transmitting 18 bytes and the 16C550 has only a 16 byte FIFO. But I'm not able to pinpoint a solution. I don't have hardware flow control as RTS/CTS are not used, and Xon/Xoff is not working. It completed missed the transmission. Each receive only got 17 bytes as opposed to 18 bytes I used to get without the flow control (except the occasional errors).

    Friday, September 14, 2012 6:52 PM
  • Can any one comment on what the relationship between the XOnLim/XOffLim and the UART FIFO size? When people talk about flow control using XOn/XOff, the input buffer/receive buffer is the UART FIFO or something inside PC that the driver allocates?

    In general I'm not clear how readfile() reads from the UART. When receive FIFO reaches the trigger level, and before CPU issues readfile(), where is the receive data transferred to, and how does CPU know how many bytes to transfer?

    Thanks you so much for the help in advance.

    Friday, September 14, 2012 7:52 PM
  • Can you verify the underflow and overflow bytes in the UART.  If you are not getting these errors then the problem is some where else.

    jdweng

    Friday, September 14, 2012 8:50 PM
  • That makes sense. I stopped the program (in Visual Studio) when error is detected. How to access the UART? Do I need to write code to dump the status out pr it can be viewed in the debug window? Thank you very much in advance as I realize this must have been very basic.
    Friday, September 14, 2012 9:55 PM
  • Which bytes do you lose - the first ones, the last ones or some in the middle - and do you always lose the same bytes?


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Saturday, September 15, 2012 8:13 AM
  • Sorry for the delay!

    It's always the first two bytes that are corrupted. I transferred a fixed 18 bytes, and only the first two bytes are wrong. Sometimes I noticed the first byte happen to have the value as the last byte. It could be from the last transfer or this transfer as packets are the same.

    Tuesday, September 18, 2012 6:29 PM
  • Try adding two stop bits for the transmiter and see if that fixes the problem.

    jdweng

    Tuesday, September 18, 2012 6:33 PM
  • Newsoft10

    Is your receive also timed? In that case, make it event driven. Generally it is a very bad idea to make a communication timing driven.

    It seems that you have some kind of buffer overrun. For example you may not have emptied the receive buffer before a new telegram is received.

    "It could be from the last transfer or this transfer as packets are the same."

    Why don't you find out? It cannot be that difficult to use 18 different bytes.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Wednesday, September 19, 2012 11:17 AM
  • The UART in the PC have buffers and with only 18 bytes being sent I don't think the problem has to do with buffer over run and under run unless.  Even though RTS/CTS are not used they must be tied properly.  the RTS isn't important but the CTS must be set to the active position for the UAR to be able to send data.

    jdweng

    Wednesday, September 19, 2012 11:25 AM
  • Thanks you both for the reply. I'm trying these suggestions.
    Wednesday, September 19, 2012 1:59 PM
  • First tried two STOP bits. It improved the error rate, but not completed eliminated it.

    One thing I did earlier is to make the packets different. I was investigating if the two incorrect bytes are coming from previous packet or current packet, and I found the same packet runs may be masking out some other errors. With different packet, more bytes come to be incorrect. Understand it's not an apple to apple comparison now, but I feel using different packets exposes more problem than the same packet.

    With two STOP bits, it's seeing 11 bytes when transmitting 10 bytes/ The 11 received bytes do not resemble in any way the transmitted bytes.

    Both RTS and CTS on the DB9 port is open (not driven). Below is the connection sletch:

    PC Port1 TX ==> PC Port2 RX

    PC Port1 RX <== PC Port2 TX

    PC Port1 GND == PC Port2 GND

    All rest pins are not connected/not driven.

    Wednesday, September 19, 2012 3:39 PM
  • @ Newsoft10

    If 2 stop bits can improve the situation, it is quite obvious that your receiver cannot keep the pace.

    Try to transmit only 16 bytes and see if everything works. If it is OK, try to make a long delay between loading the first 16 bytes and the next 2. If it still works, it is an overrun in the receiver FIFO.

    Show us some code - especially on the receiver side.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Wednesday, September 19, 2012 6:19 PM
  • Thanks for the response.

    Here is the main loop that does the transmit and receive on both ports. The latest code transmit packet size of 10-byte. It also transmits different byte each time. Even with 10 byte message, it still receives incorrect bytes some time.

    void TestTask::doTestBatch(void) {

        BYTE rxBuf[100];

    BYTE rxBuf2[100];

        int portNums[2];

        HANDLE portHandles[2];

    int i;

     

        portNums[0] = GUI->GetPort(0);

        portNums[1] = GUI->GetPort(1);

     

        portHandles[0] = ComPort_Open(portNums[0], 19200, SPACEPARITY);

     

        if(!ComPort_ValidPort(portHandles[0])) {

            haltTest(TEST_STOPPED, "could not open portA");

            return;

        }

     

        portHandles[1] = ComPort_Open(portNums[1], 19200, SPACEPARITY);

     

        if(!ComPort_ValidPort(portHandles[1])) {

            ComPort_Close(portHandles[0]);

     

            haltTest(TEST_STOPPED, "could not open portB");

            return;

        }

     

    for (i=0; i<sizeof(testSequence); i++){

    testSequence[i] = MsgCount[0] + i;

    }

     

        for(size_t portIdx = 0; portIdx < 2; portIdx++) {

    bool errorfound = false;

     

            ComPort_Write(portHandles[portIdx], testSequence, sizeof(testSequence));

    improvedSleep(15);

     

            unsigned int rxLen = ComPort_Read(portHandles[1 - portIdx], rxBuf, sizeof(rxBuf));

    unsigned int rxLen2 = 0;

     

    if (rxLen < sizeof(testSequence)) {

    //improvedSleep(100);

    improvedSleep(10);

    rxLen2 = ComPort_Read(portHandles[1 - portIdx], rxBuf2, sizeof(rxBuf2));

    memcpy(&rxBuf[rxLen], rxBuf2, rxLen2);

    rxLen += rxLen2;

    MsgRepeatErrors[portIdx]++;

    }

            MsgCount[portIdx]++;

     

            if(rxLen <= 0) {

                MsgNotRxedErrors[portIdx]++;

    errorfound = true;

            }

            else if(rxLen < sizeof(testSequence)) {

    MsgTooShortErrors[portIdx]++;

    errorfound = true;

            }

            else if(rxLen > sizeof(testSequence)) {

                MsgTooLongErrors[portIdx]++;

    errorfound = true;

            }

            else if(memcmp(testSequence, rxBuf, sizeof(testSequence))) {

    if (memcmp(testSequence+2, rxBuf+2, sizeof(testSequence)-2)) {

    MsgCorruptedErrors[portIdx]++;

    errorfound = true;

    }

    else {

    // Known PC behavior where the first two bytes tend to be corrupted.

    // Allow this for now.

    MsgTwoByteCorrupted[portIdx]++;

    errorfound = true;

    }

            }

     

    if (errorfound && (GUI->TestInfo.GetHaltOnError() == HALT_ON_ERROR)) {

    GUI->TestInfo.ChangeHaltOnError(HALT_ERROR_FOUND);

    GUI->TestInfo.SetDesiredTestStatus(TEST_PAUSED);

    ErrorBufPort = 1 - portIdx;

    ErrorBufCount = rxLen;

    for (size_t i = 0; i < sizeof(ErrorBuf); i++) {

    if (i < (size_t)rxLen)

    ErrorBuf[i] = rxBuf[i];

    else

    rxBuf[i] = 0x12;

    }

    break;

    }

    else {

    ErrorBufPort = -1;

    ErrorBufCount = -1;

    }

     

    improvedSleep(50);

        }

     

        LastMeasurementTime = time(NULL);

     

        ComPort_Close(portHandles[0]);

        ComPort_Close(portHandles[1]);

     

        updateTestDataListBox();

    }


    Thursday, September 20, 2012 6:21 PM
  • Why do you make a 15 mS delay between write and read (improvedSleep(15))?

    At 19200 bit/s and 1 stop bit it takes 0.52 mS to transmit 1 byte and therefore 9.37 mS for 18 bytes, so when you call ComPort_Read, all bytes are already transmitted. Because the receiver FIFO in a 16C550 UART is only 16 bytes long, you will (always) lose two bytes. You cannot benefit from the receive buffer in SerialPort before you call a read method.

    I simply don't understand why you don't want to make an event driven receiver. If you do that, the receiver FIFO in the UART shall just be able to buffer all bytes until the receiver interrupt is handled, which typical takes approximately 1 ms. Therefore, you will be able to use the port up to 115.2 kbit/s.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Thursday, September 20, 2012 8:20 PM
  • Thanks for the response.

    I do plan to try out the event driven. A few clarifications regarding your observations:

    1). This is puzzling. When I transmit 18 bytes, the code does not ALWAYS lose two bytes. In fact, the receive error rate is is less than 0.1%.

    2). I also tried to transmit only 10 bytes. I'm seeing similar error rate.

    Looks to me the UART driver has some intelligence when receiving data. It provided the data when the FIFO is about full, and was able to receive the next two bytes most of the time.

    Thursday, September 20, 2012 8:53 PM