This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

What exactly does the nrf_serial_flush?

Hello, 

I'm doing a project with Zigbee using the nRF52840 and I want to read some sensors that talk via UART. 

I have ported with success the nrf_uart example but after discovering that this library doesn't have support for multiple UART instances I've changed to the nrf_serial library. 

Everything is working, but I'm lacking some understandings regarding for instance the nrf_serial_flush() function. What is the purpose of this function? In the beginning, I thought that the purpose of this function was to clear out the buffer and assure the transmission in a blocking state. However, that's not true.

I want to be able to toggle a GPIO pin after the transmission done, like having a transmission done pin. How can I do that? I'm using DMA and for now, the only way that I discover to do that was by using the nrf_queue_is_empty() function to constantly check if the queue is already empty.... That solves the problem but creates an unnecessary overhead to the CPU in my option because I'm polling the nrf_queue_is_empty() function.

Thanks in advance,

Best regards,

Fernando

Parents
  • Everything is working, but I'm lacking some understandings regarding for instance the nrf_serial_flush() function. What is the purpose of this function?

     I understand that the name is a bit confusing to what this function actually does. When you define the instance for nrf_serial using NRF_SERIAL_CONFIG_DEF you have a _sleep variable which is the function pointer for the application-specific sleep function.

    nrf_serial_flush only keeping calling this sleep function until the serial queue is being handled in the background (in the uart interrupt) or the timeout happens. It does not brute force a flush as the name suggests.

     

    I want to be able to toggle a GPIO pin after the transmission done, like having a transmission done pin. How can I do that?

     nrf_serial_flush is a synchronous cal which does not return with NRF_SUCCESS until the transmit queue is empty. So you can check the return value of nrf_serial_flush and toggle the pin.

  • Hi Susheel,

    Thank you very much for your explanation. It seems to work. However, now I'm having a strange behavior on the serial communication. 

    Everything is working for a while and suddenly I start to receive strange characters on the serial port and the 

    nrf_serial_read function stops working.
    Increasing the FIFO size seems to improve, but does not fixes the issue... Do you have any idea of what could be the reason? I'm handling the serial port on a task (using freertos) and I understand that it could happen to lose some characters if the FIFO overruns, but why stop receiving at all? And what is the reason for the strange characters on the serial TX port?
    Do you have any idea of a possible reason for that? Maybe I should give up on using DMA ... 
    Best regards,
    Fernando
  • Fernando Fontes said:

    With the NODEB turned off, the NODEA is able to tranmitt forever without any problems (allways this data: 0x01 0x30 0x30 0x02 0x53 0x31 0x03 0x45 0x41 0x0d : 10bytes at 9600 bps).

    With the NODEB turned on and responding after receiving the sent command, the NODEA after a while starts to send corrupted data and stops receiving the response from the NODEB (data: 0x01 0xc0 0x02 0x4a 0x0a 0x45 0x90 0xf8, 0x01 0xc0 0x02 0x2a 0x1a 0x45 0x90 0xf8 , ...)

    Sounds like NODEA starts to misbehave both in transmit and receive when NODEB starts to send data. While you are waiting for the flush to happen, it is possible that the NODEB sends too much data that it might cause an overflow error in NODEA while waiting for the TX flush to happen?  How is your application handling errors like overflow and framing errors? What is the size of the nrf_serial RX and TX buffers? 

  • The NODEB will only reply to NODEA upon receiving the terminator character ('\r') so I don't think so. But I will add a small delay to eliminate this possibility. 

    I'm not handling overflow and framing errors. When does the overflow occur? 


    #define SERIAL_FIFO_TX_SIZE 100
    #define SERIAL_FIFO_RX_SIZE 100

    #define SERIAL_BUFF_TX_SIZE 1
    #define SERIAL_BUFF_RX_SIZE 1

    Those are my defines, so in theory, since the FIFO size is always bigger than the data sent from both nodes, the overflow shouldn't occur right? But even if I decided to go with a smaller FIFO, since I'm lopping the nrf_serial_read function, that shouldn't also be a problem, since the FIFO is always being clear out? 

    What I'm doing before transmitting is clearing both transmit and receive buffers, so that messages pendent to send or to receive don't interfere in the new transmissions.

  • Just tested and it is indeed a frame error. I added an event handler for the NRF_SERIAL_EVENT_DRV_ERR, and now, every time I get this framing error I'm un-initializing and initializing again the serial module. This kinda solves my problem, but I'm constantly receiving framing errors and losing messages. Why these framing errors are happening so often? I'm using FreeRtos... I read some threads with related issues when using the UART with the freeRtos... 

  • I do not think that the framing error is due to the FreeRTOs+UART combo. Framing errors normally happen due to clock accuracy differences on both ends of UART. Please check the HFCLK clock accuracy (more specifically clock that effects the UART baudrate accuracy) on both ends to see if both nRF UART and the peer UART's clocks are drifting away with time? 

    If it was FreeRTOS+UART combo that causes the problem, I would expect it to be OVERRUN error and not FRAMING error. 

    FreeRTOS port we have does not touch any HFCLK and does not touch any peripheral (other than RTC) registers for the RTOS/Kernel to work. So I would not suspect the combo right away. 

  • I'm only running the ret_code_t err_code = nrf_drv_clock_init(); to initialize the clock.

    I noticed that this function is a legacy one, could it be the reason? Should I waste some time trying to change these functions?

