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

LIBUARTE on ble_app_uart with DMA

Hi All,

I have 2 boards nrf52840 pc10056 and I need to run ble_app_uart using LIBUARTE with DMA in order to obtain a more robust uart communication

I would like to use an uart DMA that will work in background saving the byte received in a buffer (fixed length) and once that it is full having an interrupt where I can check this buffer and send it to the central unit.

Is there any easy way to set  everything up and change the code of ble_app_uart? Any suggestion??

Thanks

Parents
  • Hello

    I don't know what exactly to assist you with here, as you will just have to work through these errors until you have the libuarte configured correctly. If you get stuck on anything specific, I will, of course, help you out, but this process is something you will have to go through and fix yourself.

    Best regards,

    Simon

  • Hello,

    I managed to implement libuarte in ble_app_uart and, finally I have no problems compiling and I can send data from the "peripheral" to the "central".

    Obviously sending the data I have a lot of errors yet that I hope you will be able to help me.

     

    For now I have focused only on the "peripheral" side, which means that the central remained as from SDK 15.3 (except for the fact that I removed the ECHO of the data, so the data received are not sent back).

     

    Of course I’ve modified something in the sdk_config.h and the main in the ble_app_uart example.

    In the MAIN, compare to the ble_app_uart example, I’ve changed the init of the UART:

    //UART INIT:
    …………………
    NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 3, 0, 4, 75, 3);
    ………………………………………………………..
    
    static void uart_init(void)
    {
    nrf_libuarte_async_config_tnrf_libuarte_async_config = {
                      .tx_pin     = TX_PIN_NUMBER,
                      .rx_pin     = RX_PIN_NUMBER,
                      .baudrate   = NRF_UARTE_BAUDRATE_115200,
                      .parity     = NRF_UARTE_PARITY_EXCLUDED,
                      .hwfc       = NRF_UARTE_HWFC_DISABLED,
                      .timeout_us = 100,
              };
    
    ret_code_terr_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, &libuarte);
    
              APP_ERROR_CHECK(err_code);
    
    nrf_libuarte_async_enable(&libuarte);
    
    }
    

    and the "void uart_event_handler" method which I report below:

    /**@snippet [UART Initialization] */
    
    //UART_EVENT_HANDLER:
    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
            nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
                uint32_t       err_code;
            ret_code_t ret;
            
            
            switch (p_evt->type)
                {
                        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                            bsp_board_led_invert(0);
                            break;
                        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                        	ret=nrf_libuarte_async_tx(p_libuarte,  p_evt->data.rxtx.p_data , p_evt->data.rxtx.length);
                        	bsp_board_led_invert(2);
                        
                        //	do
                        //                    {
                        //                        uint16_t length = (uint16_t)index;
                        //                        err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
                        //                        if ((err_code != NRF_ERROR_INVALID_STATE) &&
                        //                            (err_code != NRF_ERROR_RESOURCES) &&
                        //                            (err_code != NRF_ERROR_NOT_FOUND))
                        //                        {
                        //                            APP_ERROR_CHECK(err_code);
                        //                        }
                        //                    } while (err_code == NRF_ERROR_RESOURCES);
                        
                        	nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data,p_evt->data.rxtx.length);
                        	break;
                        case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                            bsp_board_led_invert(3);
                            break;
                            default:
                            break;
                }
    }
    

    The idea is:

    Write from microcontroller on the peripheral UART, the peripheral receives and sends to the central. Before doing this, or using the "ble_nus_data_send" I would like to see what happen in the peripheral side, so,once I received  the data on the UART, instead to use "ble_nus_data_send" (that for sure once I remove the comments will give some problem),I print everything on the peripheral UART terminal with "nrf_libuarte_async_tx".

    If with a microcontroller I send a string of "N" characters that ends with "\n" every "s" m_seconds what should happen is:

    As is the program, (considering the commented lines) once the string is received it is printed. The problem is that what I print is not exactly what I send, but it is like that in the buffer something is stored and something is repleced from a new data.

    If I'm sending a buffer like this:

    ABCDEFG\n, for instance I get something "similar":

    ABCDEFG\n

    ABCDEFG\n

    ABCDEFG\n

    ABCDEFABCDEFGABCDEFGABCDEFG\n

    .

    .

    .

    ABCABCDEFG\nABCDEFG

    ABCDEFG\n

    ABCDEFG\n

    I do believe that is something releated to the size of the buffer here:

    "NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 3, 0, 4, 75, 3);"

    But, if I try with the experimental_libuarte it works perfectly. In that example I modified few rows that I report here:

     

    MAIN experimental_libuarte:

    voiduart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    
    ret_code_t ret;
    
    switch (p_evt->type)
        {
    case NRF_LIBUARTE_ASYNC_EVT_ERROR:
    bsp_board_led_invert(0);
    break;
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
    bsp_board_led_invert(1);
    ret = nrf_libuarte_async_tx(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
    nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
    break;
    case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
    bsp_board_led_invert(2);
    break;
    default:
    break;
        }
    }
    

    This works perfectly.

      

    What am I doing wrong?

    Am I missing something?

    To be honest, I didn't understand how the buffer (DMA size etc) works. Can you help me?

    For instance, I would like the characters to be stored in the DMA buffer (which I don't know how to access), and an interrupt to be triggered only when the buffer is filled. Once that the interrupt happens the program goes into the event handler routine in the main and I print the buffer.

     

    - Another thing is that with the ble_app_uart that I modified, the board works just in debug. If I just flash it in Release or Debug and then I try to use, it does not work.

    -The experimental_libuarte that you released in SDK15.3 in "DEBUG" mode goes directly to NRF_BREAKPOINT_COND, in Release no.

    Thanks

Reply
  • Hello,

    I managed to implement libuarte in ble_app_uart and, finally I have no problems compiling and I can send data from the "peripheral" to the "central".

    Obviously sending the data I have a lot of errors yet that I hope you will be able to help me.

     

    For now I have focused only on the "peripheral" side, which means that the central remained as from SDK 15.3 (except for the fact that I removed the ECHO of the data, so the data received are not sent back).

     

    Of course I’ve modified something in the sdk_config.h and the main in the ble_app_uart example.

    In the MAIN, compare to the ble_app_uart example, I’ve changed the init of the UART:

    //UART INIT:
    …………………
    NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 3, 0, 4, 75, 3);
    ………………………………………………………..
    
    static void uart_init(void)
    {
    nrf_libuarte_async_config_tnrf_libuarte_async_config = {
                      .tx_pin     = TX_PIN_NUMBER,
                      .rx_pin     = RX_PIN_NUMBER,
                      .baudrate   = NRF_UARTE_BAUDRATE_115200,
                      .parity     = NRF_UARTE_PARITY_EXCLUDED,
                      .hwfc       = NRF_UARTE_HWFC_DISABLED,
                      .timeout_us = 100,
              };
    
    ret_code_terr_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, &libuarte);
    
              APP_ERROR_CHECK(err_code);
    
    nrf_libuarte_async_enable(&libuarte);
    
    }
    

    and the "void uart_event_handler" method which I report below:

    /**@snippet [UART Initialization] */
    
    //UART_EVENT_HANDLER:
    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
            nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
                uint32_t       err_code;
            ret_code_t ret;
            
            
            switch (p_evt->type)
                {
                        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                            bsp_board_led_invert(0);
                            break;
                        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                        	ret=nrf_libuarte_async_tx(p_libuarte,  p_evt->data.rxtx.p_data , p_evt->data.rxtx.length);
                        	bsp_board_led_invert(2);
                        
                        //	do
                        //                    {
                        //                        uint16_t length = (uint16_t)index;
                        //                        err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
                        //                        if ((err_code != NRF_ERROR_INVALID_STATE) &&
                        //                            (err_code != NRF_ERROR_RESOURCES) &&
                        //                            (err_code != NRF_ERROR_NOT_FOUND))
                        //                        {
                        //                            APP_ERROR_CHECK(err_code);
                        //                        }
                        //                    } while (err_code == NRF_ERROR_RESOURCES);
                        
                        	nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data,p_evt->data.rxtx.length);
                        	break;
                        case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                            bsp_board_led_invert(3);
                            break;
                            default:
                            break;
                }
    }
    

    The idea is:

    Write from microcontroller on the peripheral UART, the peripheral receives and sends to the central. Before doing this, or using the "ble_nus_data_send" I would like to see what happen in the peripheral side, so,once I received  the data on the UART, instead to use "ble_nus_data_send" (that for sure once I remove the comments will give some problem),I print everything on the peripheral UART terminal with "nrf_libuarte_async_tx".

    If with a microcontroller I send a string of "N" characters that ends with "\n" every "s" m_seconds what should happen is:

    As is the program, (considering the commented lines) once the string is received it is printed. The problem is that what I print is not exactly what I send, but it is like that in the buffer something is stored and something is repleced from a new data.

    If I'm sending a buffer like this:

    ABCDEFG\n, for instance I get something "similar":

    ABCDEFG\n

    ABCDEFG\n

    ABCDEFG\n

    ABCDEFABCDEFGABCDEFGABCDEFG\n

    .

    .

    .

    ABCABCDEFG\nABCDEFG

    ABCDEFG\n

    ABCDEFG\n

    I do believe that is something releated to the size of the buffer here:

    "NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 3, 0, 4, 75, 3);"

    But, if I try with the experimental_libuarte it works perfectly. In that example I modified few rows that I report here:

     

    MAIN experimental_libuarte:

    voiduart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    
    ret_code_t ret;
    
    switch (p_evt->type)
        {
    case NRF_LIBUARTE_ASYNC_EVT_ERROR:
    bsp_board_led_invert(0);
    break;
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
    bsp_board_led_invert(1);
    ret = nrf_libuarte_async_tx(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
    nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
    break;
    case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
    bsp_board_led_invert(2);
    break;
    default:
    break;
        }
    }
    

    This works perfectly.

      

    What am I doing wrong?

    Am I missing something?

    To be honest, I didn't understand how the buffer (DMA size etc) works. Can you help me?

    For instance, I would like the characters to be stored in the DMA buffer (which I don't know how to access), and an interrupt to be triggered only when the buffer is filled. Once that the interrupt happens the program goes into the event handler routine in the main and I print the buffer.

     

    - Another thing is that with the ble_app_uart that I modified, the board works just in debug. If I just flash it in Release or Debug and then I try to use, it does not work.

    -The experimental_libuarte that you released in SDK15.3 in "DEBUG" mode goes directly to NRF_BREAKPOINT_COND, in Release no.

    Thanks

Children
  • Hi,

    I have to admit it's been a while since I worked with libuarte. but the Libuarte driver is a bit special given that it uses a timer to stop RX if the peer does not send date for a certain amount of time. This means that if you send multiple short packets with a given delay inbetween your application might not be able to read the data from the RX buffer before it is switced to the next buffer and then back again. the pointer for DMA will typically be updated between the rx events. Also this means that the other part of the uart communication has to respect these limitations. so if it want to send a lot of data to one buffer that has to be completed within a certain time (you cannot wait to send more data as the rx timer will expire). Or if you want to send short packets you have to wait for the timeout to occur, before sending the next one.

    If it's possible to use HW flow control, you could disable the timer and use that instead. Not sure if this is possible with the driver at this stage. Note that the timeout was added to make it possible to transimt at high baudrates without hwfc.

  • Hi All,

    I have partially solved the problem. When I try to send the data over Bluetooth, from the other side I get them, but the peripheral stops at certain point to send data.

    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        uint32_t       err_code;
        ret_code_t ret;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                bsp_board_led_invert(1);
                break;
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                bsp_board_led_invert(2);
                err_code= ble_nus_data_send(&m_nus, p_evt->data.rxtx.p_data, &p_evt->data.rxtx.length, m_conn_handle);
                do
                {
                    if ((err_code != NRF_ERROR_INVALID_STATE) &&
                        (err_code != NRF_ERROR_RESOURCES) &&
                        (err_code != NRF_ERROR_NOT_FOUND))
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_RESOURCES);
                nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data , p_evt->data.rxtx.length);    
                break;
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                bsp_board_led_invert(3);
                break;
            default:
                break;
        }
    }

    Exactly sends the data based on the size of the buffer when I define the NRF_LIBUARTE (the RX in this case). The larger the buffer the greater the number of packets sent, then it stops to send packets.

    NRF_LIBUARTE_ASYNC_DEFINE (libuarte, 0, 3, 0, 4, "RX", 3);

    The same thing happen if for example, in stead to send the data received from UART to the central, I print them again on the UART of the peripheral and I do not make free the RX buffer:

    "nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data , p_evt->data.rxtx.length);  " 

    See the code below:

    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        uint32_t       err_code;
        ret_code_t ret;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                bsp_board_led_invert(1);
                break;
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                bsp_board_led_invert(2);
                ret = nrf_libuarte_async_tx(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
    //          err_code= ble_nus_data_send(&m_nus, p_evt->data.rxtx.p_data, &p_evt->data.rxtx.length, m_conn_handle);
                do
                {
                    if ((err_code != NRF_ERROR_INVALID_STATE) &&
                        (err_code != NRF_ERROR_RESOURCES) &&
                        (err_code != NRF_ERROR_NOT_FOUND))
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_RESOURCES);
                nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data , p_evt->data.rxtx.length);    // if I remove this line of code I will have more or less the same behavior 
                break;
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                bsp_board_led_invert(3);
                break;
            default:
                break;
        }
    }

    Any help is appreciated ;) Upside downUpside down 

    Thank you all Slight smileSlight smileSlight smile

Related