cpu/stm32_common: add support for lpuart

This commit is contained in:
Alexandre Abadie 2018-05-21 21:46:32 +02:00
parent e0997b4fc7
commit 133968ce8a
3 changed files with 116 additions and 17 deletions

View File

@ -51,6 +51,11 @@ uint32_t periph_apb_clk(uint8_t bus)
if (bus == APB1) {
return CLOCK_APB1;
}
#if defined (CPU_FAM_STM32L4)
else if (bus == APB12) {
return CLOCK_APB1;
}
#endif
else {
return CLOCK_APB2;
}
@ -74,6 +79,11 @@ void periph_clk_en(bus_t bus, uint32_t mask)
case APB2:
RCC->APB2ENR |= mask;
break;
#if defined(CPU_FAM_STM32L4)
case APB12:
RCC->APB1ENR2 |= mask;
break;
#endif
#if defined(CPU_FAM_STM32L0)
case AHB:
RCC->AHBENR |= mask;
@ -122,6 +132,11 @@ void periph_clk_dis(bus_t bus, uint32_t mask)
case APB2:
RCC->APB2ENR &= ~(mask);
break;
#if defined(CPU_FAM_STM32L4)
case APB12:
RCC->APB1ENR2 &= ~(mask);
break;
#endif
#if defined(CPU_FAM_STM32L0)
case AHB:
RCC->AHBENR &= ~(mask);

View File

@ -96,6 +96,9 @@ extern "C" {
typedef enum {
APB1, /**< APB1 bus */
APB2, /**< APB2 bus */
#if defined(CPU_FAM_STM32L4)
APB12, /**< AHB1 bus, second register */
#endif
#if defined(CPU_FAM_STM32L0)
AHB, /**< AHB bus */
IOP, /**< IOP bus */
@ -332,6 +335,14 @@ typedef struct {
uint8_t irqn; /**< global IRQ channel */
} qdec_conf_t;
/**
* @brief UART hardware module types
*/
typedef enum {
STM32_USART, /**< STM32 USART module type */
STM32_LPUART, /**< STM32 Low-power UART (LPUART) module type */
} uart_type_t;
/**
* @brief Structure for UART configuration data
*/
@ -358,6 +369,10 @@ typedef struct {
gpio_af_t rts_af; /**< alternate function for RTS pin */
#endif
#endif
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4)
uart_type_t type; /**< hardware module type (USART or LPUART) */
uint32_t clk_src; /**< clock source used for UART */
#endif
} uart_conf_t;
/**

View File

@ -1,6 +1,7 @@
/*
* Copyright (C) 2014-2017 Freie Universität Berlin
* Copyright (C) 2016 OTA keys
* Copyright (C) 2018 Inria
*
* 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
@ -20,6 +21,7 @@
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Hermann Lelong <hermann@otakeys.com>
* @author Toon Stegen <toon.stegen@altran.com>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
@ -44,18 +46,15 @@ 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)
static inline void uart_init_usart(uart_t uart, uint32_t baudrate);
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4)
#ifdef MODULE_PERIPH_LPUART
static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate);
#endif
#endif
static inline void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb)
{
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 TX pin */
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
/* set TX pin high to avoid garbage during further initialization */
@ -84,6 +83,17 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
#endif
}
#endif
}
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
assert(uart < UART_NUMOF);
/* save ISR context */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
uart_init_pins(uart, rx_cb);
/* enable the clock */
uart_poweron(uart);
@ -93,11 +103,22 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
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);
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4)
switch (uart_config[uart].type) {
case STM32_USART:
uart_init_usart(uart, baudrate);
break;
#ifdef MODULE_PERIPH_LPUART
case STM32_LPUART:
uart_init_lpuart(uart, baudrate);
break;
#endif
default:
return UART_NODEV;
}
#else
uart_init_usart(uart, baudrate);
#endif
/* enable RX interrupt if applicable */
if (rx_cb) {
@ -118,6 +139,54 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
return UART_OK;
}
static inline void uart_init_usart(uart_t uart, uint32_t baudrate)
{
uint16_t mantissa;
uint8_t fraction;
uint32_t clk;
/* 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);
}
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4)
#ifdef MODULE_PERIPH_LPUART
static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate)
{
uint32_t clk;
switch (uart_config[uart].clk_src) {
case 0:
clk = periph_apb_clk(uart_config[uart].bus);
break;
case RCC_CCIPR_LPUART1SEL_0:
clk = CLOCK_CORECLOCK;
break;
case (RCC_CCIPR_LPUART1SEL_0 | RCC_CCIPR_LPUART1SEL_1):
clk = 32768;
break;
default: /* HSI is not supported */
return;
}
RCC->CCIPR |= uart_config[uart].clk_src;
/* LSE can only be used with baudrate <= 9600 */
if ( (clk < (3 * baudrate)) || (clk > (4096 * baudrate))) {
return;
}
/* LPUARTDIV = f_clk * 256 / baudrate */
uint32_t brr = (uint32_t)(((uint64_t)clk << 8) / baudrate);
dev(uart)->BRR = brr;
}
#endif /* MODULE_PERIPH_LPUART */
#endif /* STM32L0 || STM32L4 */
static inline void send_byte(uart_t uart, uint8_t byte)
{
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \