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 <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2016-10-25 14:06:55 +02:00 committed by Anas Nashif
commit 33d17497d2
2 changed files with 87 additions and 13 deletions

View file

@ -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_ */

View file

@ -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);