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

UART event handler continually called with event APP_UART_TX_EMPTY

We are using nRF52832 with SDK_15.3.0 running the Nordic UART service (NUS) example.

Out of the box we find that the uart event handler is continually being called with event APP_UART_TX_EMPTY..   I would  expect that this event would only occur at the point the TX FIFO becomes empty.  

Looking into the source it appears that NRF_DRV_UART_EVT_TX_DONE event is continually being triggered.  I am assuming (and could be wrong) that this  event is set when the UART hardware transmit buffer becomes empty, after the last bit is clocked out.  

My concern is that the uart event handler is a call-back function that ultimately is called from the uart interrupt.  This would indicate that the uart interrupt is continually occurring.  It's as if an interrupt is not being acknowledged in the driver. 

Could someone please confirm this.

How can we prevent the uart event handler being called contrinuously, preferably without modifying the uart driver source?  Is there a setting to enable this event?

Parents
  • Hi,

    are you using app_uart.c or app_uart_fifo.c in your project? The later should behave exactly as you expected. Anyway, both modules are based on legacy NRF_UART module that has no hardware buffer, so interrupt is generated for each transmitted character. If your goal is to get rid of interrupt events, consider an nrf_libuarte library - it is based on NRF_UARTE that works with EasyDMA.

  • Dmitry,

    Our application is derived from example "ble_app_uart_c" in SDK_15.3.0,  This application uses app_uart_fifo.c.  It does not behave as I expect.

    Tracing back through the code, in file app_uart_fifo.c, function uart_event_handler()  iscalled from the UART interrupt handler.  In uart_event_handler()  is this case:

    case NRF_DRV_UART_EVT_TX_DONE:
    // Get next byte from FIFO.
    if (app_fifo_get(&m_tx_fifo, tx_buffer) == NRF_SUCCESS)
    {
       (void)nrf_drv_uart_tx(&app_uart_inst, tx_buffer, 1);                <---- Send the next byte
    }
    else
    {
       // Last byte from FIFO transmitted, notify the application.
       app_uart_event.evt_type = APP_UART_TX_EMPTY;
      m_event_handler(&app_uart_event);                                    <------ This calls uart_event_handle() in main.c
    }
    break;

    You can see that when the TX FIFO is empty, the application is notified via call-back function in function pointer m_event_handler  However, the application is continuously being notified, when it should be notified only once.  This indicates that the UART interrupt is continuously firing. 

    Commenting out the line highlighted above stops uart_event_handle() being called over and over.  But it is obvious that the UART interrupt handler will still be firing. 

    If our application never transmits a byte, this event never occurs.  If we transmit a single byte at the start of the program, then the UART interrupt occurs continuously, forever.  It cannot be stopped.

    This looks like a UART interrupt is occurring when the TX buffer register (in UART hardware) becomes empty, but the interrupt is not being cleared by software.

    It is not our "goal" to get rid of interrupt events.  It's how interrupt driven UART transmit should work in the first place.  I have been writing interrupt driven comms at hardware level for 20yrs.

    Can you please confirm that the UART interrupt is not being acknowledged or cleared when the last byte has been transmitted by the UART hardware and the TX FIFO is software is empty in the UART driver used by the "ble_app_uart_c" example project.

    Can you please confirm that the UART interrupt is being acknowledged or cleared when the last byte has been transmitted by the UART hardware and the TX FIFO is software is empty in the lib_uarte UART driver.

Reply
  • Dmitry,

    Our application is derived from example "ble_app_uart_c" in SDK_15.3.0,  This application uses app_uart_fifo.c.  It does not behave as I expect.

    Tracing back through the code, in file app_uart_fifo.c, function uart_event_handler()  iscalled from the UART interrupt handler.  In uart_event_handler()  is this case:

    case NRF_DRV_UART_EVT_TX_DONE:
    // Get next byte from FIFO.
    if (app_fifo_get(&m_tx_fifo, tx_buffer) == NRF_SUCCESS)
    {
       (void)nrf_drv_uart_tx(&app_uart_inst, tx_buffer, 1);                <---- Send the next byte
    }
    else
    {
       // Last byte from FIFO transmitted, notify the application.
       app_uart_event.evt_type = APP_UART_TX_EMPTY;
      m_event_handler(&app_uart_event);                                    <------ This calls uart_event_handle() in main.c
    }
    break;

    You can see that when the TX FIFO is empty, the application is notified via call-back function in function pointer m_event_handler  However, the application is continuously being notified, when it should be notified only once.  This indicates that the UART interrupt is continuously firing. 

    Commenting out the line highlighted above stops uart_event_handle() being called over and over.  But it is obvious that the UART interrupt handler will still be firing. 

    If our application never transmits a byte, this event never occurs.  If we transmit a single byte at the start of the program, then the UART interrupt occurs continuously, forever.  It cannot be stopped.

    This looks like a UART interrupt is occurring when the TX buffer register (in UART hardware) becomes empty, but the interrupt is not being cleared by software.

    It is not our "goal" to get rid of interrupt events.  It's how interrupt driven UART transmit should work in the first place.  I have been writing interrupt driven comms at hardware level for 20yrs.

    Can you please confirm that the UART interrupt is not being acknowledged or cleared when the last byte has been transmitted by the UART hardware and the TX FIFO is software is empty in the UART driver used by the "ble_app_uart_c" example project.

    Can you please confirm that the UART interrupt is being acknowledged or cleared when the last byte has been transmitted by the UART hardware and the TX FIFO is software is empty in the lib_uarte UART driver.

Children
  • Looking at the datasheet for the nRF52832 (nRF52832_PS_v1.4.pdf), it appears that the UART doesn't have the traditional interrupt pending flag, but instead uses a TXRDY event.

    Bytes are transmitted by writing to the TXD register. When a byte has been successfully transmitted the
    UART will generate a TXDRDY event after which a new byte can be written to the TXD register

    However, my point still applies.  How can we be sure that once the TX FIFO is empty, the UART hardware doesn't keep generating TXRDY events?

    Does this only occur in the driver for UART but not in the driver for UARTE?

  • Phil,

    UARTE works differently -  there's no TXRDY event, instead an ENDTX event is generated when the whole DMA buffer is transferred. Sorry, I cannot check your point now - it's an old project for nrf51 where I used NRF_UART.

    BTW, I found that nrf_drv_uarte in SDK 15.3.0 depends on NRF_DRV_UART_WITH_UARTE - if it's defined, driver should use UARTE instead of UART. Meybe this can help?

Related