There are some code examples of compile time UART baud rate calculation but all I’ve seen is either buggy or limited.
So I made this piece of code to generate the most correct values for the register BRG (UART Baud Rate Generator) and the bit BRGH (High Baud Rate Enable bit).
Note: This code is for 16-bit PIC devices. For other families it may have to be modified.
The code calculates the baud rate for all 4 possibilities:
- BRGH = 0 and BRG = round to the closest lower integer
- BRGH = 0 and BRG = round to the closest higher integer
- BRGH = 1 and BRG = round to the closest lower integer
- BRGH = 1 and BRG = round to the closest higher integer
And then it checks which solution gives the lowest baud rate error.
If the final error is higher than 5.8%, an error is generated. If it’s between 2.9% and 5.8%, only a warning is produced by the compiler.
User only have to define the following:
- GetInstructionClock() - Frequency of instruction cycle in Hz. For 16-bit PICs this is Fclock/2.
- BAUD_RATE – Desired UART baud rate in bps.
After this code, the user has to copy the values of BRG and BRGH to their corresponding registers. The name of these registers may be slightly different from PIC to PIC.
// Compile time UART baud rate calculation
// Tested on PIC24FJ256DA series - Only for 16-bit Baud Rate Generator
// Calculate BRG values for all possible UART configurations
#define BRG_HIGH ((GetInstructionClock()/4)/BAUD_RATE-1)
#define BRG_LOW ((GetInstructionClock()/16)/BAUD_RATE-1)
// Check limits
#if (BRG_HIGH > 65535)
#undef BRG_HIGH
#define BRG_HIGH 65535
#endif
#if (BRG_LOW > 65535)
#undef BRG_LOW
#define BRG_LOW 65535
#endif
#if (BRG_HIGH < 65535)
#define BRG_HIGH_INC (BRG_HIGH+1)
#else
#define BRG_HIGH_INC (BRG_HIGH)
#endif
#if (BRG_LOW < 65535)
#define BRG_LOW_INC (BRG_LOW+1)
#else
#define BRG_LOW_INC (BRG_LOW)
#endif
// Calculate real baud rates and errors
#define BAUD_HIGH ((GetInstructionClock()/4)/(BRG_HIGH+1))
#define BAUD_HIGH_INC ((GetInstructionClock()/4)/(BRG_HIGH_INC+1))
#define ERROR_HIGH (((BAUD_HIGH-BAUD_RATE)*10000)/BAUD_RATE)
#define ERROR_HIGH_INC (((BAUD_RATE-BAUD_HIGH_INC)*10000)/BAUD_RATE)
#define BAUD_LOW ((GetInstructionClock()/16)/(BRG_LOW+1))
#define BAUD_LOW_INC ((GetInstructionClock()/16)/(BRG_LOW_INC+1))
#define ERROR_LOW (((BAUD_LOW-BAUD_RATE)*10000)/BAUD_RATE)
#define ERROR_LOW_INC (((BAUD_RATE-BAUD_LOW_INC)*10000)/BAUD_RATE)
// Choose the solution with less error
#if (ERROR_HIGH < ERROR_HIGH_INC)
#define ERROR_H ERROR_HIGH
#define BRG_H BRG_HIGH
#else
#define ERROR_H ERROR_HIGH_INC
#define BRG_H BRG_HIGH_INC
#endif
#if (ERROR_LOW < ERROR_LOW_INC)
#define ERROR_L ERROR_LOW
#define BRG_L BRG_LOW
#else
#define ERROR_L ERROR_LOW_INC
#define BRG_L BRG_LOW_INC
#endif
#if (ERROR_H < ERROR_L)
#define ERROR ERROR_H
#define BRG BRG_H
#define BRGH 1
#else
#define ERROR ERROR_L
#define BRG BRG_L
#define BRGH 0
#endif
#if (ERROR > 580)
#error "Baud rate error exceeds 5.8%"
#elif (ERROR > 290)
#warning "Baud rate error exceeds 2.9%"
#endif
BRG // <- BRG register value
BRGH // <- BRGH bit value