experimental_libuarte example: EVENTS_ENDTX cannt trigger TASKS_STARTTX

Hi Nordic,

nrf5 sdk 15.2.0, nrf52832.

I am testing the UARTE with the example experimental_libuarte.   I changed two functions like below:

1. nrf_libuarte_tx(): m_tx_len = len;  --> m_tx_len = 3*len;

2. comment the below lines included in UART_DRV_IRQHandler() : 

nrfx_err_t err = nrfx_ppi_channel_disable(m_ppi_channels[PPI_CH_ENDTX_STARTTX]);
ASSERT(err == NRFX_SUCCESS);

I had expected to send the below text 3 times, but I just got once.  When I added a function 

nrf_uarte_task_trigger(UART_DRV_UARTE, NRF_UARTE_TASK_STARTTX) in the commented place, I can get sending the text 3 times successfully. 

static uint8_t text[] = "UART example started.\r\n Loopback:\r\n";

My question is : the initialization has configured the ppi endtx-->starttx, why did need the trigger manually every time?

Parents
  • Hi,

    I'm not sure I understand the logic in your approach. Changing the 'len' variable in nrf_libuarte_tx will not duplicate the data in 'p_data' input, it will just set the length of the provided buffer to 3 times its size. If you have other data in the RAM area following the provided buffer, this will be output over UART. If you want to send the provided buffer multiple times, you need to duplicate the data in the pointed RAM region as well.

    The PPI channel from ENDTX to STARTTX is only enabled in nrf_libuarte_tx() if the len variable is larger than MAX_DMA_XFER_LEN (255 bytes for nRF52832). The intention of this is to setup two buffers in RAM to transfer back to back, providing support for longer buffers. When you trigger the STARTTX task in the interrupt handler, you essentially start a new transfer with the previously configured buffer and length.

    What are you trying to achieve by making these changes? I think it would be easier approach to duplicate the text outside of the function, rather than modifying the library?

    Best regards,
    Jørgen

  • Hi Jørgen,

    Thanks for your reply.  Now I haved downloaded the sdk5 17.0.2. With examples\peripheral\libuarte, I am trying to understand how the libuarte work.  It seems to be more easier to understand. From reading the source code and debuging, I understood the data structures and the procession of tranmission, receiving, pool block allocation and freeing. Now I have one question about the queue (queue within libuarte, not within main.c). I just got that the start address of the allocated block is pushed into the queue, and then it is popped from the queue into the p_curr_rx_buf.  There is somthing I have missed ? 

    What is the purpose with this queue?   How to be used within the libuarte? 

    Another question:  How to figure out when we should invoke nrf_libuarte_async_rx_free() to free the allocated block?  Every time nrf52832 received the message at application layer?  How to get the address for freeing?   From the example, I got that after nrf52832 had reveived datas and tranmit, it invoked this call when ...TX_DONE event was genereated. 

Reply
  • Hi Jørgen,

    Thanks for your reply.  Now I haved downloaded the sdk5 17.0.2. With examples\peripheral\libuarte, I am trying to understand how the libuarte work.  It seems to be more easier to understand. From reading the source code and debuging, I understood the data structures and the procession of tranmission, receiving, pool block allocation and freeing. Now I have one question about the queue (queue within libuarte, not within main.c). I just got that the start address of the allocated block is pushed into the queue, and then it is popped from the queue into the p_curr_rx_buf.  There is somthing I have missed ? 

    What is the purpose with this queue?   How to be used within the libuarte? 

    Another question:  How to figure out when we should invoke nrf_libuarte_async_rx_free() to free the allocated block?  Every time nrf52832 received the message at application layer?  How to get the address for freeing?   From the example, I got that after nrf52832 had reveived datas and tranmit, it invoked this call when ...TX_DONE event was genereated. 

Children
  • Young said:
    What is the purpose with this queue?

    As far as I can see, this queue only holds the RX buffer passed to the libUARTE driver from the async library, until the transfers are completed and passed along to the application.

    Young said:
    How to be used within the libuarte? 

    You are not supposed to use this queue in your application. The queue is part of the libUARTE library, which you should not need to modify.

    Young said:
    How to figure out when we should invoke nrf_libuarte_async_rx_free() to free the allocated block? 

    The function should be called as soon as you have processed the received data in the buffer. Failing to free the buffer in time will lead to libUARTE running out of available buffers, preventing you from receiving more data over UART.

    Young said:
    Every time nrf52832 received the message at application layer?

    If you process the data in the buffer quickly in the handler, that would be preferable. If not, you should call it as soon as the data in the buffer is no longer needed in your application.

    Young said:
    How to get the address for freeing?

    Address and size of the received buffer portion is given in p_evt->data.rxtx.p_data and p_evt->data.rxtx.length in the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. If you do not free the buffer inside this event, it is important that you store these variables for freeing later. You need to free the exact number of received bytes in order for the full buffer to be released once the number of bytes corresponding to the defined buffer size is received, if not the buffer can't be reused and libUARTE will eventually fail.

    Young said:
    From the example, I got that after nrf52832 had reveived datas and tranmit, it invoked this call when ...TX_DONE event was genereated. 

    Yes, the example is a loopback example, which transmits back what it receives. The buffer is not freed until the TX event, as this is when the example is done processing/using the data in the received buffer. 

  • Hi Jørgen,
    Thank you very much for you detailed answer. 
    By the way, for the first question, I read the section about the queue again.  Now my understanding is that ..queue_pop() lets p_curr_rx_buf (within async)  point to the next allocated block (which is the current block for rx), so p_curr_rx_buf can be consistent with p_cur_rx since p_cur_rx has been changed within drv previously. 
Related