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

nRF52840 nrfx_uart TX working, RX not

For nRF52840 (Rigado BMD-340), SDK 15.0.0, custom board:

I'm trying to implement nrfx_uart directly to communicate to another microcontroller. I've configured it for blocking mode. In this mode, I've been able to transmit (115200 8N1) a message from the nRF52840 to the microcontroller, have the microcontroller successfully read and process the message, and then have the microcontroller successfully construct and transmit a response back to the nRF52840. All of this has been verified by breakpoints and oscilloscope traces.

However, this is where things go wrong. The nRF52840 nrfx_uart code generates an internal error when trying to receive the message sent by the microcontroller. Reading address 0x40002480 (UART0 ERRORSRC, right?) gives a value of 0x0D, i.e. BREAK, ERROR, and OVERRUN are all present.

The code is written modularly, but basically after pasting things together the listing looks like this:

main.c: main()
nrfx_clock_init(nrfx_clock_event_handler);
nrfx_clock_enable();
nrfx_clock_lfclk_start();
nrfx_clock_hfclk_start();
...
my_uart_init();

my_uart.c: my_uart_init()
{
    nrfx_uart_config_t uartConfig = {
    	.pseltxd            = pin_tx,
    	.pselrxd            = pin_rx,
    	.pselcts            = NRF_UART_PSEL_DISCONNECTED,
    	.pselrts            = NRF_UART_PSEL_DISCONNECTED,
    	.p_context          = NULL,
    	.hwfc               = NRF_UART_HWFC_DISABLED,
    	.parity             = NRF_UART_PARITY_EXCLUDED,
    	.interrupt_priority = NRFX_UART_DEFAULT_CONFIG_IRQ_PRIORITY
    };
    uartConfig.baudrate = NRF_UART_BAUDRATE_115200;
    	
    nrfx_err_t nrfx_err = nrfx_uart_init (&(bus->nrfx_uart), &uartConfig, BLOCKING_MODE);
    APP_ERROR_CHECK(nrfx_err);
    
    nrfx_uart_rx_enable(&(bus->nrfx_uart));
}

... sometime later an event happens and I transmit a message successfully then attempt a read:

my_uart.c: read(nBytes)
{
    uart_err_t uartErr = UART_RETRY;    //uart_err_t is my typedef
    while(uartErr == UART_RETRY)
    {
    	uartErr = _uart_errorHandler(nrfx_uart_rx(&(uart_interface->bus->nrfx_uart), rxBuffer, nBytes));
    }
    
    return uartErr;
}

Some additional context:

This is the first time I've used a Nordic BLE module. I've been going through the learning curve fairly well over the past few months, but maybe I'm missing something simple that more experienced users would know. I started the application from ble_app_uart, but have commented out all the BLE functionality for now (i.e. ble_stack_init etc. are not called). Instead, I've only started lfclk and hfclk directly through nrfx_clock and a number of other unrelated code modules as well. Also, I've implemented nrfx_twi similarly to how I want to implement nrfx_uart, and it's working perfectly.

What I've tried so far:

I've tried different combinations of when to use rx_enable and rx_disable around the nrfx_uart_rx function, ultimately settling for using it in my my_uart_init() function. I've added and removed delays between messages being sent and received. I've looked at different forum posts and didn't see one line up exactly with what I'm experiencing, but I did enable hfclk just in case I needed to explicitly start it (nrf52840 product spec seems to imply that I don't need to, but I'm new to nRF so I could be wrong...).

What I'm going to try in the mean time: 

While waiting for help here, I'm going to try switching to nrfx_uarte and, if not, implement app_uart in my uart.c file, but I'd rather keep with nrfx_uart if I can for consistency.

How you can help:

Do you have any ideas about what else I can try to get nrfx_uart_rx to work? I greatly appreciate any and all advice. Thank you!

  

Parents
  • Hi,

     

    Which GPIOs are you using for TXD and RXD?

    Reading address 0x40002480 (UART0 ERRORSRC, right?) gives a value of 0x0D, i.e. BREAK, ERROR, and OVERRUN are all present.

     This register accumulates errors, so if you do not clear it, it might show errors from an earlier session.

     Remember to clear this register after reading.

    What does the nrfx_uart_rx() function return?

    Do you have any ideas about what else I can try to get nrfx_uart_rx to work?

    What do you pass as nBytes into ::read()? Have you tried setting this to poll one-and-one byte to see if that makes any difference?

    Have you debugged the solution to see where it returns in the function?

    Kind regards,

    Håkon 

  • TX is P0.06 and RX is P0.08

    Regarding ERRORSRC: The error happens on the first UART transmission / reception and that's when I see all 3 flags noted above are set. I don't read this register in code. I was just reading it through the debugger after I hit the breakpoint when the function fails.

    The nrfx_uart_rx function returns NRFX_ERROR_INTERNAL. The contents of the buffer passed to nrfx_uart_rx is garbage, though I'm not sure if that's from heap allocation (malloc'd to 16 bytes, never freed) or nrfx_uart_rx putting bytes there. I'm requesting 10 bytes of data to be read (nBytes = 10), which is the entire length of the response I'm expecting.

    The function returns at nrfx_uart.c line 442 (line 27 below). Here's the snippet for your convenience:

    bool rxrdy;
    bool rxto;
    bool error;
    do
    {
        do
        {
            error = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_ERROR);
            rxrdy = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY);
            rxto  = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXTO);
        } while ((!rxrdy) && (!rxto) && (!error));
    
        if (error || rxto)
        {
            break;
        }
        rx_byte(p_instance->p_reg, p_cb);
    } while (p_cb->rx_buffer_length > p_cb->rx_counter);
    
    p_cb->rx_buffer_length = 0;
    if (error)
    {
        err_code = NRFX_ERROR_INTERNAL;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

    Update 1: ERRORSRC is set to 12 when rx_enable is called. This is probably expected because RX pin is not high at this time because the other microcontroller is asleep. I will move this call after the other microcontroller is awake.

Reply
  • TX is P0.06 and RX is P0.08

    Regarding ERRORSRC: The error happens on the first UART transmission / reception and that's when I see all 3 flags noted above are set. I don't read this register in code. I was just reading it through the debugger after I hit the breakpoint when the function fails.

    The nrfx_uart_rx function returns NRFX_ERROR_INTERNAL. The contents of the buffer passed to nrfx_uart_rx is garbage, though I'm not sure if that's from heap allocation (malloc'd to 16 bytes, never freed) or nrfx_uart_rx putting bytes there. I'm requesting 10 bytes of data to be read (nBytes = 10), which is the entire length of the response I'm expecting.

    The function returns at nrfx_uart.c line 442 (line 27 below). Here's the snippet for your convenience:

    bool rxrdy;
    bool rxto;
    bool error;
    do
    {
        do
        {
            error = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_ERROR);
            rxrdy = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXDRDY);
            rxto  = nrf_uart_event_check(p_instance->p_reg, NRF_UART_EVENT_RXTO);
        } while ((!rxrdy) && (!rxto) && (!error));
    
        if (error || rxto)
        {
            break;
        }
        rx_byte(p_instance->p_reg, p_cb);
    } while (p_cb->rx_buffer_length > p_cb->rx_counter);
    
    p_cb->rx_buffer_length = 0;
    if (error)
    {
        err_code = NRFX_ERROR_INTERNAL;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

    Update 1: ERRORSRC is set to 12 when rx_enable is called. This is probably expected because RX pin is not high at this time because the other microcontroller is asleep. I will move this call after the other microcontroller is awake.

Children
Related