Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LIBUARTE RX Buffer Full event

Hello,

I am having an issue with the nrf_libuarte_async librairie.

I am sending data via nrf_libuarte_async_tx and receiving the data properly via the IRQ handler (user implemented). I copy the data received into a buffer and then send a notification to my task that the uart reception is completed and ready for pick-up. However issue arise when the buffer get full. The nrf_libuarte_async generates two NRF_LIBUARTE_ASYNC_EVT_RX_DATA event, the first one to notify that the buffer is full, the second one to notify that the reception is complete. My message reception is now bad as the message is split in two. The first half in the first buffer and the second half in the second buffer.

Here are my questions:

1. How can I determine that the first event is a buffer Full event and not a completed reception event?

2. I cannot change the number of buffer to 1 as it is asserted in nrf_libuarte_async.h (STATIC_ASSERT(_rx_buf_cnt >= 3, "Wrong number of RX buffers");\)

3. Is there a way to use a ring buffer instead of changing the buffer for reception. As a user I dont care that the buffer is full, when you interrupt me to tell me reception is complete I expect that reception is complete. 

I am using the SDK 17.1.0

Thank you,

Vincent

Parents
  • Hello,

    1:

    There is no way to tell from the uart_event_handler() in main.c (looking at the SDK\examples\peripheral\libuarte example) to tell what generated the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. If you want to separate on the two cases where the buffer is full and the timeout, I guess I would've tried adding a parameter saying what generated the event in nrf_libuarte_async.c.

    As you can tell, it is either line 243 or 321 that generate the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. Try adding this to the nrf_libuarte_async_evt_t:

    typedef struct
    {
        nrf_libuarte_async_evt_type_t type; ///< Event type.
        union {
            nrf_libuarte_async_data_t rxtx;                   ///< RXD/TXD data.
            uint8_t                   errorsrc;               ///< Error source.
            nrf_libuarte_async_overrun_err_evt_t overrun_err; ///< Overrun error data.
            uint8_t                   src;                    ///< what triggered the event  <- add this line
        } data;                                 ///< Union with data.
    } nrf_libuarte_async_evt_t;

    And then in the nrf_libuarte_async.c use this parameter to say whether the event was triggered by a timeout or a buffer that is full. E.g by setting it to 0 when the buffer was full or 1 when the timeout occured:

        case NRF_LIBUARTE_DRV_EVT_RX_DATA:
        {
    
            uint32_t rx_amount = p_evt->data.rxtx.length - p_libuarte->p_ctrl_blk->sub_rx_count;
            if (rx_amount)
            {
                p_libuarte->p_ctrl_blk->rx_count += rx_amount;
                nrf_libuarte_async_evt_t evt = {
                    .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
                    .data = {
                        .rxtx = {
                            .p_data = &p_evt->data.rxtx.p_data[p_libuarte->p_ctrl_blk->sub_rx_count],
                            .length = rx_amount,
                            .src = 0
                        }
                    }
                };
                
                
    ...
    void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte)
    {
        NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
    
        uint32_t capt_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
    
        if (capt_rx_count > p_libuarte->p_ctrl_blk->rx_count)
        {
            uint32_t rx_amount = capt_rx_count - p_libuarte->p_ctrl_blk->rx_count;
            nrf_libuarte_async_evt_t evt = {
                .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
                .data = {
                    .rxtx = {
                        .p_data = &p_libuarte->p_ctrl_blk->p_curr_rx_buf[p_libuarte->p_ctrl_blk->sub_rx_count],
                        .length = rx_amount,
                        .src = 1,
                    }
                }

    This way you can tell from main.c where the event is coming from:

    ...
    
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                if (p_evt->data.src == 0)
                {
                    NRF_LOG_INFO("triggered by full buffer");
                }
                else if (p_evt->data.src == 1)
                {
                    NRF_LOG_INFO("Triggered by timeout");
                }
                ret = nrf_libuarte_async_tx(p_libuarte,p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                if (ret == NRF_ERROR_BUSY)
                {
                    buffer_t buf = {
                        .p_data = p_evt->data.rxtx.p_data,
                        .length = p_evt->data.rxtx.length,
                    };
    
                    ret = nrf_queue_push(&m_buf_queue, &buf);
                    APP_ERROR_CHECK(ret);
                }
    
    ...

    And if you want it to be fancy, you can create an enum instead of using the "0" and "1". 

    2:

    That is correct.

    3:

    That is not the way it is done in the libuarte library. You can use the above workaround to just copy the data if the event was caused by a full buffer, and attach the last part of the message from the timeout later before you process the data, or you can look into implementing a ring buffer. There is no simple way to make libuarte use a ring buffer out of the box, unfortunately. 

    Best regards,

    Edvin

Reply
  • Hello,

    1:

    There is no way to tell from the uart_event_handler() in main.c (looking at the SDK\examples\peripheral\libuarte example) to tell what generated the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. If you want to separate on the two cases where the buffer is full and the timeout, I guess I would've tried adding a parameter saying what generated the event in nrf_libuarte_async.c.

    As you can tell, it is either line 243 or 321 that generate the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. Try adding this to the nrf_libuarte_async_evt_t:

    typedef struct
    {
        nrf_libuarte_async_evt_type_t type; ///< Event type.
        union {
            nrf_libuarte_async_data_t rxtx;                   ///< RXD/TXD data.
            uint8_t                   errorsrc;               ///< Error source.
            nrf_libuarte_async_overrun_err_evt_t overrun_err; ///< Overrun error data.
            uint8_t                   src;                    ///< what triggered the event  <- add this line
        } data;                                 ///< Union with data.
    } nrf_libuarte_async_evt_t;

    And then in the nrf_libuarte_async.c use this parameter to say whether the event was triggered by a timeout or a buffer that is full. E.g by setting it to 0 when the buffer was full or 1 when the timeout occured:

        case NRF_LIBUARTE_DRV_EVT_RX_DATA:
        {
    
            uint32_t rx_amount = p_evt->data.rxtx.length - p_libuarte->p_ctrl_blk->sub_rx_count;
            if (rx_amount)
            {
                p_libuarte->p_ctrl_blk->rx_count += rx_amount;
                nrf_libuarte_async_evt_t evt = {
                    .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
                    .data = {
                        .rxtx = {
                            .p_data = &p_evt->data.rxtx.p_data[p_libuarte->p_ctrl_blk->sub_rx_count],
                            .length = rx_amount,
                            .src = 0
                        }
                    }
                };
                
                
    ...
    void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte)
    {
        NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
    
        uint32_t capt_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
    
        if (capt_rx_count > p_libuarte->p_ctrl_blk->rx_count)
        {
            uint32_t rx_amount = capt_rx_count - p_libuarte->p_ctrl_blk->rx_count;
            nrf_libuarte_async_evt_t evt = {
                .type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
                .data = {
                    .rxtx = {
                        .p_data = &p_libuarte->p_ctrl_blk->p_curr_rx_buf[p_libuarte->p_ctrl_blk->sub_rx_count],
                        .length = rx_amount,
                        .src = 1,
                    }
                }

    This way you can tell from main.c where the event is coming from:

    ...
    
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                if (p_evt->data.src == 0)
                {
                    NRF_LOG_INFO("triggered by full buffer");
                }
                else if (p_evt->data.src == 1)
                {
                    NRF_LOG_INFO("Triggered by timeout");
                }
                ret = nrf_libuarte_async_tx(p_libuarte,p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                if (ret == NRF_ERROR_BUSY)
                {
                    buffer_t buf = {
                        .p_data = p_evt->data.rxtx.p_data,
                        .length = p_evt->data.rxtx.length,
                    };
    
                    ret = nrf_queue_push(&m_buf_queue, &buf);
                    APP_ERROR_CHECK(ret);
                }
    
    ...

    And if you want it to be fancy, you can create an enum instead of using the "0" and "1". 

    2:

    That is correct.

    3:

    That is not the way it is done in the libuarte library. You can use the above workaround to just copy the data if the event was caused by a full buffer, and attach the last part of the message from the timeout later before you process the data, or you can look into implementing a ring buffer. There is no simple way to make libuarte use a ring buffer out of the box, unfortunately. 

    Best regards,

    Edvin

Children
No Data
Related