165 lines
3.9 KiB
C
165 lines
3.9 KiB
C
#include "includes.h"
|
||
#include "usart.h"
|
||
|
||
#define BUFF_SIZE 512
|
||
|
||
/* 纯比较宏:参数必须是普通局部变量(非 volatile),
|
||
避免同一表达式多次访问 volatile 触发 Pa082 且逻辑不稳 */
|
||
#define IS_FULL(head, tail) ((((head) + 1) % BUFF_SIZE) == (tail))
|
||
#define IS_EMPTY(head, tail) ((head) == (tail))
|
||
|
||
/* ==================== 环形队列结构体 ==================== */
|
||
|
||
/* 一个串口实例的环形队列(收发各一) */
|
||
typedef struct
|
||
{
|
||
uint8_t rx_buff[BUFF_SIZE];
|
||
volatile uint16_t rx_head;
|
||
volatile uint16_t rx_tail;
|
||
|
||
uint8_t tx_buff[BUFF_SIZE];
|
||
volatile uint16_t tx_head;
|
||
volatile uint16_t tx_tail;
|
||
|
||
usart_type *usart; /* 关联的串口外设(USART2 / UART4) */
|
||
} uart_ring_t;
|
||
|
||
/* USART2 和 UART4 各一个实例 */
|
||
static uart_ring_t uart2;
|
||
static uart_ring_t uart4;
|
||
|
||
/* 初始化:关联串口外设(由 wk_usart2_init / wk_uart4_init 调用) */
|
||
void uart_ring_usart2_init(void)
|
||
{
|
||
uart2.usart = USART2;
|
||
}
|
||
|
||
void uart_ring_uart4_init(void)
|
||
{
|
||
uart4.usart = UART4;
|
||
}
|
||
|
||
/* ==================== 通用入队/出队(带实例参数) ==================== */
|
||
|
||
/* 入队(ISR 调用)。先快照 volatile 值再操作,避免 Pa082 */
|
||
static void ring_rx_push(uart_ring_t *rb, uint8_t c)
|
||
{
|
||
uint16_t h = rb->rx_head;
|
||
uint16_t t = rb->rx_tail;
|
||
if(IS_FULL(h, t)) return; /* 满则丢,防止覆盖未读数据 */
|
||
rb->rx_buff[h] = c;
|
||
rb->rx_head = (h + 1) % BUFF_SIZE;
|
||
}
|
||
|
||
/* 出队(业务线程调用) */
|
||
static uint8_t ring_rx_pop(uart_ring_t *rb, uint8_t *c)
|
||
{
|
||
uint16_t h = rb->rx_head;
|
||
uint16_t t = rb->rx_tail;
|
||
if(IS_EMPTY(h, t)) return 0;
|
||
*c = rb->rx_buff[t];
|
||
rb->rx_tail = (t + 1) % BUFF_SIZE;
|
||
return 1;
|
||
}
|
||
|
||
/* 写入 tx 队列(调用前应已关中断,防止 ISR 同时读) */
|
||
static void ring_tx_write(uart_ring_t *rb, uint8_t *data, uint16_t len)
|
||
{
|
||
uint16_t h = rb->tx_head;
|
||
uint16_t t = rb->tx_tail;
|
||
for(uint16_t i = 0; i < len; i++)
|
||
{
|
||
if(IS_FULL(h, t)) break; /* 用 tx 判满 */
|
||
rb->tx_buff[h] = data[i];
|
||
h = (h + 1) % BUFF_SIZE;
|
||
}
|
||
rb->tx_head = h; /* 最后一次性写回 volatile */
|
||
}
|
||
|
||
/* ==================== 发送接口(带串口参数) ==================== */
|
||
|
||
/* 通用发送:关中断 → 写队列 → 开 TDBE 中断触发发送 */
|
||
static void uart_ring_send(uart_ring_t *rb, uint8_t *data, uint16_t len)
|
||
{
|
||
rt_base_t level = rt_hw_interrupt_disable();
|
||
|
||
ring_tx_write(rb, data, len);
|
||
usart_interrupt_enable(rb->usart, USART_TDBE_INT, TRUE); /* 开发送中断 */
|
||
|
||
rt_hw_interrupt_enable(level);
|
||
}
|
||
|
||
/* USART2 发送(对外,midi_send.c 等在用) */
|
||
void USART2_SendData(uint8_t *data, uint16_t len)
|
||
{
|
||
uart_ring_send(&uart2, data, len);
|
||
}
|
||
|
||
/* UART4 发送(对外) */
|
||
void USART4_SendData(uint8_t *data, uint16_t len)
|
||
{
|
||
uart_ring_send(&uart4, data, len);
|
||
}
|
||
|
||
/* USART2 接收出队(对外) */
|
||
uint8_t USART2_RxPop(uint8_t *c)
|
||
{
|
||
return ring_rx_pop(&uart2, c);
|
||
}
|
||
|
||
/* UART4 接收出队(对外) */
|
||
uint8_t UART4_RxPop(uint8_t *c)
|
||
{
|
||
return ring_rx_pop(&uart4, c);
|
||
}
|
||
|
||
/* ==================== 串口中断 ==================== */
|
||
|
||
static void uart_ring_isr(uart_ring_t *rb)
|
||
{
|
||
/* 接收:收到字节 → 入 rx 队列 */
|
||
if(usart_flag_get(rb->usart, USART_RDBF_FLAG) == SET)
|
||
{
|
||
uint8_t data = usart_data_receive(rb->usart); /* 读数据(自动清 RDBF) */
|
||
ring_rx_push(rb, data);
|
||
if(rb->usart == UART4)
|
||
{
|
||
rt_sem_release(UART4_sem);
|
||
}
|
||
}
|
||
|
||
/* 发送:tx 队列有数据 → 发一个字节;发完 → 关 TDBE 中断 */
|
||
if(usart_flag_get(rb->usart, USART_TDBE_FLAG) == SET)
|
||
{
|
||
uint16_t h = rb->tx_head;
|
||
uint16_t t = rb->tx_tail;
|
||
if(!IS_EMPTY(h, t))
|
||
{
|
||
usart_data_transmit(rb->usart, rb->tx_buff[t]);
|
||
rb->tx_tail = (t + 1) % BUFF_SIZE;
|
||
}
|
||
else
|
||
{
|
||
usart_interrupt_enable(rb->usart, USART_TDBE_INT, FALSE); /* 发完关中断 */
|
||
}
|
||
}
|
||
|
||
/* 错误处理:清溢出标志,防止反复进中断卡死 */
|
||
if(usart_flag_get(rb->usart, USART_ROERR_FLAG) == SET)
|
||
usart_flag_clear(rb->usart, USART_ROERR_FLAG);
|
||
}
|
||
|
||
void USART2_IRQHandler(void)
|
||
{
|
||
rt_interrupt_enter();
|
||
uart_ring_isr(&uart2);
|
||
rt_interrupt_leave();
|
||
}
|
||
|
||
void UART4_IRQHandler(void)
|
||
{
|
||
rt_interrupt_enter();
|
||
uart_ring_isr(&uart4);
|
||
rt_interrupt_leave();
|
||
}
|