summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-10-20 10:54:13 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-10-20 10:54:13 -0600
commit5878a15f0a5b32e2e73e95d8602c0ca9d669a06c (patch)
tree73f63be1e00eee1f359ac1a0fb9b6ac310df6c3e
parentee4069b0d94874fa74cd019c8f67d6ebd98891e6 (diff)
downloadpx4-nuttx-5878a15f0a5b32e2e73e95d8602c0ca9d669a06c.tar.gz
px4-nuttx-5878a15f0a5b32e2e73e95d8602c0ca9d669a06c.tar.bz2
px4-nuttx-5878a15f0a5b32e2e73e95d8602c0ca9d669a06c.zip
EFM32 USART: Fix oversampling selection; Should be biased toward higher oversampling rates
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_lowputc.c60
1 files changed, 46 insertions, 14 deletions
diff --git a/nuttx/arch/arm/src/efm32/efm32_lowputc.c b/nuttx/arch/arm/src/efm32/efm32_lowputc.c
index 3199017b9..c42935853 100644
--- a/nuttx/arch/arm/src/efm32/efm32_lowputc.c
+++ b/nuttx/arch/arm/src/efm32/efm32_lowputc.c
@@ -110,39 +110,71 @@
static void efm32_setbaud(uintptr_t base, uint32_t baud)
{
uint64_t clkdiv;
+ uint64_t minover;
uint32_t oversample;
uint32_t regval;
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))
- {
- oversample = 16;
- ovs = USART_CTRL_OVS_X16;
- }
- else if (baud <= (BOARD_HFPERCLK_FREQUENCY / 6))
+ minover = ((BOARD_HFPERCLK_FREQUENCY << 8) / 280) / baud;
+ if (minover >= 16)
{
+ DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 16));
oversample = 16;
ovs = USART_CTRL_OVS_X16;
}
- else if (baud <= (BOARD_HFPERCLK_FREQUENCY / 8))
+ else if (minover >= 8)
{
+ DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 8));
oversample = 8;
ovs = USART_CTRL_OVS_X8;
}
- else /* if (baud <= (BOARD_HFPERCLK_FREQUENCY / 16)) */
+ else if (minover >= 6)
{
- DEBUGASSERT(baud <= (BOARD_HFPERCLK_FREQUENCY / 16));
- oversample = 16;
- ovs = USART_CTRL_OVS_X16;
+ 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 = 256 * (fHFPERCLK/(oversample * baud) - 1)
+ * CLKDIV = 256 * (fHFPERCLK/(oversample * baud) - 1)
+ *
* or
- * CLKDIV = (256 * fHFPERCLK)/(oversample * baud) - 256
+ *
+ * CLKDIV = (256 * fHFPERCLK)/(oversample * baud) - 256
*/
clkdiv = ((uint64_t)BOARD_HFPERCLK_FREQUENCY << 8) / ((uint64_t)baud * oversample);