nRF52832 Product Specification V1.4, page 344 lists predefined baud rates only.
Is it possible to use other values for custom baud rate, and if so, what is the relationship between the Value and the actual generated baud rate?
nRF52832 Product Specification V1.4, page 344 lists predefined baud rates only.
Is it possible to use other values for custom baud rate, and if so, what is the relationship between the Value and the actual generated baud rate?
Helpful feedback, and I verified 1.5MHz. Following on, it looks like the receiver is using a 9-sample mechanism for voting on each received bit. MSP430 uses 3 samples, older uarts use 16 samples. For 9 samples, at least 5 high samples are required for deciding a '1', ditto 5 or more low for a '0'. 16MHz / 9 => 1.777778 MHz. Setting this value as the baud rate gives zero errors in 256-byte packets (8N1). I'll run a test with (say) 4 k packet sizes, but this is good news.
I spent a while longer on this, and have some helpful information.
First the single UART/E on the nRF52832 and both the UART/Es on the nRF52840 can be used in loopback mode (with or without DMA) with a single pin and no jumper wires; this is useful for testing, 1-wire applications and RS485. Second the max value for large packets seems to be 1,777,760 baud register 1C71'B000 which I verified by loopback testing of 2048-byte packets on the nRF52840 and 128-byte packets on the nRF52832 and checking for framing and other errors.
This is the bare-metal code in case it is useful to others:
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 2048 // 16-bit on nRF52840, only 8-bit on nRF52832 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 (RequiredBaudRate = 1000000; RequiredBaudRate < 8000000; ) { // 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); 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; } 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_RX; // For single pin loopback use PIN_UART_TX here // 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 if using this during tests // just delay .. not actually required but helps with testing 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) ; // Flush fifo //pUART->TASKS_FLUSHRX = 1; // Return packet when postLastRxByteTime indicates end-of-packet timeout return 0; }
Good Job! The mechanism for receiver to identify the first byte seems more complicated, need more efforts to understand it, we'll do more test in future.