Reply Children
  • Do you have XO HFCLK on your board? If so you should also call nrf_drv_clock_hfclk_request to be able to explicitly start the crystal. If you have not done this, then most probably you are using internal RC HFCLK which is less accurate and would explain why you get framing errors so often.

  • Yes, I have both 32Mhz and 32.768kHz external clocks. I tried to call the nrf_drv_clock_hfclk_request and the behavior is still the same. One of the tasks that I'm running in parallel is a Zigbee application and I noticed that with that task off, the framing errors are very low. So, I did a quick search to see if the easyDMA of UART1 is using repeated addresses but I guess no. I'm starting to think that this is somehow a priority-related issue... Is that possible? How are the DMA to RAM transfers being handled? Do I need to change the priority values?

  • Fernando Fontes said:
    I'm starting to think that this is somehow a priority-related issue... Is that possible? How are the DMA to RAM transfers being handled? Do I need to change the priority values?

     The priority of ISR handling becomes very important if you are not using HW flow control. But with this, i would still expect to see overrun errors and not framing errors. 

     

    Fernando Fontes said:
    One of the tasks that I'm running in parallel is a Zigbee application and I noticed that with that task off, the framing errors are very low.

    I cannot put my head around this behavior. Are you seeing less errors per average transaction or are you seeing less errors per average time? Because if it is the second, I could understand as Zigbee task and stack taking more time to process its data and giving UART ISR less time to process its data.

    Fernando Fontes said:
    Yes, I have both 32Mhz and 32.768kHz external clocks. I tried to call the nrf_drv_clock_hfclk_request

    nrf_serial is somewhat less preffered library over libuarte and is also a reason we removed it from latest SDKs. Can you please try to move to libuarte? I know that this sounds like work, but there could be only two possibilities to explore. One is clock inaccuracies and the other is possible nrf_serial bug. I know that the libuarte is very stable so atleast we can exclude one suspecting direction.

  • Well, I switched to the app_uart_fifo implementation. It's a lot more stable than the nrf_serial. Libuarte would be my next option. But since app_uart_fifo seems to be stable I will stick with this one. 

    However, I've just finished the implementation a few minutes ago. It would be great if you could explain a few things about app_uart_fifo implementation. 

    How is handled the reception in this implementation? Is it by interrupts? I know that there is an event handler putting the RX data into a buffer, but is this module still using easyDMA?

  • Fernando Fontes said:
    How is handled the reception in this implementation? Is it by interrupts? I know that there is an event handler putting the RX data into a buffer, but is this module still using easyDMA?

     Yes, it is interrupt based which is handled in nrfx_uarte.c/nrfx_uart.c. If EasyDMA is used or not depends on what you have set in nRF5_SDK_17.0.2_d674dde\integration\nrfx\legacy\apply_old_config.h NRFX_UARTE_ENABLED which inturn depends on your settings in sdk_config.h.   Just set UARTX_ENABLED and UART_EASY_DMA_SUPPORT to 1 in sdk_config.h and you will see that easydma will be used though the hal driver nrfx_uarte.c

Related