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

app_uart_fifo & rx length

Hi,

Sorry if the answer is obvious but I'm not getting it :-)

I looked at ble_app_uart, more specifically the uart_event_handle function and its interactions with app_uart_fifo's FIFO. I cannot see how more than one byte in the RX FIFO could be used since the uart_event_handle is called in interrupt context. By unrolling the whole code we basically have

app_uart_event_handler:
  app_fifo_put(c);
  if(FIFO_LENGTH() == 1) uart_event_handle();

uart_event_handle:
  app_fifo_get(c); // So FIFO length is back to 0 (thus 1 on next byte rvcd)

Can someone please enlighten me?

Regards

Parents
  • FWIW, I switched to app_scheduler to avoid having too much code in the IRQ handler part of code. This way the FIFO is really useful (well… in fact I currently don't have anything to put on the back of my device's UART so maybe theory won't match realty). The UART relevant code is now

    APP_UART_FIFO_INIT( &comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_schedule,
                       APP_IRQ_PRIORITY_LOW,
                       err_code);
    
    void uart_event_schedule(app_uart_evt_t * p_event) {
        uint32_t err_code;
        
        switch (p_event->evt_type) {
            case APP_UART_DATA_READY:
                // We can unconditionally post the event since this function is only
                // called on first byte put into FIFO
                err_code = app_sched_event_put(NULL, 0, uart_event_handler);
                APP_ERROR_CHECK(err_code);
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    
    static void uart_event_handler(void * p_event_data, uint16_t event_size) {
            // Real processing, outside of IRQ handler with app_uart_get()
    }
    

    That way, the only job of the UART IRQ is to queue a call to the UART event handler which will then be executed in main context. That mean that if we get a burst of data on UART, handler will be executed after IRQ (because it is now interruptible), and FIFO is now really useful.

    Haven't dug into SDK code but at a first glance it seems that using this method, I'll have to guard app_uart_get() with a critical section since we could run into a race condition where we are interrupted by IRQ which will fill FIFO, while getting data from the fifo and things could go wrong.

    Regards

Reply
  • FWIW, I switched to app_scheduler to avoid having too much code in the IRQ handler part of code. This way the FIFO is really useful (well… in fact I currently don't have anything to put on the back of my device's UART so maybe theory won't match realty). The UART relevant code is now

    APP_UART_FIFO_INIT( &comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_schedule,
                       APP_IRQ_PRIORITY_LOW,
                       err_code);
    
    void uart_event_schedule(app_uart_evt_t * p_event) {
        uint32_t err_code;
        
        switch (p_event->evt_type) {
            case APP_UART_DATA_READY:
                // We can unconditionally post the event since this function is only
                // called on first byte put into FIFO
                err_code = app_sched_event_put(NULL, 0, uart_event_handler);
                APP_ERROR_CHECK(err_code);
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    
    static void uart_event_handler(void * p_event_data, uint16_t event_size) {
            // Real processing, outside of IRQ handler with app_uart_get()
    }
    

    That way, the only job of the UART IRQ is to queue a call to the UART event handler which will then be executed in main context. That mean that if we get a burst of data on UART, handler will be executed after IRQ (because it is now interruptible), and FIFO is now really useful.

    Haven't dug into SDK code but at a first glance it seems that using this method, I'll have to guard app_uart_get() with a critical section since we could run into a race condition where we are interrupted by IRQ which will fill FIFO, while getting data from the fifo and things could go wrong.

    Regards

Children
No Data
Related