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

un-init and then re-init buarte_async module will report NRF_LIBUARTE_ASYNC_EVT_ERROR

Hi, support team 

       I need to realize two-wire uarte receiver(with low power), in the scenario there is no data come from TX in most time, so after receiving the data I need to un-initialize the uarte module and step into low-power mode. I choose libuarte sample on SDK16.0.0 + nrf52840 platform. the logic is like this :

      gpiote init(waiting port event)-> libuarte_async_init->received data until timeout -> libuarte_async_uninit->re-init gpiote (waiting for port event and new data)

      So I directly made some modification on our libuarte sample.

      First, I defined my instance as easy as possible:

           NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1, 3);

      Then in my main loop, once gpio port event coming , myGPIOTE_EVENT_FLAG will be set, and then prepares to receive uarte data(un-init gpiote/init+enable libuarte_async) ; when the timeout event coming(myRX_DONE_FLAG be set) , it un-init libuarte_async module and re-init the two PORT to gpio mode(wait event). My main C file is here:

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "nrf_libuarte_async.h"
#include "nrf_drv_clock.h"
#include <bsp.h>
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_queue.h"
#include "nrf_log.h"
#include "nrf_drv_gpiote.h"
volatile bool myGPIOTE_EVENT_FLAG=false;
volatile bool myRX_DONE_FLAG=false;
NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1, 3);
volatile uint8_t myindex=0;
uint8_t rxdata_array[10]={0};
#define RXD_GPIOTE_PIN 26
#define TXD_GPIOTE_PIN 27
nrf_libuarte_async_config_t nrf_libuarte_async_config = {
        .tx_pin     = TXD_GPIOTE_PIN,
        .rx_pin     = RXD_GPIOTE_PIN,
        .baudrate   = NRF_UARTE_BAUDRATE_115200,
        .parity     = NRF_UARTE_PARITY_EXCLUDED,
        .hwfc       = NRF_UARTE_HWFC_DISABLED,
        .timeout_us = 100,
        .int_prio   = APP_IRQ_PRIORITY_LOW
};

static void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    myGPIOTE_EVENT_FLAG=true;
    for(int i=0;i<50;i++);
}

static void gpio_init(void)
{
    ret_code_t err_code;
    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
    in_config.pull = NRF_GPIO_PIN_PULLUP; //Pin pull-up resistor enabled.
    err_code = nrf_drv_gpiote_in_init(RXD_GPIOTE_PIN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);
    nrf_drv_gpiote_in_event_enable(RXD_GPIOTE_PIN, true);
	myGPIOTE_EVENT_FLAG=false;
}

static void gpio_uninit(void)
{
    nrf_drv_gpiote_in_event_disable(RXD_GPIOTE_PIN);
    nrf_drv_gpiote_in_uninit(RXD_GPIOTE_PIN);
    nrf_drv_gpiote_uninit();
}

void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    switch (p_evt->type)
    {
        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
            NRF_LOG_INFO("uart_event_handler:NRF_LIBUARTE_ASYNC_EVT_ERROR");
            break;
        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
            NRF_LOG_INFO("received %d byte %d",p_evt->data.rxtx.length,p_evt->data.rxtx.p_data[0]);
            rxdata_array[myindex]=p_evt->data.rxtx.p_data[0];
            myindex+=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_TIMEROUT:
            myRX_DONE_FLAG=true;
            NRF_LOG_INFO("Timeout+++++++");
            
        default:
            break;
    }
}

/**
 * @brief Function for main application entry.
 */
int main(void)
{
    bsp_board_init(BSP_INIT_LEDS);
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);
    err_code = NRF_LOG_INIT(app_timer_cnt_get);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    gpio_init();
    NRF_LOG_INFO("Main");
    while(true){
        __WFE();
        __SEV();
        if(myGPIOTE_EVENT_FLAG){
            NRF_LOG_INFO("step into main loop!");
            NRF_LOG_FLUSH();
            bsp_board_led_on(BSP_BOARD_LED_0); 
            gpio_uninit();
            err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, (void *)&libuarte);
            APP_ERROR_CHECK(err_code);
            nrf_libuarte_async_enable(&libuarte);
            bsp_board_led_off(BSP_BOARD_LED_0);
            while(!myRX_DONE_FLAG);
            myRX_DONE_FLAG=false;
            NRF_LOG_INFO("DONE!,index =%d,last value:%d", myindex, rxdata_array[myindex-1]);
            NRF_LOG_FLUSH();
            //nrf_libuarte_async_disable(&libuarte);
            nrf_libuarte_async_uninit(&libuarte);
            gpio_init();
            memset(rxdata_array,0x0,10);
            myindex=0;
        }
        __SEV();
        __WFE();
    }
}

/** @} */

