diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/stm32f4/console/usart.c')
-rw-r--r-- | c/src/lib/libbsp/arm/stm32f4/console/usart.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/stm32f4/console/usart.c b/c/src/lib/libbsp/arm/stm32f4/console/usart.c new file mode 100644 index 0000000000..539423faa2 --- /dev/null +++ b/c/src/lib/libbsp/arm/stm32f4/console/usart.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2012 Sebastian Huber. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <libchip/sersupp.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/usart.h> +#include <bsp/stm32f4.h> + +static volatile stm32f4_usart *usart_get_regs(const console_tbl *ct) +{ + return (stm32f4_usart *) ct->ulCtrlPort1; +} + +#if 0 +static rtems_vector_number usart_get_irq_number(const console_tbl *ct) +{ + return ct->ulIntVector; +} +#endif + +static const uint8_t usart_pclk_index [] = { 1, 0, 0, 0, 0, 1 }; + +static const uint32_t usart_pclk_by_index [] = { + STM32F4_PCLK1, + STM32F4_PCLK2 +}; + +static uint32_t usart_get_pclk(const console_tbl *ct) +{ + return usart_pclk_by_index [usart_pclk_index [ct->ulCtrlPort2]]; +} + +static uint32_t usart_get_baud(const console_tbl *ct) +{ + return ct->ulClock; +} + +/* + * a = 8 * (2 - CR1[OVER8]) + * + * usartdiv = div_mantissa + div_fraction / a + * + * baud = pclk / (a * usartdiv) + * + * usartdiv = pclk / (a * baud) + * + * Calculation in integer arithmetic: + * + * 1. div_mantissa = pclk / (a * baud) + * + * 2. div_fraction = pclk / (baud - a * div_mantissa) + */ +static uint32_t usart_get_bbr( + volatile stm32f4_usart *usart, + uint32_t pclk, + uint32_t baud +) +{ + uint32_t a = 8 * (2 - ((usart->cr1 & STM32F4_USART_CR1_OVER8) != 0)); + uint32_t div_mantissa_low = pclk / (a * baud); + uint32_t div_fraction_low = pclk / (baud - a * div_mantissa_low); + uint32_t div_mantissa_high; + uint32_t div_fraction_high; + uint32_t high_err; + uint32_t low_err; + uint32_t div_mantissa; + uint32_t div_fraction; + + if (div_fraction_low < a - 1) { + div_mantissa_high = div_fraction_low; + div_fraction_high = div_fraction_low + 1; + } else { + div_mantissa_high = div_fraction_low + 1; + div_fraction_high = 0; + } + + high_err = pclk - baud * (a * div_mantissa_high + div_fraction_high); + low_err = baud * (a * div_mantissa_low + div_fraction_low) - pclk; + + if (low_err < high_err) { + div_mantissa = div_mantissa_low; + div_fraction = div_fraction_low; + } else { + div_mantissa = div_mantissa_high; + div_fraction = div_fraction_high; + } + + return STM32F4_USART_BBR_DIV_MANTISSA(div_mantissa) + | STM32F4_USART_BBR_DIV_FRACTION(div_fraction); +} + +static void usart_initialize(int minor) +{ + const console_tbl *ct = Console_Port_Tbl [minor]; + volatile stm32f4_usart *usart = usart_get_regs(ct); + uint32_t pclk = usart_get_pclk(ct); + uint32_t baud = usart_get_baud(ct); + volatile stm32f4_rcc *rcc = &STM32F4_RCC; + + rcc->apb2enr |= STM32F4_RCC_APB2ENR_USART1_EN; + + usart->cr1 = 0; + usart->cr2 = 0; + usart->cr3 = 0; + usart->bbr = usart_get_bbr(usart, pclk, baud); + usart->cr1 = STM32F4_USART_CR1_UE + | STM32F4_USART_CR1_TE + | STM32F4_USART_CR1_RE; +} + +static int usart_first_open(int major, int minor, void *arg) +{ + rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg; + struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1; + const console_tbl *ct = Console_Port_Tbl [minor]; + console_data *cd = &Console_Port_Data [minor]; + + cd->termios_data = tty; + rtems_termios_set_initial_baud(tty, ct->ulClock); + + return 0; +} + +static int usart_last_close(int major, int minor, void *arg) +{ + return 0; +} + +static int usart_read_polled(int minor) +{ + const console_tbl *ct = Console_Port_Tbl [minor]; + volatile stm32f4_usart *usart = usart_get_regs(ct); + + if ((usart->sr & STM32F4_USART_SR_RXNE) != 0) { + return STM32F4_USART_DR_GET(usart->dr); + } else { + return -1; + } +} + +static void usart_write_polled(int minor, char c) +{ + const console_tbl *ct = Console_Port_Tbl [minor]; + volatile stm32f4_usart *usart = usart_get_regs(ct); + + while ((usart->sr & STM32F4_USART_SR_TXE) == 0) { + /* Wait */ + } + + usart->dr = STM32F4_USART_DR(c); +} + +static ssize_t usart_write_support_polled( + int minor, + const char *s, + size_t n +) +{ + ssize_t i = 0; + + for (i = 0; i < n; ++i) { + usart_write_polled(minor, s [i]); + } + + return n; +} + +static int usart_set_attributes(int minor, const struct termios *term) +{ + return -1; +} + +console_fns stm32f4_usart_fns = { + .deviceProbe = libchip_serial_default_probe, + .deviceFirstOpen = usart_first_open, + .deviceLastClose = usart_last_close, + .deviceRead = usart_read_polled, + .deviceWrite = usart_write_support_polled, + .deviceInitialize = usart_initialize, + .deviceWritePolled = usart_write_polled, + .deviceSetAttributes = usart_set_attributes, + .deviceOutputUsesInterrupts = false +}; |