cpu/stm32f1: reworked UART implementation
This commit is contained in:
parent
91904a469c
commit
dff203e7dd
@ -125,6 +125,18 @@ typedef struct {
|
|||||||
uint8_t irqn; /**< global IRQ channel */
|
uint8_t irqn; /**< global IRQ channel */
|
||||||
} timer_conf_t;
|
} 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
|
* @brief Configure the alternate function for the given pin
|
||||||
*
|
*
|
||||||
|
|||||||
@ -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
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
* details.
|
* directory for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,142 +33,107 @@
|
|||||||
/**
|
/**
|
||||||
* @brief Allocate memory to store the callback functions.
|
* @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 uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
||||||
{
|
{
|
||||||
int res;
|
uint32_t bus_clk;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
uint16_t mantissa;
|
uint16_t mantissa;
|
||||||
uint8_t fraction;
|
uint8_t fraction;
|
||||||
|
|
||||||
/* enable UART and port clocks and select devices */
|
/* make sure the given device is valid */
|
||||||
switch (uart) {
|
if (uart >= UART_NUMOF) {
|
||||||
#if UART_0_EN
|
return -1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save ISR context */
|
||||||
|
isr_ctx[uart].rx_cb = rx_cb;
|
||||||
|
isr_ctx[uart].arg = arg;
|
||||||
|
|
||||||
/* configure RX and TX pin */
|
/* configure RX and TX pin */
|
||||||
gpio_init_af(tx_pin, GPIO_AF_OUT_PP);
|
gpio_init(uart_config[uart].rx_pin, GPIO_DIR_IN, GPIO_NOPULL);
|
||||||
gpio_init(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 */
|
/* enable the clock */
|
||||||
bus_freq /= baudrate;
|
clk_en(uart);
|
||||||
mantissa = (uint16_t)(bus_freq / 16);
|
|
||||||
fraction = (uint8_t)(bus_freq - (mantissa * 16));
|
/* reset UART configuration -> defaults to 8N1 mode */
|
||||||
dev->BRR = 0;
|
dev(uart)->CR1 = 0;
|
||||||
dev->BRR |= ((mantissa & 0x0fff) << 4) | (0x0f & fraction);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
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++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (!(dev->SR & USART_SR_TXE)) {}
|
while(!(dev(uart)->SR & USART_SR_TXE)) {}
|
||||||
dev->DR = data[i];
|
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) {
|
uint32_t status = dev(uart)->SR;
|
||||||
uint8_t data = (uint8_t)dev->DR;
|
|
||||||
config[uartnum].rx_cb(config[uartnum].arg, data);
|
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 */
|
/* ORE is cleared by reading SR and DR sequentially */
|
||||||
dev->DR;
|
dev(uart)->DR;
|
||||||
}
|
}
|
||||||
if (sched_context_switch_request) {
|
if (sched_context_switch_request) {
|
||||||
thread_yield();
|
thread_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UART_0_EN
|
#ifdef UART_0_ISR
|
||||||
void UART_0_ISR(void)
|
void UART_0_ISR(void)
|
||||||
{
|
{
|
||||||
irq_handler(UART_0, UART_0_DEV);
|
irq_handler(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UART_1_EN
|
#ifdef UART_1_ISR
|
||||||
void UART_1_ISR(void)
|
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
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user