[platform][stm32f7xx][uart] add support for more than one active uart
At the moment still only has hard coded bits for uart 1 and 3. Things are declared in a wonky way to avoid allocating large structures unnecessarily.
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/debug.h>
|
||||
@@ -35,165 +36,228 @@
|
||||
#include <platform/stm32.h>
|
||||
#include <arch/arm/cm.h>
|
||||
|
||||
#ifdef ENABLE_UART3
|
||||
cbuf_t uart3_rx_buf;
|
||||
#ifndef UART3_FLOWCONTROL
|
||||
#define UART3_FLOWCONTROL USART_HardwareFlowControl_None
|
||||
#define DEFAULT_FLOWCONTROL UART_HWCONTROL_NONE
|
||||
#define DEFAULT_BAUDRATE 115200
|
||||
#define DEFAULT_RXBUF_SIZE 16
|
||||
|
||||
#define NUM_UARTS 8
|
||||
|
||||
struct uart_instance {
|
||||
UART_HandleTypeDef handle;
|
||||
cbuf_t rx_buf;
|
||||
};
|
||||
|
||||
#if ENABLE_UART1
|
||||
static struct uart_instance uart1;
|
||||
#ifndef UART1_FLOWCONTROL
|
||||
#define UART1_FLOWCONTROL DEFAULT_FLOWCONTROL
|
||||
#endif
|
||||
#ifndef UART3_BAUDRATE
|
||||
#define UART3_BAUDRATE 115200
|
||||
#ifndef UART1_BAUDRATE
|
||||
#define UART1_BAUDRATE DEFAULT_BAUDRATE
|
||||
#endif
|
||||
#ifndef UART3_RXBUF_SIZE
|
||||
#define UART3_RXBUF_SIZE 16
|
||||
#ifndef UART1_RXBUF_SIZE
|
||||
#define UART1_RXBUF_SIZE DEFAULT_RXBUF_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static UART_HandleTypeDef handle;
|
||||
#if ENABLE_UART3
|
||||
static struct uart_instance uart3;
|
||||
#ifndef UART3_FLOWCONTROL
|
||||
#define UART3_FLOWCONTROL DEFAULT_FLOWCONTROL
|
||||
#endif
|
||||
#ifndef UART3_BAUDRATE
|
||||
#define UART3_BAUDRATE DEFAULT_BAUDRATE
|
||||
#endif
|
||||
#ifndef UART3_RXBUF_SIZE
|
||||
#define UART3_RXBUF_SIZE DEFAULT_RXBUF_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLE_UART2 || ENABLE_UART4 || ENABLE_UART5 || ENABLE_UART6 || ENABLE_UART7 || ENABLE_UART8
|
||||
#error add support for additional uarts
|
||||
#endif
|
||||
|
||||
static struct uart_instance * const uart[NUM_UARTS + 1] = {
|
||||
#if ENABLE_UART1
|
||||
[1] = &uart1,
|
||||
#endif
|
||||
#if ENABLE_UART3
|
||||
[3] = &uart3,
|
||||
#endif
|
||||
};
|
||||
|
||||
// This function is called by HAL_UART_Init().
|
||||
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (huart != &handle) {
|
||||
// !! harcoded only for USART1, like the rest of this file.
|
||||
ITM_SendChar('!');
|
||||
return;
|
||||
}
|
||||
|
||||
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
|
||||
|
||||
/*##-1- Enable Clocks #################################*/
|
||||
/* Select SysClk as source of UART clocks */
|
||||
switch ((uintptr_t)huart->Instance) {
|
||||
case (uintptr_t)USART1:
|
||||
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
|
||||
RCC_PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK;
|
||||
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
|
||||
|
||||
/* Select SysClk as source of USART1 clocks */
|
||||
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3;
|
||||
RCC_PeriphClkInit.Usart1ClockSelection = RCC_USART3CLKSOURCE_SYSCLK;
|
||||
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
|
||||
__HAL_RCC_USART1_CLK_ENABLE();
|
||||
break;
|
||||
case (uintptr_t)USART3:
|
||||
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3;
|
||||
RCC_PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_SYSCLK;
|
||||
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
|
||||
|
||||
/* Enable USARTx clock */
|
||||
__HAL_RCC_USART3_CLK_ENABLE();
|
||||
|
||||
/*##-2- Make sure the irq handler is disabled for now */
|
||||
/* NVIC for USARTx */
|
||||
HAL_NVIC_DisableIRQ(USART3_IRQn);
|
||||
__HAL_RCC_USART3_CLK_ENABLE();
|
||||
break;
|
||||
default:
|
||||
panic("unimplemented clock set up for uart\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void usart_init1_early(USART_TypeDef *usart, uint32_t baud, uint16_t flowcontrol, int irqn)
|
||||
static void usart_init_early(struct uart_instance *u, USART_TypeDef *usart, uint32_t baud, uint16_t flowcontrol)
|
||||
{
|
||||
handle.Instance = usart;
|
||||
handle.Init.BaudRate = baud;
|
||||
handle.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
handle.Init.StopBits = UART_STOPBITS_1;
|
||||
handle.Init.Parity = UART_PARITY_NONE;
|
||||
handle.Init.Mode = UART_MODE_TX_RX;
|
||||
handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
handle.Init.OverSampling = UART_OVERSAMPLING_8;
|
||||
HAL_UART_Init(&handle);
|
||||
u->handle.Instance = usart;
|
||||
u->handle.Init.BaudRate = baud;
|
||||
u->handle.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
u->handle.Init.StopBits = UART_STOPBITS_1;
|
||||
u->handle.Init.Parity = UART_PARITY_NONE;
|
||||
u->handle.Init.Mode = UART_MODE_TX_RX;
|
||||
u->handle.Init.HwFlowCtl = flowcontrol;
|
||||
u->handle.Init.OverSampling = UART_OVERSAMPLING_8;
|
||||
HAL_UART_Init(&u->handle);
|
||||
}
|
||||
|
||||
static void usart_init1(USART_TypeDef *usart, int irqn, cbuf_t *rxbuf, size_t rxsize)
|
||||
static void usart_init(struct uart_instance *u, USART_TypeDef *usart, uint irqn, size_t rxsize)
|
||||
{
|
||||
cbuf_initialize(rxbuf, rxsize);
|
||||
cbuf_initialize(&u->rx_buf, rxsize);
|
||||
|
||||
/* Enable the UART Parity Error Interrupt */
|
||||
__HAL_UART_ENABLE_IT(&handle, UART_IT_PE);
|
||||
__HAL_UART_ENABLE_IT(&u->handle, UART_IT_PE);
|
||||
|
||||
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
|
||||
__HAL_UART_ENABLE_IT(&handle, UART_IT_ERR);
|
||||
__HAL_UART_ENABLE_IT(&u->handle, UART_IT_ERR);
|
||||
|
||||
/* Enable the UART Data Register not empty Interrupt */
|
||||
__HAL_UART_ENABLE_IT(&handle, UART_IT_RXNE);
|
||||
__HAL_UART_ENABLE_IT(&u->handle, UART_IT_RXNE);
|
||||
|
||||
HAL_NVIC_EnableIRQ(USART3_IRQn);
|
||||
HAL_NVIC_EnableIRQ(irqn);
|
||||
}
|
||||
|
||||
void uart_init_early(void)
|
||||
{
|
||||
#if ENABLE_UART1
|
||||
usart_init_early(uart[1], USART1, UART1_BAUDRATE, UART1_FLOWCONTROL);
|
||||
#endif
|
||||
#if ENABLE_UART3
|
||||
usart_init1_early(USART3, UART3_BAUDRATE, 0, USART3_IRQn);
|
||||
usart_init_early(uart[3], USART3, UART3_BAUDRATE, UART3_FLOWCONTROL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
#ifdef ENABLE_UART1
|
||||
usart_init(uart[1], USART1, USART1_IRQn, UART1_RXBUF_SIZE);
|
||||
#endif
|
||||
#ifdef ENABLE_UART3
|
||||
usart_init1(USART3, USART3_IRQn, &uart3_rx_buf, UART3_RXBUF_SIZE);
|
||||
usart_init(uart[3], USART3, USART3_IRQn, UART3_RXBUF_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void stm32_USART3_IRQ(void)
|
||||
static void stm32_usart_shared_irq(struct uart_instance *u)
|
||||
{
|
||||
bool resched = false;
|
||||
|
||||
arm_cm_irq_entry();
|
||||
|
||||
/* UART parity error interrupt occurred -------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_PE) != RESET)) {
|
||||
__HAL_UART_CLEAR_PEFLAG(&handle);
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_PE) != RESET)) {
|
||||
__HAL_UART_CLEAR_PEFLAG(&u->handle);
|
||||
|
||||
printf("UART PARITY ERROR\n");
|
||||
}
|
||||
|
||||
/* UART frame error interrupt occurred --------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_FEFLAG(&handle);
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_FEFLAG(&u->handle);
|
||||
|
||||
printf("UART FRAME ERROR\n");
|
||||
}
|
||||
|
||||
/* UART noise error interrupt occurred --------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_NEFLAG(&handle);
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_NEFLAG(&u->handle);
|
||||
|
||||
printf("UART NOISE ERROR\n");
|
||||
}
|
||||
|
||||
/* UART Over-Run interrupt occurred -----------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_OREFLAG(&handle);
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_ERR) != RESET)) {
|
||||
__HAL_UART_CLEAR_OREFLAG(&u->handle);
|
||||
|
||||
printf("UART OVERRUN ERROR\n");
|
||||
}
|
||||
|
||||
/* UART in mode Receiver ---------------------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_RXNE) != RESET)) {
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_RXNE) != RESET)) {
|
||||
|
||||
/* we got a character */
|
||||
uint8_t c = (uint8_t)(handle.Instance->RDR & 0xff);
|
||||
if (cbuf_write_char(&uart3_rx_buf, c, false) != 1) {
|
||||
uint8_t c = (uint8_t)(u->handle.Instance->RDR & 0xff);
|
||||
if (cbuf_write_char(&u->rx_buf, c, false) != 1) {
|
||||
printf("WARNING: uart cbuf overrun!\n");
|
||||
}
|
||||
resched = true;
|
||||
|
||||
/* Clear RXNE interrupt flag */
|
||||
__HAL_UART_SEND_REQ(&handle, UART_RXDATA_FLUSH_REQUEST);
|
||||
__HAL_UART_SEND_REQ(&u->handle, UART_RXDATA_FLUSH_REQUEST);
|
||||
}
|
||||
|
||||
/* UART in mode Transmitter ------------------------------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_TXE) != RESET)) {
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_TXE) != RESET)) {
|
||||
;
|
||||
}
|
||||
|
||||
/* UART in mode Transmitter (transmission end) -----------------------------*/
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_TC) != RESET)) {
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_TC) != RESET)) {
|
||||
;
|
||||
}
|
||||
|
||||
arm_cm_irq_exit(resched);
|
||||
}
|
||||
|
||||
#if ENABLE_UART1
|
||||
void stm32_USART1_IRQ(void)
|
||||
{
|
||||
stm32_usart_shared_irq(uart[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_UART3
|
||||
void stm32_USART3_IRQ(void)
|
||||
{
|
||||
stm32_usart_shared_irq(uart[3]);
|
||||
}
|
||||
#endif
|
||||
|
||||
int uart_putc(int port, char c)
|
||||
{
|
||||
while (__HAL_UART_GET_FLAG(&handle, UART_FLAG_TXE) == RESET)
|
||||
struct uart_instance *u = uart[port];
|
||||
if (port < 0 || port > NUM_UARTS || !u)
|
||||
return ERR_BAD_HANDLE;
|
||||
|
||||
while (__HAL_UART_GET_FLAG(&u->handle, UART_FLAG_TXE) == RESET)
|
||||
;
|
||||
handle.Instance->TDR = (c & (uint8_t)0xFF);
|
||||
u->handle.Instance->TDR = (c & (uint8_t)0xFF);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uart_getc(int port, bool wait)
|
||||
{
|
||||
struct uart_instance *u = uart[port];
|
||||
if (port < 0 || port > NUM_UARTS || !u)
|
||||
return ERR_BAD_HANDLE;
|
||||
|
||||
char c;
|
||||
if (cbuf_read_char(&uart3_rx_buf, &c, wait) == 0)
|
||||
return -1;
|
||||
if (cbuf_read_char(&u->rx_buf, &c, wait) == 0)
|
||||
return ERR_IO;
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -204,11 +268,15 @@ int uart_pputc(int port, char c)
|
||||
|
||||
int uart_pgetc(int port)
|
||||
{
|
||||
if ((__HAL_UART_GET_IT(&handle, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&handle, UART_IT_RXNE) != RESET)) {
|
||||
uint8_t c = (uint8_t)(handle.Instance->RDR & 0xff);
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
struct uart_instance *u = uart[port];
|
||||
if (port < 0 || port > NUM_UARTS || !u)
|
||||
return ERR_BAD_HANDLE;
|
||||
|
||||
if ((__HAL_UART_GET_IT(&u->handle, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(&u->handle, UART_IT_RXNE) != RESET)) {
|
||||
uint8_t c = (uint8_t)(u->handle.Instance->RDR & 0xff);
|
||||
return c;
|
||||
}
|
||||
return ERR_IO;
|
||||
}
|
||||
|
||||
void uart_flush_tx(int port) {}
|
||||
|
||||
Reference in New Issue
Block a user