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

What causes a UARTE Internal Error?

I'm trying to create an application on the nRF52840 that can read serial input from an external GPS chip and also provide log output via USB. As I understand it, the UART to USB output will occupy UART peripheral 0. So, I've configured the external GPS chip to connect via the UART peripheral 1 using UARTE. I've connected the TX pin from the GPS chip to P1.04 on the nRF52840 board. Here is my uarte_init() code:

#define SER_APP_RX_PIN                  NRF_GPIO_PIN_MAP(1,4)
#define SER_APP_TX_PIN                  NRF_GPIO_PIN_MAP(1,3)

static void uarte_init(void)
{
    ret_code_t      err_code;

    nrfx_uarte_config_t config1 = {
        .pseltxd            = SER_APP_TX_PIN,
        .pselrxd            = SER_APP_RX_PIN,
        .pselcts            = 0xFFFFFFFF,// no cts pin
        .pselrts            = 0xFFFFFFFF,// no rts pin
        .p_context          = NULL,
        .hwfc               = 0,//disabled
        .parity             = NRFX_UARTE_DEFAULT_CONFIG_PARITY,
        .baudrate           = NRF_UARTE_BAUDRATE_9600,
        .interrupt_priority = NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY
    };
    err_code = nrfx_uarte_init(&uarte1, &config1, NULL);
    APP_ERROR_CHECK(err_code);
}

Then I try to read from the GPS with the following:

        static char buf[64];
        uint8_t c;
        ret_code_t ret;

        ret = nrfx_uarte_rx(&uarte1, &c, sizeof(c));

The ret is always code 3, which is NRF_ERROR_INTERNAL.

Any suggestions regarding what I'm doing wrong would be greatly appreciated. If I should accomplish this is a different way, I'd appreciate any suggestions along those lines as well.

Parents
  • Hi

    Which SDK version are you using?

    Have you tried to run the debugger and see what causes the error?

    I expect it is caused by the ERROR event of the UARTE peripheral, which will trigger line 508 of nrfx_uarte.c (assuming SDK v17.0.2):

    When this occurs it could be interesting to try and read out the state of the ERRORSRC register in the UARTE peripheral. 

    A common error when enabling the UART is the BREAK error, which occurs when the RX pin is low for a long time (both UART pins should be high when idle). Can you check the state of the RX pin to ensure it is high whenever the GPS module is not sending anything?

    A BREAK error could also occur if the GPS module is using a lower baudrate than the one you have configured in the nRF device. 

    Best regards
    Torbjørn

  • Thanks for the response! I'm using SDK 17.0.2. Yes, I've used the debugger to see where it fails, and you are correct that it is line 508 of nrfx_uarte.c.

    Thanks for pointing me to the ERRORSRC register. The value is 0x1, which indicates an OVERRUN error, correct?

    I'm not using flow control. I'm fine with just grabbing the most recent messages in an fifo queue, but I had trouble figuring out how to set that up. I've reviewed this thread: https://devzone.nordicsemi.com/f/nordic-q-a/64143/buffering-uart-data.

    The documentation says: "If the TXD.PTR and the RXD.PTR are not pointing to the Data RAM region, an EasyDMA transfer may result in a HardFault or RAM corruption." I used this to put the read buffer in the Data RAM region:

    static uint8_t m_rx_buffer[32] __attribute__ ((section (".non_init"))); 
    

    which seemed to work. But, I'm completely unexperienced in memory management for embedded programming. Is this correct? I started from the ble_app_blinky example and didn't make any changes to the flash_placement.xml file, so that is where the '.non_init' is coming from.

    I'm now using an event handler in the nrfx_uarte_init call.

    My call to nrfx_uarte_rx now uses the 32 byte m_rx_buffer receive buffer to avoid the overrun error. This seems to be working. I'm getting the GPS data that I expect.

    If there are any comments on what I've describe here, I would appreciate any corrections or guidance. After that, this case can be closed. Thanks again!

  • Hi 

    brinton said:
    The documentation says: "If the TXD.PTR and the RXD.PTR are not pointing to the Data RAM region, an EasyDMA transfer may result in a HardFault or RAM corruption." I used this to put the read buffer in the Data RAM region:

    All you have to do to avoid this problem is to make sure the variable is not declared as const, since this will put it in flash memory rather than in RAM.  

    It is not necessary to put the buffer in the non_init section, but doing this will save you some clock cycles after reset as the buffer will not be 0 initialized. 
    (Only variables that the code expect to be 0 after a reset need to be 0 initialized.)

    It does make sense that if you start the receiver with only a one byte buffer you might not be able to process the UART interrupt fast enough to prepare the next buffer, and using a larger buffer is recommended. 

    For a more sophisticated UART implementation that is more suited to applications where you don't know exactly when you will receive data, or how many bytes you will receive, you might look into using the lib_uarte or lib_uarte_async driver instead of using nrfx_uarte directly. 

    Best regards
    Torbjørn

Reply
  • Hi 

    brinton said:
    The documentation says: "If the TXD.PTR and the RXD.PTR are not pointing to the Data RAM region, an EasyDMA transfer may result in a HardFault or RAM corruption." I used this to put the read buffer in the Data RAM region:

    All you have to do to avoid this problem is to make sure the variable is not declared as const, since this will put it in flash memory rather than in RAM.  

    It is not necessary to put the buffer in the non_init section, but doing this will save you some clock cycles after reset as the buffer will not be 0 initialized. 
    (Only variables that the code expect to be 0 after a reset need to be 0 initialized.)

    It does make sense that if you start the receiver with only a one byte buffer you might not be able to process the UART interrupt fast enough to prepare the next buffer, and using a larger buffer is recommended. 

    For a more sophisticated UART implementation that is more suited to applications where you don't know exactly when you will receive data, or how many bytes you will receive, you might look into using the lib_uarte or lib_uarte_async driver instead of using nrfx_uarte directly. 

    Best regards
    Torbjørn

Children
No Data
Related