UART Sample Code for Receiving Transmission

Hello, I currently have UART code that can transmit a character. However, I am wondering if there's any sample code for receiving a UART transmission? Thank you!

#include <nrf.h>

#define PIN_TXD        (6)
#define PIN_RXD        (8)

int main(void)
{
  uint8_t hello_world[] = "Hello World!\n";
  
  // Configure the UARTE with no flow control, one parity bit and 115200 baud rate
  NRF_UARTE0->CONFIG = (UART_CONFIG_HWFC_Disabled   << UART_CONFIG_HWFC_Pos) |
                       (UART_CONFIG_PARITY_Included << UART_CONFIG_PARITY_Pos); 
  
  NRF_UARTE0->BAUDRATE = UARTE_BAUDRATE_BAUDRATE_Baud115200 << UARTE_BAUDRATE_BAUDRATE_Pos;
  
  // Select TX and RX pins
  NRF_UARTE0->PSEL.TXD = PIN_TXD;
  NRF_UARTE0->PSEL.RXD = PIN_RXD;
  
  // Enable the UART (starts using the TX/RX pins)
  NRF_UARTE0->ENABLE = UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos;
  
  // Configure transmit buffer and start the transfer
  NRF_UARTE0->TXD.MAXCNT = sizeof(hello_world);
  NRF_UARTE0->TXD.PTR = (uint32_t)&hello_world;
  NRF_UARTE0->TASKS_STARTTX = 1;
  
  // Wait until the transfer is complete
  while (NRF_UARTE0->EVENTS_ENDTX == 0)
  {
  }
  
  // Stop the UART TX
  NRF_UARTE0->TASKS_STOPTX = 1;
  // Wait until we receive the stopped event
  while (NRF_UARTE0->EVENTS_TXSTOPPED == 0);
  
  // Disable the UARTE (pins are now available for other use)
  NRF_UARTE0->ENABLE = UARTE_ENABLE_ENABLE_Disabled << UARTE_ENABLE_ENABLE_Pos;
  
  while (1)
  {
    __WFE();
  }
}

I also noticed that my UART code for transmission only transmits 1 byte and not the entire string. In this case, it only transmits "H". Is there a way to have it transmit more than 8 bits? 

  • Hi there,

    is there a specific reason for why you want to do this bare metal? There is several examples that shows how to receive data through UART but they use our drivers, which is what we always recommend. 

    regards

    Jared 

  • Hello, it's because I am hoping to get more experience with lower level register programming. It'd also potentially give me more control. 

  • Try this; I wrote this code to test different baud rates but it does what you are looking for I think, just choose a single baud rate; note you can use the Tx pin as the Rx pin for loopback testing without another device such as a PC (I set Loopback mode in this snippet):

    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  256 //2048
    
    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] = "";
    uint32_t RequiredBaudRate = 1000000UL;
    uint32_t MaxOkdBaudRate = 0UL;
    uint32_t CalculatedRegisterValue;
    uint32_t RegisterValueAtMaxBaud = 0;
    uint64_t SystemClock = 16000000ULL;    // Typically 16MHz
    uint64_t MagicScaler = 32;             // Preserves bits on divisions, shift 32 bits
    
    void UART_BaudTest(void)
    {
       // Enable crystal osc for 3rd party serial devices, don't care for Loopback testing
       //for (RequiredBaudRate = 1000000; RequiredBaudRate < 2000000; )
       {
          //  Baudrate generator for the UART is the top 20 bits of a 32-bit field; add in rounding 0.5 ls bit
          CalculatedRegisterValue = (uint32_t)(((((uint64_t)RequiredBaudRate << MagicScaler) + (SystemClock >> 1)) / SystemClock) + 0x800) & 0xFFFFF000;
          // Setup UART from scratch for each baud rate test
          SetupUART(CalculatedRegisterValue); // 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))
          {
             MaxOkdBaudRate = RequiredBaudRate;
             RegisterValueAtMaxBaud = CalculatedRegisterValue;
             //break;
          }
          RequiredBaudRate += 20;
       }
       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
       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; note 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 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) ;
       // 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)
    {
       // Disable the UARTE
       pUART->ENABLE = 0;
       // De-Select TX and RX pins
       pUART->PSEL.TXD = 0x80000000;
       pUART->PSEL.RXD = 0x80000000;
    }
    
    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
       // or just delay a bit ..
       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 0;
    }

Related