I add an NRF_LIBUARTE_ASYNC_EVT_TIMEROUT event to inform the main loop that it ‘s time to change to gpio mode.

It defined in components\libraries\libuarte\nrf_libuarte_async.c => nrf_libuarte_async_timeout_handler(), I added the logic:

    ......
    if (capt_rx_count > p_libuarte->p_ctrl_blk->rx_count)
    {
       ......//default code
    }
    else if(capt_rx_count = p_libuarte->p_ctrl_blk->rx_count){
        nrf_libuarte_async_evt_t evt = {
            .type = NRF_LIBUARTE_ASYNC_EVT_TIMEROUT
            .data = NULL
        };
        p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
    }
    ......

    In my test demo, I choose TX send 5Byte data each round and then sleep 10s, then sending 5Byte, then sleep…always looping .

     I run my RX code in nrf52840DK, The first round of receiving 5Byte data is right(in fact, in each round the first Byte is for triggering gpio port event , I do not care its detail), But when the second round of data coming, it reports error. like this :

Maybe before I un-init the module, I need to clear something or recover something to default?  so the next the re-init & receiving can becomes normal??

And also I'm not sure of the right using of timeout event.

Please help to give some advices, thanks!

BR

Smile

Top Replies

  • Hi,

    If you toggle wakeup directly from the RXD pin, then the UART is in the process of receiving a byte when you init the libuarte library. This will cause a UART framing error -> NRF_LIBUARTE_ASYNC_EVT_TIMEROUT. I think this is expected based on the description, you can ignore the error.

    You can also try to add a delay of 100ms when if(myGPIOTE_EVENT_FLAG) is true, then you know there is no more UART activity when you init libuarte.

    If this is not the problem, then I suggest to try to reset the peripherals used by the libuarte library after uninit by using the follwing address for each peripheral until you find which peripheral is the problem:

    *(volatile uint32_t *)[peripheral base address + 0xFFC] = 0;
    *(volatile uint32_t *)[peripheral base address + 0xFFC;
    *(volatile uint32_t *)[peripheral base address + 0xFFC] = 1;

    Base addresses (e.g. uart, timer, rtc) is found here:
    https://infocenter.nordicsemi.com/topic/ps_nrf52840/memory.html#topic

    Best regards,
    Kenneth

  • Hi Kenneth
           I think you may not get my issue, thanks for the three suggestions you provided, I gave some explanations here based on my Rx code:
          1. The first byte from Tx is to wake up the the RxD pin, so the RxD pin SENSE the signal as an gpiote port event, then in the gpiote event interrupt I added a delay like: "for(int i=0;i<50;i++);", so it's not the problem;
          Because Rx cannot know when to close the libuarte and step into idle mode(with gpio SENSE),I added the new event                  NRF_LIBUARTE_ASYNC_EVT_TIMEROUT to inform the main loop that : there is a time that TX not sending data and it's time to stop libuarte.


          2.it's OK to received correctly data in the first round, the error is in the second round, the RX program running like this:
          system_idle1->gpiote port event->uninit gpiote, init libuarte->received all data correctly->(because Tx sent all the data and started long delay) Rx timeout, so uninit libuarte->reinit gpiote->system_idle2; then untill the second round data coming:
         -> gpiote port event->un-init gpiote, init libuarte-> NRF_LIBUARTE_ASYNC_EVT_ERROR
         So in my loop, system_idle2 seems to not completely the same with system_idle1, thus cause the  NRF_LIBUARTE_ASYNC_EVT_ERROR event.


         3.I will try your method, in fact I already had an simplified test case(only with uart+gpiote+app_timer). it can work not needing to reset the peripheral, it's possible to work without resetting peripherals.
    Attached my test case with two nrf52840DK, needed to power on Tx firstly then power on Rx,

    haha.7z

    Just for your reference. and hoping for your reply

    Smile

    BR

  • Hi Kenneth

        I tried to reset the uarte used by the libuarte library after uninit , then the event"

    NRF_LIBUARTE_DRV_EVT_RX_DATA" will never come , I just can receive the last byte from timeout event...
    Smile
    BR
  • Can you toggle a GPIO when you call nrf_libuarte_async_enable() so you can monitor on a logic analyzer to make sure that no UART byte is in the middle of a transaction when you enable it?

    Also, instead of modifying libuarte, have you considered starting an app_timer in application to handle if no data is received on UART after nrf_libuarte_async_enable?

    The timeout in libuarte is used to detect inactivity on the UART lines (e.g. no more data received since last byte), the timeout will likely not start unless it first receive a byte.

    Best regards,
    Kenneth

  • Hi  Kenneth

         I think the problemed solved, I just tried to reset uarte0, then the whole round always works~~, think you.

    BR

    Smile

Related