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

Libuarte stops working after a certain amount of bytes have been recieved/transmitted

Hi,

I am running into some problems with libuarte. I have two nRF52840-DKs talking to each other over UART. My setup is not ordinary however. The hardware configuration looks like this:

I am basically trying to communicate over a 1-wire bus using libuarte. The way I'm doing it is by having the TX pin configured as an input when in "RX mode" and have the TX pin configured as an output pin when in "TX mode". One problem that is faced with such a configuration is that the transmitted data will also be received by the transmitter. But this data can be discarded by comparing each incoming packet with the latest transmitted packet.

My code looks like this:

#define UNUSED_DEV_PIN NRF_GPIO_PIN_MAP(1, 15)

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

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)
    {
        int txCmp;
        case NRF_LIBUARTE_ASYNC_EVT_ERROR:
            NRF_LOG_ERROR("NRF_LIBUARTE_ASYNC_EVT_ERROR\r\n");
            break;
        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
            txCmp = memcmp((uint8_t *)libuarte.p_libuarte->uarte->TXD.PTR ,p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
            if (0 == txCmp)
            {
                // This message was a message we transmitted, ignore!
                nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                break;
            }

            // handle_received_data(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:
            enable_uart_rx();
            break;
        default:
            break;
    }
}

uint32_t pot_serial_init()
{
    ret_code_t err_code;

    nrf_libuarte_async_config_t nrf_libuarte_async_config = {
            .tx_pin     = UART_TX_PIN_NUMBER,
            .rx_pin     = UART_RX_PIN_NUMBER,
            .baudrate   = NRF_UARTE_BAUDRATE_460800,
            .parity     = NRF_UARTE_PARITY_EXCLUDED,
            .hwfc       = NRF_UARTE_HWFC_DISABLED,
            .timeout_us = 100,
            .int_prio   = APP_IRQ_PRIORITY_LOW
    };

    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);
;
    enable_uart_rx();

    return 0;
}

uint32_t serial_tx(uint16_t conn_key, uint8_t *p_data, uint16_t length)
{
    enable_uart_tx();
    ret_code_t err_code = nrf_libuarte_async_tx(&libuarte, p_data, length);

    return err_code;
}

static void enable_uart_tx()
{

    nrf_gpio_pin_set(UART_TX_PIN_NUMBER);
    nrf_gpio_cfg_output(UART_TX_PIN_NUMBER);
    nrf_uarte_txrx_pins_set(libuarte.p_libuarte->uarte, UART_TX_PIN_NUMBER, UART_RX_PIN_NUMBER);
}

static void enable_uart_rx()
{
    nrf_gpio_cfg_input(UART_TX_PIN_NUMBER, NRF_GPIO_PIN_NOPULL);
    nrf_uarte_txrx_pins_set(libuarte.p_libuarte->uarte, UNUSED_DEV_PIN, UART_RX_PIN_NUMBER);
}

This implementation works fine up until a certain point. The problem I am facing is that after a while, the communication stops working...The problem can be remedied by increasing the rx_buf_size in the NRF_LIBUARTE_ASYNC_DEFINE macro call. I don't understand why this could be happening, I am calling nrf_libuarte_async_rx_free in every instance the libuarte event handler is called with event type NRF_LIBUARTE_ASYNC_EVT_RX_DATA. It's worth noting that both sides (both nRF52840-DKs) experience this issue.

Am I missing something?


I am using arm-gcc 9.2.1 on MacOS with nRF5SDK v.17.0.2.


Best regards,

Tofik

  • I also measured the performance of app_uart is not up to par with libuarte in terms of retrieving the received bytes, which makes us more interested in using libuarte instead...

  • In terms of your application, this  code is effectively a bug (although not in the intended use):

        if (nrf_uart_event_check(p_uart, NRF_UART_EVENT_TXDRDY))
        {
            // Use a local variable to avoid undefined order of accessing two volatile variables
            // in one statement.
            size_t const tx_buffer_length = p_cb->tx_buffer_length;
            if (p_cb->tx_counter < tx_buffer_length && !p_cb->tx_abort)
            {
                tx_byte(p_uart, p_cb);
            }
            else
            {
                nrf_uart_event_clear(p_uart, NRF_UART_EVENT_TXDRDY);
                if (p_cb->tx_buffer_length)
                {
                    tx_done_event(p_cb, p_cb->tx_buffer_length);
                }
            }
        }
    

    I say this as the TXDRDY event is set when the transmitted byte is loaded into the 10-bit output shift register, not when the last bit has left the output shift register. I have assumed ENDTX is the event for last-bit-cleared the shift register, but the documentation doesn't actually confirm that. Using the code as is without adding a delay of 1 x 10-bit character time after transmit before turning around the TxRx line loses the last byte. Some users compensate for this by adding an extra byte at the end of a packet with all bits typically set to '1'. In RS485 I simply wait for the ENDTX event but can't guarantee that is actually safe.

    To avoid switching glitches I would also leave the pull-up enabled at all times on the TxRx pin; it applies to the actual port pin not the input buffer.

  • Thanks for the reply hmolesworth.

    It seems that when I use NRF_UARTE_PSEL_DISCONNECTED instead of an unused pin in enable_uart_tx and enable_uart_rx, the problem with the rx buffer is resolved. However, the communication was unstable until I enabled the pullup resistor for TxRx pin as you suggested! (pullup_rx = true in nrf_libuarte_async_config)

    Io direction switch functions now look like this:

    static void enable_uart_tx()
    {
    
        nrf_gpio_pin_set(UART_TX_PIN_NUMBER);
        nrf_gpio_cfg_output(UART_TX_PIN_NUMBER);
        nrf_uarte_txrx_pins_set(libuarte.p_libuarte->uarte, UART_TX_PIN_NUMBER, NRF_UARTE_PSEL_DISCONNECTED);
    }
    
    static void enable_uart_rx()
    {
        nrf_gpio_cfg(
            UART_TX_PIN_NUMBER,
            NRF_GPIO_PIN_DIR_INPUT,
            NRF_GPIO_PIN_INPUT_DISCONNECT,
            NRF_GPIO_PIN_PULLUP,
            NRF_GPIO_PIN_S0S1,
            NRF_GPIO_PIN_NOSENSE);
        nrf_uarte_txrx_pins_set(libuarte.p_libuarte->uarte, NRF_UARTE_PSEL_DISCONNECTED, UART_RX_PIN_NUMBER);
    }
    

  • Hi

    What is the status? Were you able to get this working with the libuarte library?

    If it works with app_uart I can't really see any reason why it wouldn't work with libuarte also. 

    Best regards
    Torbjørn

  • Yes! My previous comment describes how I was able to get it to work with libuarte.

    Regards,

    Tofik

Related