Why can't the UARTE of nRF52840 perform loopback testing?

     I am developing UARTE using nRF52840.I use a wire to connect the TX and RX pins together, and send something out the TX.

     However, RX did not receive any data, and the interrupt handler's RX_DONE did not trigger, nor did the RXDR event. Only the TX_DONE triggered in the interrupt, indicating that data had been sent out.

     However, everything works fine when not performing loopback testing; nRF52840 can receive messages from other peripherals, and the interrupt handler's RX_DONE can trigger, with the RXDR event also occurring. Why is this happening, and how should I solve this problem?Thanks.

  • Wires? Don't need wires! Loopback is trivial, but not officially supported by Nordic and upper software driver layers may forbid you using it. Set the Tx pin to both input and output, not just output; set the Rx pin to the same pin as the Tx pin. Voila! Instant loopback - whatever is transmitted is now received. Brilliant, if I may say so.

  •   But how do I determine if UARTE can both receive and transmit simultaneously? Using loopback testing is to verify whether UARTE can perform simultaneous receive and transmit operations.

      I just tried the method you mentioned, setting both input and output of UARTE to the same pin, but it didn't work either; still no data received.

  • Yes simultaneous transmit and receive works in UARTE  loopback; try this code. Remember Rx has to be started before issuing the Tx, using DMA for both. This is tested code. The Rx complete can just be a delay or use Rx Events, but short delay is good for testing.

    static void SetupUART(const uint32_t BaudRate);
    static void StartUART_Transmit(const uint8_t * const pMsg, const uint16_t MsgLength);
    static void DisableUART(void);
    static uint16_t SetupUART_Receive(uint8_t * const pMsg, const uint16_t MaxMsgLength);
    static uint16_t WaitUART_Receive(void);
    
    static NRF_UARTE_Type *pUART = NRF_UARTE0;
    
    #define PIN_UART_TX         PIN_FEATHER_TXD
    #define PIN_UART_RX         PIN_FEATHER_RXD
    #define MAX_TX_PACKET_SIZE  128 //2048  nRF52832 8-bit, nRF52840 16-bit
    
    static uint8_t TxMsg[MAX_TX_PACKET_SIZE] = "Baudrate generator for the UART is the top 20 bits of a 32-bit field; add in rounding 0.5 ls bit";
    #define TX_PACKET_SIZE sizeof(TxMsg)
    #define RX_PACKET_SIZE (TX_PACKET_SIZE - 1)
    static uint8_t RxMsg[RX_PACKET_SIZE] = "";
    
    void UART_Loopback(void)
    {
       // Enable crystal osc for external decices, don't care for loopback
        // Setup UART from scratch for each test
        SetupUART(NRF_UART_BAUDRATE_230400);
        SetupUART_Receive(RxMsg, sizeof(RxMsg));
        StartUART_Transmit(TxMsg, TX_PACKET_SIZE);
        WaitUART_Receive();
        DisableUART();
        if ((memcmp(TxMsg, RxMsg, RX_PACKET_SIZE) == 0) && (pUART->EVENTS_ERROR == 0) && (pUART->ERRORSRC == 0x0000))
        {
          PassCount++;
        }
        while (1)  ;
    }
    
    static void SetupUART(const uint32_t BaudRate)
    {
       // Disable the UARTE
       pUART->ENABLE = 0;
       // Configure UARTE with no flow control, no parity bit and selected baud rate
       pUART->CONFIG = 0;
       pUART->BAUDRATE = BaudRate;
       // Select TX and RX pin default disconnected mode to avoid sending break indication on disabling uart ie NRF_GPIO_PIN_INPUT_DISCONNECT on Rx
       nrf_gpio_cfg(PIN_UART_RX, NRF_GPIO_PIN_DIR_INPUT,  NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
       nrf_gpio_cfg(PIN_UART_TX, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_CONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
       // Select TX and RX pins; not for Loopback testing or 1-wire or RS485 a single pin can be used for both Rx and Tx
       pUART->PSEL.TXD = PIN_UART_TX;
       pUART->PSEL.RXD = PIN_UART_TX;  // For single pin loopback use PIN_UART_TX here, normal uart use PIN_UART_RX
       // Disable all interrupts and clear events
       pUART->INTENCLR = 0xFFFFFFFFUL;
       pUART->EVENTS_TXSTARTED = 0;
       pUART->EVENTS_TXSTOPPED = 0;
       pUART->EVENTS_RXSTARTED = 0;
       pUART->EVENTS_ERROR = 0;
       pUART->ERRORSRC = 0x000F;    // Write '1's to clear any errors left set
       pUART->EVENTS_ENDTX = 0;
       pUART->EVENTS_ENDRX = 0;
       // Enable the UART, note 0x04 for UART no DMA and 0x08 for UARTE with DMA
       pUART->ENABLE = 0x08;
    }
    STATIC_ASSERT (UARTE_ENABLE_ENABLE_Enabled == 0x08, "UARTE_ENABLE_ENABLE_Enabled == 0x08 Failed");
    
    static void StartUART_Transmit(const uint8_t * const pMsg, const uint16_t MsgLength)
    {
       // Configure transmit buffer and start the transfer
       pUART->TXD.MAXCNT = MsgLength;
       pUART->TXD.PTR    = (uint32_t)pMsg;
       pUART->TASKS_STARTTX = 1;
       __DSB();
       // Wait until the transfer start event is indicated
       while (pUART->EVENTS_TXSTARTED == 0) ;
       // Wait until the transfer is complete
       while (pUART->EVENTS_ENDTX == 0) ; //add timeout here also add LEDs blinking during tests
    
       // Stop the UART TX
       pUART->TASKS_STOPTX = 1;
       __DSB();
       // Wait until we receive the stopped event
       while (pUART->EVENTS_TXSTOPPED == 0) ;
    }
    
    static void DisableUART(void)
    {
       // De-Select TX and RX pins
       pUART->PSEL.TXD = 0x80000000;
       pUART->PSEL.RXD = 0x80000000;
       // Disable the UARTE
       pUART->ENABLE = 0;
    }
    
    static uint16_t SetupUART_Receive(uint8_t * const pMsg, const uint16_t MaxMsgLength)
    {
       volatile uint32_t Timeout;
       // Clear receive buffer
       memcpy(pMsg, "-----------------", MaxMsgLength);
       // Configure receive buffer and start reception
       pUART->RXD.MAXCNT = MaxMsgLength;
       pUART->RXD.PTR    = (uint32_t)pMsg;
       pUART->EVENTS_ENDRX = 0;
       pUART->TASKS_STARTRX = 1;
       __DSB();
       // Wait until the transfer start event is indicated
       while (pUART->EVENTS_RXSTARTED == 0) ;
       return 0;
    }
    
    static uint16_t WaitUART_Receive(void)
    {
       // Wait until the transfer is complete
       //while (pUART->EVENTS_ENDRX == 0) ; //add timeout here also add LEDs blinking during tests
       // just delay ..
       nrf_delay_ms(1);
       // Stop the UART RX
       pUART->TASKS_STOPRX = 1;
       __DSB();
       // Wait until we receive the stopped event
       //while (pUART->EVENTS_ENDRX == 0) ;
       // Return packet when postLastRxByteTime indicates end-of-packet timeout
       return 0;
    }

  • Thank you very much for your professional answer. I have solved the problem through another approach.

Related