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?
Such a good question, and highlights the fun the hardware design engineer must have been having that day .. this is what I use, inclusive of the rounding
// Baud rate calculation on nRF51 and nRF52832 // =========================================== // // Calculate BAUDRATE value settings for the black-magic 20-bit baud rate generator uint32_t CalculatedRegisterValue; uint64_t SystemClock = 16000000ULL; // Typically 16MHz uint64_t MagicScaler = 32; // Preserves bits on divisions, shift 32 bits // 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) + 0x800) & 0xFFFFF000;
So does it work? Well it doesn't exactly match the datasheet quoted values:
typedef struct { uint32_t QuotedRegisterValue; uint32_t RequiredBaudRate; uint32_t QuotedActualBaudRate; } BaudCheck_t; // Quoted values from nRF52832 v1.4 datasheet static BaudCheck_t BaudCheck[] = { {0x0004F000, 1200, 1205}, {0x0009D000, 2400, 2396}, {0x0013B000, 4800, 4808}, {0x00275000, 9600, 9598}, {0x003AF000, 14400, 14401}, {0x004EA000, 19200, 19208}, {0x0075C000, 28800, 28777}, {0x009D0000, 38400, 38369}, {0x00EB0000, 57600, 57554}, {0x013A9000, 76800, 76923}, {0x01D60000, 115200, 115108}, {0x03B00000, 230400, 231884}, {0x04000000, 250000, 250000}, {0x07400000, 460800, 457143}, {0x0F000000, 921600, 941176}, {0x10000000, 1000000, 1000000}}; #define NUM_BAUD_TESTS (sizeof(BaudCheck)/sizeof(BaudCheck[0])) static void BaudRateDivisorTest(void) { // Baud rate calculation on nRF51 and nRF52832 // =========================================== // // Calculate BAUDRATE value settings for the black-magic 20-bit baud rate generator uint32_t OkCountRegister = 0, FailCountRegister = 0, CalculatedRegisterValue; uint32_t OkCountActualBaud = 0, FailCountActualBaud = 0; uint32_t BaudIndex, ActualBaudRate; uint64_t SystemClock = 16000000ULL; // Typically 16MHz uint64_t MagicScaler = 32; // Preserves bits on divisions, shift 32 bits for (BaudIndex = 0; BaudIndex < NUM_BAUD_TESTS; BaudIndex++) { // 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)BaudCheck[BaudIndex].RequiredBaudRate << MagicScaler) / SystemClock) + 0x800) & 0xFFFFF000; if ( BaudCheck[BaudIndex].QuotedRegisterValue == CalculatedRegisterValue) { OkCountRegister++; } else { FailCountRegister++; } ActualBaudRate = (uint32_t)(((uint64_t)CalculatedRegisterValue * SystemClock) >> MagicScaler); if ( BaudCheck[BaudIndex].QuotedActualBaudRate == ActualBaudRate) { OkCountActualBaud++; } else { FailCountActualBaud++; } } while(1) ; }
The values either exactly match the data sheet or are close; that may be a code issue or a datasheet issue, who knows but I think the h/w guy was teasing us..
I checked the nRF52840 Product Specification, and interestingly there have been some additions and corrections, but 10 of the 26 quoted values still seem incorrect, although now not by much. I'm also curious as to whether the baud rate generator is indeed only 20 bits, given that all 32 bits are writable .. I may test this if I get time.
// Quoted values from nRF52832 v1.4 datasheet - 16 correct, 10 incorrect static BaudCheck_t BaudCheck[] = { // -------Documentation--------- -------Calculated--------- // Register Required Actual Register Actual Ok? Index // ========== ======== ====== ========== ====== ==== ===== {0x0004F000, 1200, 1205, 0x0004F000, 1205, " Ok"}, // 0 {0x0009D000, 2400, 2396, 0x0009D000, 2395, " Ok"}, // 1 {0x0013B000, 4800, 4808, 0x0013B000, 4806, " Ok"}, // 2 {0x00275000, 9600, 9598, 0x00275000, 9597, " Ok"}, // 3 {0x003AF000, 14400, 14401, 0x003B0000, 14404, " -"}, // 4 {0x004EA000, 19200, 19208, 0x004EA000, 19195, " Ok"}, // 5 {0x0075C000, 28800, 28777, 0x0075F000, 28793, " -"}, // 6 {0x009D0000, 38400, 38369, 0x009D5000, 38406, " -"}, // 7 {0x00EB0000, 57600, 57554, 0x00EBF000, 57601, " -"}, // 8 {0x013A9000, 76800, 76923, 0x013A9000, 76797, " Ok"}, // 9 {0x01D60000, 115200, 115108, 0x01D7E000, 115203, " -"}, // 10 {0x03B00000, 230400, 231884, 0x03AFB000, 230392, " -"}, // 11 {0x04000000, 250000, 250000, 0x04000000, 250000, " Ok"}, // 12 {0x07400000, 460800, 457143, 0x075F7000, 460800, " -"}, // 13 {0x0F000000, 921600, 941176, 0x0EBEE000, 921600, " -"}, // 14 {0x10000000, 1000000, 1000000, 0x10000000, 1000000, " Ok"}, // 15 // Extra and changed values from nRF52840 Product Specification {0x003B0000, 14400, 14414, 0x003B0000, 14404, " Ok"}, // 16 {0x0075F000, 28800, 28829, 0x0075F000, 28793, " Ok"}, // 17 {0x00800000, 31250, 31250, 0x00800000, 31250, " Ok"}, // 18 {0x009D5000, 38400, 38462, 0x003B0000, 38406, " Ok"}, // 19 {0x00E50000, 56000, 55944, 0x00E56000, 55999, " -"}, // 20 {0x00EBF000, 57600, 57762, 0x00EBF000, 57601, " Ok"}, // 21 {0x01D7E000, 115200, 115942, 0x01D7E000, 115203, " Ok"}, // 22 {0x03AFB000, 230400, 231884, 0x03AFB000, 230392, " Ok"}, // 23 {0x075F7000, 460800, 470588, 0x075F7000, 460800, " Ok"}, // 24 {0x0EBED000, 921600, 941176, 0x0EBEE000, 921600, " -"}}; // 25
I added rounding on the system clock, but that doesn't affect results:
// 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;
nRF52832 (rev 2) NRF_UARTE0->BAUDRATE values and corresponding baud rates.
Bits 11-0 are not used.
nrf52832_uarte_baud_rates.txt
Hi hmolesworth,
Thank you so much!
The equation :
CalculatedRegisterValue = (uint32_t)((((uint64_t)RequiredBaudRate << MagicScaler) + (SystemClock>>1) / SystemClock) + 0x800) & 0xFFFFF000;
should be modified as following in my SES IDE :
CalculatedRegisterValue = (uint32_t)(( ( ((uint64_t)RequiredBaudRate << MagicScaler) + (SystemClock>>1) )/ SystemClock) + 0x800) & 0xFFFFF000;
Hi hmolesworth,
Thank you so much!
The equation :
CalculatedRegisterValue = (uint32_t)((((uint64_t)RequiredBaudRate << MagicScaler) + (SystemClock>>1) / SystemClock) + 0x800) & 0xFFFFF000;
should be modified as following in my SES IDE :
CalculatedRegisterValue = (uint32_t)(( ( ((uint64_t)RequiredBaudRate << MagicScaler) + (SystemClock>>1) )/ SystemClock) + 0x800) & 0xFFFFF000;
Good catch!
FYI: We've finished some loopback test, when buadrate is set to 2Mbps, no data can be received and no events can be triggered, however when baudrate is set to 2.5Mbps, some events can be triggered according to TX data, maybe we can use it to build a special full-duplex system.
I tested Tx up to a tad less than 8MHz (7.99999MHz) and Tx works fine, but the Rx probably uses /16 or /3 for voting on high/low for each bit; I posted the baud rates I tested on Tx here some years ago framing-error-and-noisy-data-when-using-uarte-at-high-baud-rate
Might be worth us doing a loopback test at all baud rates, maybe run overnight ..
We've finished more loopback tests. It shows 2.5Mbps with RX buffer length=1(>1 can't) can work well, 1.5Mbps(1.6Mbps can't) with RX buffer length=64(>64 should OK too) can work well. We guest there is some unknown factor causing the strange results. For our application, 2.5Mbps with RX buffer length=1 is OK. Thank you for your great contribution!
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.