From dff203e7dda95240286c5a0852c8b17205746d06 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Wed, 16 Mar 2016 10:27:43 +0100 Subject: [PATCH] cpu/stm32f1: reworked UART implementation --- cpu/stm32f1/include/periph_cpu.h | 12 +++ cpu/stm32f1/periph/uart.c | 175 +++++++++++++------------------ 2 files changed, 82 insertions(+), 105 deletions(-) diff --git a/cpu/stm32f1/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h index 23306fbbba..cd7d47bcd4 100644 --- a/cpu/stm32f1/include/periph_cpu.h +++ b/cpu/stm32f1/include/periph_cpu.h @@ -125,6 +125,18 @@ typedef struct { uint8_t irqn; /**< global IRQ channel */ } timer_conf_t; +/** + * @brief UART configuration options + */ +typedef struct { + USART_TypeDef *dev; /**< UART device */ + gpio_t rx_pin; /**< TX pin */ + gpio_t tx_pin; /**< RX pin */ + uint32_t rcc_pin; /**< bit in the RCC register */ + uint8_t bus; /**< peripheral bus */ + uint8_t irqn; /**< interrupt number */ +} uart_conf_t; + /** * @brief Configure the alternate function for the given pin * diff --git a/cpu/stm32f1/periph/uart.c b/cpu/stm32f1/periph/uart.c index 3d18eb4d3b..bfe88789b8 100644 --- a/cpu/stm32f1/periph/uart.c +++ b/cpu/stm32f1/periph/uart.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2016 Freie Universität Berlin * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. */ /** @@ -33,142 +33,107 @@ /** * @brief Allocate memory to store the callback functions. */ -static uart_isr_ctx_t config[UART_NUMOF]; +static uart_isr_ctx_t isr_ctx[UART_NUMOF]; -static int init_base(uart_t uart, uint32_t baudrate); +static inline USART_TypeDef *dev(uart_t uart) +{ + return uart_config[uart].dev; +} + +static void clk_en(uart_t uart) +{ + if (uart_config[uart].bus == APB1) { + RCC->APB1ENR |= uart_config[uart].rcc_pin; + } + else { + RCC->APB2ENR |= uart_config[uart].rcc_pin; + } +} int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { - int res; - - /* initialize UART in blocking mode first */ - res = init_base(uart, baudrate); - if (res < 0) { - return res; - } - - /* enable global interrupt and configure the interrupts priority */ - switch (uart) { -#if UART_0_EN - case UART_0: - NVIC_EnableIRQ(UART_0_IRQ); - UART_0_DEV->CR1 |= USART_CR1_RXNEIE; - break; -#endif -#if UART_1_EN - case UART_1: - NVIC_EnableIRQ(UART_1_IRQ); - UART_1_DEV->CR1 |= USART_CR1_RXNEIE; - break; -#endif - default: - return -2; - } - - /* register callbacks */ - config[uart].rx_cb = rx_cb; - config[uart].arg = arg; - - return 0; -} - -static int init_base(uart_t uart, uint32_t baudrate) -{ - USART_TypeDef *dev; - uint32_t bus_freq; - gpio_t rx_pin, tx_pin; + uint32_t bus_clk; uint16_t mantissa; uint8_t fraction; - /* enable UART and port clocks and select devices */ - switch (uart) { -#if UART_0_EN - case UART_0: - dev = UART_0_DEV; - rx_pin = UART_0_RX_PIN; - tx_pin = UART_0_TX_PIN; - bus_freq = UART_0_BUS_FREQ; - /* enable clocks */ - UART_0_CLKEN(); - break; -#endif -#if UART_1_EN - case UART_1: - dev = UART_1_DEV; - tx_pin = UART_1_TX_PIN; - rx_pin = UART_1_RX_PIN; - bus_freq = UART_1_BUS_FREQ; - /* enable clocks */ - UART_1_CLKEN(); - break; -#endif - default: - return -2; + /* make sure the given device is valid */ + if (uart >= UART_NUMOF) { + return -1; } + + /* save ISR context */ + isr_ctx[uart].rx_cb = rx_cb; + isr_ctx[uart].arg = arg; + /* configure RX and TX pin */ - gpio_init_af(tx_pin, GPIO_AF_OUT_PP); - gpio_init(rx_pin, GPIO_DIR_IN, GPIO_NOPULL); + gpio_init(uart_config[uart].rx_pin, GPIO_DIR_IN, GPIO_NOPULL); + gpio_init_af(uart_config[uart].tx_pin, GPIO_AF_OUT_PP); - /* configure UART to mode 8N1 with given baudrate */ - bus_freq /= baudrate; - mantissa = (uint16_t)(bus_freq / 16); - fraction = (uint8_t)(bus_freq - (mantissa * 16)); - dev->BRR = 0; - dev->BRR |= ((mantissa & 0x0fff) << 4) | (0x0f & fraction); + /* enable the clock */ + clk_en(uart); + + /* reset UART configuration -> defaults to 8N1 mode */ + dev(uart)->CR1 = 0; + dev(uart)->CR2 = 0; + dev(uart)->CR3 = 0; + + /* calculate and apply baudrate */ + bus_clk = (uart_config[uart].bus == APB1) ? CLOCK_APB1 : CLOCK_APB2; + bus_clk /= baudrate; + mantissa = (uint16_t)(bus_clk / 16); + fraction = (uint8_t)(bus_clk - (mantissa * 16)); + dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f); + + /* enable the UART's global interrupt and activate it */ + NVIC_EnableIRQ(uart_config[uart].irqn); + dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE | + USART_CR1_RE | USART_CR1_RXNEIE); - /* enable receive and transmit mode */ - dev->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; return 0; } void uart_write(uart_t uart, const uint8_t *data, size_t len) { - USART_TypeDef *dev; - - switch (uart) { -#if UART_0_EN - case UART_0: - dev = UART_0_DEV; - break; -#endif -#if UART_1_EN - case UART_1: - dev = UART_1_DEV; - break; -#endif - } - for (size_t i = 0; i < len; i++) { - while (!(dev->SR & USART_SR_TXE)) {} - dev->DR = data[i]; + while(!(dev(uart)->SR & USART_SR_TXE)) {} + dev(uart)->DR = data[i]; } } -static inline void irq_handler(uart_t uartnum, USART_TypeDef *dev) +static inline void irq_handler(uart_t uart) { - if (dev->SR & USART_SR_RXNE) { - uint8_t data = (uint8_t)dev->DR; - config[uartnum].rx_cb(config[uartnum].arg, data); + uint32_t status = dev(uart)->SR; + + if (status & USART_SR_RXNE) { + char data = (char)dev(uart)->DR; + isr_ctx[uart].rx_cb(isr_ctx[uart].arg, data); } - else if (dev->SR & USART_SR_ORE) { + if (status & USART_SR_ORE) { /* ORE is cleared by reading SR and DR sequentially */ - dev->DR; + dev(uart)->DR; } if (sched_context_switch_request) { thread_yield(); } } -#if UART_0_EN +#ifdef UART_0_ISR void UART_0_ISR(void) { - irq_handler(UART_0, UART_0_DEV); + irq_handler(0); } #endif -#if UART_1_EN +#ifdef UART_1_ISR void UART_1_ISR(void) { - irq_handler(UART_1, UART_1_DEV); + irq_handler(1); +} +#endif + +#ifdef UART_2_ISR +void UART_2_ISR(void) +{ + irq_handler(2); } #endif