Skip to content
Snippets Groups Projects
Commit 60f745a0 authored by Yegor Yefremov's avatar Yegor Yefremov
Browse files

cpu/stm32_common: add support for uart_mode routine


Add support for specifying data bits, stop bits and parity at
runtime.

Introduce feature periph_uart_modecfg for uart_mode() till all
other CPUs implement it.

STM32 L1, F1, F2, F4 supports following modes:

* 7E1, 7E2
* 7O1, 7O2
* 8N1, 8N2
* 8E1, 8E2
* 8O1, 8O2

STM32 L0, L4, F0, F3, F7 supports following modes:

* 6E1, 6E2
* 6O1, 6O2
* 7E1, 7E2
* 7O1, 7O2
* 7N1, 7N2
* 8N1, 8N2
* 8E1, 8E2
* 8O1, 8O2

Use USART_CR1_M1 macro to detect 7-bit support because
even inside one family there could be devices that don't
support 7-bit mode. So just using a family macro is not
enough.

As stated in the datasheets for L0, L4, F0, F3, F7 devices,
data bits can only be changed when UART is disabled (UE=0).
Introduce uart_stop() routine to satisfy this requirement.

STM32 UART adds parity to the MSB of a byte to send. The same
also applies to the received bytes. As a result this bit must
be masked in order to get the pure data.

Signed-off-by: default avatarYegor Yefremov <yegorslists@googlemail.com>
parent ddf19783
No related branches found
No related tags found
No related merge requests found
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += puf_sram
FEATURES_PROVIDED += periph_uart_modecfg
ifneq (,$(filter $(BOARDS_WITHOUT_HWRNG),$(BOARD)))
FEATURES_PROVIDED := $(filter-out periph_hwrng,$(FEATURES_PROVIDED))
......
......@@ -370,6 +370,56 @@ typedef enum {
STM32_LPUART, /**< STM32 Low-power UART (LPUART) module type */
} uart_type_t;
/**
* @brief Invalid UART mode mask
*
* This mask is also used to force data_bits_t to be uint32_t type
* since it may be assigned a uint32_t variable in uart_mode
*/
#define UART_INVALID_MODE (0x8000000)
/**
* @brief Override parity values
* @{
*/
#define HAVE_UART_PARITY_T
typedef enum {
UART_PARITY_NONE = 0, /**< no parity */
UART_PARITY_EVEN = USART_CR1_PCE, /**< even parity */
UART_PARITY_ODD = (USART_CR1_PCE | USART_CR1_PS), /**< odd parity */
UART_PARITY_MARK = UART_INVALID_MODE | 4, /**< not supported */
UART_PARITY_SPACE = UART_INVALID_MODE | 5 /**< not supported */
} uart_parity_t;
/** @} */
/**
* @brief Override data bits length values
* @{
*/
#define HAVE_UART_DATA_BITS_T
typedef enum {
UART_DATA_BITS_5 = UART_INVALID_MODE | 1, /**< not supported */
UART_DATA_BITS_6 = UART_INVALID_MODE | 2, /**< not supported unless parity is set */
#if defined(USART_CR1_M1)
UART_DATA_BITS_7 = USART_CR1_M1, /**< 7 data bits */
#else
UART_DATA_BITS_7 = UART_INVALID_MODE | 3, /**< not supported unless parity is set */
#endif
UART_DATA_BITS_8 = 0, /**< 8 data bits */
} uart_data_bits_t;
/** @} */
/**
* @brief Override stop bits length values
* @{
*/
#define HAVE_UART_STOP_BITS_T
typedef enum {
UART_STOP_BITS_1 = 0, /**< 1 stop bit */
UART_STOP_BITS_2 = USART_CR2_STOP_1, /**< 2 stop bits */
} uart_stop_bits_t;
/** @} */
/**
* @brief Structure for UART configuration data
*/
......
......@@ -53,8 +53,15 @@
/**
* @brief Allocate memory to store the callback functions
*
* Extend standard uart_isr_ctx_t with data_mask field. This is needed
* in order to mask parity bit.
*/
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
static struct {
uart_rx_cb_t rx_cb; /**< data received interrupt callback */
void *arg; /**< argument to both callback routines */
uint8_t data_mask; /**< mask applied to the data register */
} isr_ctx[UART_NUMOF];
static inline USART_TypeDef *dev(uart_t uart)
{
......@@ -105,8 +112,9 @@ 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;
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
isr_ctx[uart].data_mask = 0xFF;
uart_init_pins(uart, rx_cb);
......@@ -154,6 +162,53 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
return UART_OK;
}
#ifdef MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
assert(uart < UART_NUMOF);
isr_ctx[uart].data_mask = 0xFF;
if (parity) {
switch (data_bits) {
case UART_DATA_BITS_6:
data_bits = UART_DATA_BITS_7;
isr_ctx[uart].data_mask = 0x3F;
break;
case UART_DATA_BITS_7:
data_bits = UART_DATA_BITS_8;
isr_ctx[uart].data_mask = 0x7F;
break;
case UART_DATA_BITS_8:
data_bits = USART_CR1_M;
break;
default:
return UART_NOMODE;
}
}
if ((data_bits & UART_INVALID_MODE) || (parity & UART_INVALID_MODE)) {
return UART_NOMODE;
}
#ifdef USART_CR1_M1
if (!(dev(uart)->ISR & USART_ISR_TC)) {
return UART_INTERR;
}
dev(uart)->CR1 &= ~(USART_CR1_UE | USART_CR1_TE);
dev(uart)->CR1 &= ~USART_CR1_M1;
#endif
dev(uart)->CR2 &= ~USART_CR2_STOP;
dev(uart)->CR1 &= ~(USART_CR1_PS | USART_CR1_PCE | USART_CR1_M);
dev(uart)->CR2 |= stop_bits;
dev(uart)->CR1 |= (USART_CR1_UE | USART_CR1_TE | data_bits | parity);
return UART_OK;
}
#endif /* MODULE_PERIPH_UART_MODECFG */
static inline void uart_init_usart(uart_t uart, uint32_t baudrate)
{
uint16_t mantissa;
......@@ -301,7 +356,8 @@ static inline void irq_handler(uart_t uart)
uint32_t status = dev(uart)->ISR;
if (status & USART_ISR_RXNE) {
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, (uint8_t)dev(uart)->RDR);
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
(uint8_t)dev(uart)->RDR & isr_ctx[uart].data_mask);
}
if (status & USART_ISR_ORE) {
dev(uart)->ICR |= USART_ICR_ORECF; /* simply clear flag on overrun */
......@@ -312,7 +368,8 @@ static inline void irq_handler(uart_t uart)
uint32_t status = dev(uart)->SR;
if (status & USART_SR_RXNE) {
isr_ctx[uart].rx_cb(isr_ctx[uart].arg, (uint8_t)dev(uart)->DR);
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
(uint8_t)dev(uart)->DR & isr_ctx[uart].data_mask);
}
if (status & USART_SR_ORE) {
/* ORE is cleared by reading SR and DR sequentially */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment