Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Receiving for UART with FreeRTOS

Hello,

I have implemented a somewhat working RX algorithm for receiving data over UART but I'm looking for a good way to make it more robust. I haven't found any good answers to this in either the forum or the infocenter and I get a little bit confused regrading the driver setup.

My implementation:

  • Custom board using nRF52840
  • Using the nRF5 SDK v15.0.0.
  • Using FreeRTOS, built from the "ble_app_hrs_freertos"-example. (At the moment without BLE stack initialization.)
  • Implemented FreeRTOS task for handling UART communication.
  • Have a module connected over UART that use AT-commands.

Assumptions:

  • As it is AT-commands I always know the ending of the message, though I don't know the length as the reply to one command can be different.
    • An example is reading the ID which gives 24 bytes as answer. If there is a failure, the answer is simply "+ERR=x".
    • There is a response to every TX, thus I want to have RX after TX.

So far I have tried mostly with the "Serial port library" and I have tried using blocking-mode similar to:

uint32_t received_bytes = 0;
err = nrf_serial_write(&serial_uart, tx_tmp, tx_size, NULL, NRF_SERIAL_MAX_TIMEOUT);
err = nrf_serial_read(&serial_uart, rx_tmp, 50, &received_bytes, 100);

This does however only work for the first message. The second time I try with nrf_serial_read() I get an error as the handle for the timer is not null, somewhere around line 136 in app_timer_freertos.c (DUH, it is already created). For experimentation I changed to the following in app_timer_create() function in app_timer_freertos.c and now it works (even though I know it is a VERY ugly solution):

    if (pinfo->osHandle == NULL)
    {
        /* New timer is created */
        memset(pinfo, 0, sizeof(app_timer_info_t));

        if (mode == APP_TIMER_MODE_SINGLE_SHOT)
            timer_mode = pdFALSE;
        else
            timer_mode = pdTRUE;

        pinfo->func = timeout_handler;
        pinfo->osHandle = xTimerCreate(" ", 1000, timer_mode, pinfo, app_timer_callback);

        if (pinfo->osHandle == NULL)
            err_code = NRF_ERROR_NULL;
    }
    else
    {
        xTimerReset(pinfo->osHandle, 100);
        /* Timer cannot be reinitialized using FreeRTOS API */
        //return NRF_ERROR_INVALID_STATE;
    }

So is this a bug or am I using it totally wrong? Is the approach of using software timers good, or should I change to some other method?

Regards

Robert

Parents
  • I have also found issues when using the app_timer when I know the exact amount of bytes, i.e. I know that I will recieve 10 bytes and thus I set:

    err = nrf_serial_read(&serial_uart, tmp_rx, 10, &received_bytes, 100);

    The problem at this stage is that the timer is actually not reset when the correct amount of bytes are recieved. I think an "app_timer_stop(*p_serial->p_rx_timer);" should be set also when the expected byte count is recieved such as:

    do
        {
            size_t rcnt = serial_rx(p_serial, p_buff, left);
            left -= rcnt;
            p_buff += rcnt;
            if (!left)
            {
                (void)app_timer_stop(*p_serial->p_rx_timer);
                break;
            }
    
            if (tout_ctx.expired)
            {
                if (p_serial->p_ctx->p_config->mode != NRF_SERIAL_MODE_POLLING)
                {
                    nrf_drv_uart_rx_abort(&p_serial->instance);
                }
                break;
            }
    
            sleep_handler(p_serial);
        } while (1);

    In nrf_serial_read() function approx at line 460 to 479 in nrf_serial.c.

    I guess there should be a check if the timer is active before trying to stop it, or maybe that doesn't matter...?

Reply
  • I have also found issues when using the app_timer when I know the exact amount of bytes, i.e. I know that I will recieve 10 bytes and thus I set:

    err = nrf_serial_read(&serial_uart, tmp_rx, 10, &received_bytes, 100);

    The problem at this stage is that the timer is actually not reset when the correct amount of bytes are recieved. I think an "app_timer_stop(*p_serial->p_rx_timer);" should be set also when the expected byte count is recieved such as:

    do
        {
            size_t rcnt = serial_rx(p_serial, p_buff, left);
            left -= rcnt;
            p_buff += rcnt;
            if (!left)
            {
                (void)app_timer_stop(*p_serial->p_rx_timer);
                break;
            }
    
            if (tout_ctx.expired)
            {
                if (p_serial->p_ctx->p_config->mode != NRF_SERIAL_MODE_POLLING)
                {
                    nrf_drv_uart_rx_abort(&p_serial->instance);
                }
                break;
            }
    
            sleep_handler(p_serial);
        } while (1);

    In nrf_serial_read() function approx at line 460 to 479 in nrf_serial.c.

    I guess there should be a check if the timer is active before trying to stop it, or maybe that doesn't matter...?

Children
No Data
Related