Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Serial port abstraction layer API nrf_serial_read() timeout/data-size issues with a UART sensor

Hi all,

I'm working with NRF52DK using Segger Embedded Studio with NRF SDK 15.0 trying to communicate to a UART sensor using the serial port abstraction layer API. Following the serial_port example and various threads on this forum, I've managed to establish a communication link between the DK and the sensor; however, I ran into 2 issues:

1. I'm using the serial port abstraction layer methods with the instance being set to the IRQ mode. If I set the "timeout in ms" parameter within nrf_serial_read() to "NULL", then what seems to happen is that my sensor isn't replying fast enough after I write to it using nrf_serial_write() (again, with "NULL" passed to nrf_serial_write() for the timeout parameter). That leads to me getting the NRF_ERROR_TIMEOUT from the nrf_serial_read() since it expects there to be data to be read when the program gets to it but there is none. Now, if I do set the timeout parameter to, say, 1000 ms, then the data transmission succeeds; however, as I've read in the documentation,  that may lead to a deadlock. What can I do in this case?

2. How can I establish the data size to be read if I don't know it in advance? As an example, depending on what the sensor reads, it can transmit either an ACK or a NACK with an error code, each having a different payload size. If I declare a size to be read larger than the actual transmission happens to be, then I get the NRF_ERROR_TIMEOUT again. From my understanding, there are no ways around it other than to handle this in the RX event handler? What is the best way to handle it inside the handler? Is it possible to just timeout from the function and move on, without running into the possible deadlock issue?

3. This is not an issue, but I'm not completely clear on whether the queues are cleared after RX/TX. If they are not automatically cleared, how do I clear them and make sure I don't overflow them?

Thank you so much in advance!

Parents
  • Hello,

    So if this is going to work with different sensors, there is no way of knowing what the incoming packet is going to look like? Does it have a start byte, or a byte that is always the same at the end?

    Uart is sort of a "simple" protocol. It can send bytes, and receive bytes. But it has no "length" field or something like that, so you need to know something about what the incoming packet looks like. Either a length field, that it ends with a '\n' (newline), or that it starts with a specific byte. If not, you will just receive a fixed length of bytes, but you don't know if that is the end of the previous message + the start of a new message, or if they belong together.

    If you look at the datasheet of typical UART sensors, they typically describe what the output data looks like, but it varies from sensor to sensor what that format is. 

    There is a library in the SDK called libuarte, which has an option to set a timeout, meaning if it doesn't receive a byte within a certain amount of time, it will consider the message "complete". This is also interrupt driven, but it will not send the event to the top layer until either the buffer is full, or the timer has timed out. 

    If you want to do other things simultaneously as you are using the UART, you should stay clear of the blocking uart functions.

    Best regards,

    Edvin

  • Hi Edvin,

    So if this is going to work with different sensors, there is no way of knowing what the incoming packet is going to look like? Does it have a start byte, or a byte that is always the same at the end?

    The sensors I work with do describe the how to outcoming (incoming to nRF) packets look like. I was wondering if there is a way to not have to necessarily do extensive if/else/switch conditionals or even trees; e.g. the serial_read() would read all the data and then I would process it without having to handle each buffer transmission. If that is the best way to go about this, however, than that its fine.

    There is a library in the SDK called libuarte, which has an option to set a timeout, meaning if it doesn't receive a byte within a certain amount of time, it will consider the message "complete". This is also interrupt driven, but it will not send the event to the top layer until either the buffer is full, or the timer has timed out. 

    This is in the case that the sensor doesn't reply fast enough for my application? Is it excessive if I declare a one shot timer such that when it expires I use the serial_read() function (essentially, a delay) or can that lead to a deadlock too?

    If you want to do other things simultaneously as you are using the UART, you should stay clear of the blocking uart functions.

    Eventually I'm looking to incorporate several DK52s/Thingy52s into a mesh and have them use UART/I2C sensors. Is it inherently better to use non-blocking uart functions or for mesh it wouldn't be much different? I'm not completely sure how SoftDevice interacts with the rest of the application.

    Thank you!

  • nikostpn said:
    Eventually I'm looking to incorporate several DK52s/Thingy52s into a mesh and have them use UART/I2C sensors. Is it inherently better to use non-blocking uart functions or for mesh it wouldn't be much different? I'm not completely sure how SoftDevice interacts with the rest of the application.

     Whether you use Mesh, Bluetooth Low Energy, or none, I recommend you use the interrupt driven UART, like it is done in the ble_app_uart example in the SDK. 

    Let's do a thought experiment:

    The UART receives an interrupt every time it receives a single byte. Let us say you have two different sensors using UART. How do you want to determine when you have a complete message consisting of one sensor reading (possibly several bytes), what sensor it came from, and what the actual data (temperature or distance) is?

    Whatever approach you use, this is the base of the HW that you are using. There are some libraries (libuarte) that can give interrupts only when a buffer is filled, or if a timer times out (timer started since last received byte). However, these libraries have no meaning of what a packet from a certain sensor should look like. 

  • Edvin,

    It seems like that would be the best practice. Thank you so much for your help!

Reply Children
No Data
Related