Recover from APP_UART_COMMUNICATION_ERROR

Hi, We are using SDK17 and are implementing the UART y APP_UART_FIFO_INIT. Every now and then we encounter APP_UART_COMMUNICATION_ERROR. I know this is related to buffer overrun during reception. How do we gracefully recover from this? If the data in the buffer is lost, we can handle this in an other way. But for now, the error is not cleared and the only way to get it working again is reset the device.

Parents
  • Hi,

    Without further information, my best guess is that your code run a APP_ERROR_CHECK or APP_ERROR_HANDLER when you receive a callback with APP_UART_COMMUNICATION_ERROR? That and you are building with the Debug option and default nRF5 SDK app_error implementation.

    If my above guesses are correct, APP_ERROR_CHECK and APP_ERROR_HANDLER are calling functions in the Error Module.
    In Debug build, those function stop the firmware anytime they detect an error, and also produce logs on the error.
    In Release build, the functions reset the firmware instead.

    To gracefully recover from an APP_UART_COMMUNICATION_ERROR, you should handle the app_uart_evt_t. You can find implementation hint in the documentation of the app_uart_evt_t.data.error_communication field, quote below.

    Field used if evt_type is: APP_UART_COMMUNICATION_ERROR. This field contains the value in the ERRORSRC register for the UART peripheral. The UART_ERRORSRC_x defines from nrf5x_bitfields.h can be used to parse the error code. See also the nRF5 Series Reference Manual for specification.

    I can't find nrf5x_bitfields.h anywhere, but the ERRORSRC register documentations are available in the nRF52840 Product Specification.

    To further refine the handling of error, please also look into the behavior of the Error Module and the possibility having your own custom app_error_fault_handler() implementation.

    By the way, please also note that the error name in the log provided by the Error Module would be incorrected for this case. Just note the number and look up the Product Specification. See RE: NRF_ERROR_SVC_HANDLER_MISSING of uart  

    Best regards,

    Hieu.

  • Hi Hieu,

    Thanks for your reply.

    However this does not answer my question yet. My question is how to recover from such an error event.

    In case I just print some info (NRF_LOG_ERR) the error condition/flag is not cleared. The quote in the link is talking about the origin of the error (UART_ERRORSRC_x defines from nrf5x_bitfields.h). Is a simple clear those bits sufficient? Is there a nice call to do that or should I dig into the register itself? 

  • Hi Hieu,

    I don't think we are on the same page..
    Let me try to explain once more.

    I send data to an external device over the UART by:

    sprintf(ti_tx_buffer,"resetDevice\r");
    if(nrfx_uart_tx(&myapp_uart_inst, ti_tx_buffer, strlen(ti_tx_buffer)) == NRF_SUCCESS)
    {
        ti_data_send_done = true;
    }
    ....
    
     

    My event handler looks like:

    void uart_error_handle(app_uart_evt_t * p_event)
    {
        uint8_t cr;
        switch(p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                NRF_LOG_INFO("uart_error_handle, APP_UART_DATA_READY");
            break;
            case APP_UART_TX_EMPTY:
            
            break;
            case APP_UART_DATA:
            
            while (app_uart_get(&cr) == NRF_SUCCESS)
            {
                *rx_pointer = cr;
                rx_pointer++;
            }
            break;
            case APP_UART_COMMUNICATION_ERROR:
                NRF_LOG_ERROR("uart_error_handle, APP_UART_COMMUNICATION_ERROR: %d.\r\n",p_event->data.error_communication);
                
            break;
            case  APP_UART_FIFO_ERROR:
                NRF_LOG_ERROR("uart_error_handle, APP_UART_FIFO_ERROR: %d.\r\n",p_event->data.error_code);
                
            break;
            default:
                NRF_LOG_ERROR("uart_error_handle, unknown event type: %d.\r\n",p_event->evt_type);
            break;
        }
    }

    After sending similar commands, I am getting "APP_UART_COMMUNICATION_ERROR: 1."

    Now any new reply from my device cannot be received. 
    I want to clear this error some how and proceed as before. What do I need to do (except from avoiding the situation in the first place).

  • Hi,

    Yes, we indeed was not on the same page... I am afraid I still am not on the same page yet though. Slight smile

    I am quite confused about the code snippets you sent me. Are you using the UART Module (app_uart.h) or are you using the driver directly? Or are you perhaps using a modified implementation of app_uart.c/app_uart_fifo.c?

    Your UART event handler is for the UART Module, but you are using nrfx_uart_tx() to send bytes. What makes it look strange to me is that the UART Module wrap the entire nrfx_uart_t instance within itself, hiding it from you. Therefore if you are using the UART Module you should not be using nrfx_uart_t.

    What do I need to do (except from avoiding the situation in the first place).

    By this, do you mean you are not able to modify the current implementation at the moment?

    Best regards,

    Hieu

  • Hi,

    Yes, I use a slightly modified version of the app_uart and app_uart_fifo files. In those file we replaced all nrf_drv_* for nrfx_*. 

    The reason why I used nrfx_uart_tx is that app_uart_put is using that call. However using the app_uart_put I need to repeat the app_uart_put cal for every character I want to send. With nrfx_uart_tx I can send the whole string at once
    This all works fine for several minutes. Than I encounter the APP_UART_COMMUNICATION_ERROR. From other questions about this on the forum, I think this is due an overrun error. 
    I want a methode to just go on with the next (or repeated) transmission to my external device. But the answers from the device cannot be handled anymore. It looks like the underlying software is in an error state still. I want to reset this state or flag(s) somehow.

  • Ok I think we are on the same page now. One final thing before I dig deeper into this. Are you open to changing your implementation?

  • Yes, anything that will create a more reliable solution.

Reply Children
  • Hi,

    Firstly, regarding what can be done, here are a few ideas:

    1. Revert to the original implementation of app_uart_fifo and use either app_uart_tx or printf.

      app_uart_tx provide a software buffer for processing data which needs to be send, and it already implements some graceful handling when data are being produced faster than consumed.

      app_uart_tx() can be used without terribly bloated code:
      uint32_t buf_len, buf_idx;
      
      buf_len = snprintf(buf, BUF_MAX_LEN, "your format", ...);
      for (buf_idx = 0; buf_idx < buf_len; buf_idx++)
      {
          app_uart_put(buf[buf_idx]);
      }
      



      With \libraries\uart\retarget.c, you can also just use printf()
      A point to note is Segger Embedded Studio v6.20a and later added a feature which causes incompatibility with retarget.c and printf()
      If printf() is highly desirable I recommend using SES v5.42a, which SDK v17.1.0 was released and tested with.

    2. Increase your baud rate so that HW can consume data faster, and thus less data queue up in the application software.

    3. As a complete alternative options, you can take a look at the Advanced UARTE Driver library: https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/lib_libuarte.html

      The example for this library locates at: <SDK Root>/examples/peripheral/libuarte
      The documentation of the example is at: https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/libuarte_example.html

    I tested both printf() and app_uart_put() methods.
    With baud 1M, I can push ~500-550 bytes out at once just fine even with a app_uart_fifo buffer of mere 16 bytes.

    Regarding your original code and problem, I tried to look into the nrfx_uart driver, nrfx_uart_tx() in particular, to see what could cause your software to hang but nothing immediately stood out.
    If there is an interest in what is going on, enable RTT logging, and logging for the NRFX_UART module and give me the log.

    Best regards,

    Hieu

Related