1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/esp*: move periph/uart to cpu/esp_common

tmp
This commit is contained in:
Gunar Schorcht 2019-12-16 08:07:21 +01:00
parent 0ef723c6f7
commit b0517c6733
3 changed files with 29 additions and 452 deletions

View File

@ -509,6 +509,10 @@ typedef struct {
gpio_t rxd; /**< GPIO used as RxD pin */
} uart_conf_t;
/**
* @brief Maximum number of UART interfaces
*/
#define UART_NUMOF_MAX (3)
/** @} */
#ifdef __cplusplus

View File

@ -1,415 +0,0 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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.
*/
/**
* @ingroup cpu_esp32
* @ingroup drivers_periph_uart
* @{
*
* @file
* @brief Low-level UART driver implementation
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "esp_common.h"
#include "cpu.h"
#include "irq_arch.h"
#include "log.h"
#include "sched.h"
#include "thread.h"
#include "periph/gpio.h"
#include "periph/uart.h"
#include "gpio_arch.h"
#include "driver/periph_ctrl.h"
#include "esp/common_macros.h"
#include "rom/ets_sys.h"
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/gpio_struct.h"
#include "soc/rtc.h"
#include "soc/uart_reg.h"
#include "soc/uart_struct.h"
#include "xtensa/xtensa_api.h"
#undef UART_CLK_FREQ
#define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */
struct uart_hw_t {
uart_dev_t* regs; /* pointer to register data struct of the UART device */
uint8_t mod; /* peripheral hardware module of the UART interface */
bool used; /* indicates whether UART is used */
uint32_t baudrate; /* used baudrate */
uart_data_bits_t data; /* used data bits */
uart_stop_bits_t stop; /* used stop bits */
uart_parity_t parity; /* used parity bits */
uart_isr_ctx_t isr_ctx; /* callback functions */
uint8_t signal_txd; /* TxD signal from the controller */
uint8_t signal_rxd; /* RxD signal to the controller */
uint8_t int_src; /* peripheral interrupt source used by the UART device */
};
/* hardware resources */
static struct uart_hw_t _uarts[] = {
{
.regs = &UART0,
.mod = PERIPH_UART0_MODULE,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U0TXD_OUT_IDX,
.signal_rxd = U0RXD_IN_IDX,
.int_src = ETS_UART0_INTR_SOURCE
},
{
.regs = &UART1,
.mod = PERIPH_UART1_MODULE,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U1TXD_OUT_IDX,
.signal_rxd = U1RXD_IN_IDX,
.int_src = ETS_UART1_INTR_SOURCE
},
{
.regs = &UART2,
.mod = PERIPH_UART2_MODULE,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U2TXD_OUT_IDX,
.signal_rxd = U2RXD_IN_IDX,
.int_src = ETS_UART2_INTR_SOURCE
}
};
/* declaration of external functions */
extern void uart_div_modify(uint8_t uart_no, uint32_t div);
/* forward declaration of internal functions */
static int _uart_set_baudrate(uart_t uart, uint32_t baudrate);
static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits);
static uint8_t IRAM _uart_rx_one_char (uart_t uart);
static void _uart_tx_one_char(uart_t uart, uint8_t data);
static void _uart_intr_enable (uart_t uart);
static void _uart_config (uart_t uart);
static void IRAM _uart_intr_handler (void *para);
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
DEBUG("%s uart=%d, rate=%d, rx_cb=%p, arg=%p\n", __func__, uart, baudrate, rx_cb, arg);
CHECK_PARAM_RET (uart < UART_NUMOF, -1);
/* UART1 and UART2 have configurable pins */
if (uart == UART_DEV(1) || uart == UART_DEV(2)) {
/* reset the pins when they were already used as UART pins */
if (gpio_get_pin_usage(uart_config[uart].txd) == _UART) {
gpio_set_pin_usage(uart_config[uart].txd, _GPIO);
}
if (gpio_get_pin_usage(uart_config[uart].rxd) == _UART) {
gpio_set_pin_usage(uart_config[uart].rxd, _GPIO);
}
/* try to initialize the pins as GPIOs first */
if (gpio_init (uart_config[uart].rxd, GPIO_IN) ||
gpio_init (uart_config[uart].txd, GPIO_OUT)) {
return -1;
}
/* store the usage type in GPIO table */
gpio_set_pin_usage(uart_config[uart].txd, _UART);
gpio_set_pin_usage(uart_config[uart].rxd, _UART);
/* connect TxD pin to the TxD output signal through the GPIO matrix */
GPIO.func_out_sel_cfg[uart_config[uart].txd].func_sel = _uarts[uart].signal_txd;
/* connect RxD input signal to the RxD pin through the GPIO matrix */
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = uart_config[uart].rxd;
}
_uarts[uart].baudrate = baudrate;
/* register interrupt context */
_uarts[uart].isr_ctx.rx_cb = rx_cb;
_uarts[uart].isr_ctx.arg = arg;
/* enable and configure the according UART module */
uart_poweron(uart);
return UART_OK;
}
#if 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)
{
return _uart_set_mode(uart, data_bits, parity, stop_bits);
}
#endif
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
CHECK_PARAM (uart < UART_NUMOF);
for (size_t i = 0; i < len; i++) {
_uart_tx_one_char(uart, data[i]);
}
}
void uart_poweron (uart_t uart)
{
CHECK_PARAM (uart < UART_NUMOF);
periph_module_enable(_uarts[uart].mod);
_uart_config(uart);
}
void uart_poweroff (uart_t uart)
{
CHECK_PARAM (uart < UART_NUMOF);
periph_module_disable(_uarts[uart].mod);
}
/* systemwide UART initializations */
void uart_system_init (void)
{
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
/* reset all UART interrupt status registers */
_uarts[uart].regs->int_clr.val = ~0;
}
}
void uart_print_config(void)
{
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
printf("\tUART_DEV(%u)\ttxd=%d rxd=%d\n", uart,
uart_config[uart].txd, uart_config[uart].rxd);
}
}
static void IRAM _uart_intr_handler (void *arg)
{
/* to satisfy the compiler */
(void)arg;
irq_isr_enter ();
/* UART0, UART1, UART2 peripheral interrupt sources are routed to the same
interrupt, so we have to use the status to distinguish interruptees */
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
if (_uarts[uart].used) {
DEBUG("%s uart=%d int_st=%08x\n", __func__,
uart, _uarts[uart].regs->int_st.val);
if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) {
/* read one byte of data */
uint8_t data = _uart_rx_one_char (uart);
/* if registered, call the RX callback function */
if (_uarts[uart].isr_ctx.rx_cb) {
_uarts[uart].isr_ctx.rx_cb(_uarts[uart].isr_ctx.arg, data);
}
/* clear interrupt flag */
_uarts[uart].regs->int_clr.rxfifo_full = 1;
}
/* TODO handle other types of interrupts, for the moment just clear them */
_uarts[uart].regs->int_clr.val = ~0x0;
}
}
irq_isr_exit ();
}
/* RX/TX FIFO capacity is 128 byte */
#define UART_FIFO_MAX 127
/* receive one data byte with wait */
static uint8_t IRAM _uart_rx_one_char (uart_t uart)
{
/* wait until at least von byte is in RX FIFO */
while (!_uarts[uart].regs->status.rxfifo_cnt) {}
/* read the lowest byte from RX FIFO register */
return _uarts[uart].regs->fifo.rw_byte;
}
/* send one data byte with wait */
static void _uart_tx_one_char(uart_t uart, uint8_t data)
{
/* wait until at least one byte is available in the TX FIFO */
while (_uarts[uart].regs->status.txfifo_cnt >= UART_FIFO_MAX) {}
/* send the byte by placing it in the TX FIFO using MPU */
WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data);
}
static void _uart_intr_enable(uart_t uart)
{
_uarts[uart].regs->int_ena.rxfifo_full = 1;
_uarts[uart].regs->int_clr.rxfifo_full = 1;
_uarts[uart].used = true;
DEBUG("%s %08x\n", __func__, _uarts[uart].regs->int_ena.val);
}
static void _uart_config (uart_t uart)
{
CHECK_PARAM (uart < UART_NUMOF);
/* setup the baudrate */
if (uart == UART_DEV(0) || uart == UART_DEV(1)) {
/* wait until TX FIFO is empty */
while (_uarts[uart].regs->status.txfifo_cnt) { }
/* for UART0 and UART1, we can us the ROM function */
uart_div_modify(uart, (UART_CLK_FREQ << 4) / _uarts[uart].baudrate);
}
else if (_uart_set_baudrate(uart, _uarts[uart].baudrate) != UART_OK) {
return;
}
/* set number of data bits, stop bits and parity mode */
if (_uart_set_mode(uart, _uarts[uart].data, _uarts[uart].stop,
_uarts[uart].parity) != UART_OK) {
return;
}
/* reset the FIFOs */
_uarts[uart].regs->conf0.rxfifo_rst = 1;
_uarts[uart].regs->conf0.rxfifo_rst = 0;
_uarts[uart].regs->conf0.txfifo_rst = 1;
_uarts[uart].regs->conf0.txfifo_rst = 0;
if (_uarts[uart].isr_ctx.rx_cb) {
/* since reading can only be done byte by byte, we set
UART_RXFIFO_FULL_THRHD interrupt level to 1 byte */
_uarts[uart].regs->conf1.rxfifo_full_thrhd = 1;
/* enable the RX FIFO FULL interrupt */
_uart_intr_enable (uart);
/* route all UART interrupt sources to same the CPU interrupt */
intr_matrix_set(PRO_CPU_NUM, _uarts[uart].int_src, CPU_INUM_UART);
/* we have to enable therefore the CPU interrupt here */
xt_set_interrupt_handler(CPU_INUM_UART, _uart_intr_handler, NULL);
xt_ints_on(BIT(CPU_INUM_UART));
}
}
static int _uart_set_baudrate(uart_t uart, uint32_t baudrate)
{
DEBUG("%s uart=%d, rate=%d\n", __func__, uart, baudrate);
CHECK_PARAM_RET (uart < UART_NUMOF, -1);
/* wait until TX FIFO is empty */
while (_uarts[uart].regs->status.txfifo_cnt != 0) { }
critical_enter();
_uarts[uart].baudrate = baudrate;
/* use APB_CLK */
_uarts[uart].regs->conf0.tick_ref_always_on = 1;
/* compute and set the integral and the decimal part */
uint32_t clk = (UART_CLK_FREQ << 4) / baudrate;
_uarts[uart].regs->clk_div.div_int = clk >> 4;
_uarts[uart].regs->clk_div.div_frag = clk & 0xf;
critical_exit();
return UART_OK;
}
static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits)
{
DEBUG("%s uart=%d, data_bits=%d parity=%d stop_bits=%d\n", __func__,
uart, data_bits, parity, stop_bits);
CHECK_PARAM_RET (uart < UART_NUMOF, UART_NODEV);
critical_enter();
/* set number of data bits */
switch (data_bits) {
case UART_DATA_BITS_5: _uarts[uart].regs->conf0.bit_num = 0; break;
case UART_DATA_BITS_6: _uarts[uart].regs->conf0.bit_num = 1; break;
case UART_DATA_BITS_7: _uarts[uart].regs->conf0.bit_num = 2; break;
case UART_DATA_BITS_8: _uarts[uart].regs->conf0.bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of data bits\n");
critical_exit();
return UART_NOMODE;
}
/* store changed number of data bits in configuration */
_uarts[uart].data = data_bits;
/* set number of stop bits */
#ifdef MCU_ESP32
/* workaround for hardware bug when stop bits are set to 2-bit mode. */
switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1;
_uarts[uart].regs->rs485_conf.dl1_en = 0;
break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 1;
_uarts[uart].regs->rs485_conf.dl1_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#else
switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#endif
/* store changed number of stop bits in configuration */
_uarts[uart].stop = stop_bits;
/* set parity mode */
switch (parity) {
case UART_PARITY_NONE: _uarts[uart].regs->conf0.parity_en = 0;
break;
case UART_PARITY_EVEN: _uarts[uart].regs->conf0.parity = 0;
_uarts[uart].regs->conf0.parity_en = 1;
break;
case UART_PARITY_ODD: _uarts[uart].regs->conf0.parity = 1;
_uarts[uart].regs->conf0.parity_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid or unsupported parity mode\n");
critical_exit();
return UART_NOMODE;
}
/* store changed parity in configuration */
_uarts[uart].parity = parity;
critical_exit();
return UART_OK;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Gunar Schorcht
* Copyright (C) 2018 Gunar Schorcht
*
* 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
@ -7,7 +7,7 @@
*/
/**
* @ingroup cpu_esp8266
* @ingroup cpu_esp_common
* @ingroup drivers_periph_uart
* @{
*
@ -68,8 +68,6 @@
struct uart_hw_t {
uart_dev_t* regs; /* pointer to register data struct of the UART device */
uint8_t pin_txd; /* TxD pin used */
uint8_t pin_rxd; /* RxD pin used */
bool used; /* indicates whether UART is used */
uint32_t baudrate; /* used baudrate */
uart_data_bits_t data; /* used data bits */
@ -136,7 +134,7 @@ static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
static uint8_t IRAM _uart_rx_one_char(uart_t uart);
static void _uart_tx_one_char(uart_t uart, uint8_t data);
static void _uart_intr_enable(uart_t uart);
static void _uart_config (uart_t uart);
static void _uart_config(uart_t uart);
static void IRAM _uart_intr_handler(void *para);
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
@ -146,38 +144,36 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
assert(uart < UART_NUMOF_MAX);
assert(uart < UART_NUMOF);
_uarts[uart].pin_txd = uart_config[uart].txd;
_uarts[uart].pin_rxd = uart_config[uart].rxd;
#ifdef MCU_ESP32
/* UART1 and UART2 have configurable pins */
if ((uart == UART_DEV(1) || uart == UART_DEV(2))) {
if ((UART_NUMOF > 0 && uart == UART_DEV(1)) ||
(UART_NUMOF > 1 && uart == UART_DEV(2))) {
/* reset the pins when they were already used as UART pins */
if (gpio_get_pin_usage(_uarts[uart].pin_txd) == _UART) {
gpio_set_pin_usage(_uarts[uart].pin_txd, _GPIO);
if (gpio_get_pin_usage(uart_config[uart].txd) == _UART) {
gpio_set_pin_usage(uart_config[uart].txd, _GPIO);
}
if (gpio_get_pin_usage(_uarts[uart].pin_rxd) == _UART) {
gpio_set_pin_usage(_uarts[uart].pin_rxd, _GPIO);
if (gpio_get_pin_usage(uart_config[uart].rxd) == _UART) {
gpio_set_pin_usage(uart_config[uart].rxd, _GPIO);
}
/* try to initialize the pins as GPIOs first */
if (gpio_init(_uarts[uart].pin_txd, GPIO_OUT) ||
gpio_init(_uarts[uart].pin_rxd, GPIO_IN)) {
if (gpio_init(uart_config[uart].txd, GPIO_OUT) ||
gpio_init(uart_config[uart].rxd, GPIO_IN)) {
return -1;
}
/* store the usage type in GPIO table */
gpio_set_pin_usage(_uarts[uart].pin_txd, _UART);
gpio_set_pin_usage(_uarts[uart].pin_rxd, _UART);
gpio_set_pin_usage(uart_config[uart].txd, _UART);
gpio_set_pin_usage(uart_config[uart].rxd, _UART);
/* connect TxD pin to the TxD output signal through the GPIO matrix */
GPIO.func_out_sel_cfg[_uarts[uart].pin_txd].func_sel = _uarts[uart].signal_txd;
GPIO.func_out_sel_cfg[uart_config[uart].txd].func_sel = _uarts[uart].signal_txd;
/* connect RxD input signal to the RxD pin through the GPIO matrix */
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = _uarts[uart].pin_rxd;
GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = uart_config[uart].rxd;
}
#endif
_uarts[uart].baudrate = baudrate;
@ -202,16 +198,16 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
CHECK_PARAM(uart < UART_NUMOF);
assert(uart < UART_NUMOF);
for (size_t i = 0; i < len; i++) {
_uart_tx_one_char(uart, data[i]);
}
}
void uart_poweron (uart_t uart)
void uart_poweron(uart_t uart)
{
CHECK_PARAM(uart < UART_NUMOF);
assert(uart < UART_NUMOF);
#ifdef MCU_ESP32
periph_module_enable(_uarts[uart].mod);
@ -219,9 +215,9 @@ void uart_poweron (uart_t uart)
_uart_config(uart);
}
void uart_poweroff (uart_t uart)
void uart_poweroff(uart_t uart)
{
CHECK_PARAM(uart < UART_NUMOF);
assert(uart < UART_NUMOF);
#ifdef MCU_ESP32
periph_module_disable(_uarts[uart].mod);
@ -229,7 +225,7 @@ void uart_poweroff (uart_t uart)
}
/* systemwide UART initializations */
void uart_system_init (void)
void uart_system_init(void)
{
for (unsigned uart = 0; uart < UART_NUMOF; uart++) {
/* reset all UART interrupt status registers */
@ -261,7 +257,7 @@ static void IRAM _uart_intr_handler(void *arg)
if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) {
/* read one byte of data */
uint8_t data = _uart_rx_one_char (uart);
uint8_t data = _uart_rx_one_char(uart);
/* if registered, call the RX callback function */
if (_uarts[uart].isr_ctx.rx_cb) {
_uarts[uart].isr_ctx.rx_cb(_uarts[uart].isr_ctx.arg, data);
@ -282,7 +278,7 @@ static void IRAM _uart_intr_handler(void *arg)
#define UART_FIFO_MAX 128
/* receive one data byte with wait */
static uint8_t IRAM _uart_rx_one_char (uart_t uart)
static uint8_t IRAM _uart_rx_one_char(uart_t uart)
{
#if defined(MODULE_ESP_QEMU) && defined(MCU_ESP8266)
/* wait until at least von byte is in RX FIFO */
@ -331,15 +327,7 @@ static void _uart_config(uart_t uart)
{
assert(uart < UART_NUMOF);
while (_uarts[uart].regs->status.txfifo_cnt != 0) { }
#if 0
/* setup the baudrate */
if (uart == UART_DEV(0) || uart == UART_DEV(1)) {
/* for UART0 and UART1, we can us the ROM function */
uart_div_modify(uart, (UART_CLK_FREQ << 4) / _uarts[uart].baudrate);
}
else
#endif
if (_uart_set_baudrate(uart, _uarts[uart].baudrate) != UART_OK) {
return;
}
@ -379,7 +367,7 @@ static int _uart_set_baudrate(uart_t uart, uint32_t baudrate)
{
DEBUG("%s uart=%d, rate=%d\n", __func__, uart, baudrate);
CHECK_PARAM_RET (uart < UART_NUMOF, -1);
assert(uart < UART_NUMOF);
/* wait until TX FIFO is empty */
while (_uarts[uart].regs->status.txfifo_cnt != 0) { }
@ -412,7 +400,7 @@ static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
DEBUG("%s uart=%d, data_bits=%d parity=%d stop_bits=%d\n", __func__,
uart, data_bits, parity, stop_bits);
CHECK_PARAM_RET (uart < UART_NUMOF, UART_NODEV);
assert(uart < UART_NUMOF);
critical_enter();