338 lines
8.5 KiB
C
338 lines
8.5 KiB
C
|
|
#include "uart_driver.h"
|
||
|
|
#include "py32md530.h"
|
||
|
|
#include "system_py32md530.h"
|
||
|
|
#include "system_driver.h"
|
||
|
|
#include "config.h"
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#define UART_FIFO_SIZE 256
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
uint8_t buffer[UART_FIFO_SIZE];
|
||
|
|
volatile uint32_t head;
|
||
|
|
volatile uint32_t tail;
|
||
|
|
uint8_t initialized;
|
||
|
|
} uart_fifo_t;
|
||
|
|
|
||
|
|
static uart_fifo_t uart_fifos[UART_ID_COUNT];
|
||
|
|
static uart_stats_t uart_statistics[UART_ID_COUNT];
|
||
|
|
|
||
|
|
static void uart_fifo_init(uart_fifo_t *fifo)
|
||
|
|
{
|
||
|
|
fifo->head = 0;
|
||
|
|
fifo->tail = 0;
|
||
|
|
fifo->initialized = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void uart_stats_init(void)
|
||
|
|
{
|
||
|
|
uint32_t i;
|
||
|
|
for (i = 0; i < UART_ID_COUNT; i++) {
|
||
|
|
uart_statistics[i].tx_bytes = 0;
|
||
|
|
uart_statistics[i].rx_bytes = 0;
|
||
|
|
uart_statistics[i].overflow_errors = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void uart_fifo_push(uart_fifo_t *fifo, uint8_t data)
|
||
|
|
{
|
||
|
|
uint32_t next = (fifo->head + 1) % UART_FIFO_SIZE;
|
||
|
|
if (next != fifo->tail) {
|
||
|
|
fifo->buffer[fifo->head] = data;
|
||
|
|
fifo->head = next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t uart_fifo_pop(uart_fifo_t *fifo, uint8_t *data)
|
||
|
|
{
|
||
|
|
if (fifo->tail == fifo->head) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
*data = fifo->buffer[fifo->tail];
|
||
|
|
fifo->tail = (fifo->tail + 1) % UART_FIFO_SIZE;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t uart_fifo_count(uart_fifo_t *fifo)
|
||
|
|
{
|
||
|
|
return (fifo->head - fifo->tail) % UART_FIFO_SIZE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void USART1_IRQHandler(void)
|
||
|
|
{
|
||
|
|
if (USART1->SR & USART_SR_RXNE_Msk) {
|
||
|
|
uint8_t data = (uint8_t)(USART1->DR & 0xFF);
|
||
|
|
uart_statistics[UART_ID_USART1].rx_bytes++;
|
||
|
|
{
|
||
|
|
uint32_t next = (uart_fifos[UART_ID_USART1].head + 1) % UART_FIFO_SIZE;
|
||
|
|
if (next == uart_fifos[UART_ID_USART1].tail) {
|
||
|
|
uart_statistics[UART_ID_USART1].overflow_errors++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
uart_fifo_push(&uart_fifos[UART_ID_USART1], data);
|
||
|
|
}
|
||
|
|
if (USART1->SR & USART_SR_TC_Msk) {
|
||
|
|
USART1->SR &= ~USART_SR_TC_Msk;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void UART1_IRQHandler(void)
|
||
|
|
{
|
||
|
|
if (UART1->SR & USART_SR_RXNE_Msk) {
|
||
|
|
uint8_t data = (uint8_t)(UART1->DR & 0xFF);
|
||
|
|
uart_statistics[UART_ID_UART1].rx_bytes++;
|
||
|
|
{
|
||
|
|
uint32_t next = (uart_fifos[UART_ID_UART1].head + 1) % UART_FIFO_SIZE;
|
||
|
|
if (next == uart_fifos[UART_ID_UART1].tail) {
|
||
|
|
uart_statistics[UART_ID_UART1].overflow_errors++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
uart_fifo_push(&uart_fifos[UART_ID_UART1], data);
|
||
|
|
}
|
||
|
|
if (UART1->SR & USART_SR_TC_Msk) {
|
||
|
|
UART1->SR &= ~USART_SR_TC_Msk;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void LPUART1_IRQHandler(void)
|
||
|
|
{
|
||
|
|
if (LPUART1->ISR & (1UL << 5)) {
|
||
|
|
uint8_t data = (uint8_t)(LPUART1->DR & 0xFF);
|
||
|
|
uart_statistics[UART_ID_LPUART1].rx_bytes++;
|
||
|
|
{
|
||
|
|
uint32_t next = (uart_fifos[UART_ID_LPUART1].head + 1) % UART_FIFO_SIZE;
|
||
|
|
if (next == uart_fifos[UART_ID_LPUART1].tail) {
|
||
|
|
uart_statistics[UART_ID_LPUART1].overflow_errors++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
uart_fifo_push(&uart_fifos[UART_ID_LPUART1], data);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static ret_code_t usart1_init(const uart_config_t *config)
|
||
|
|
{
|
||
|
|
uint32_t brr;
|
||
|
|
|
||
|
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||
|
|
|
||
|
|
USART1->CR1 &= ~USART_CR1_UE_Msk;
|
||
|
|
|
||
|
|
brr = (SystemCoreClock + config->baudrate / 2) / config->baudrate;
|
||
|
|
USART1->BRR = brr;
|
||
|
|
|
||
|
|
USART1->CR1 = USART_CR1_UE_Msk
|
||
|
|
| USART_CR1_TE_Msk
|
||
|
|
| USART_CR1_RE_Msk
|
||
|
|
| USART_CR1_RXNEIE_Msk;
|
||
|
|
|
||
|
|
USART1->CR3 = USART_CR3_DMAR_Msk
|
||
|
|
| USART_CR3_DMAT_Msk;
|
||
|
|
|
||
|
|
NVIC_SetPriority(USART1_IRQn, 0x08);
|
||
|
|
NVIC_EnableIRQ(USART1_IRQn);
|
||
|
|
|
||
|
|
uart_stats_init();
|
||
|
|
uart_fifo_init(&uart_fifos[UART_ID_USART1]);
|
||
|
|
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ret_code_t uart1_init(const uart_config_t *config)
|
||
|
|
{
|
||
|
|
uint32_t brr;
|
||
|
|
|
||
|
|
RCC->APB1ENR |= RCC_APB1ENR_UART1EN;
|
||
|
|
|
||
|
|
UART1->CR1 &= ~USART_CR1_UE_Msk;
|
||
|
|
|
||
|
|
brr = (SystemCoreClock + config->baudrate / 2) / config->baudrate;
|
||
|
|
UART1->BRR = brr;
|
||
|
|
|
||
|
|
UART1->CR1 = USART_CR1_UE_Msk
|
||
|
|
| USART_CR1_TE_Msk
|
||
|
|
| USART_CR1_RE_Msk
|
||
|
|
| USART_CR1_RXNEIE_Msk;
|
||
|
|
|
||
|
|
UART1->CR3 = USART_CR3_DMAR_Msk
|
||
|
|
| USART_CR3_DMAT_Msk;
|
||
|
|
|
||
|
|
NVIC_SetPriority(UART1_IRQn, 0x08);
|
||
|
|
NVIC_EnableIRQ(UART1_IRQn);
|
||
|
|
|
||
|
|
uart_fifo_init(&uart_fifos[UART_ID_UART1]);
|
||
|
|
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
static ret_code_t lpuart1_init(const uart_config_t *config)
|
||
|
|
{
|
||
|
|
RCC->APB1ENR |= RCC_APB1ENR_LPUART1EN;
|
||
|
|
|
||
|
|
LPUART1->CR1 &= ~(1UL << 0);
|
||
|
|
|
||
|
|
LPUART1->BRR = (256 * SystemCoreClock + config->baudrate / 2) / config->baudrate;
|
||
|
|
|
||
|
|
LPUART1->CR1 = (1UL << 0)
|
||
|
|
| (1UL << 2)
|
||
|
|
| (1UL << 3)
|
||
|
|
| (1UL << 5);
|
||
|
|
|
||
|
|
NVIC_SetPriority(LPUART1_IRQn, 0x08);
|
||
|
|
NVIC_EnableIRQ(LPUART1_IRQn);
|
||
|
|
|
||
|
|
uart_fifo_init(&uart_fifos[UART_ID_LPUART1]);
|
||
|
|
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_init(uart_id_t id, const uart_config_t *config)
|
||
|
|
{
|
||
|
|
if (id >= UART_ID_COUNT || config == NULL) {
|
||
|
|
return RET_INVALID_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (id) {
|
||
|
|
case UART_ID_USART1:
|
||
|
|
return usart1_init(config);
|
||
|
|
case UART_ID_UART1:
|
||
|
|
return uart1_init(config);
|
||
|
|
case UART_ID_LPUART1:
|
||
|
|
return lpuart1_init(config);
|
||
|
|
default:
|
||
|
|
return RET_ERROR;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_deinit(uart_id_t id)
|
||
|
|
{
|
||
|
|
switch (id) {
|
||
|
|
case UART_ID_USART1:
|
||
|
|
NVIC_DisableIRQ(USART1_IRQn);
|
||
|
|
USART1->CR1 = 0;
|
||
|
|
RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;
|
||
|
|
break;
|
||
|
|
case UART_ID_UART1:
|
||
|
|
NVIC_DisableIRQ(UART1_IRQn);
|
||
|
|
UART1->CR1 = 0;
|
||
|
|
RCC->APB1ENR &= ~RCC_APB1ENR_UART1EN;
|
||
|
|
break;
|
||
|
|
case UART_ID_LPUART1:
|
||
|
|
NVIC_DisableIRQ(LPUART1_IRQn);
|
||
|
|
LPUART1->CR1 = 0;
|
||
|
|
RCC->APB1ENR &= ~RCC_APB1ENR_LPUART1EN;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return RET_INVALID_PARAM;
|
||
|
|
}
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_send(uart_id_t id, const uint8_t *data, uint32_t len)
|
||
|
|
{
|
||
|
|
uint32_t i;
|
||
|
|
|
||
|
|
if (id == UART_ID_USART1) {
|
||
|
|
uart_set_rs485_dir(UART_ID_USART1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < len; i++) {
|
||
|
|
switch (id) {
|
||
|
|
case UART_ID_USART1:
|
||
|
|
while (!(USART1->SR & USART_SR_TXE_Msk));
|
||
|
|
USART1->DR = data[i];
|
||
|
|
while (!(USART1->SR & USART_SR_TC_Msk));
|
||
|
|
uart_statistics[UART_ID_USART1].tx_bytes++;
|
||
|
|
break;
|
||
|
|
case UART_ID_UART1:
|
||
|
|
while (!(UART1->SR & USART_SR_TXE_Msk));
|
||
|
|
UART1->DR = data[i];
|
||
|
|
while (!(UART1->SR & USART_SR_TC_Msk));
|
||
|
|
uart_statistics[UART_ID_UART1].tx_bytes++;
|
||
|
|
break;
|
||
|
|
case UART_ID_LPUART1:
|
||
|
|
while (!(LPUART1->ISR & (1UL << 0)));
|
||
|
|
LPUART1->DR = data[i];
|
||
|
|
uart_statistics[UART_ID_LPUART1].tx_bytes++;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return RET_INVALID_PARAM;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (id == UART_ID_USART1) {
|
||
|
|
volatile uint32_t delay = (SystemCoreClock / 1000000) * 2;
|
||
|
|
while (delay--);
|
||
|
|
uart_set_rs485_dir(UART_ID_USART1, 0);
|
||
|
|
}
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_receive(uart_id_t id, uint8_t *data, uint32_t len, uint32_t timeout)
|
||
|
|
{
|
||
|
|
uint32_t i;
|
||
|
|
uint32_t tick_start = 0;
|
||
|
|
|
||
|
|
if (timeout > 0) {
|
||
|
|
tick_start = system_get_tick();
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < len; i++) {
|
||
|
|
while (uart_fifo_count(&uart_fifos[id]) == 0) {
|
||
|
|
if (timeout > 0) {
|
||
|
|
if ((system_get_tick() - tick_start) >= timeout) {
|
||
|
|
return RET_TIMEOUT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
uart_fifo_pop(&uart_fifos[id], &data[i]);
|
||
|
|
}
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_send_dma(uart_id_t id, const uint8_t *data, uint32_t len)
|
||
|
|
{
|
||
|
|
return uart_send(id, data, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_receive_dma(uart_id_t id, uint8_t *data, uint32_t len)
|
||
|
|
{
|
||
|
|
return uart_receive(id, data, len, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t uart_available(uart_id_t id)
|
||
|
|
{
|
||
|
|
return uart_fifo_count(&uart_fifos[id]);
|
||
|
|
}
|
||
|
|
|
||
|
|
ret_code_t uart_set_rs485_dir(uart_id_t id, uint8_t tx_mode)
|
||
|
|
{
|
||
|
|
if (id != UART_ID_USART1) {
|
||
|
|
return RET_NOT_SUPPORTED;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (tx_mode) {
|
||
|
|
USART1_RS485_DIR_PORT->BSRR = (1UL << USART1_RS485_DIR_PIN);
|
||
|
|
} else {
|
||
|
|
USART1_RS485_DIR_PORT->BRR = (1UL << USART1_RS485_DIR_PIN);
|
||
|
|
}
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
const uart_stats_t* uart_get_stats(uart_id_t id)
|
||
|
|
{
|
||
|
|
if (id >= UART_ID_COUNT) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
return &uart_statistics[id];
|
||
|
|
}
|
||
|
|
|
||
|
|
void uart_reset_stats(uart_id_t id)
|
||
|
|
{
|
||
|
|
if (id >= UART_ID_COUNT) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
uart_statistics[id].tx_bytes = 0;
|
||
|
|
uart_statistics[id].rx_bytes = 0;
|
||
|
|
uart_statistics[id].overflow_errors = 0;
|
||
|
|
}
|