EFM32 USART: Fix oversampling selection; Should be biased toward higher oversampling rates

This commit is contained in:
Gregory Nutt 2014-10-20 10:54:13 -06:00
parent 8c99adf42c
commit 09f6908aa1

View File

@ -110,39 +110,71 @@
static void efm32_setbaud(uintptr_t base, uint32_t baud) static void efm32_setbaud(uintptr_t base, uint32_t baud)
{ {
uint64_t clkdiv; uint64_t clkdiv;
uint64_t minover;
uint32_t oversample; uint32_t oversample;
uint32_t regval; uint32_t regval;
uint32_t ovs; uint32_t ovs;
/* Select oversampling */ /* Select oversampling. We would like to oversample at the standard value
* of 16, but we may not be able to achieve the baud with sufficient
* accuracy if the baud is close to the HFPERCLK frequency.
*
* USART baud is generated according to:
*
* baud = fHFPERCLK/(oversample * (1 + CLKDIV/256))
*
* Or, equivalently:
*
* CLKDIV = 256 * fHFPERCLK/(oversample * baud) - 1
* oversample = 256 * fHFPERCLK / (baud * (CLKDIV + 256))
*
* Example: fHPERCLK = 32MHz, baud=115200
* oversample = 8,192,000,000 / (115200 * (CLKDIV + 256))
* CLKDIV = 71111.1111 / oversample + 1
*
* Suppose we insist on a CLKDIV >= 24, then:
*
* MINoversample = 256 * fHFPERCLK / (280 * baud))
*
* Example: fHPERCLK = 32MHz, baud=115200
* MINoversample = 254.0 -> 16
* CLKDIV = 4445.4
* baud = 115,249.3
*/
if (baud <= (BOARD_HFPERCLK_FREQUENCY / 4)) minover = ((BOARD_HFPERCLK_FREQUENCY << 8) / 280) / baud;
{ if (minover >= 16)
oversample = 16;
ovs = USART_CTRL_OVS_X16;
}
else if (baud <= (BOARD_HFPERCLK_FREQUENCY / 6))
{
oversample = 16;
ovs = USART_CTRL_OVS_X16;
}
else if (baud <= (BOARD_HFPERCLK_FREQUENCY / 8))
{
oversample = 8;
ovs = USART_CTRL_OVS_X8;
}
else /* if (baud <= (BOARD_HFPERCLK_FREQUENCY / 16)) */
{ {
DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 16)); DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 16));
oversample = 16; oversample = 16;
ovs = USART_CTRL_OVS_X16; ovs = USART_CTRL_OVS_X16;
} }
else if (minover >= 8)
{
DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 8));
oversample = 8;
ovs = USART_CTRL_OVS_X8;
}
else if (minover >= 6)
{
DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 6));
oversample = 6;
ovs = USART_CTRL_OVS_X6;
}
else /* if (minover >= 4) */
{
DEBUGASSERT(minover >= 4 && baud <= (BOARD_HFPERCLK_FREQUENCY / 4));
oversample = 4;
ovs = USART_CTRL_OVS_X4;
}
/* CLKDIV in asynchronous mode is given by: /* CLKDIV in asynchronous mode is given by:
* *
* CLKDIV = 256 * (fHFPERCLK/(oversample * baud) - 1) * CLKDIV = 256 * (fHFPERCLK/(oversample * baud) - 1)
*
* or * or
* CLKDIV = (256 * fHFPERCLK)/(oversample * baud) - 256 *
* CLKDIV = (256 * fHFPERCLK)/(oversample * baud) - 256
*/ */
clkdiv = ((uint64_t)BOARD_HFPERCLK_FREQUENCY << 8) / ((uint64_t)baud * oversample); clkdiv = ((uint64_t)BOARD_HFPERCLK_FREQUENCY << 8) / ((uint64_t)baud * oversample);