modbus: missing rx bytes at high baud rate (460800)

Hello,

I am using the nRF52840 as modbus client and experiencing some missing bytes during communication (RTU mode) when using a high baud rate (460800). This tends to happen more often when requesting a big chunk of data at once, but does also happen when requesting only two registers (4 bytes). 

I opened an issue ticket on github (Link to github) describing this problem with some comments on how to mitigate. However, the problem is still present 


Can someone try to give me any input?

I do also have a few questions related to UARTE in interrupt driven mode (as I am using it):

  1. it is stated in the uart (not uarte) documentation under 6.33.5 of the product specification that "The UART receiver chain implements a FIFO capable of storing six incoming RXD bytes before data is overwritten.". However, I did not find any information about this hardware FIFO size when it comes to UARTE. Is it the same (6)?

  2. is the following correct? The data will be received in the hardware FIFO buffer of UARTE (of depth x?), then it will be copied with EasyDMA to be placed in RAM in a buffer of size 1 as in zephyr/drivers/serial/uart_nrfx_uarte.c (see code below). The modbus driver does then implement a cb_handler_rx that gets triggered when bytes are received and copies them from the previous RAM buffer one by one to another driver specific buffer of custom size. Is this correct? 
    nrf_uarte_rx_buffer_set(uarte, data->rx_data, 1);
      
  3. When I am missing a byte, I was able to check the ERRORSRC register to see that an overrun has occured (value of the register =1). How much time do I have before getting an overrun?

  4. When does the overrun occur: is it when the first bit is received while data still in FIFO or in RAM buffer?

I am looking forward to your answers and input on how to solve the missing bytes problem.

FYI: the use of Hardware flow control is unfortunately not an option in our case, as the server does not support it. Moreover, I am not able of reducing the baud rate as this is constant (from the server side as well).  

Parents
  • Hi,

    However, I did not find any information about this hardware FIFO size when it comes to UARTE. Is it the same (6)?

    Generally, this is different with the UARTE peripheral, as it use DMA and writes directly to the provided Rx buffer in RAM. So there is no risk of overwriting data within a single transaction. 

    The data will be received in the hardware FIFO buffer of UARTE (of depth x?), then it will be copied with EasyDMA to be placed in RAM in a buffer of size 1 as in zephyr/drivers/serial/uart_nrfx_uarte.c (see code below).

    When using the interrupt driven API in zephyr each transaction is 1 byte (so it does not utilize he benefits of DMA compared to the legacy UART peripheral).

    When I am missing a byte, I was able to check the ERRORSRC register to see that an overrun has occured (value of the register =1). How much time do I have before getting an overrun?

    That depends on he baud rate (the time until the next bye is received/clocked in).

    When does the overrun occur: is it when the first bit is received while data still in FIFO or in RAM buffer?

    It occurs when a start bit is received while the previous data still lies in RXD.

    Although modbus is supported in Zephyr, we have not worked on that specifically. Generally thogh, I would recomend using the async UART API with  with the HW async feature enabled (which use a timer in counter mode to count received bytes). This is important for the reliability, and inolves these configs in addition to those you can see in samples that use async UART (adjust for the correct instances):

    CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2
    CONFIG_UART_0_NRF_HW_ASYNC=y

  • Thanks for your support . This turned out to be the solution: using the uarte ASYNC Api along with the hardware timer for counting rx bytes. Using Async Api without the hardware timer for counting the bytes is not enough for a stable communication as you already mentioned. 

    Notes: 

    • This however means rewriting the modbus_serial.c file on my own to make use of the async api (per default only the interrupt driven is implemented). I will try to make my changes public in the next few weeks so that anybody can use serial modbus with UART async api, which is a must for applications with high baudrates and no hardware control. 

    • This solution also forced me to re-implement my own application that was making use of all timers and ppi channels in order to leave a free timer and ppi channel for the hardware counting of bytes.

    • Another problem I still have to fix though (unrelated to async api sepcifically) is desribed in this ticket: Choose the UARTE API (Async/interrupt driven) during runtime 
Reply
  • Thanks for your support . This turned out to be the solution: using the uarte ASYNC Api along with the hardware timer for counting rx bytes. Using Async Api without the hardware timer for counting the bytes is not enough for a stable communication as you already mentioned. 

    Notes: 

    • This however means rewriting the modbus_serial.c file on my own to make use of the async api (per default only the interrupt driven is implemented). I will try to make my changes public in the next few weeks so that anybody can use serial modbus with UART async api, which is a must for applications with high baudrates and no hardware control. 

    • This solution also forced me to re-implement my own application that was making use of all timers and ppi channels in order to leave a free timer and ppi channel for the hardware counting of bytes.

    • Another problem I still have to fix though (unrelated to async api sepcifically) is desribed in this ticket: Choose the UARTE API (Async/interrupt driven) during runtime 
Children
No Data
Related