From 33d17497d20e06837bf7632bc88a7c27d465c674 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 25 Oct 2016 14:06:55 +0200 Subject: [PATCH] drivers: uart_nrf5: Use MDK baudrate divisor constants The baudrate calculation present in set_baudrate() is causing the UART to emit inital bytes incorrectly, for a reason currently unknown, but directly related to the fact that __aeabi_uldivmod is being invoked. Since the nRF5x Product Specifications do not provide a standard formula to calculate baudrates and instead list a predefined set of divisor values, we opt here to use the official values and remove the attempt at calculating them manually. Change-Id: Ic3ff42ea6d065e9a1d26a5350ce5bf5ad661160a Signed-off-by: Carles Cufi --- .../arm/soc/nordic_nrf5/include/nrf5_common.h | 24 ++++++ drivers/serial/uart_nrf5.c | 76 +++++++++++++++---- 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/arch/arm/soc/nordic_nrf5/include/nrf5_common.h b/arch/arm/soc/nordic_nrf5/include/nrf5_common.h index eecbf3cf438..0677056650f 100644 --- a/arch/arm/soc/nordic_nrf5/include/nrf5_common.h +++ b/arch/arm/soc/nordic_nrf5/include/nrf5_common.h @@ -71,4 +71,28 @@ #define NRF52_IRQ_I2S_IRQn 37 #define NRF52_IRQ_FPU_IRQn 38 +/** + * @file UART baudrate divisors for NRF51/NRF52 family processors. + * + * Based on Nordic MDK included header file: nrf52_bitfields.h + * Uses the UARTE_BAUDRATE macros since they are more precise. + */ + +#define NRF5_UART_BAUDRATE_1200 0x0004f000 +#define NRF5_UART_BAUDRATE_2400 0x0009d000 +#define NRF5_UART_BAUDRATE_4800 0x0013b000 +#define NRF5_UART_BAUDRATE_9600 0x00275000 +#define NRF5_UART_BAUDRATE_14400 0x003af000 +#define NRF5_UART_BAUDRATE_19200 0x004ea000 +#define NRF5_UART_BAUDRATE_28800 0x0075c000 +#define NRF5_UART_BAUDRATE_38400 0x009d0000 +#define NRF5_UART_BAUDRATE_57600 0x00eb0000 +#define NRF5_UART_BAUDRATE_76800 0x013a9000 +#define NRF5_UART_BAUDRATE_115200 0x01d60000 +#define NRF5_UART_BAUDRATE_230400 0x03b00000 +#define NRF5_UART_BAUDRATE_250000 0x04000000 +#define NRF5_UART_BAUDRATE_460800 0x07400000 +#define NRF5_UART_BAUDRATE_921600 0x0f000000 +#define NRF5_UART_BAUDRATE_1000000 0x10000000 + #endif /* _NRF5_SOC_COMMON_H_ */ diff --git a/drivers/serial/uart_nrf5.c b/drivers/serial/uart_nrf5.c index 03a584e7183..d5a95950ef7 100644 --- a/drivers/serial/uart_nrf5.c +++ b/drivers/serial/uart_nrf5.c @@ -106,24 +106,70 @@ static struct uart_driver_api uart_nrf5_driver_api; * @return N/A */ -static void baudrate_set(struct device *dev, +static int baudrate_set(struct device *dev, uint32_t baudrate, uint32_t sys_clk_freq_hz) { volatile struct _uart *uart = UART_STRUCT(dev); - uint32_t set_baudrate; /* baud rate divisor */ + uint32_t divisor; /* baud rate divisor */ - if ((baudrate != 0) && (sys_clk_freq_hz != 0)) { - set_baudrate = (uint32_t) ( - (uint64_t)baudrate * - (uint64_t)UINT32_MAX / - (uint64_t)sys_clk_freq_hz - ); - - /* Round the value */ - set_baudrate = (set_baudrate + 0x800) & 0xFFFFF000; - uart->BAUDRATE = set_baudrate << UART_BAUDRATE_BAUDRATE_Pos; + /* Use the common nRF5 macros */ + switch (baudrate) { + case 1200: + divisor = NRF5_UART_BAUDRATE_1200; + break; + case 2400: + divisor = NRF5_UART_BAUDRATE_2400; + break; + case 4800: + divisor = NRF5_UART_BAUDRATE_4800; + break; + case 9600: + divisor = NRF5_UART_BAUDRATE_9600; + break; + case 14400: + divisor = NRF5_UART_BAUDRATE_14400; + break; + case 19200: + divisor = NRF5_UART_BAUDRATE_19200; + break; + case 28800: + divisor = NRF5_UART_BAUDRATE_28800; + break; + case 38400: + divisor = NRF5_UART_BAUDRATE_38400; + break; + case 57600: + divisor = NRF5_UART_BAUDRATE_57600; + break; + case 76800: + divisor = NRF5_UART_BAUDRATE_76800; + break; + case 115200: + divisor = NRF5_UART_BAUDRATE_115200; + break; + case 230400: + divisor = NRF5_UART_BAUDRATE_230400; + break; + case 250000: + divisor = NRF5_UART_BAUDRATE_250000; + break; + case 460800: + divisor = NRF5_UART_BAUDRATE_460800; + break; + case 921600: + divisor = NRF5_UART_BAUDRATE_921600; + break; + case 1000000: + divisor = NRF5_UART_BAUDRATE_1000000; + break; + default: + return -EINVAL; } + + uart->BAUDRATE = divisor << UART_BAUDRATE_BAUDRATE_Pos; + + return 0; } /** @@ -140,6 +186,7 @@ static int uart_nrf5_init(struct device *dev) { volatile struct _uart *uart = UART_STRUCT(dev); struct device *gpio_dev; + int err; gpio_dev = device_get_binding(CONFIG_GPIO_NRF5_P0_DEV_NAME); (void) gpio_pin_configure(gpio_dev, @@ -170,8 +217,11 @@ static int uart_nrf5_init(struct device *dev) DEV_DATA(dev)->baud_rate = CONFIG_UART_NRF5_BAUD_RATE; /* Set baud rate */ - baudrate_set(dev, DEV_DATA(dev)->baud_rate, + err = baudrate_set(dev, DEV_DATA(dev)->baud_rate, DEV_CFG(dev)->sys_clk_freq); + if (err) { + return err; + } /* Enable receiver and transmitter */ uart->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);