Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mbed serial readable() seeing all bytes #343

Closed
TravisJoe opened this issue Jun 3, 2014 · 18 comments
Closed

mbed serial readable() seeing all bytes #343

TravisJoe opened this issue Jun 3, 2014 · 18 comments

Comments

@TravisJoe
Copy link

Hello,

I have used mbed on and off for several years without having any issues with the serial port. Recently I started using a IC that has a UART output (Silabs si8900).When powered has an auto baud function that happens were you send a single byte until it can match the baud and send a single byte response . I have no trouble receiving and reading the single character during auto baud, only when I try to read the 3 byte response during normal use does it appear to not read the 2nd and 3rd byte.

Below is an image showing what is going on.

The top section of code shows my read statement which picks bytes from the buffer while readable() returns 1. The 3 byte response comes after I send a request byte, which is not shown.

The middle section shows the values during debugging which shows I read the first byte but shows no values stored in the other bytes due to readable() returning 0.

The third section is the logic analyzer output showing the 3 byte response.

readlineissue

The only thing I can think of is there is no delay between bytes and the serial port might see it as a single byte with framing issues. I do not know enough about the serial port library to know what could be causing this issue. It would be helpful if somebody could take a look at this and see if they can find anything.

As a side note, I programmed simple software serial functions but due to how quickly the response is from the IC the timing does not work out well.

Any help would be appreciated.

@TravisJoe
Copy link
Author

Here is a better image showing timing of the sent package and the response. You can see there is almost no time between the two. Also the returning bytes are a continues stream and are barely separated by the start/stop bits.

This is at 57600 baud.

It is frustrating because I see the characters in the logic analyzer and on the scope, but it continues to read only the first byte when checking readable().

screenshot_32

@TravisJoe TravisJoe changed the title mbed serial not seeing all the bytes being mbed serial readable() seeing all bytes Jun 4, 2014
@0xc0170
Copy link
Contributor

0xc0170 commented Jun 5, 2014

Hello TravisJoe,

isn't this hw related issue?
Does it change if you lower baudrate? IF you suspect there can be framing error, does your target have a flag for it?

Would you eliminate the mbed library from the picture and use directly registers in the application to catch those 3 bytes? This might not have any impact as mbed API layer is thin and the code below in serial in this case, it's short, mostly 1/2 lines..

Regards,
0xc0170

@mbednotifications
Copy link

I experienced same problem with Nucleo and CC2530 boards connected trough
UART.
I have tried UART loop on Nucleo board, and the same problem in interrupt
received only 1st byte.
But logic analyzer showed whole packet.

On Thu, Jun 5, 2014 at 10:32 AM, Martin Kojtal notifications@github.com
wrote:

Hello TravisJoe,

isn't this hw related issue?
Does it change if you lower baudrate? IF you suspect there can be framing
error, does your target have a flag for it?

Would you eliminate the mbed library from the picture and use directly
registers in the application to catch those 3 bytes? This might not have
any impact as mbed API layer is thin and the code below in serial in this
case, it's short, mostly 1/2 lines..

Regards,
0xc0170


Reply to this email directly or view it on GitHub
#343 (comment).

You received this message because you are subscribed to the Google Groups
"mbed-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to mbed-devel+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Best regards.
V.Golovanov

@TravisJoe
Copy link
Author

Thanks for both of your comments.

0xc0170,
I will look into using CMSIS, or at least another serial library, to read the port and see if the results change. Hopefully this can point to hardware or to the code. I will also try to jumper another micro to those pins and try to mimic the packet, maybe by bit banging.

mbednotifications??,
In some ways this is comforting to know others have seen my issue... however you did not say you found a solutions so that also makes me worry. Did you ever find a solution or work around?

Thanks

@adamgreen
Copy link
Contributor

Where is your code? In the snippet above from your debugging session I see something like:

while (serial.readable())
    array[i++] = serial.getc();

If you are expecting 3 bytes, then I think you need to call getc() 3 times. There is nothing guaranteeing that readable() will return true right after you read the first byte since the UART may not have received the second byte yet.

@TravisJoe
Copy link
Author

Thanks I will try this. I cannot remember if getc() is blocking until a byte shows up.

Also here is more of my code for reference:

    if(channel == 2){
            sendADCSerialChar(ADC_CHANNEL2); 
    }

    //Wait for ADC conversion
    wait_ms(2);

    //Get bytes from ADC
    counter = 0;

    while(serialADC.readable()){
        valueCharArray[counter] = serialADC.getc();
        counter++;
    }

@TravisJoe
Copy link
Author

I am still having a lot of trouble with this. I have tried interrupts, timing and other adjustments and it just seems to not notice the 2nd and 3rd bytes. I have (and many others) used the simple readable() loop to read iterate through characters in the RX buffer. But for some reason I cannot figure out why this is not working.

Because it has worked on other platforms I would think that the issue is in the LPC812 specific portions of the code.

Does anybody have this same issue or could potentially help me look into this more? I will do what I can, but my knowledge of low level code especially on this newer processor is limited.

@TravisJoe
Copy link
Author

I am back at this. I am using a different port and a different way of communicating, but getting the same results.

