Merge pull request #6187 from haukepetersen/opt_stm32_uart
cpu/stm32x: unified UART driver implementationspr/spi.typo
commit
ade8bd2a17
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2016 Freie Universität Berlin
|
||||
* Copyright (C) 2016 OTA keys
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup cpu_stm32f2
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level UART driver implementation
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hermann Lelong <hermann@otakeys.com>
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "sched.h"
|
||||
#include "thread.h"
|
||||
#include "assert.h"
|
||||
#include "periph/uart.h"
|
||||
#include "periph/gpio.h"
|
||||
|
||||
#ifdef UART_NUMOF
|
||||
|
||||
#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)
|
||||
|
||||
/**
|
||||
* @brief Allocate memory to store the callback functions
|
||||
*/
|
||||
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
|
||||
|
||||
static inline USART_TypeDef *dev(uart_t uart)
|
||||
{
|
||||
return uart_config[uart].dev;
|
||||
}
|
||||
|
||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
||||
{
|
||||
uint16_t mantissa;
|
||||
uint8_t fraction;
|
||||
uint32_t clk;
|
||||
|
||||
assert(uart < UART_NUMOF);
|
||||
|
||||
/* save ISR context */
|
||||
isr_ctx[uart].rx_cb = rx_cb;
|
||||
isr_ctx[uart].arg = arg;
|
||||
|
||||
/* configure RX and TX pin */
|
||||
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
|
||||
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
|
||||
/* set TX pin high to avoid garbage during further initialization */
|
||||
gpio_set(uart_config[uart].tx_pin);
|
||||
#ifdef CPU_FAM_STM32F1
|
||||
gpio_init_af(uart_config[uart].tx_pin, GPIO_AF_OUT_PP);
|
||||
#else
|
||||
gpio_init_af(uart_config[uart].tx_pin, uart_config[uart].tx_af);
|
||||
gpio_init_af(uart_config[uart].rx_pin, uart_config[uart].rx_af);
|
||||
#endif
|
||||
|
||||
/* enable the clock */
|
||||
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcc_mask);
|
||||
|
||||
/* reset UART configuration -> defaults to 8N1 mode */
|
||||
dev(uart)->CR1 = 0;
|
||||
dev(uart)->CR2 = 0;
|
||||
dev(uart)->CR3 = 0;
|
||||
|
||||
/* calculate and apply baudrate */
|
||||
clk = periph_apb_clk(uart_config[uart].bus) / baudrate;
|
||||
mantissa = (uint16_t)(clk / 16);
|
||||
fraction = (uint8_t)(clk - (mantissa * 16));
|
||||
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f);
|
||||
|
||||
/* enable RX interrupt if applicable */
|
||||
if (rx_cb) {
|
||||
NVIC_EnableIRQ(uart_config[uart].irqn);
|
||||
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE | RXENABLE);
|
||||
}
|
||||
else {
|
||||
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE);
|
||||
}
|
||||
|
||||
return UART_OK;
|
||||
}
|
||||
|
||||
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||
{
|
||||
assert(uart < UART_NUMOF);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
|
||||
while (!(dev(uart)->ISR & USART_ISR_TXE)) {}
|
||||
dev(uart)->TDR = data[i];
|
||||
#else
|
||||
while (!(dev(uart)->SR & USART_SR_TXE)) {}
|
||||
dev(uart)->DR = data[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
/* make sure the function is synchronous by waiting for the transfer to
|
||||
* finish */
|
||||
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
|
||||
while (!(dev(uart)->ISR & USART_ISR_TC)) {}
|
||||
#else
|
||||
while (!(dev(uart)->SR & USART_SR_TC)) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
void uart_poweron(uart_t uart)
|
||||
{
|
||||
assert(uart < UART_NUMOF);
|
||||
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcc_mask);
|
||||
}
|
||||
|
||||
void uart_poweroff(uart_t uart)
|
||||
{
|
||||
assert(uart < UART_NUMOF);
|
||||
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcc_mask);
|
||||
}
|
||||