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

nrfx_uarte works in non-blocking mode but nrfx_uart can only send 1 byte.

Hi,

I am working on a 2-wire uart to save GPIO and try to get as low current consumption as I can get.

Here is how I want it to be:

My custom 52840 board have 2-wire rx/tx connected to a sensor's UART and there is no RTS/CTS.

After received UART data from the sensor, 52840 will wake up and then process the data sent by the sensor and then back to sleep again.

The sensor will resend uart data until hear UART response from 52840, so I don't need to worry about data lost.

I looked up in devzone and found out that I can not use zephyr uart driver or lpuart to achieve my goal.

(Or is there a valid approach that I do not find?)

I checked sample/nrf/nrfx_prs, I think I can follow this sample and make it works like this:

Config rx pin of 52840 as an GPIO and register an IRQ.

When there were data comes in then reconfig UART at runtime using nrfx_uarte_init() and start sending/recving data.

After no more data comes in, call nrfx_uarte_uninit and reconfig the rx pin to GPIO and register an IRQ to save power.

It works using nrfx_uarte_init() and then use nrfx_uarte_tx() to send data using non-blocking mode.

Then I found this thread: 52833-uart-power-consumption, It looks like using EasyDMA will have a higher current consumption.

So I try to use nrfx_uart to replace nrfx_uarte. This is where I met the issue:

After I changed .overlay to use "nordic,nrf-uart" to replace "nordic.nrf-uarte", and use nrfx_uart_xxx APIs to replace nrfx_uarte_xxx APIs.

Then I put 12 bytes in the tx buffer of nrfx_uart_tx() and only 1 byte recved. (I use a USB-Serial cable to connect 52840 with my PC and with nrfx_uarte_xxx APIs, it works properly)

Then I try to set the callback func to NULL in nrfx_uart_init() to make it works in blocking mode, after that all 12 bytes recved.

Removed all my code and only called nrfx_uart_init() and nrfx_uart_tx() and the issue is still there.

Any suggestions?

How can I use nrfx_uart in non-blocking mode?

Regards,

Anthony Yuan