It seems that readable() is cleared after reading one byte, but when looking at several example of using the serial port and past code I have used it seems that readable() should still return 1 unit the RX buffer is cleared.

Has anybody tried this on their LPC812 devices?

Here is my latest code. I am currently using RawSerial instead of standard serial.

while(serialRS485.readable()){
    receive[counter] = serialRS485.getc();
    counter++;
    if(counter >= RS485_BUFFER_SIZE){
        break;
    }
}

@fritzprix
Copy link
Contributor

Your code should be like
uint32_t idx = 0;
while(idx < buffersize){
while(!serial.readable()); // busy waiting for data available
rxbuf [idx++] = serial.getc();
}

@fritzprix
Copy link
Contributor

it's more safe to insert timeout condition in busy wait loop for more stable system operation
but why serial HAL doesn't use DMA feature or receive buffer which guarantees more efficient io operation?

@0xc0170
Copy link
Contributor

0xc0170 commented Jul 14, 2014

@fritzprix that's what we would like to improve !

@TravisJoe
Copy link
Author

First, thanks for helping with my issue. It seems to be an ongoing problem with what I am doing, and I appreciate the help.

I looked over some mbed code and the manual and found this.

From the LPC8xx manual
RXRDY - Receiver Ready flag. When 1, indicates that data is available to be read from the receiver buffer. Cleared after a read of the RXDAT or RXDATSTAT registers.

RXDAT is called when getc() is called which seems to clear the readable() flag. I do not know if this is handled differently with the LPC176x library.

What I am not sure of now is how to get more than one byte, without knowing the number of bytes in the buffer, after readable() is called. Even with using an interrupt how would I know how many times to call getc() if there was more than one byte that was in the buffer already.

Code from LPC8xx mbed library

int serial_getc(serial_t *obj) {
    while (!serial_readable(obj));
    return obj->uart->RXDATA;
}
int serial_readable(serial_t *obj) {
    return obj->uart->STAT & RXRDY;
}

For reference here is the LPC176x library

int serial_getc(serial_t *obj) {
    while (!serial_readable(obj));
    int data = obj->uart->RBR;
    if (NC != uart_data[obj->index].sw_rts.pin) {
        gpio_write(&uart_data[obj->index].sw_rts, 0);
        obj->uart->IER |= 1 << RxIrq;
    }
    return data;
}
int serial_readable(serial_t *obj) {
    return obj->uart->LSR & 0x01;
}

@fritzprix
Copy link
Contributor

basically, you are right. so I think HAL Interface could be improved but if interface change happened, every Hal Port of other HW tree should be also changed accordingly. so I think it's better to keep the interface itself unchanged as possible and add just few functions to support buffered IO based on MsgQ (which is cmsis ipc feature)

@fritzprix
Copy link
Contributor

LPC84x's getc routine is blocking call. So you can simplify the snippet i suggested at first by removing busy waiting loop.

@fritzprix
Copy link
Contributor

How many bytes to be read is depend on your decision.
I mean typically there are two largely used cases to communicate between host and its slave using serial.
first is packet size is fixed so you can assume specific size of packet after you send some command.
second is packet size is not fixed but packet has header in its front part so that you can get the size of packet ,type and so on.

first case is relatively more simple than second one. because second one usually needs implement packet parser top of the serial interface

so actually, how many bytes to be read is rarely matter.

but busy waiting is the real problem because it degrade over all performance because thread (or executing process) occupy cpu until io operation accomplished which is typically takes a few thousands of cpu clocks

and I guess presumably that you seem to be confusing some point because you think there is internal receiving buffer which has more than one byte. but the fact is there is only one byte of buffer(RXD register) so if you don't read data in proper way, data might be lost.

@TravisJoe
Copy link
Author

In my experiences I have always used variable length packets with indicators for start and finish like brackets. They usually have some for of CRC also. Modbus would be an example.

I could be wrong but I thought, at the very least on the LPC1768/9, has a 16byte FIFO serial buffer as part of the MCU.

So I managed to figure out a method that finally worked. It seems that I have not found a way to allow for simple polling of the RS485 buffer. I was able to get the this to work by making my own buffer instead of relying on buffering on the MCU and and interrupts to quickly dump the data into the buffer. I wish I would of done this much sooner instead of trying to figure out why readable() was not behaving as I expected.

void RS485interrupt(void){

    RS485buffer[RS485bufferCounter] = serialRS485.getc();
    RS485bufferCounter++;

    // Avoid overrun
    if(RS485bufferCounter >= RS485_BUFFER_SIZE){
        RS485bufferCounter = 0;
    }
}

@0xc0170 0xc0170 closed this as completed Oct 17, 2014
@malay29
Copy link

malay29 commented Mar 1, 2017

@TravisJoe

How you dealt with storing variable length packets in array without getting stuck at getc() ?
Because, in my case the getc() function waits for more data, when the data received is shorter then the buffer size, and hence resulting halt of program.

@TravisJoe
Copy link
Author

@malay29
It has been a couple years now so I am not sure how the API has changed, but hopefully it has improved. If you are using the main mbed platforms likely the readable() function correctly tells you if there is data in the buffer.

You could do a while loop based around what readable() returns and only use getc() when there is items in the buffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants