This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Technical question regarding UART baud rate generator (BAUDRATE register, offset 0x524)

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..

  • You are welcome .. but in passing this has now become something of an issue as it turns out we have shipped product using incorrect values based on the manual; some of the differences are significant:

    {0x0F000000, 921600, 941176, 0x0EBEE000, 921600, " -"}, // 14

    All the quoted values are here:

    #define RESULT_STRING_LENGTH 3   // "Yes" or "  -"
    
    typedef struct {
       uint32_t QuotedRegisterValue;
       uint32_t RequiredBaudRate;
       uint32_t QuotedActualBaudRate;
       uint32_t CalculatedRegisterValue;
       uint32_t CalculatedActualBaudRate;
       char     DoesRegisterMatch[RESULT_STRING_LENGTH];
    } BaudCheck_t;
    
    // Quoted values from nRF52832 v1.4 datasheet
    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
    #define NUM_BAUD_TESTS (sizeof(BaudCheck)/sizeof(BaudCheck[0]))
    

    I am hoping someone might critique this and reassure us that is not the case. This is the test code which backfills the table above:

    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;
          BaudCheck[BaudIndex].CalculatedRegisterValue = CalculatedRegisterValue;
          if ( BaudCheck[BaudIndex].QuotedRegisterValue == CalculatedRegisterValue)
          {
             OkCountRegister++;
             memcpy(BaudCheck[BaudIndex].DoesRegisterMatch, " Ok", RESULT_STRING_LENGTH);
          }
          else
          {
             FailCountRegister++;
          }
          ActualBaudRate = (uint32_t)(((uint64_t)CalculatedRegisterValue * SystemClock) >> MagicScaler);
          BaudCheck[BaudIndex].CalculatedActualBaudRate = ActualBaudRate;
          if ( BaudCheck[BaudIndex].QuotedActualBaudRate == ActualBaudRate)
          {
             OkCountActualBaud++;
          }
          else
          {
             FailCountActualBaud++;
          }
       }
       while(1) ;
    }
    

  • 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

Related