2016-12-07 16:17:12 +01:00
|
|
|
/*
|
2017-02-09 10:42:03 +01:00
|
|
|
* Copyright (C) 2014-2017 Freie Universität Berlin
|
2016-12-07 16:17:12 +01:00
|
|
|
* Copyright (C) 2016 OTA keys
|
2018-05-21 21:46:32 +02:00
|
|
|
* Copyright (C) 2018 Inria
|
2016-12-07 16:17:12 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2017-10-01 21:55:59 +02:00
|
|
|
* @ingroup cpu_stm32_common
|
2017-06-22 15:43:17 +02:00
|
|
|
* @ingroup drivers_periph_uart
|
2016-12-07 16:17:12 +01:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @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>
|
2018-05-21 21:46:32 +02:00
|
|
|
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
2016-12-07 16:17:12 +01:00
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "sched.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "assert.h"
|
|
|
|
#include "periph/uart.h"
|
|
|
|
#include "periph/gpio.h"
|
2017-10-23 11:36:52 +02:00
|
|
|
#include "pm_layered.h"
|
2016-12-07 16:17:12 +01:00
|
|
|
|
2019-07-15 13:39:20 +02:00
|
|
|
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
|
|
|
|
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
|
|
|
|
defined(CPU_FAM_STM32F7)
|
2018-05-23 19:08:03 +02:00
|
|
|
#define ISR_REG ISR
|
|
|
|
#define ISR_TXE USART_ISR_TXE
|
|
|
|
#define ISR_TC USART_ISR_TC
|
|
|
|
#define TDR_REG TDR
|
|
|
|
#else
|
|
|
|
#define ISR_REG SR
|
|
|
|
#define ISR_TXE USART_SR_TXE
|
|
|
|
#define ISR_TC USART_SR_TC
|
|
|
|
#define TDR_REG DR
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2016-12-07 16:17:12 +01:00
|
|
|
#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Allocate memory to store the callback functions
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
*
|
|
|
|
* Extend standard uart_isr_ctx_t with data_mask field. This is needed
|
|
|
|
* in order to mask parity bit.
|
2016-12-07 16:17:12 +01:00
|
|
|
*/
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
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];
|
2016-12-07 16:17:12 +01:00
|
|
|
|
|
|
|
static inline USART_TypeDef *dev(uart_t uart)
|
|
|
|
{
|
|
|
|
return uart_config[uart].dev;
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:46:32 +02:00
|
|
|
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
|
2016-12-07 16:17:12 +01:00
|
|
|
|
2020-03-10 12:47:28 +01:00
|
|
|
#ifdef MODULE_PERIPH_UART_HW_FC
|
2019-08-27 19:01:58 +02:00
|
|
|
static inline void uart_init_rts_pin(uart_t uart)
|
|
|
|
{
|
2019-08-30 14:14:35 +02:00
|
|
|
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
|
2019-08-27 19:01:58 +02:00
|
|
|
gpio_init(uart_config[uart].rts_pin, GPIO_OUT);
|
|
|
|
#ifdef CPU_FAM_STM32F1
|
|
|
|
gpio_init_af(uart_config[uart].rts_pin, GPIO_AF_OUT_PP);
|
|
|
|
#else
|
|
|
|
gpio_init_af(uart_config[uart].rts_pin, uart_config[uart].rts_af);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void uart_init_cts_pin(uart_t uart)
|
|
|
|
{
|
|
|
|
if (uart_config[uart].cts_pin != GPIO_UNDEF) {
|
|
|
|
gpio_init(uart_config[uart].cts_pin, GPIO_IN);
|
|
|
|
#ifndef CPU_FAM_STM32F1
|
|
|
|
gpio_init_af(uart_config[uart].cts_pin, uart_config[uart].cts_af);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-05-21 21:46:32 +02:00
|
|
|
static inline void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb)
|
|
|
|
{
|
|
|
|
/* configure TX pin */
|
2016-12-07 16:17:12 +01:00
|
|
|
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);
|
|
|
|
#endif
|
2017-02-09 10:42:03 +01:00
|
|
|
/* configure RX pin */
|
|
|
|
if (rx_cb) {
|
2019-09-15 22:38:18 +02:00
|
|
|
gpio_init(uart_config[uart].rx_pin, GPIO_IN_PU);
|
2017-02-09 10:42:03 +01:00
|
|
|
#ifndef CPU_FAM_STM32F1
|
|
|
|
gpio_init_af(uart_config[uart].rx_pin, uart_config[uart].rx_af);
|
|
|
|
#endif
|
|
|
|
}
|
2020-03-10 12:47:28 +01:00
|
|
|
#ifdef MODULE_PERIPH_UART_HW_FC
|
2019-08-27 19:01:58 +02:00
|
|
|
uart_init_cts_pin(uart);
|
|
|
|
uart_init_rts_pin(uart);
|
2017-01-05 14:22:02 +01:00
|
|
|
#endif
|
2018-05-21 21:46:32 +02:00
|
|
|
}
|
|
|
|
|
2019-08-26 12:19:17 +02:00
|
|
|
static inline void uart_enable_clock(uart_t uart)
|
|
|
|
{
|
|
|
|
#ifdef STM32_PM_STOP
|
|
|
|
if (isr_ctx[uart].rx_cb) {
|
|
|
|
pm_block(STM32_PM_STOP);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcc_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void uart_disable_clock(uart_t uart)
|
|
|
|
{
|
|
|
|
periph_clk_dis(uart_config[uart].bus, uart_config[uart].rcc_mask);
|
|
|
|
#ifdef STM32_PM_STOP
|
|
|
|
if (isr_ctx[uart].rx_cb) {
|
|
|
|
pm_unblock(STM32_PM_STOP);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:46:32 +02:00
|
|
|
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
|
|
|
{
|
|
|
|
assert(uart < UART_NUMOF);
|
|
|
|
|
|
|
|
/* save ISR context */
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
isr_ctx[uart].rx_cb = rx_cb;
|
|
|
|
isr_ctx[uart].arg = arg;
|
|
|
|
isr_ctx[uart].data_mask = 0xFF;
|
2018-05-21 21:46:32 +02:00
|
|
|
|
|
|
|
uart_init_pins(uart, rx_cb);
|
2016-12-07 16:17:12 +01:00
|
|
|
|
2019-08-26 12:19:17 +02:00
|
|
|
uart_enable_clock(uart);
|
2016-12-07 16:17:12 +01:00
|
|
|
|
|
|
|
/* reset UART configuration -> defaults to 8N1 mode */
|
|
|
|
dev(uart)->CR1 = 0;
|
|
|
|
dev(uart)->CR2 = 0;
|
|
|
|
dev(uart)->CR3 = 0;
|
|
|
|
|
2018-05-21 21:46:32 +02:00
|
|
|
#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
|
2016-12-07 16:17:12 +01:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2020-03-10 12:47:28 +01:00
|
|
|
#ifdef MODULE_PERIPH_UART_HW_FC
|
2017-01-05 14:22:02 +01:00
|
|
|
if (uart_config[uart].cts_pin != GPIO_UNDEF) {
|
2019-08-30 14:14:35 +02:00
|
|
|
dev(uart)->CR3 |= USART_CR3_CTSE;
|
|
|
|
}
|
|
|
|
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
|
|
|
|
dev(uart)->CR3 |= USART_CR3_RTSE;
|
2017-01-05 14:22:02 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-12-07 16:17:12 +01:00
|
|
|
return UART_OK;
|
|
|
|
}
|
|
|
|
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
#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:
|
2019-03-17 18:44:07 +01:00
|
|
|
#ifdef USART_CR1_M0
|
|
|
|
data_bits = USART_CR1_M0;
|
|
|
|
#else
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
data_bits = USART_CR1_M;
|
2019-03-17 18:44:07 +01:00
|
|
|
#endif
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
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);
|
|
|
|
#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 */
|
|
|
|
|
2018-05-21 21:46:32 +02:00
|
|
|
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 */
|
|
|
|
|
2017-09-28 18:03:17 +02:00
|
|
|
static inline void send_byte(uart_t uart, uint8_t byte)
|
2016-12-07 16:17:12 +01:00
|
|
|
{
|
2018-11-20 11:59:29 +01:00
|
|
|
while (!(dev(uart)->ISR_REG & ISR_TXE)) {}
|
2018-05-23 19:08:03 +02:00
|
|
|
dev(uart)->TDR_REG = byte;
|
2017-09-28 18:03:17 +02:00
|
|
|
}
|
2016-12-07 16:17:12 +01:00
|
|
|
|
2017-09-28 18:03:17 +02:00
|
|
|
static inline void wait_for_tx_complete(uart_t uart)
|
|
|
|
{
|
2018-05-23 19:08:03 +02:00
|
|
|
while (!(dev(uart)->ISR_REG & ISR_TC)) {}
|
2016-12-07 16:17:12 +01:00
|
|
|
}
|
|
|
|
|
2017-09-28 18:03:17 +02:00
|
|
|
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
assert(uart < UART_NUMOF);
|
2018-12-14 11:08:51 +01:00
|
|
|
#if DEVELHELP
|
|
|
|
/* If tx is not enabled don't try to send */
|
|
|
|
if (!(dev(uart)->CR1 & USART_CR1_TE)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2017-09-28 18:03:17 +02:00
|
|
|
#ifdef MODULE_PERIPH_DMA
|
|
|
|
if (!len) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (uart_config[uart].dma != DMA_STREAM_UNDEF) {
|
|
|
|
if (irq_is_in()) {
|
|
|
|
uint16_t todo = 0;
|
|
|
|
if (dev(uart)->CR3 & USART_CR3_DMAT) {
|
|
|
|
/* DMA transfer for UART on-going */
|
|
|
|
todo = dma_suspend(uart_config[uart].dma);
|
|
|
|
}
|
|
|
|
if (todo) {
|
|
|
|
dma_stop(uart_config[uart].dma);
|
|
|
|
dev(uart)->CR3 &= ~USART_CR3_DMAT;
|
|
|
|
}
|
|
|
|
for (unsigned i = 0; i < len; i++) {
|
|
|
|
send_byte(uart, data[i]);
|
|
|
|
}
|
|
|
|
if (todo > 0) {
|
|
|
|
wait_for_tx_complete(uart);
|
|
|
|
dev(uart)->CR3 |= USART_CR3_DMAT;
|
|
|
|
dma_resume(uart_config[uart].dma, todo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dma_acquire(uart_config[uart].dma);
|
|
|
|
dev(uart)->CR3 |= USART_CR3_DMAT;
|
|
|
|
dma_transfer(uart_config[uart].dma, uart_config[uart].dma_chan, data,
|
2018-05-23 19:08:03 +02:00
|
|
|
(void *)&dev(uart)->TDR_REG, len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
|
2017-09-28 18:03:17 +02:00
|
|
|
|
|
|
|
/* make sure the function is synchronous by waiting for the transfer to
|
|
|
|
* finish */
|
|
|
|
wait_for_tx_complete(uart);
|
|
|
|
dev(uart)->CR3 &= ~USART_CR3_DMAT;
|
2019-02-04 23:25:59 +01:00
|
|
|
dma_release(uart_config[uart].dma);
|
2017-09-28 18:03:17 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
send_byte(uart, data[i]);
|
|
|
|
}
|
|
|
|
/* make sure the function is synchronous by waiting for the transfer to
|
|
|
|
* finish */
|
|
|
|
wait_for_tx_complete(uart);
|
|
|
|
}
|
|
|
|
|
2016-12-07 16:17:12 +01:00
|
|
|
void uart_poweron(uart_t uart)
|
|
|
|
{
|
|
|
|
assert(uart < UART_NUMOF);
|
2019-08-26 12:19:17 +02:00
|
|
|
|
|
|
|
uart_enable_clock(uart);
|
|
|
|
|
|
|
|
dev(uart)->CR1 |= (USART_CR1_UE);
|
2019-08-27 19:01:58 +02:00
|
|
|
|
2020-03-10 12:47:28 +01:00
|
|
|
#ifdef MODULE_PERIPH_UART_HW_FC
|
2019-08-27 19:01:58 +02:00
|
|
|
/* STM32F4 errata 2.10.9: nRTS is active while RE or UE = 0
|
|
|
|
* we should only configure nRTS pin after setting UE */
|
|
|
|
uart_init_rts_pin(uart);
|
|
|
|
#endif
|
2016-12-07 16:17:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void uart_poweroff(uart_t uart)
|
|
|
|
{
|
|
|
|
assert(uart < UART_NUMOF);
|
2017-10-23 11:36:52 +02:00
|
|
|
|
2020-03-10 12:47:28 +01:00
|
|
|
#ifdef MODULE_PERIPH_UART_HW_FC
|
2019-08-27 19:01:58 +02:00
|
|
|
/* the uart peripheral does not put RTS high from hardware when
|
|
|
|
* UE flag is cleared, so we need to do this manually */
|
2019-08-30 14:14:35 +02:00
|
|
|
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
|
2019-08-27 19:01:58 +02:00
|
|
|
gpio_init(uart_config[uart].rts_pin, GPIO_OUT);
|
|
|
|
gpio_set(uart_config[uart].rts_pin);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-08-26 12:19:17 +02:00
|
|
|
dev(uart)->CR1 &= ~(USART_CR1_UE);
|
|
|
|
|
|
|
|
uart_disable_clock(uart);
|
2016-12-07 16:17:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void irq_handler(uart_t uart)
|
|
|
|
{
|
2019-07-15 13:39:20 +02:00
|
|
|
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
|
|
|
|
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
|
|
|
|
defined(CPU_FAM_STM32F7)
|
2016-12-07 16:17:12 +01:00
|
|
|
|
|
|
|
uint32_t status = dev(uart)->ISR;
|
|
|
|
|
|
|
|
if (status & USART_ISR_RXNE) {
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
|
|
|
|
(uint8_t)dev(uart)->RDR & isr_ctx[uart].data_mask);
|
2016-12-07 16:17:12 +01:00
|
|
|
}
|
|
|
|
if (status & USART_ISR_ORE) {
|
|
|
|
dev(uart)->ICR |= USART_ICR_ORECF; /* simply clear flag on overrun */
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
uint32_t status = dev(uart)->SR;
|
|
|
|
|
|
|
|
if (status & USART_SR_RXNE) {
|
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: Yegor Yefremov <yegorslists@googlemail.com>
2019-01-08 11:10:49 +01:00
|
|
|
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
|
|
|
|
(uint8_t)dev(uart)->DR & isr_ctx[uart].data_mask);
|
2016-12-07 16:17:12 +01:00
|
|
|
}
|
|
|
|
if (status & USART_SR_ORE) {
|
|
|
|
/* ORE is cleared by reading SR and DR sequentially */
|
|
|
|
dev(uart)->DR;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
cortexm_isr_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UART_0_ISR
|
|
|
|
void UART_0_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(0));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UART_1_ISR
|
|
|
|
void UART_1_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(1));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UART_2_ISR
|
|
|
|
void UART_2_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(2));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UART_3_ISR
|
|
|
|
void UART_3_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(3));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UART_4_ISR
|
|
|
|
void UART_4_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(4));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UART_5_ISR
|
|
|
|
void UART_5_ISR(void)
|
|
|
|
{
|
|
|
|
irq_handler(UART_DEV(5));
|
|
|
|
}
|
|
|
|
#endif
|