Initial commit

This commit is contained in:
2026-10-09 18:45:50 +08:00
commit 8feba5e015
213 changed files with 1046832 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
/*!
\file gd32f4xx_it.c
\brief interrupt service routines
\version 2025-02-10, V2.4.0, demo for GD32F4xx
*/
/*
Copyright (c) 2025, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "gd32f4xx_it.h"
#include "systick.h"
#include "uart.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include "board_config.h"
/*!
\brief this function handles NMI exception
\param[in] none
\param[out] none
\retval none
*/
void NMI_Handler(void)
{
/* if NMI exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles HardFault exception
\param[in] none
\param[out] none
\retval none
*/
void HardFault_Handler(void)
{
/* if Hard Fault exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles MemManage exception
\param[in] none
\param[out] none
\retval none
*/
void MemManage_Handler(void)
{
/* if Memory Manage exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles BusFault exception
\param[in] none
\param[out] none
\retval none
*/
void BusFault_Handler(void)
{
/* if Bus Fault exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles UsageFault exception
\param[in] none
\param[out] none
\retval none
*/
void UsageFault_Handler(void)
{
/* if Usage Fault exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SVC exception
\param[in] none
\param[out] none
\retval none
*/
void SVC_Handler(void)
{
/* if SVC exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles PendSV exception
\param[in] none
\param[out] none
\retval none
*/
void PendSV_Handler(void)
{
/* if PendSV exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void) {
led_heart_beat(); // LED心跳指示灯
delay_decrement();
}
/* 调试串口静态绑定 USART1(PA2/PA3),直接调用其处理函数。
若业务改用其它串口,同步修改 board_config.h 的 UART_* 并在此补对应 IRQHandler。 */
void USART0_IRQHandler(void) {
usart0_irq_handler();
}
void USART1_IRQHandler(void) {
usart1_irq_handler();
}
void USART2_IRQHandler(void) {
usart2_irq_handler();
}
+57
View File
@@ -0,0 +1,57 @@
#include "led.h"
/**
* @brief LED心跳指示灯功能
* @details 实现类似心跳的LED闪烁模式:快闪两次然后暂停
* 适合在SysTick中断中调用,通过计数器控制闪烁节拍
* @note 假设SysTick中断频率为1ms,心跳周期约为2秒
* 心跳模式:亮200ms->灭200ms->亮200ms->灭1400ms(循环)
*/
void led_heart_beat(void)
{
static uint16_t heart_beat_counter = 0;
// 心跳周期:2000ms (假设SysTick为1ms中断)
// 模式:亮200ms -> 灭200ms -> 亮200ms -> 灭1400ms
heart_beat_counter++;
if (heart_beat_counter <= 200) {
// 第一次亮:0-200ms
led_on();
}
else if (heart_beat_counter <= 400) {
// 第一次灭:200-400ms
led_off();
}
else if (heart_beat_counter <= 600) {
// 第二次亮:400-600ms
led_on();
}
else if (heart_beat_counter <= 2000) {
// 长时间灭:600-2000ms
led_off();
}
else {
// 重置计数器,开始新的心跳周期
heart_beat_counter = 0;
}
}
void led_init(void) {
rcu_periph_clock_enable(LED_RCU);
gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PIN);
gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED_PIN);
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_on(void) {
gpio_bit_reset(LED_PORT, LED_PIN);
}
void led_off(void) {
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_toggle(void) {
gpio_bit_toggle(LED_PORT, LED_PIN);
}
+82
View File
@@ -0,0 +1,82 @@
/*!
\file main.c
\brief GD32F4xx 工程模板入口(LED 心跳 + 串口收发框架)
基于 GD32E23x 工程模板移植,目标芯片 GD32F405RET6(Cortex-M4 @168MHz,512KB Flash)。
*/
/*
Copyright (c) 2025, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "gd32f4xx.h"
#include "systick.h"
#include "uart.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include <stdio.h>
#include "board_config.h"
/* TODO: 以下模块尚未从 GD32E23x 工程移植,编译验证通过后逐步补充:
* - i2c.c/i2c.h I2C 主机读写驱动(硬件 I2C0 + 总线恢复)
* - command.c/h 串口命令协议解析(D5 帧格式)
* 移植时将对应文件加入 CMakeLists.txt 的 TARGET_SRC 即可。
*/
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
led_init();
systick_config();
uart_ring_buffer_init();
uart_init();
#if DEBUG_MODE == CFG_ENABLE
printf("Hello World!\r\n");
printf("GD32F405 template, flash size: %u KB\r\n", GD32_FLASH_SIZE_KB);
#endif
#if SEGGER_RTT_DETECTION == CFG_ENABLE
RTT_printf(0, "Hello World!\r\n");
#endif
printf("Hello World!\r\n");
/* ========== Command Testing ========== */
/* ========== */
while(1){
/* TODO: command_process(); 命令模块移植后启用 */
delay_ms(10);
}
}
+171
View File
@@ -0,0 +1,171 @@
/* Support files for GNU libc. Files in the system namespace go here.
Files in the C namespace (ie those that do not start with an
underscore) go in .c. */
#include <_ansi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h>
#include <reent.h>
#include <unistd.h>
#include <sys/wait.h>
#include "gd32f4xx_usart.h"
#include "board_config.h"
#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
caddr_t _sbrk(int incr)
{
extern char _end[];
static char *curbrk = _end;
if ((curbrk + incr < _end))
return NULL - 1;
curbrk += incr;
return curbrk - incr;
}
/*
* _gettimeofday primitive (Stub function)
* */
int _gettimeofday (struct timeval * tp, struct timezone * tzp)
{
/* Return fixed data for the timezone. */
if (tzp)
{
tzp->tz_minuteswest = 0;
tzp->tz_dsttime = 0;
}
return 0;
}
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {}
}
int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar( *ptr++ );
}
return len;
}
int _close(int file)
{
return -1;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _read(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}
// UART printf重定向实现
int __io_putchar(int ch) {
// 等待发送缓冲区空
while (usart_flag_get(DEBUG_UART, USART_FLAG_TBE) == RESET) {}
usart_data_transmit(DEBUG_UART, (uint8_t)ch);
return ch;
}
File diff suppressed because it is too large Load Diff
+83
View File
@@ -0,0 +1,83 @@
/**
* ************************************************************************
*
* @file systick.c
* @author GD32
* @brief 通过 SysTick 定时器进行微秒级别和毫秒级别的延时函数
*
* ************************************************************************
* @copyright Copyright (c) 2024 GD32
* ************************************************************************
*/
#include "gd32f4xx.h"
#include "systick.h"
static __IO uint32_t delay_count = 0;
/**
* ************************************************************************
* @brief 配置 SysTick 定时器
*
*
* ************************************************************************
*/
void systick_config(void)
{
//设置了 SysTick 定时器的时钟源为 HCLK
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);
// 配置SysTick为1ms周期中断
// 注意:SysTick_Config会自动设置时钟源为HCLK,所以需要使用SystemCoreClock/1000
SysTick_Config(SystemCoreClock / 1000U); // 1ms中断
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/**
* ************************************************************************
* @brief delay_10us 10微秒延时函数
*
* @param[in] count 10微秒值
* @note 基于循环的粗略延时(Cortex-M4 @168MHz 约 3 个周期/次迭代),
* 实际延时需上板实测校准分母系数
*
* ************************************************************************
*/
void delay_10us(uint32_t count)
{
// 168MHz 下每 10us 约 560 次迭代 → 分母取 300000
uint32_t loops_per_10us = SystemCoreClock / 300000;
for(uint32_t i = 0; i < count; i++) {
for(__IO uint32_t j = 0; j < loops_per_10us; j++);
}
}
/**
* ************************************************************************
* @brief delay_ms 毫秒延时函数
*
* @param[in] count 毫秒值
*
* ************************************************************************
*/
void delay_ms(uint32_t count)
{
delay_count = count; // 设置延时计数
while (delay_count != 0U);
}
/**
* ************************************************************************
* @brief 每个 SysTick 中断调用时,减少延时计数
*
* @param[in] void
*
* ************************************************************************
*/
void delay_decrement(void)
{
if (delay_count != 0U)
{
delay_count--;
}
}
+131
View File
@@ -0,0 +1,131 @@
#include "uart.h"
#include "gd32f4xx_usart.h"
#include "gd32f4xx_rcu.h"
#include "gd32f4xx_gpio.h"
#include "board_config.h"
#include "uart_ring_buffer.h"
void uart_init(void) {
/* 使能 GPIOA 和 USART 时钟 */
rcu_periph_clock_enable(UART_GPIO_RCU);
rcu_periph_clock_enable(UART_RCU);
/* 配置 PA9 为 USART0_TX,PA10 为 USART0_RX(AF7) */
gpio_af_set(UART_GPIO_PORT, GPIO_AF_7, UART_TX_PIN | UART_RX_PIN);
gpio_mode_set(UART_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UART_TX_PIN | UART_RX_PIN);
gpio_output_options_set(UART_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UART_TX_PIN | UART_RX_PIN);
#if RS485_MODE == CFG_ENABLE
/* 配置 RS485 DE 引脚为普通推挽输出(默认接收态) */
rcu_periph_clock_enable(RS485_DE_RCU);
gpio_mode_set(RS485_DE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_DE_PIN);
gpio_output_options_set(RS485_DE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_DE_PIN);
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN);
#endif
/* 配置波特率、数据位、停止位等 */
usart_deinit(UART_PHY);
usart_word_length_set(UART_PHY, USART_WL_8BIT);
usart_stop_bit_set(UART_PHY, USART_STB_1BIT);
usart_parity_config(UART_PHY, USART_PM_NONE);
usart_baudrate_set(UART_PHY, UART_BAUDRATE);
usart_receive_config(UART_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(UART_PHY, USART_TRANSMIT_ENABLE);
usart_enable(UART_PHY);
nvic_irq_enable(UART_IRQ, 0, 0);
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);
}
#if RS485_MODE == CFG_ENABLE
void rs485_de_set(void) {
gpio_bit_set(RS485_DE_PORT, RS485_DE_PIN); /* 发送态 */
}
void rs485_de_clear(void) {
gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN); /* 接收态 */
}
#endif
/******************************************************************************/
/* 具体的中断处理函数实现 */
/******************************************************************************/
void usart0_irq_handler(void) {
// 处理USART0的接收中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART0);
// 使用原有的环形缓冲区处理逻辑
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
}
// 处理USART0的空闲中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
// 在这里添加空闲中断处理逻辑
}
}
void usart1_irq_handler(void) {
// 处理USART1的接收中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART1);
(void)uart_ring_buffer_put(data);
}
// 处理USART1的空闲中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
}
}
void usart2_irq_handler(void) {
// 处理USART2的接收中断
if(usart_interrupt_flag_get(USART2, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART2);
(void)uart_ring_buffer_put(data);
}
// 处理USART2的空闲中断
if(usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART2, USART_INT_FLAG_IDLE);
}
}
/* 调试串口初始化(与 uart_init 相同配置的独立入口,便于单独初始化打印口) */
void debug_usart_init(void)
{
/* 使能 GPIOA 和 USART1 时钟 */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART1);
/* 配置 PA2(TX) 和 PA3(RX) 复用功能 AF7 */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2 | GPIO_PIN_3);
/* 配置 GPIO 模式 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2 | GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2 | GPIO_PIN_3);
/* USART1 配置 */
usart_deinit(USART1);
usart_baudrate_set(USART1, 115200U);
usart_word_length_set(USART1, USART_WL_8BIT);
usart_stop_bit_set(USART1, USART_STB_1BIT);
usart_parity_config(USART1, USART_PM_NONE);
usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
usart_enable(USART1);
}
+121
View File
@@ -0,0 +1,121 @@
/**
* @file uart_ring_buffer.c
* @brief 字节环形接收缓冲区的实现。
* @details 适用于中断接收(写)与主循环解析(读)的典型串口场景;
* 采用“预留一格”区分空/满,最大可用容量为 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
#include "uart_ring_buffer.h"
#include "gd32f4xx.h"
static __IO uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];
static __IO uint8_t write_index = 0;
static __IO uint8_t read_index = 0;
static __IO 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 & 0x1) == 0) {
__enable_irq();
}
}
/**
* @brief 重置环形缓冲区状态。
* @details 将读指针、写指针与丢弃计数清零,不清空数据区内容。
* @note 内部工具函数;对外请优先使用 uart_ring_buffer_init()/uart_ring_buffer_clear()。
* @ingroup RingBuffer
*/
static void uart_ring_buffer_reset_state(void) {
write_index = 0;
read_index = 0;
dropped_bytes = 0;
}
/**
* @brief 初始化环形缓冲区。
* @details 调用内部重置逻辑,复位读写索引与丢弃计数,准备接收数据。
* @note 若在中断环境使用,初始化前建议关闭相关接收中断以避免并发竞争。
* @ingroup RingBuffer
*/
void uart_ring_buffer_init(void) {
uint32_t primask = irq_save();
uart_ring_buffer_reset_state();
irq_restore(primask);
}
/**
* @brief 获取当前可读的字节数。
* @details 通过读/写指针的快照计算可读长度,范围为 [0, UART_RX_BUFFER_SIZE-1]。
* @return uint8_t 可读字节数。
* @note 预留一个空槽区分“空/满”,因此满时返回 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
uint8_t uart_ring_buffer_available(void) {
/* 使用快照减少并发不一致窗口 */
uint8_t w = write_index;
uint8_t r = read_index;
return (uint8_t)((w + UART_RX_BUFFER_SIZE - r) % UART_RX_BUFFER_SIZE);
}
/**
* @brief 从环形缓冲区读取一个字节。
* @details 若缓冲区非空,返回队头字节并推进读指针;若为空,返回 -1。
* @return int 读取到的字节(0..255),或 -1 表示缓冲区为空。
* @ingroup RingBuffer
*/
int uart_ring_buffer_get(void) {
if (read_index == write_index) return -1; // 空
uint8_t data = uart_rx_buffer[read_index];
read_index = (read_index + 1) % UART_RX_BUFFER_SIZE;
return data;
}
/**
* @brief 向环形缓冲区写入一个字节。
* @details 尝试写入一个新字节;若缓冲区已满则丢弃并计数。
* @param data 待写入的字节。
* @return bool 是否写入成功。
* @retval true 写入成功。
* @retval false 写入失败(缓冲区已满,数据被丢弃并计数)。
* @note 如需“覆盖写入”策略,可在满时先推进读指针再写入。
* @ingroup RingBuffer
*/
bool uart_ring_buffer_put(uint8_t data) {
uint8_t next = (write_index + 1) % UART_RX_BUFFER_SIZE;
if (next != read_index) { // 缓冲区未满
uart_rx_buffer[write_index] = data;
write_index = next;
return true;
} else {
/* 缓冲区已满,丢弃新字节并计数 */
dropped_bytes++;
return false;
}
}
/**
* @brief 清空环形缓冲区。
* @details 复位读写索引与丢弃计数,相当于逻辑上丢弃所有已接收数据,不擦除数据区内容。
* @ingroup RingBuffer
*/
void uart_ring_buffer_clear(void) {
uint32_t primask = irq_save();
uart_ring_buffer_reset_state();
irq_restore(primask);
}
/**
* @brief 获取因满而被丢弃的字节累计数量。
* @details 写入时缓冲区满会丢弃新字节并累加计数;该计数在 init/clear 时清零。
* @return uint32_t 丢弃的累计字节数。
* @ingroup RingBuffer
*/
uint32_t uart_ring_buffer_drop_count(void) {
return dropped_bytes;
}