From 8a20155b75b094b06495e94fa83ebded155b340d Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Wed, 17 Jul 2019 10:37:26 -0500 Subject: [PATCH 01/14] Save CONFIG_ARCH_BOARD_CUSTOM when running 'make savedefconfig' --- tools/Makefile.unix | 1 + tools/Makefile.win | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index eb889627e9a02..122fa93ecbc47 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -547,6 +547,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp diff --git a/tools/Makefile.win b/tools/Makefile.win index d6a5bce57e9a4..1c5d12ddacdd8 100644 --- a/tools/Makefile.win +++ b/tools/Makefile.win @@ -534,6 +534,7 @@ savedefconfig: do_savedefconfig -$(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp -$(Q) grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp -$(Q) grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp + -$(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp $(Q) cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From 835b5e9d6fcbea02cb0203c063b0e121fa57ba9e Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Mon, 29 Jul 2019 12:10:59 -0500 Subject: [PATCH 02/14] Only use PCLKSEL0 for ADC on LPC176x family. --- arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c index c09512813fb6c..81b1df06e9c94 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c @@ -213,10 +213,13 @@ static void adc_reset(FAR struct adc_dev_s *dev) putreg32(ADC_CR_PDN, LPC17_40_ADC_CR); +/* PCLKSEL0 only exists in LPC176x family parts */ +#ifdef LPC176x regval = getreg32(LPC17_40_SYSCON_PCLKSEL0); regval &= ~SYSCON_PCLKSEL0_ADC_MASK; regval |= (SYSCON_PCLKSEL_CCLK8 << SYSCON_PCLKSEL0_ADC_SHIFT); putreg32(regval, LPC17_40_SYSCON_PCLKSEL0); +#endif #ifdef CONFIG_LPC17_40_ADC_BURSTMODE clkdiv = LPC17_40_CCLK / 3 / 65 / priv->sps; From c43e5a83bfee7f34c3b9368043d84b3d7e3da687 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 16 Aug 2019 10:43:49 -0500 Subject: [PATCH 03/14] Made grep search expression more specific. --- tools/Makefile.unix | 2 +- tools/Makefile.win | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index 122fa93ecbc47..fac35b612e226 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -547,7 +547,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true - $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp diff --git a/tools/Makefile.win b/tools/Makefile.win index 1c5d12ddacdd8..b91a0773bfd9e 100644 --- a/tools/Makefile.win +++ b/tools/Makefile.win @@ -534,7 +534,7 @@ savedefconfig: do_savedefconfig -$(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp -$(Q) grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp -$(Q) grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp - -$(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp + -$(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config >> defconfig.tmp $(Q) cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From 38b51f0c6d9612de755c102a53846ca7488cdf14 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Mon, 19 Aug 2019 13:41:55 -0500 Subject: [PATCH 04/14] Added missing '=' to second grep --- tools/Makefile.unix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index fac35b612e226..265ef713ee889 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -547,7 +547,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true - $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From c7856075eb30651235275afe22cf33d9768a03e5 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Mon, 19 Aug 2019 14:19:43 -0500 Subject: [PATCH 05/14] Revert "Only use PCLKSEL0 for ADC on LPC176x family." This reverts commit 835b5e9d6fcbea02cb0203c063b0e121fa57ba9e. --- arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c index 81b1df06e9c94..c09512813fb6c 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_adc.c @@ -213,13 +213,10 @@ static void adc_reset(FAR struct adc_dev_s *dev) putreg32(ADC_CR_PDN, LPC17_40_ADC_CR); -/* PCLKSEL0 only exists in LPC176x family parts */ -#ifdef LPC176x regval = getreg32(LPC17_40_SYSCON_PCLKSEL0); regval &= ~SYSCON_PCLKSEL0_ADC_MASK; regval |= (SYSCON_PCLKSEL_CCLK8 << SYSCON_PCLKSEL0_ADC_SHIFT); putreg32(regval, LPC17_40_SYSCON_PCLKSEL0); -#endif #ifdef CONFIG_LPC17_40_ADC_BURSTMODE clkdiv = LPC17_40_CCLK / 3 / 65 / priv->sps; From aa2ed7f7833cc9aab1bab2de7e2b5188a2a7ec3a Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Mon, 19 Aug 2019 14:20:38 -0500 Subject: [PATCH 06/14] Revert "Added missing '=' to second grep" This reverts commit 38b51f0c6d9612de755c102a53846ca7488cdf14. --- tools/Makefile.unix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index 265ef713ee889..fac35b612e226 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -547,7 +547,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP_" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true - $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From 3a6f68ef2d18c8540f05b7e21f14e1e5c4eec348 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Mon, 19 Aug 2019 14:46:24 -0500 Subject: [PATCH 07/14] Added a missing '=' in the second grep statement --- tools/Makefile.unix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index 26c33853888cb..c8c964eed182c 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -561,7 +561,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP=" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true - $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From c6c603d3a1099ec7baf5ad6d9816dee971d0dae1 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Thu, 29 Aug 2019 13:22:49 -0500 Subject: [PATCH 08/14] Don't compile up_earlyserialinit if USE_EARLYSERIALINIT is not defined --- arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index 7b3c920013b13..8e6527a21f51c 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -1421,7 +1421,7 @@ static bool up_txempty(struct uart_dev_s *dev) * very early in the boot sequence. * ****************************************************************************/ - +#ifdef USE_EARLYSERIALINIT void up_earlyserialinit(void) { /* Configure all UARTs (except the CONSOLE UART) and disable interrupts */ @@ -1475,6 +1475,8 @@ void up_earlyserialinit(void) #endif } +#endif + /**************************************************************************** * Name: up_serialinit * From 509fe86d5d9cd4b5a79475db4b7eb70e076f39ef Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 6 Sep 2019 14:47:26 -0500 Subject: [PATCH 09/14] Revert extra = in CONFIG_ARCH_BOARD_CUSTOM --- tools/Makefile.unix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Makefile.unix b/tools/Makefile.unix index c17b395876b25..5ac78bb1efab8 100644 --- a/tools/Makefile.unix +++ b/tools/Makefile.unix @@ -604,7 +604,7 @@ savedefconfig: do_savedefconfig $(Q) grep "^CONFIG_ARCH_CHIP=" .config >> defconfig.tmp; true $(Q) grep "CONFIG_ARCH_BOARD=" .config && grep "CONFIG_ARCH_BOARD=" .config >> defconfig.tmp; true $(Q) grep "^CONFIG_ARCH_CUSTOM" .config && grep "^CONFIG_ARCH_CUSTOM" .config >> defconfig.tmp; true - $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config >> defconfig.tmp; true + $(Q) grep "^CONFIG_ARCH_BOARD_CUSTOM=" .config && grep "^CONFIG_ARCH_BOARD_CUSTOM" .config >> defconfig.tmp; true $(Q) export LC_ALL=C; cat defconfig.tmp | sort | uniq > sortedconfig.tmp $(Q) echo "#" > warning.tmp $(Q) echo "# This file is autogenerated: PLEASE DO NOT EDIT IT." >> warning.tmp From fb1b845c718888c80deb9c361d6a1645dcbadcae Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Wed, 25 Sep 2019 15:39:28 -0500 Subject: [PATCH 10/14] Added support for RS485 direction control on LPC17xx UART1 --- arch/arm/src/lpc17xx_40xx/Kconfig | 26 +++++++++++++++++++++ arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 20 +++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/lpc17xx_40xx/Kconfig b/arch/arm/src/lpc17xx_40xx/Kconfig index ec9a595ff60ea..5a9a399402fb7 100644 --- a/arch/arm/src/lpc17xx_40xx/Kconfig +++ b/arch/arm/src/lpc17xx_40xx/Kconfig @@ -561,6 +561,32 @@ config LPC17_40_UART1_RINGINDICATOR ---help--- Enable UART1 ring indicator +config LPC17_40_UART1_RS485 + bool "RS-485 on UART1" + default n + depends on LPC17_40_UART1 + ---help--- + Enable RS-485 interface on UART1. Your board config will have to + provide GPIO_UART1_RS485_DIR pin definition. + +config LPC17_40_RS485_DIR_POLARITY + int "UART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on LPC17_40_UART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +config LPC17_40_UART1_RS485_DIR_DTR + bool "UART1 RS-485 DIR pin use DTR" + default n + depends on LPC17_40_UART1_RS485 + ---help--- + Selects between RTS and DTR pins for RS485 DIR. This must correspond to + the GPIO_USART1_RS485_DIR pin specified in your board config. The DTR pin + will be used if selected, the RTS pin will be used otherwise. + endmenu menu "ADC driver options" diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index 8e6527a21f51c..9ea0e20f14c9f 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -734,7 +734,20 @@ static inline void lpc17_40_uart1config(void) putreg32(regval, LPC17_40_SYSCON_PCLKSEL0); #endif - /* Step 3: Configure I/O pins */ + /* Step 3: Configure RS-485 control register */ +#ifdef CONFIG_LPC17_40_UART1_RS485 + regval = getreg32(LPC17_40_UART1_RS485CTRL); + regval |= UART_RS485CTRL_DCTRL; +#if (CONFIG_LPC17_40_RS485_DIR_POLARITY == 1) + regval |= UART_RS485CTRL_OINV; +#endif +#ifdef CONFIG_LPC17_40_UART1_RS485_DIR_DTR + regval |= UART_RS485CTRL_SEL; +#endif + putreg32(regval, LPC17_40_UART1_RS485CTRL); +#endif + + /* Step 4: Configure I/O pins */ lpc17_40_configgpio(GPIO_UART1_TXD); lpc17_40_configgpio(GPIO_UART1_RXD); @@ -748,6 +761,11 @@ static inline void lpc17_40_uart1config(void) lpc17_40_configgpio(GPIO_UART1_RI); #endif #endif + +#ifdef CONFIG_LPC17_40_UART1_RS485 + lpc17_40_configgpio(GPIO_UART1_RS485_DIR); +#endif + leave_critical_section(flags); }; #endif From 7c07648f60ba0ab79a88733ddc36d05510942837 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 18 Oct 2019 15:01:21 -0500 Subject: [PATCH 11/14] First pass at fractional baud rate divider on LPC17xx/40xx --- arch/arm/src/lpc17xx_40xx/Kconfig | 4 + arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 183 ++++++++++++++++++-- arch/arm/src/lpc43xx/lpc43_uart.c | 2 +- 3 files changed, 172 insertions(+), 17 deletions(-) diff --git a/arch/arm/src/lpc17xx_40xx/Kconfig b/arch/arm/src/lpc17xx_40xx/Kconfig index 5a9a399402fb7..c6de37320b235 100644 --- a/arch/arm/src/lpc17xx_40xx/Kconfig +++ b/arch/arm/src/lpc17xx_40xx/Kconfig @@ -587,6 +587,10 @@ config LPC17_40_UART1_RS485_DIR_DTR the GPIO_USART1_RS485_DIR pin specified in your board config. The DTR pin will be used if selected, the RTS pin will be used otherwise. +config LPC17_40_UART_USE_FRACTIONAL_DIVIDER + bool "Use fractional divider for UART baud rate" + default n + endmenu menu "ADC driver options" diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index 9ea0e20f14c9f..dac341a57136a 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -546,7 +546,148 @@ static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) up_serialout(priv, LPC17_40_UART_LCR_OFFSET, lcr); } +#ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER +/**************************************************************************** + * Name: lpc17_40_setbaud + * + * Description: + * Configure the UART divisors to accomplish the desired BAUD given the + * UART base frequency. + * + * This computationally intensive algorithm is based on the same logic + * used in the NXP sample code. + * + ****************************************************************************/ + +static void up_setbaud(struct up_dev_s *priv, uint32_t baud) +{ + uint32_t basefreq; /* Base frequency of the UART peripheral */ + + uint32_t lcr; /* Line control register value */ + uint32_t dl; /* Best DLM/DLL full value */ + uint32_t mul; /* Best FDR MULVALL value */ + uint32_t divadd; /* Best FDR DIVADDVAL value */ + uint32_t best; /* Error value associated with best {dl, mul, divadd} */ + uint32_t cdl; /* Candidate DLM/DLL full value */ + uint32_t cmul; /* Candidate FDR MULVALL value */ + uint32_t cdivadd; /* Candidate FDR DIVADDVAL value */ + uint32_t errval; /* Error value associated with the candidate */ + + /* The UART buad is given by: + * + * Fbaud = Fbase * mul / (mul + divadd) / (16 * dl) + * dl = Fbase * mul / (mul + divadd) / Fbaud / 16 + * = Fbase * mul / ((mul + divadd) * Fbaud * 16) + * = ((Fbase * mul) >> 4) / ((mul + divadd) * Fbaud) + * + * Where the value of MULVAL and DIVADDVAL comply with: + * + * 0 < mul < 16 + * 0 <= divadd < mul + */ + + basefreq = LPC17_40_CCLK / priv->cclkdiv; + best = UINT32_MAX; + divadd = 0; + mul = 0; + dl = 0; + + /* Try each multiplier value in the valid range */ + + for (cmul = 1 ; cmul < 16; cmul++) + { + /* Try each divider value in the valid range */ + + for (cdivadd = 0 ; cdivadd < cmul ; cdivadd++) + { + /* Candidate: + * dl = ((Fbase * mul) >> 4) / ((mul + cdivadd) * Fbaud) + * (dl << 32) = (Fbase << 28) * cmul / ((mul + cdivadd) * Fbaud) + */ + + uint64_t dl64 = ((uint64_t)basefreq << 28) * cmul / + ((cmul + cdivadd) * baud); + + /* The lower 32-bits of this value is the error */ + + errval = (uint32_t)(dl64 & 0x00000000ffffffffull); + + /* The upper 32-bits is the candidate DL value */ + + cdl = (uint32_t)(dl64 >> 32); + + /* Round up */ + + if (errval > (1 << 31)) + { + errval = -errval; + cdl++; + } + + /* Check if the resulting candidate DL value is within range */ + + if (cdl < 1 || cdl > 65536) + { + /* No... try a different divadd value */ + + continue; + } + + /* Is this the best combination that we have seen so far? */ + + if (errval < best) + { + /* Yes.. then the candidate is out best guess so far */ + + best = errval; + dl = cdl; + divadd = cdivadd; + mul = cmul; + + /* If the new best guess is exact (within our precision), then + * we are finished. + */ + + if (best == 0) + { + break; + } + } + } + } + + DEBUGASSERT(dl > 0); + /* Enter DLAB=1 */ + + lcr = getreg32(priv->uartbase + LPC17_40_UART_LCR_OFFSET); + putreg32(lcr | UART_LCR_DLAB, priv->uartbase + LPC17_40_UART_LCR_OFFSET); + + /* Save then divider values */ + + putreg32(dl >> 8, priv->uartbase + LPC17_40_UART_DLM_OFFSET); + putreg32(dl & 0xff, priv->uartbase + LPC17_40_UART_DLL_OFFSET); + + /* Clear DLAB */ + + putreg32(lcr & ~UART_LCR_DLAB, priv->uartbase + LPC17_40_UART_LCR_OFFSET); + + /* Then save the fractional divider values */ + + putreg32((mul << UART_FDR_MULVAL_SHIFT) | (divadd << UART_FDR_DIVADDVAL_SHIFT), + priv->uartbase + LPC17_40_UART_FDR_OFFSET); +} +# ifdef LPC176x +static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) +{ +/* + * If we're using the fractional divider, assume that the full PCLK speed + * will be acceptable. + */ + return SYSCON_PCLKSEL_CCLK; +} +# endif +#else /************************************************************************************ * Name: lpc17_40_uartcclkdiv * @@ -576,7 +717,7 @@ static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) * ************************************************************************************/ -#ifdef LPC176x +# ifdef LPC176x static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) { /* Ignoring the fractional divider, the BAUD is given by: @@ -662,8 +803,8 @@ static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) return SYSCON_PCLKSEL_CCLK8; } } -#endif /* LPC176x */ - +# endif /* LPC176x */ +#endif /* CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER */ /************************************************************************************ * Name: lpc17_40_uart0config, uart1config, uart2config, and uart3config * @@ -844,8 +985,8 @@ static inline void lpc17_40_uart3config(void) * the same peripheral and that logic could easily leveraged here). * ************************************************************************************/ - -#ifdef LPC176x +#ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER +# ifdef LPC176x static inline uint32_t lpc17_40_uartdl(uint32_t baud, uint8_t divcode) { uint32_t num; @@ -877,6 +1018,7 @@ static inline uint32_t lpc17_40_uartdl(uint32_t baud) { return (uint32_t)BOARD_PCLK_FREQUENCY / (baud << 4); } +# endif #endif /**************************************************************************** @@ -896,7 +1038,9 @@ static int up_setup(struct uart_dev_s *dev) { #ifndef CONFIG_SUPPRESS_UART_CONFIG struct up_dev_s *priv = (struct up_dev_s *)dev->priv; +# ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER uint16_t dl; +# endif uint32_t lcr; /* Clear fifos */ @@ -950,15 +1094,17 @@ static int up_setup(struct uart_dev_s *dev) up_serialout(priv, LPC17_40_UART_LCR_OFFSET, (lcr | UART_LCR_DLAB)); /* Set the BAUD divisor */ - -#ifdef LPC176x - dl = lpc17_40_uartdl(priv->baud, priv->cclkdiv); +#ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER + up_setbaud(priv, priv->baud); #else +# ifdef LPC176x + dl = lpc17_40_uartdl(priv->baud, priv->cclkdiv); +# else dl = lpc17_40_uartdl(priv->baud); -#endif +# endif up_serialout(priv, LPC17_40_UART_DLM_OFFSET, dl >> 8); up_serialout(priv, LPC17_40_UART_DLL_OFFSET, dl & 0xff); - +#endif /* Clear DLAB */ up_serialout(priv, LPC17_40_UART_LCR_OFFSET, lcr); @@ -1230,8 +1376,10 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) case TCSETS: { struct termios *termiosp = (struct termios *)arg; +# ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER uint32_t lcr; /* Holds current values of line control register */ uint16_t dl; /* Divisor latch */ +# endif if (!termiosp) { @@ -1251,10 +1399,12 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) /* TODO: Re-calculate the optimal CCLK divisor for the new baud and * and reset the divider in the CLKSEL0/1 register. */ - -#if 0 /* ifdef LPC176x */ +# ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER + up_setbaud(priv, priv->baud); +# else +# if 0 /* ifdef LPC176x */ priv->cclkdiv = lpc17_40_uartcclkdiv(priv->baud); -#endif +# endif /* DLAB open latch */ /* REVISIT: Shouldn't we just call up_setup() to do all of the following? */ @@ -1263,17 +1413,18 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) /* Set the BAUD divisor */ -#ifdef LPC176x +# ifdef LPC176x dl = lpc17_40_uartdl(priv->baud, priv->cclkdiv); -#else +# else dl = lpc17_40_uartdl(priv->baud); -#endif +# endif up_serialout(priv, LPC17_40_UART_DLM_OFFSET, dl >> 8); up_serialout(priv, LPC17_40_UART_DLL_OFFSET, dl & 0xff); /* Clear DLAB */ up_serialout(priv, LPC17_40_UART_LCR_OFFSET, lcr); +# endif } break; #endif diff --git a/arch/arm/src/lpc43xx/lpc43_uart.c b/arch/arm/src/lpc43xx/lpc43_uart.c index 766edc99cdbec..85cb375195ffd 100644 --- a/arch/arm/src/lpc43xx/lpc43_uart.c +++ b/arch/arm/src/lpc43xx/lpc43_uart.c @@ -619,7 +619,7 @@ void lpc43_setbaud(uintptr_t uartbase, uint32_t basefreq, uint32_t baud) mul = 0; dl = 0; - /* Try each mulitplier value in the valid range */ + /* Try each multiplier value in the valid range */ for (cmul = 1 ; cmul < 16; cmul++) { From c642d5cfc22e677969e99dbf0a4899a4d9809793 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 18 Oct 2019 17:25:51 -0500 Subject: [PATCH 12/14] Added support for fractional divider to console UART --- arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c | 6 +++++ arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 23 ++++++++++---------- arch/arm/src/lpc17xx_40xx/lpc17_40_serial.h | 1 + arch/arm/src/lpc43xx/lpc43_uart.c | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c index 166050befed7a..9450bbfcb2929 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c @@ -396,6 +396,7 @@ void lpc17_40_lowsetup(void) putreg32(UART_FCR_FIFOEN | UART_FCR_RXTRIGGER_8, CONSOLE_BASE + LPC17_40_UART_FCR_OFFSET); +#ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER /* Disable FDR (fractional divider), * ignored by baudrate calculation => has to be disabled */ @@ -403,15 +404,20 @@ void lpc17_40_lowsetup(void) putreg32((1 << UART_FDR_MULVAL_SHIFT) + (0 << UART_FDR_DIVADDVAL_SHIFT), CONSOLE_BASE + LPC17_40_UART_FDR_OFFSET); +#endif /* Set up the LCR and set DLAB=1 */ putreg32(CONSOLE_LCR_VALUE | UART_LCR_DLAB, CONSOLE_BASE + LPC17_40_UART_LCR_OFFSET); +#ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER + up_setbaud(CONSOLE_BASE, CONSOLE_NUMERATOR, CONSOLE_BAUD); +#else /* Set the BAUD divisor */ putreg32(CONSOLE_DL >> 8, CONSOLE_BASE + LPC17_40_UART_DLM_OFFSET); putreg32(CONSOLE_DL & 0xff, CONSOLE_BASE + LPC17_40_UART_DLL_OFFSET); +#endif /* Clear DLAB */ diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index dac341a57136a..c1e379bda9130 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -546,6 +546,7 @@ static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) up_serialout(priv, LPC17_40_UART_LCR_OFFSET, lcr); } + #ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER /**************************************************************************** * Name: lpc17_40_setbaud @@ -559,9 +560,8 @@ static inline void up_enablebreaks(struct up_dev_s *priv, bool enable) * ****************************************************************************/ -static void up_setbaud(struct up_dev_s *priv, uint32_t baud) +void up_setbaud(uintptr_t uartbase, uint32_t basefreq, uint32_t baud) { - uint32_t basefreq; /* Base frequency of the UART peripheral */ uint32_t lcr; /* Line control register value */ uint32_t dl; /* Best DLM/DLL full value */ @@ -586,7 +586,6 @@ static void up_setbaud(struct up_dev_s *priv, uint32_t baud) * 0 <= divadd < mul */ - basefreq = LPC17_40_CCLK / priv->cclkdiv; best = UINT32_MAX; divadd = 0; mul = 0; @@ -660,22 +659,22 @@ static void up_setbaud(struct up_dev_s *priv, uint32_t baud) /* Enter DLAB=1 */ - lcr = getreg32(priv->uartbase + LPC17_40_UART_LCR_OFFSET); - putreg32(lcr | UART_LCR_DLAB, priv->uartbase + LPC17_40_UART_LCR_OFFSET); + lcr = getreg32(uartbase + LPC17_40_UART_LCR_OFFSET); + putreg32(lcr | UART_LCR_DLAB, uartbase + LPC17_40_UART_LCR_OFFSET); - /* Save then divider values */ + /* Save the divider values */ - putreg32(dl >> 8, priv->uartbase + LPC17_40_UART_DLM_OFFSET); - putreg32(dl & 0xff, priv->uartbase + LPC17_40_UART_DLL_OFFSET); + putreg32(dl >> 8, uartbase + LPC17_40_UART_DLM_OFFSET); + putreg32(dl & 0xff, uartbase + LPC17_40_UART_DLL_OFFSET); /* Clear DLAB */ - putreg32(lcr & ~UART_LCR_DLAB, priv->uartbase + LPC17_40_UART_LCR_OFFSET); + putreg32(lcr & ~UART_LCR_DLAB, uartbase + LPC17_40_UART_LCR_OFFSET); /* Then save the fractional divider values */ putreg32((mul << UART_FDR_MULVAL_SHIFT) | (divadd << UART_FDR_DIVADDVAL_SHIFT), - priv->uartbase + LPC17_40_UART_FDR_OFFSET); + uartbase + LPC17_40_UART_FDR_OFFSET); } # ifdef LPC176x static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) @@ -1095,7 +1094,7 @@ static int up_setup(struct uart_dev_s *dev) /* Set the BAUD divisor */ #ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER - up_setbaud(priv, priv->baud); + up_setbaud(priv->uartbase, LPC17_40_CCLK / priv->cclkdiv, priv->baud); #else # ifdef LPC176x dl = lpc17_40_uartdl(priv->baud, priv->cclkdiv); @@ -1400,7 +1399,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) * and reset the divider in the CLKSEL0/1 register. */ # ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER - up_setbaud(priv, priv->baud); + up_setbaud(priv->uartbase, LPC17_40_CCLK / priv->cclkdiv, priv->baud); # else # if 0 /* ifdef LPC176x */ priv->cclkdiv = lpc17_40_uartcclkdiv(priv->baud); diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.h b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.h index 624deaa7b45aa..d4a9fd914932e 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.h +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.h @@ -129,5 +129,6 @@ /************************************************************************************ * Public Functions ************************************************************************************/ +void up_setbaud(uintptr_t uartbase, uint32_t basefreq, uint32_t baud); #endif /* __ARCH_ARM_SRC_LPC17XX_40XX_LPC17_40_SERIAL_H */ diff --git a/arch/arm/src/lpc43xx/lpc43_uart.c b/arch/arm/src/lpc43xx/lpc43_uart.c index 85cb375195ffd..69b317156d455 100644 --- a/arch/arm/src/lpc43xx/lpc43_uart.c +++ b/arch/arm/src/lpc43xx/lpc43_uart.c @@ -690,7 +690,7 @@ void lpc43_setbaud(uintptr_t uartbase, uint32_t basefreq, uint32_t baud) lcr = getreg32(uartbase + LPC43_UART_LCR_OFFSET); putreg32(lcr | UART_LCR_DLAB, uartbase + LPC43_UART_LCR_OFFSET); - /* Save then divider values */ + /* Save the divider values */ putreg32(dl >> 8, uartbase + LPC43_UART_DLM_OFFSET); putreg32(dl & 0xff, uartbase + LPC43_UART_DLL_OFFSET); From 9453799bf8d095297514b032c228f1844550f3fd Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 18 Oct 2019 17:49:21 -0500 Subject: [PATCH 13/14] Small fixes for fractional baud rate on console --- arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c | 32 +++++++++++--------- arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 8 ++--- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c index 9450bbfcb2929..8e041caf4ee62 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_lowputc.c @@ -154,9 +154,6 @@ * And for the LPC178x/40xx, the PCLK is determined by the global divisor setting in * the PLKSEL register. * - * Ignoring the fractional divider for now. (If you want to extend this driver - * to support the fractional divider, see lpc43xx_uart.c. The LPC43xx uses - * the same peripheral and that logic could easily leveraged here). */ #ifdef LPC178x_40xx @@ -165,6 +162,10 @@ # define CONSOLE_NUMERATOR BOARD_PCLK_FREQUENCY #else +# ifdef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER +# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK +# define CONSOLE_NUMERATOR (LPC17_40_CCLK) +# else /* Calculate and optimal PCLKSEL0/1 divisor. * First, check divisor == 1. This works if the upper limit is met: * @@ -181,9 +182,9 @@ * BAUD <= CCLK / 16 / MinDL */ -# if CONSOLE_BAUD < (LPC17_40_CCLK / 16 / UART_MINDL) -# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK -# define CONSOLE_NUMERATOR (LPC17_40_CCLK) +# if CONSOLE_BAUD < (LPC17_40_CCLK / 16 / UART_MINDL) +# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK +# define CONSOLE_NUMERATOR (LPC17_40_CCLK) /* Check divisor == 2. This works if: * @@ -196,9 +197,9 @@ * BAUD <= CCLK / 8 / MinDL */ -# elif CONSOLE_BAUD < (LPC17_40_CCLK / 8 / UART_MINDL) -# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK2 -# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 2) +# elif CONSOLE_BAUD < (LPC17_40_CCLK / 8 / UART_MINDL) +# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK2 +# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 2) /* Check divisor == 4. This works if: * @@ -211,9 +212,9 @@ * BAUD <= CCLK / 4 / MinDL */ -# elif CONSOLE_BAUD < (LPC17_40_CCLK / 4 / UART_MINDL) -# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK4 -# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 4) +# elif CONSOLE_BAUD < (LPC17_40_CCLK / 4 / UART_MINDL) +# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK4 +# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 4) /* Check divisor == 8. This works if: * @@ -226,9 +227,10 @@ * BAUD <= CCLK / 2 / MinDL */ -# else /* if CONSOLE_BAUD < (LPC17_40_CCLK / 2 / UART_MINDL) */ -# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK8 -# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 8) +# else /* if CONSOLE_BAUD < (LPC17_40_CCLK / 2 / UART_MINDL) */ +# define CONSOLE_CCLKDIV SYSCON_PCLKSEL_CCLK8 +# define CONSOLE_NUMERATOR (LPC17_40_CCLK / 8) +# endif # endif #endif /* LPC178x_40xx */ diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index c1e379bda9130..676f1b064f170 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -698,9 +698,6 @@ static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) * PCLK = CCLK / divisor * BAUD = PCLK / (16 * DL) * - * Ignoring the fractional divider for now. (If you want to extend this driver - * to support the fractional divider, see lpc43xx_uart.c. The LPC43xx uses - * the same peripheral and that logic could easily leveraged here). * * For the LPC176x the PCLK is determined by the UART-specific divisor in * PCLKSEL0 or PCLKSEL1: @@ -979,9 +976,6 @@ static inline void lpc17_40_uart3config(void) * BAUD = PCLK / (16 * DL), or * DL = PCLK / BAUD / 16 * - * Ignoring the fractional divider for now. (If you want to extend this driver - * to support the fractional divider, see lpc43xx_uart.c. The LPC43xx uses - * the same peripheral and that logic could easily leveraged here). * ************************************************************************************/ #ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER @@ -1081,12 +1075,14 @@ static int up_setup(struct uart_dev_s *dev) lcr |= (UART_LCR_PE | UART_LCR_PS_EVEN); } +#ifndef CONFIG_LPC17_40_UART_USE_FRACTIONAL_DIVIDER /* Disable FDR (fractional divider), * ignored by baudrate calculation => has to be disabled */ up_serialout(priv, LPC17_40_UART_FDR_OFFSET, (1 << UART_FDR_MULVAL_SHIFT) + (0 << UART_FDR_DIVADDVAL_SHIFT)); +#endif /* Enter DLAB=1 */ From bced7c3443a218f37ef718421c7049f39a9ceba6 Mon Sep 17 00:00:00 2001 From: Joshua Lange Date: Fri, 18 Oct 2019 17:50:48 -0500 Subject: [PATCH 14/14] fix typo --- arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c index 676f1b064f170..a5335e8617be5 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_serial.c @@ -691,7 +691,7 @@ static inline uint32_t lpc17_40_uartcclkdiv(uint32_t baud) * Name: lpc17_40_uartcclkdiv * * Description: - * Select a CCLK divider to produce the UART PCLK. The stratey is to select the + * Select a CCLK divider to produce the UART PCLK. The strategy is to select the * smallest divisor that results in an solution within range of the 16-bit * DLM and DLL divisor: *