Parents
  • Hi,

    Can you share your non-blocking uart code?

    regards

    Jared 

  • //In overlay file
    &uart0 {
    	compatible = "nordic,nrf-uart";
    	status = "disabled";
    	current-speed = <115200>;
    	tx-pin = <6>;
    	rx-pin = <8>;
    	/* delete rts-pin&cts-pin to release the related 2 pins for other uses */
    	/delete-property/ rts-pin;
    	/delete-property/ cts-pin;
    };
    
    
    //In .c file
    static nrfx_uart_t uart = NRFX_UART_INSTANCE(0);
    
    //callback func of nrfx_uart
    static void uart_cb(const nrfx_uart_event_t *p_event, void *p_context)
    {
    	if (p_event->type == NRFX_UART_EVT_RX_DONE) {
            LOG_INF("NRFX_UART_EVT_RX_DONE in uart_cb()");
    	} else if (p_event->type == NRFX_UART_EVT_TX_DONE) {
            LOG_INF("NRFX_UART_EVT_TX_DONE in uart_cb()");
    	} else if (p_event->type == NRFX_UART_EVT_ERROR) {
            LOG_INF("NRFX_UART_EVT_ERROR in uart_cb()");        
        }
    }
    
    // runtime config uart
    static bool switch_to_uart(void)
    {
        nrfx_err_t err;
        nrfx_uart_config_t uart_config = NRFX_UART_DEFAULT_CONFIG(
            /* Take pin numbers from devicetree. */
            DT_PROP(UART_NODE, tx_pin),
            DT_PROP(UART_NODE, rx_pin));
        uart_config.baudrate = NRF_UART_BAUDRATE_115200;
    
        err = nrfx_uart_init(&uart, &uart_config, uart_cb);
        if (err != NRFX_SUCCESS) {
            return false;
        } else {
            return true;
        }
    }
    
    static void uart_thread(void *dummy1, void *dummy2, void *dummy3)
    {
        static uint32_t uart_len;
        static uint8_t tx_buffer[255];
    
    	ARG_UNUSED(dummy1);
    	ARG_UNUSED(dummy2);
    	ARG_UNUSED(dummy3);
    
        switch_to_uart();
    
        while (1) {
            struct uart_data_t *buf = k_fifo_get(&fifo_uart_tx_data, K_FOREVER); //K_FOREVER
            if ((buf != NULL) && (buf->len < UART_BUF_SIZE)) {
                // send data via uart
                int err = 0; 
                memcpy(tx_buffer, buf->data, buf->len);
                /* breakpoint here and tx_buffer seems normal and buf->len == 12
                * but there is only the first byte read in PC's uart
                * If I change all nrfx_uart APIs to nrfx_uarte APIs and change the overlay accourdingly, it works properly.
                */ 
                err = nrfx_uart_tx(&uart, tx_buffer, buf->len); 
                LOG_INF("uart tx len %d and result is %d", uart_len, buf->len); 
            }
            k_free(buf);
        }
    }

  • Hi,

    Can you try moving the uart_data_t buffer outside of the uart_thread() scope? And why are you calling the nrfx_uart_tx() in a loop?

    Also the UART peripheral is deprecated on the nRF52840, so we're limited to what we support. I strongly suggest looking at our low power UART driver and example. It uses UARTE but implements a low power version. 

    regards

    Jared 

  • Thanks for your reply Jared.

    1. The fifo was filled outside of the loop and inside the loop it check the fifo and then send data via uart.

    2. I tried set uart0 status = "okay" in the overlay file / commented nrfx_uart_init(). Then nrfx_uart_tx() works properly. I think the problem is that my code can not config nrfx_uart driver at runtime.

    3. I read lpuart sample code and it is helpful, but I have one question: lpuart uses the request pin to wake up uart, can I reconfig the 840 uart rx pin as the wake up pin and after wake up, reconfig the pin back to uart rx and start recving uart data?

    4. I think I need to work on nrfx_uarte driver and handle rx pin reconfiguration by myself, is it correct? Any other suggestions?

    5. I can not find how req-pin been handled by nrf-sw-lpuart, maybe I can take it as a reference to handle the uart wake-up and rx pin reconfiguration.

    Regards,

    Anthony Yuan

  • Hi,

    Configuring the RDY pin to RX after the receiver wakes up is not supported by the driver as the RDY pin needs to detect the state change from High to Low from the transmitter which signalizes the end of the the transaction. You can find the implementation of the uart low power protocol in ncs\v1.7.1\nrf\drivers\serial\uart_nrf_sw_lpuart.c driver.

    regards

    Jared 

  • Thanks Jared and I am using nrfx_uarte APIs to write my own uart driver.

    Here is what I see on my 840 DK:

    1, DK start up and before nrfx_uarte_init(), average current is 20uA.

    2, After nrfx_uarte_init(), I can read/write uarte properly and average current when there is no data transfer is around 305uA.

    3, Wait 5 seconds without uart data comes in/out, call nrfx_uarte_uninit(). But there is still 135uA current consumption:

    I checked uart_nrf_sw_lpuart() and I think I need to turn off HFXO(high frequency RC oscillator) after uninit uarte, to resume 20uA average power consumption.

    a) Should I using onoff manager to turn off HFXO? As my driver is using nrfx_uarte APIs directly, is there any suggested HAL/driver layer API to turn off HFXO?

    b) Any other suggestions on turn off uart to get the lowest current consumption?

    Regards,

    Anthony Yuan

  • Hi,

    Do you turn on the HFXO clock explicitly? If not then the UARTE driver will use HFINT, and disable it automatically when you uninit the driver. In that case the current consumption would be something else. 

    Could you post the PPK trace?

    regards

    Jared 

Reply
  • Hi,

    Do you turn on the HFXO clock explicitly? If not then the UARTE driver will use HFINT, and disable it automatically when you uninit the driver. In that case the current consumption would be something else. 

    Could you post the PPK trace?

    regards

    Jared 

Children
No Data
Related