1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

Merge pull request #9158 from aabadie/pr/periph/stm32_lpuart

cpu/stm32-common: add support for lpuart
This commit is contained in:
Martine Lenders 2018-12-17 12:16:27 +01:00 committed by GitHub
commit a3864aa103
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 195 additions and 38 deletions

View File

@ -81,7 +81,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB1,
.irqn = USART2_IRQn
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART1,
@ -91,7 +93,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB2,
.irqn = USART1_IRQn
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
};

View File

@ -102,6 +102,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB2,
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 6,
.dma_chan = 4
@ -116,6 +118,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF8,
.bus = APB1,
.irqn = UART4_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 5,
.dma_chan = 4

View File

@ -85,7 +85,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB1,
.irqn = USART2_IRQn
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
}
};

View File

@ -85,7 +85,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB1,
.irqn = USART2_IRQn
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART1,
@ -95,7 +97,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB2,
.irqn = USART1_IRQn
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
}
};

View File

@ -2,6 +2,7 @@
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_spi

View File

@ -85,7 +85,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB1,
.irqn = USART2_IRQn
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART1,
@ -95,23 +97,32 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF4,
.tx_af = GPIO_AF4,
.bus = APB2,
.irqn = USART1_IRQn
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
#ifdef MODULE_PERIPH_LPUART
{
.dev = USART4,
.rcc_mask = RCC_APB1ENR_USART4EN,
.dev = LPUART1,
.rcc_mask = RCC_APB1ENR_LPUART1EN,
.rx_pin = GPIO_PIN(PORT_C, 11),
.tx_pin = GPIO_PIN(PORT_C, 10),
.rx_af = GPIO_AF6,
.tx_af = GPIO_AF6,
.rx_af = GPIO_AF0,
.tx_af = GPIO_AF0,
.bus = APB1,
.irqn = USART4_5_IRQn
.irqn = LPUART1_IRQn,
.type = STM32_LPUART,
.clk_src = 0, /* Use APB clock */
},
#endif
};
#define UART_0_ISR (isr_usart2)
#define UART_1_ISR (isr_usart1)
#define UART_2_ISR (isr_usart4_5)
#ifdef MODULE_PERIPH_LPUART
#define UART_2_ISR (isr_rng_lpuart1)
#endif
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */

View File

@ -105,7 +105,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF3,
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART2_IRQn
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART1,
@ -115,7 +117,9 @@ static const uart_conf_t uart_config[] = {
.rx_af = GPIO_AF7,
.tx_af = GPIO_AF7,
.bus = APB2,
.irqn = USART1_IRQn
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
};

View File

@ -1 +1,3 @@
FEATURES_REQUIRED += periph_lpuart
include $(RIOTBOARD)/common/nucleo/Makefile.dep

View File

@ -1,5 +1,6 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_lpuart
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt

View File

@ -2,10 +2,5 @@
export CPU = stm32l4
export CPU_MODEL = stm32l433rc
# stdio is not available over st-link but on the Arduino TX/RX pins
# A serial to USB converter plugged to the host is required
PORT_LINUX ?= /dev/ttyUSB0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbmodem*)))
# load the common Makefile.include for Nucleo boards
include $(RIOTBOARD)/common/nucleo64/Makefile.include

View File

@ -106,6 +106,18 @@ static const timer_conf_t timer_config[] = {
* @{
*/
static const uart_conf_t uart_config[] = {
{
.dev = LPUART1,
.rcc_mask = RCC_APB1ENR2_LPUART1EN,
.rx_pin = GPIO_PIN(PORT_A, 3),
.tx_pin = GPIO_PIN(PORT_A, 2),
.rx_af = GPIO_AF8,
.tx_af = GPIO_AF8,
.bus = APB12,
.irqn = LPUART1_IRQn,
.type = STM32_LPUART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART1,
.rcc_mask = RCC_APB2ENR_USART1EN,
@ -115,6 +127,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB2,
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 5,
.dma_chan = 4
@ -122,7 +136,8 @@ static const uart_conf_t uart_config[] = {
}
};
#define UART_0_ISR (isr_usart1)
#define UART_0_ISR (isr_lpuart1)
#define UART_1_ISR (isr_usart1)
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */

View File

@ -118,6 +118,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
},
{
.dev = USART3,
@ -128,6 +130,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART3_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
}
};

View File

@ -121,6 +121,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 6,
.dma_chan = 4
@ -135,6 +137,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART3_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 5,
.dma_chan = 4
@ -149,6 +153,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB2,
.irqn = USART1_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 4,
.dma_chan = 4

View File

@ -121,6 +121,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART3_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 5,
.dma_chan = 4

View File

@ -102,6 +102,8 @@ static const uart_conf_t uart_config[] = {
.tx_af = GPIO_AF7,
.bus = APB1,
.irqn = USART2_IRQn,
.type = STM32_USART,
.clk_src = 0, /* Use APB clock */
#ifdef UART_USE_DMA
.dma_stream = 6,
.dma_chan = 4

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,19 +46,16 @@ 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 */
/* configure TX pin */
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);
@ -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) \

View File

@ -3,6 +3,7 @@ include ../Makefile.tests_common
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-uno nucleo-f031k6
FEATURES_REQUIRED = periph_uart
FEATURES_OPTIONAL = periph_lpuart # STM32 L0 and L4 provides lpuart support
USEMODULE += shell
USEMODULE += xtimer