From 1e50a94427f9d4edcfc2b0c91206244a6cdf7219 Mon Sep 17 00:00:00 2001 From: yelvlab Date: Tue, 24 Feb 2026 14:22:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B2=E5=8F=A3=E7=8E=AF=E5=BD=A2=E7=BC=93?= =?UTF-8?q?=E5=86=B2=E5=8C=BA=E5=BC=BA=E5=8C=96=EF=BC=9A=E5=8D=95=E7=8B=AC?= =?UTF-8?q?=E5=8D=95=E5=86=99=E5=8F=8A=E6=9C=80=E5=B0=8F=E4=B8=B4=E7=95=8C?= =?UTF-8?q?=E5=8C=BA=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Inc/uart.h | 16 ++++++++++++++++ Inc/uart_ring_buffer.h | 6 ++++++ Src/command.c | 5 +++++ Src/uart.c | 8 ++++++++ Src/uart_ring_buffer.c | 17 +++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/Inc/uart.h b/Inc/uart.h index e212ef9..c4631b7 100644 --- a/Inc/uart.h +++ b/Inc/uart.h @@ -12,4 +12,20 @@ void uart_init(void); void debug_usart_init(void); +/*! + \brief pause UART RX interrupt (RBNE) + \param[in] none + \param[out] none + \retval none +*/ +void uart_rx_irq_pause(void); + +/*! + \brief resume UART RX interrupt (RBNE) + \param[in] none + \param[out] none + \retval none +*/ +void uart_rx_irq_resume(void); + #endif // UART_H diff --git a/Inc/uart_ring_buffer.h b/Inc/uart_ring_buffer.h index effeb35..c511004 100644 --- a/Inc/uart_ring_buffer.h +++ b/Inc/uart_ring_buffer.h @@ -27,6 +27,12 @@ * @section RingBuffer_Usage 使用说明 * 典型用法:中断接收(写入环形缓冲)、主循环解析(读取环形缓冲)。 * + * 并发访问约束(SPSC,无锁单写单读): + * - ISR 生产者:仅调用 uart_ring_buffer_put() 写入数据。 + * - 主循环消费者:仅调用 uart_ring_buffer_get()/uart_ring_buffer_available() 读取数据。 + * - uart_ring_buffer_init()/uart_ring_buffer_clear() 会同时修改读写索引,内部使用最小临界区保护。 + * - 建议在主循环调用 clear/init 前先暂停 UART RX 中断,完成后再恢复,避免与 ISR 竞争。 + * * 1) 初始化 * @code{.c} * uart_ring_buffer_init(); diff --git a/Src/command.c b/Src/command.c index 698b3b4..1e7c72c 100644 --- a/Src/command.c +++ b/Src/command.c @@ -11,6 +11,7 @@ #include "command.h" #include "uart_ring_buffer.h" +#include "uart.h" #include "led.h" #include #include @@ -588,7 +589,9 @@ void command_process(void) { handle_command(cmd_buf, expected_cmd_len); } else { // 验证失败时清空缓冲区,避免后续帧受影响 + uart_rx_irq_pause(); uart_ring_buffer_clear(); + uart_rx_irq_resume(); } // 复位,等待下一帧 @@ -633,7 +636,9 @@ void command_execute(const char *cmd_str) frame_buf[frame_len - 1] = (uint8_t)(crc & 0xFF); // 清空缓冲区并执行命令 + uart_rx_irq_pause(); uart_ring_buffer_clear(); + uart_rx_irq_resume(); for (uint8_t i = 0; i < frame_len; i++) { uart_ring_buffer_put(frame_buf[i]); } diff --git a/Src/uart.c b/Src/uart.c index b31498e..347f0a8 100644 --- a/Src/uart.c +++ b/Src/uart.c @@ -32,6 +32,14 @@ void uart_init(void) { usart_interrupt_enable(UART_PHY, USART_INT_RBNE); } +void uart_rx_irq_pause(void) { + usart_interrupt_disable(UART_PHY, USART_INT_RBNE); +} + +void uart_rx_irq_resume(void) { + usart_interrupt_enable(UART_PHY, USART_INT_RBNE); +} + /******************************************************************************/ /* 具体的中断处理函数实现 */ /******************************************************************************/ diff --git a/Src/uart_ring_buffer.c b/Src/uart_ring_buffer.c index 73554f0..d8c915f 100644 --- a/Src/uart_ring_buffer.c +++ b/Src/uart_ring_buffer.c @@ -6,12 +6,25 @@ * @ingroup RingBuffer */ #include "uart_ring_buffer.h" +#include "gd32e23x.h" static volatile uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE]; static volatile uint8_t write_index = 0; static volatile uint8_t read_index = 0; static volatile uint32_t dropped_bytes = 0; +static inline uint32_t irq_save(void) { + uint32_t primask = __get_PRIMASK(); + __disable_irq(); + return primask; +} + +static inline void irq_restore(uint32_t primask) { + if (primask == 0U) { + __enable_irq(); + } +} + /** * @brief 重置环形缓冲区状态。 * @details 将读指针、写指针与丢弃计数清零,不清空数据区内容。 @@ -31,7 +44,9 @@ static void uart_ring_buffer_reset_state(void) { * @ingroup RingBuffer */ void uart_ring_buffer_init(void) { + uint32_t irq_key = irq_save(); uart_ring_buffer_reset_state(); + irq_restore(irq_key); } /** @@ -90,7 +105,9 @@ bool uart_ring_buffer_put(uint8_t data) { * @ingroup RingBuffer */ void uart_ring_buffer_clear(void) { + uint32_t irq_key = irq_save(); uart_ring_buffer_reset_state(); + irq_restore(irq_key); } /**