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.

Parents Reply Children
  • 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