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

  • 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
  • Hmm, seems like the nRF UART and the peer UART lost sync. This normally happens at high baudrates mostly when not using hardware flow control and when there are framing or overrun errors and it depends on how your application has handled it. Overrun error might be less harmful if your application is prepared and designed to tell the peer to retransmit it. But framing errors are a bit tricky as you might have to let the peer trasnmit the whole sequence of chars even after the framing error, reset nRF UART peripheral and then ask the peer to retransmit the whole sequence again to reestablish the sync.

    Easier would be to tone down the baudrate a bit and if possible use hardware flow control.

  • Hmm, this is quite odd. 

    Let me explain my setup. I have MAX485 IC connected which will translate incoming messages to serial UART. Well RS485 handles both transmitted messages and received messages on the same line. So, I need to toggle a PIN to enter in transmit mode (which will then ignore the incoming data) and then toggle it again to quickly enter in receive mode.

    This is already done thanks to your first explanation. Something like:

    // Switch to transmit mode 
    TOGGLE_TO_TRANSMIT_MODE;
    // start writting to the FIFO
    ret = nrf_serial_write(&serial1_uarte,
                    buffer,
                    buffer_size,
                    &p_written,
                    NRF_SERIAL_MAX_TIMEOUT);
    // check if we write all the buffer data
    if ( (p_written != buffer_size) || (ret != NRF_SUCCESS) ) {
        retval = pdFAIL;
    }
    // block until successfully transmit all the data
    while ( nrf_serial_flush(&serial1_uarte, 0) != NRF_SUCCESS );
    // Go back again to receive mode
    TOGGLE_TO_RECEIVE_MODE;

    Then, I switch to a polling state where I check for data until receiving a terminator character or timeout. Something like:

    // try to read from serial until receiving the terminator or timeout
    while( ((xTaskGetTickCount() - ticks) < timeout_ms) &&  (c != terminator) ) {
        // read in non-blocking mode
        ret = nrf_serial_read(&serial1_uarte, &c, sizeof(c), NULL, 0);
        // byte received?
        if (ret == NRF_SUCCESS) {
            if ( buffer_size > *read_bytes ) {
                buffer[*read_bytes] = c; // save this character
                *read_bytes = *read_bytes + 1; // increment
            } else {
                return pdFAIL; // max buffer size received
            }
        } 
    }

    So, I did a bit more testing and I experienced the following:

    Nomenclature: 

    > NODEA: NRF52840 DK

    > NODEB: Generic UART handler device

    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 , ...)

  • 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? 

Related