From 078ea063170af4100408f342596d998851b1ab5c Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Sun, 10 May 2026 21:27:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(device):=20=E7=A7=BB=E9=99=A4=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E5=B9=B6=E5=AE=8C?= =?UTF-8?q?=E5=96=84ADC=E6=A8=A1=E5=9D=97=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除不再需要的 .cproject.yml.bak_dma 和 README.md 备份文件, 同时为 ADC.cpp 添加完整的 Doxygen 风格函数注释,提升代码可读性。 --- .../GD32E508_DCU_APP.cproject.yml.bak_dma | 82 --- GD32E508_DCU_APP/device/ADC.cpp | 80 +++ GD32E508_DCU_APP/device/ADC.cpp.bak_config | 126 ----- GD32E508_DCU_APP/device/ADC.cpp.bak_dma | 119 ----- GD32E508_DCU_APP/device/ADC.cpp.bak_oop | 218 -------- GD32E508_DCU_APP/device/ADC.cpp.bak_sch | 182 ------- GD32E508_DCU_APP/device/CANFD.cpp | 493 ++++++++++++++---- .../device/CANFD.cpp.bak_align_app | 278 ---------- GD32E508_DCU_APP/device/CANFD.cpp.bak_can_isr | 283 ---------- GD32E508_DCU_APP/device/CANFD.cpp.bak_canrate | 274 ---------- GD32E508_DCU_APP/device/CANFD.cpp.bak_canrcu | 274 ---------- .../device/CANFD.cpp.bak_hideimpl | 225 -------- GD32E508_DCU_APP/device/CANFD.cpp.bak_oop | 326 ------------ GD32E508_DCU_APP/device/CANFD.cpp.bak_pa8mode | 319 ------------ GD32E508_DCU_APP/device/CANFD.cpp.bak_sch | 300 ----------- GD32E508_DCU_APP/device/Timer.cpp | 37 +- GD32E508_DCU_APP/device/Timer.cpp.bak_dma | 65 --- GD32E508_DCU_APP/device/Timer.cpp.bak_oop | 65 --- GD32E508_DCU_APP/device/Timer.h | 30 +- GD32E508_DCU_APP/device/Timer.h.bak_oop | 17 - GD32E508_DCU_APP/device/adc.h | 103 +++- GD32E508_DCU_APP/device/adc.h.bak_dma | 78 --- GD32E508_DCU_APP/device/adc.h.bak_oop | 114 ---- GD32E508_DCU_APP/device/adc.h.bak_sch | 94 ---- GD32E508_DCU_APP/device/canfd.h | 171 +++++- GD32E508_DCU_APP/device/canfd.h.bak_hideimpl | 81 --- GD32E508_DCU_APP/device/canfd.h.bak_oop | 99 ---- GD32E508_DCU_APP/device/canfd.h.bak_sch | 99 ---- GD32E508_DCU_APP/device/temp_sensor.cpp | 14 + .../device/temp_sensor.cpp.bak_oop | 25 - GD32E508_DCU_APP/device/temp_sensor.h | 17 +- GD32E508_DCU_APP/device/temp_sensor.h.bak_oop | 33 -- GD32E508_DCU_APP/device/usart0.cpp | 88 +++- GD32E508_DCU_APP/device/usart0.cpp.bak_oop | 109 ---- GD32E508_DCU_APP/device/usart0.cpp.bak_txisr | 54 -- GD32E508_DCU_APP/device/usart0.h | 61 ++- GD32E508_DCU_APP/device/usart0.h.bak_oop | 25 - GD32E508_DCU_APP/main.cpp | 24 +- GD32E508_DCU_APP/main.cpp.bak_config | 34 -- GD32E508_DCU_APP/main.cpp.bak_oop | 35 -- GD32E508_DCU_APP/main.h | 59 ++- GD32E508_DCU_APP/main.h.bak_oop | 47 -- GD32E508_DCU_APP/sys/config.h | 3 + GD32E508_DCU_APP/sys/config.h.bak_canrate | 79 --- GD32E508_DCU_APP/sys/config.h.bak_canrcu | 77 --- GD32E508_DCU_APP/sys/config.h.bak_sch | 77 --- GD32E508_DCU_APP/sys/config.h.bak_txisr | 77 --- GD32E508_DCU_APP/sys/initial.cpp | 8 +- GD32E508_DCU_APP/sys/initial.cpp.bak_dma | 28 - .../sys/initial.cpp.bak_fixinclude | 28 - GD32E508_DCU_APP/sys/initial.cpp.bak_oop | 31 -- GD32E508_DCU_APP/sys/initial.cpp.bak_restore | 28 - GD32E508_DCU_APP/sys/initial.h | 11 +- GD32E508_DCU_APP/sys/initial.h.bak_oop | 17 - GD32E508_DCU_APP/sys/systick.cpp | 30 +- .../sys/systick.cpp.bak_fixinclude | 38 -- GD32E508_DCU_APP/sys/systick.cpp.bak_oop | 38 -- GD32E508_DCU_APP/sys/systick.cpp.bak_restore | 38 -- GD32E508_DCU_APP/sys/systick.h | 24 +- GD32E508_DCU_APP/sys/systick.h.bak_oop | 26 - .../sys/task_manager.c.bak_20260510_0448 | 63 --- GD32E508_DCU_APP/sys/task_manager.cpp | 57 +- .../sys/task_manager.cpp.bak_config | 85 --- .../sys/task_manager.cpp.bak_fixinclude | 85 --- GD32E508_DCU_APP/sys/task_manager.cpp.bak_oop | 86 --- .../sys/task_manager.cpp.bak_restore | 85 --- GD32E508_DCU_APP/sys/task_manager.h | 42 +- .../sys/task_manager.h.bak_20260510_0448 | 11 - GD32E508_DCU_APP/sys/task_manager.h.bak_oop | 42 -- GD32E508_DCU_APP/sys/task_runner.cpp | 154 ++++-- .../sys/task_runner.cpp.bak_fixinclude | 179 ------- GD32E508_DCU_APP/sys/task_runner.cpp.bak_oop | 186 ------- .../sys/task_runner.cpp.bak_restore | 179 ------- GD32E508_DCU_APP/sys/task_runner.cpp.bak_sch | 179 ------- GD32E508_DCU_APP/sys/task_runner.h | 27 +- GD32E508_DCU_APP/sys/task_runner.h.bak_oop | 25 - GD32E508_DCU_APP/README.md => README.md | 0 77 files changed, 1326 insertions(+), 6074 deletions(-) delete mode 100644 GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml.bak_dma delete mode 100644 GD32E508_DCU_APP/device/ADC.cpp.bak_config delete mode 100644 GD32E508_DCU_APP/device/ADC.cpp.bak_dma delete mode 100644 GD32E508_DCU_APP/device/ADC.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/device/ADC.cpp.bak_sch delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_align_app delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_can_isr delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_canrate delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_canrcu delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_hideimpl delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_pa8mode delete mode 100644 GD32E508_DCU_APP/device/CANFD.cpp.bak_sch delete mode 100644 GD32E508_DCU_APP/device/Timer.cpp.bak_dma delete mode 100644 GD32E508_DCU_APP/device/Timer.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/device/Timer.h.bak_oop delete mode 100644 GD32E508_DCU_APP/device/adc.h.bak_dma delete mode 100644 GD32E508_DCU_APP/device/adc.h.bak_oop delete mode 100644 GD32E508_DCU_APP/device/adc.h.bak_sch delete mode 100644 GD32E508_DCU_APP/device/canfd.h.bak_hideimpl delete mode 100644 GD32E508_DCU_APP/device/canfd.h.bak_oop delete mode 100644 GD32E508_DCU_APP/device/canfd.h.bak_sch delete mode 100644 GD32E508_DCU_APP/device/temp_sensor.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/device/temp_sensor.h.bak_oop delete mode 100644 GD32E508_DCU_APP/device/usart0.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/device/usart0.cpp.bak_txisr delete mode 100644 GD32E508_DCU_APP/device/usart0.h.bak_oop delete mode 100644 GD32E508_DCU_APP/main.cpp.bak_config delete mode 100644 GD32E508_DCU_APP/main.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/main.h.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/config.h.bak_canrate delete mode 100644 GD32E508_DCU_APP/sys/config.h.bak_canrcu delete mode 100644 GD32E508_DCU_APP/sys/config.h.bak_sch delete mode 100644 GD32E508_DCU_APP/sys/config.h.bak_txisr delete mode 100644 GD32E508_DCU_APP/sys/initial.cpp.bak_dma delete mode 100644 GD32E508_DCU_APP/sys/initial.cpp.bak_fixinclude delete mode 100644 GD32E508_DCU_APP/sys/initial.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/initial.cpp.bak_restore delete mode 100644 GD32E508_DCU_APP/sys/initial.h.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/systick.cpp.bak_fixinclude delete mode 100644 GD32E508_DCU_APP/sys/systick.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/systick.cpp.bak_restore delete mode 100644 GD32E508_DCU_APP/sys/systick.h.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/task_manager.c.bak_20260510_0448 delete mode 100644 GD32E508_DCU_APP/sys/task_manager.cpp.bak_config delete mode 100644 GD32E508_DCU_APP/sys/task_manager.cpp.bak_fixinclude delete mode 100644 GD32E508_DCU_APP/sys/task_manager.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/task_manager.cpp.bak_restore delete mode 100644 GD32E508_DCU_APP/sys/task_manager.h.bak_20260510_0448 delete mode 100644 GD32E508_DCU_APP/sys/task_manager.h.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/task_runner.cpp.bak_fixinclude delete mode 100644 GD32E508_DCU_APP/sys/task_runner.cpp.bak_oop delete mode 100644 GD32E508_DCU_APP/sys/task_runner.cpp.bak_restore delete mode 100644 GD32E508_DCU_APP/sys/task_runner.cpp.bak_sch delete mode 100644 GD32E508_DCU_APP/sys/task_runner.h.bak_oop rename GD32E508_DCU_APP/README.md => README.md (100%) diff --git a/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml.bak_dma b/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml.bak_dma deleted file mode 100644 index 8b07390..0000000 --- a/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml.bak_dma +++ /dev/null @@ -1,82 +0,0 @@ -# A project translates into one executable or library. -project: - - groups: - - group: Source Files - files: - - file: ./main.h - - file: ./main.cpp - - group: sys - files: - - file: ./sys/initial.h - - file: ./sys/initial.cpp - - file: ./sys/systick.h - - file: ./sys/systick.cpp - - file: ./sys/task_manager.h - - file: ./sys/task_manager.cpp - - file: ./sys/task_runner.h - - file: ./sys/task_runner.cpp - - file: ./sys/config.h - - group: device - files: - - file: ./device/usart0.h - - file: ./device/usart0.cpp - - file: ./device/adc.h - - file: ./device/ADC.cpp - - file: ./device/canfd.h - - file: ./device/CANFD.cpp - - file: ./device/Timer.h - - file: ./device/Timer.cpp - - file: ./device/temp_sensor.h - - file: ./device/temp_sensor.cpp - - # List components to use for your application. - # A software component is a re-usable unit that may be configurable. - components: - - component: ARM::CMSIS:CORE - - component: Device:Startup - - component: Device:GD32E50x_StdPeripherals:ADC - - component: Device:GD32E50x_StdPeripherals:CAN - - component: Device:GD32E50x_StdPeripherals:CRC - - component: Device:GD32E50x_StdPeripherals:DBG - - component: Device:GD32E50x_StdPeripherals:DMA - - component: Device:GD32E50x_StdPeripherals:EXTI - - component: Device:GD32E50x_StdPeripherals:FMC - - component: Device:GD32E50x_StdPeripherals:GPIO - - component: Device:GD32E50x_StdPeripherals:MISC - - component: Device:GD32E50x_StdPeripherals:PMU - - component: Device:GD32E50x_StdPeripherals:RCU - - component: Device:GD32E50x_StdPeripherals:SPI_I2S - - component: Device:GD32E50x_StdPeripherals:TIMER - - component: Device:GD32E50x_StdPeripherals:USART - - component: Device:GD32E50x_libopt - - # List executable file formats to be generated. - output: - type: - - elf - - hex - - map - - misc: - - for-compiler: AC6 - C-CPP: - - -DGD32E508 - - -DGD32E50X - - -gdwarf-5 - - -D__MICROLIB - - -fshort-enums - - -fshort-wchar - - -Wno-register - C: - - -std=gnu11 - CPP: - - -std=gnu++17 - ASM: - - -DGD32E508 - - -DGD32E50X - - -gdwarf-5 - - -D__MICROLIB - Link: - - --library_type=microlib - - --entry=Reset_Handler diff --git a/GD32E508_DCU_APP/device/ADC.cpp b/GD32E508_DCU_APP/device/ADC.cpp index abb134f..15f74b4 100644 --- a/GD32E508_DCU_APP/device/ADC.cpp +++ b/GD32E508_DCU_APP/device/ADC.cpp @@ -18,6 +18,13 @@ volatile uint16_t s_dmaBuffer[kChannelCount] = {0U, 0U, 0U}; volatile uint8_t s_dmaReady = 0U; } // namespace +/** + * @brief 初始化 ADC DMA 循环搬运。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 配置 DMA0 Channel0,将 ADC 规则组结果连续搬运到 `s_dmaBuffer`。 + */ void Adc::initDma() { dma_parameter_struct dma_initpara{}; @@ -40,6 +47,13 @@ void Adc::initDma() dma_channel_enable(kDmaPeriph, kDmaChannel); } +/** + * @brief 初始化 ADC、DMA 与规则通道扫描配置。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 按 `VIN_ADC / TEMP / VREFINT` 三通道顺序启用连续扫描与 DMA 采样。 + */ void Adc::init() { rcu_periph_clock_enable(RCU_ADC0); @@ -74,16 +88,35 @@ void Adc::init() s_dmaReady = 1U; } +/** + * @brief 查询 ADC DMA 采样是否已经就绪。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示 DMA 已启动并完成初始稳定等待,false 表示尚未就绪。 + */ bool Adc::dmaReady() { return s_dmaReady != 0U; } +/** + * @brief 获取 ADC DMA 原始缓冲区首地址。 + * @param[in] 无。 + * @param[out] 无。 + * @retval const uint16_t* 返回 DMA 原始缓冲区首地址。 + * @note 缓冲顺序固定为 `VIN_ADC / TEMP / VREFINT`。 + */ const uint16_t *Adc::dmaBuffer() { return (const uint16_t *)s_dmaBuffer; } +/** + * @brief 按逻辑通道号读取一个原始 ADC 数值。 + * @param[in] channel 逻辑 ADC 通道号。 + * @param[out] 无。 + * @retval uint16_t 返回对应通道的原始采样值;若通道不受支持则返回 0。 + */ uint16_t Adc::readRaw(uint8_t channel) { if(channel == CONFIG_ADC_VIN_CHANNEL) return s_dmaBuffer[0]; @@ -92,27 +125,74 @@ uint16_t Adc::readRaw(uint8_t channel) return 0U; } +/** + * @brief 读取 VIN_ADC 原始采样值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t 返回 VIN_ADC 通道原始值。 + */ uint16_t Adc::readVinRaw() { return readRaw(CONFIG_ADC_VIN_CHANNEL); } + +/** + * @brief 读取内部参考电压原始采样值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t 返回 VREFINT 通道原始值。 + */ uint16_t Adc::readVrefRaw() { return readRaw(CONFIG_ADC_VREFINT_CHANNEL); } + +/** + * @brief 读取内部温度通道原始采样值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t 返回内部温度通道原始值。 + */ uint16_t Adc::readTempRaw() { return readRaw(CONFIG_ADC_TEMP_CHANNEL); } +/** + * @brief 将 VIN_ADC 原始值换算为 ADC 引脚电压。 + * @param[in] vinRaw VIN_ADC 原始采样值。 + * @param[in] vdda 当前 ADC 供电电压。 + * @param[out] 无。 + * @retval float 返回 ADC 引脚电压,单位 V。 + */ float Adc::calculateVinAdcVoltage(uint16_t vinRaw, float vdda) { return (static_cast(vinRaw) * vdda) / CONFIG_ADC_MAX_VALUE; } +/** + * @brief 根据内部参考电压原始值换算当前 VDDA。 + * @param[in] vrefRaw 内部参考电压通道原始值。 + * @param[out] 无。 + * @retval float 返回换算得到的 VDDA,单位 V;若原始值为 0,则返回默认值。 + */ float Adc::calculateVdda(uint16_t vrefRaw) { if(vrefRaw == 0U) return CONFIG_ADC_DEFAULT_VDDA; return (CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE * CONFIG_ADC_MAX_VALUE) / static_cast(vrefRaw); } +/** + * @brief 根据温度通道原始值换算芯片温度。 + * @param[in] tempRaw 温度通道原始值。 + * @param[in] vdda 当前 ADC 供电电压。 + * @param[out] 无。 + * @retval float 返回换算得到的芯片温度,单位 ℃。 + */ float Adc::calculateTemperature(uint16_t tempRaw, float vdda) { const float sensorVoltage = (static_cast(tempRaw) * vdda) / CONFIG_ADC_MAX_VALUE; return ((CONFIG_ADC_TEMP_V25 - sensorVoltage) / CONFIG_ADC_TEMP_AVG_SLOPE) + 25.0f; } +/** + * @brief 收集一组完整 ADC 采样结果。 + * @param[in] sample 指向输出采样结构体的指针。 + * @param[out] sample 输出原始值与工程值结果;允许为空。 + * @retval 无返回值。 + * @note 若 `sample == nullptr`,函数直接返回。 + */ void Adc::collectSample(Sample *sample) { if(sample == nullptr) return; diff --git a/GD32E508_DCU_APP/device/ADC.cpp.bak_config b/GD32E508_DCU_APP/device/ADC.cpp.bak_config deleted file mode 100644 index c526f1e..0000000 --- a/GD32E508_DCU_APP/device/ADC.cpp.bak_config +++ /dev/null @@ -1,126 +0,0 @@ -#include "main.h" -#include "device/adc.h" -#include "sys/systick.h" - -#define TEMP_ADC ADC0 -#define TEMP_ADC_CHANNEL ADC_CHANNEL_16 -#define VREFINT_ADC_CHANNEL ADC_CHANNEL_17 -#define ADC_MAX_VALUE 4095.0f -#define VREFINT_TYPICAL_VOLTAGE 1.20f -#define TEMP_V25 1.43f -#define TEMP_AVG_SLOPE 0.0043f - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 完成 ADC 时钟、模式、触发方式、内部通道和校准流程配置。 - */ -void adc_hw_init(void) -{ - rcu_periph_clock_enable(RCU_ADC0); - rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); - - adc_deinit(TEMP_ADC); - adc_mode_config(ADC_MODE_FREE); - adc_special_function_config(TEMP_ADC, ADC_SCAN_MODE, DISABLE); - adc_special_function_config(TEMP_ADC, ADC_CONTINUOUS_MODE, DISABLE); - adc_data_alignment_config(TEMP_ADC, ADC_DATAALIGN_RIGHT); - adc_channel_length_config(TEMP_ADC, ADC_REGULAR_CHANNEL, 1U); - adc_external_trigger_source_config(TEMP_ADC, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE); - adc_external_trigger_config(TEMP_ADC, ADC_REGULAR_CHANNEL, DISABLE); - - adc_tempsensor_vrefint_enable(); - delay_ms(2U); - - adc_enable(TEMP_ADC); - delay_ms(2U); - adc_calibration_enable(TEMP_ADC); -} - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 函数采用阻塞式等待,直到 EOC 置位后返回。 - */ -uint16_t adc_single_read(uint8_t channel) -{ - adc_regular_channel_config(TEMP_ADC, 0U, channel, ADC_SAMPLETIME_239POINT5); - adc_flag_clear(TEMP_ADC, ADC_FLAG_EOC); - adc_software_trigger_enable(TEMP_ADC, ADC_REGULAR_CHANNEL); - while(RESET == adc_flag_get(TEMP_ADC, ADC_FLAG_EOC)) { - } - return adc_regular_data_read(TEMP_ADC); -} - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void) -{ - return adc_single_read(VREFINT_ADC_CHANNEL); -} - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void) -{ - return adc_single_read(TEMP_ADC_CHANNEL); -} - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当 vref_raw 为 0 时返回默认 3.3V,避免出现除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw) -{ - if(vref_raw == 0U) { - return 3.3f; - } - return (VREFINT_TYPICAL_VOLTAGE * ADC_MAX_VALUE) / static_cast(vref_raw); -} - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda) -{ - const float sensor_voltage = (static_cast(temp_raw) * vdda) / ADC_MAX_VALUE; - return ((TEMP_V25 - sensor_voltage) / TEMP_AVG_SLOPE) + 25.0f; -} - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行任何数据写入。 - */ -void adc_collect_sample(adc_sample_t *sample) -{ - if(sample == nullptr) { - return; - } - - sample->vref_raw = adc_read_vref_raw(); - sample->temp_raw = adc_read_temp_raw(); - sample->vdda = adc_calculate_vdda(sample->vref_raw); - sample->temperature = adc_calculate_temperature(sample->temp_raw, sample->vdda); -} diff --git a/GD32E508_DCU_APP/device/ADC.cpp.bak_dma b/GD32E508_DCU_APP/device/ADC.cpp.bak_dma deleted file mode 100644 index 3894495..0000000 --- a/GD32E508_DCU_APP/device/ADC.cpp.bak_dma +++ /dev/null @@ -1,119 +0,0 @@ -#include "main.h" -#include "device/adc.h" -#include "sys/systick.h" -#include "sys/config.h" - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 完成 ADC 时钟、模式、触发方式、内部通道和校准流程配置。 - */ -void adc_hw_init(void) -{ - rcu_periph_clock_enable(RCU_ADC0); - rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); - - adc_deinit(CONFIG_ADC_INSTANCE); - adc_mode_config(ADC_MODE_FREE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_SCAN_MODE, DISABLE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_CONTINUOUS_MODE, DISABLE); - adc_data_alignment_config(CONFIG_ADC_INSTANCE, ADC_DATAALIGN_RIGHT); - adc_channel_length_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, 1U); - adc_external_trigger_source_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE); - adc_external_trigger_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, DISABLE); - - adc_tempsensor_vrefint_enable(); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - - adc_enable(CONFIG_ADC_INSTANCE); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - adc_calibration_enable(CONFIG_ADC_INSTANCE); -} - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 函数采用阻塞式等待,直到 EOC 置位后返回。 - */ -uint16_t adc_single_read(uint8_t channel) -{ - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 0U, channel, CONFIG_ADC_SAMPLE_TIME); - adc_flag_clear(CONFIG_ADC_INSTANCE, ADC_FLAG_EOC); - adc_software_trigger_enable(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL); - while(RESET == adc_flag_get(CONFIG_ADC_INSTANCE, ADC_FLAG_EOC)) { - } - return adc_regular_data_read(CONFIG_ADC_INSTANCE); -} - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void) -{ - return adc_single_read(CONFIG_ADC_VREFINT_CHANNEL); -} - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void) -{ - return adc_single_read(CONFIG_ADC_TEMP_CHANNEL); -} - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当 vref_raw 为 0 时返回默认 3.3V,避免出现除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw) -{ - if(vref_raw == 0U) { - return CONFIG_ADC_DEFAULT_VDDA; - } - return (CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE * CONFIG_ADC_MAX_VALUE) / static_cast(vref_raw); -} - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda) -{ - const float sensor_voltage = (static_cast(temp_raw) * vdda) / CONFIG_ADC_MAX_VALUE; - return ((CONFIG_ADC_TEMP_V25 - sensor_voltage) / CONFIG_ADC_TEMP_AVG_SLOPE) + 25.0f; -} - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行任何数据写入。 - */ -void adc_collect_sample(adc_sample_t *sample) -{ - if(sample == nullptr) { - return; - } - - sample->vref_raw = adc_read_vref_raw(); - sample->temp_raw = adc_read_temp_raw(); - sample->vdda = adc_calculate_vdda(sample->vref_raw); - sample->temperature = adc_calculate_temperature(sample->temp_raw, sample->vdda); -} diff --git a/GD32E508_DCU_APP/device/ADC.cpp.bak_oop b/GD32E508_DCU_APP/device/ADC.cpp.bak_oop deleted file mode 100644 index 316c66c..0000000 --- a/GD32E508_DCU_APP/device/ADC.cpp.bak_oop +++ /dev/null @@ -1,218 +0,0 @@ -#include "main.h" -#include "device/adc.h" -#include "sys/systick.h" -#include "sys/config.h" - -namespace { -constexpr uint32_t kAdcDmaPeriph = DMA0; -constexpr dma_channel_enum kAdcDmaChannel = DMA_CH0; -constexpr uint32_t kAdcChannelCount = 3U; -constexpr uint32_t kVinAdcGpio = GPIOA; -constexpr uint32_t kVinAdcPin = GPIO_PIN_6; -volatile uint16_t g_adc_dma_buffer[kAdcChannelCount] = {0U, 0U, 0U}; -volatile uint8_t g_adc_dma_ready = 0U; - -/** - * @brief 配置 ADC 原始数据到内存的 DMA 循环搬运。 - */ -void adc_dma_init(void) -{ - dma_parameter_struct dma_initpara{}; - - rcu_periph_clock_enable(RCU_DMA0); - dma_deinit(kAdcDmaPeriph, kAdcDmaChannel); - dma_struct_para_init(&dma_initpara); - - dma_initpara.periph_addr = (uint32_t)(&ADC_RDATA(CONFIG_ADC_INSTANCE)); - dma_initpara.memory_addr = (uint32_t)g_adc_dma_buffer; - dma_initpara.direction = DMA_PERIPHERAL_TO_MEMORY; - dma_initpara.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; - dma_initpara.memory_width = DMA_MEMORY_WIDTH_16BIT; - dma_initpara.periph_inc = DMA_PERIPH_INCREASE_DISABLE; - dma_initpara.memory_inc = DMA_MEMORY_INCREASE_ENABLE; - dma_initpara.number = kAdcChannelCount; - dma_initpara.priority = DMA_PRIORITY_HIGH; - dma_init(kAdcDmaPeriph, kAdcDmaChannel, &dma_initpara); - dma_circulation_enable(kAdcDmaPeriph, kAdcDmaChannel); - dma_channel_enable(kAdcDmaPeriph, kAdcDmaChannel); -} -} // namespace - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF/VIN_ADC 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 完成 ADC 三通道扫描、DMA 循环搬运、PA6(VIN_ADC) 模拟输入配置以及内部通道校准。 - */ -void adc_hw_init(void) -{ - rcu_periph_clock_enable(RCU_ADC0); - rcu_periph_clock_enable(RCU_GPIOA); - rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); - - /* 原理图:PA6 -> VIN_ADC,为外部电源分压检测输入 */ - gpio_init(kVinAdcGpio, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, kVinAdcPin); - - adc_dma_init(); - adc_deinit(CONFIG_ADC_INSTANCE); - adc_mode_config(ADC_MODE_FREE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_SCAN_MODE, ENABLE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_CONTINUOUS_MODE, ENABLE); - adc_data_alignment_config(CONFIG_ADC_INSTANCE, ADC_DATAALIGN_RIGHT); - adc_channel_length_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, kAdcChannelCount); - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 0U, CONFIG_ADC_VIN_CHANNEL, CONFIG_ADC_SAMPLE_TIME); - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 1U, CONFIG_ADC_TEMP_CHANNEL, CONFIG_ADC_SAMPLE_TIME); - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 2U, CONFIG_ADC_VREFINT_CHANNEL, CONFIG_ADC_SAMPLE_TIME); - adc_external_trigger_source_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE); - adc_external_trigger_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, DISABLE); - adc_dma_mode_enable(CONFIG_ADC_INSTANCE); - - adc_tempsensor_vrefint_enable(); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - - adc_enable(CONFIG_ADC_INSTANCE); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - adc_calibration_enable(CONFIG_ADC_INSTANCE); - adc_software_trigger_enable(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL); - delay_ms(1U); - g_adc_dma_ready = 1U; -} - -/** - * @brief 查询 ADC DMA 循环缓存是否已完成首次有效填充。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示缓存已可用,返回 0 表示仍未准备好。 - */ -uint8_t adc_dma_ready(void) -{ - return g_adc_dma_ready; -} - -/** - * @brief 获取 ADC DMA 原始循环缓存只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const uint16_t* 返回长度为 3 的原始缓存指针,顺序为 VIN_ADC、温度通道、VREF 通道。 - */ -const uint16_t *adc_dma_buffer_get(void) -{ - return (const uint16_t *)g_adc_dma_buffer; -} - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 在 DMA 缓存模式下,该函数优先返回已缓存的对应通道原始值;若通道不受支持则返回 0。 - */ -uint16_t adc_single_read(uint8_t channel) -{ - if(channel == CONFIG_ADC_VIN_CHANNEL) { - return g_adc_dma_buffer[0]; - } - if(channel == CONFIG_ADC_TEMP_CHANNEL) { - return g_adc_dma_buffer[1]; - } - if(channel == CONFIG_ADC_VREFINT_CHANNEL) { - return g_adc_dma_buffer[2]; - } - return 0U; -} - -/** - * @brief 读取外部 VIN_ADC(PA6)通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 外部 VIN_ADC 通道的原始 ADC 值。 - */ -uint16_t adc_read_vin_raw(void) -{ - return adc_single_read(CONFIG_ADC_VIN_CHANNEL); -} - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void) -{ - return adc_single_read(CONFIG_ADC_VREFINT_CHANNEL); -} - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void) -{ - return adc_single_read(CONFIG_ADC_TEMP_CHANNEL); -} - -/** - * @brief 根据外部 VIN_ADC 原始值与 VDDA 计算 ADC 引脚处电压。 - * @param[in] vin_raw 外部 VIN_ADC 通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float VIN_ADC 引脚电压,单位 V。 - * @note 当前仅计算分压后的 ADC 端电压;若需换算输入母线电压,需要补充完整分压比。 - */ -float adc_calculate_vin_adc_voltage(uint16_t vin_raw, float vdda) -{ - return (static_cast(vin_raw) * vdda) / CONFIG_ADC_MAX_VALUE; -} - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当 vref_raw 为 0 时返回默认 3.3V,避免出现除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw) -{ - if(vref_raw == 0U) { - return CONFIG_ADC_DEFAULT_VDDA; - } - return (CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE * CONFIG_ADC_MAX_VALUE) / static_cast(vref_raw); -} - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda) -{ - const float sensor_voltage = (static_cast(temp_raw) * vdda) / CONFIG_ADC_MAX_VALUE; - return ((CONFIG_ADC_TEMP_V25 - sensor_voltage) / CONFIG_ADC_TEMP_AVG_SLOPE) + 25.0f; -} - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入 VIN/温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行任何数据写入。 - */ -void adc_collect_sample(adc_sample_t *sample) -{ - if(sample == nullptr) { - return; - } - - sample->vin_raw = adc_read_vin_raw(); - sample->temp_raw = adc_read_temp_raw(); - sample->vref_raw = adc_read_vref_raw(); - sample->vdda = adc_calculate_vdda(sample->vref_raw); - sample->vin_adc_v = adc_calculate_vin_adc_voltage(sample->vin_raw, sample->vdda); - sample->temperature = adc_calculate_temperature(sample->temp_raw, sample->vdda); -} diff --git a/GD32E508_DCU_APP/device/ADC.cpp.bak_sch b/GD32E508_DCU_APP/device/ADC.cpp.bak_sch deleted file mode 100644 index e075262..0000000 --- a/GD32E508_DCU_APP/device/ADC.cpp.bak_sch +++ /dev/null @@ -1,182 +0,0 @@ -#include "main.h" -#include "device/adc.h" -#include "sys/systick.h" -#include "sys/config.h" - -namespace { -constexpr uint32_t kAdcDmaPeriph = DMA0; -constexpr dma_channel_enum kAdcDmaChannel = DMA_CH0; -constexpr uint32_t kAdcChannelCount = 2U; -volatile uint16_t g_adc_dma_buffer[kAdcChannelCount] = {0U, 0U}; -volatile uint8_t g_adc_dma_ready = 0U; - -/** - * @brief 配置 ADC 原始数据到内存的 DMA 循环搬运。 - */ -void adc_dma_init(void) -{ - dma_parameter_struct dma_initpara{}; - - rcu_periph_clock_enable(RCU_DMA0); - dma_deinit(kAdcDmaPeriph, kAdcDmaChannel); - dma_struct_para_init(&dma_initpara); - - dma_initpara.periph_addr = (uint32_t)(&ADC_RDATA(CONFIG_ADC_INSTANCE)); - dma_initpara.memory_addr = (uint32_t)g_adc_dma_buffer; - dma_initpara.direction = DMA_PERIPHERAL_TO_MEMORY; - dma_initpara.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; - dma_initpara.memory_width = DMA_MEMORY_WIDTH_16BIT; - dma_initpara.periph_inc = DMA_PERIPH_INCREASE_DISABLE; - dma_initpara.memory_inc = DMA_MEMORY_INCREASE_ENABLE; - dma_initpara.number = kAdcChannelCount; - dma_initpara.priority = DMA_PRIORITY_HIGH; - dma_init(kAdcDmaPeriph, kAdcDmaChannel, &dma_initpara); - dma_circulation_enable(kAdcDmaPeriph, kAdcDmaChannel); - dma_channel_enable(kAdcDmaPeriph, kAdcDmaChannel); -} -} // namespace - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 完成 ADC 双通道扫描、DMA 循环搬运、内部通道使能与校准流程配置。 - */ -void adc_hw_init(void) -{ - rcu_periph_clock_enable(RCU_ADC0); - rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); - - adc_dma_init(); - adc_deinit(CONFIG_ADC_INSTANCE); - adc_mode_config(ADC_MODE_FREE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_SCAN_MODE, ENABLE); - adc_special_function_config(CONFIG_ADC_INSTANCE, ADC_CONTINUOUS_MODE, ENABLE); - adc_data_alignment_config(CONFIG_ADC_INSTANCE, ADC_DATAALIGN_RIGHT); - adc_channel_length_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, kAdcChannelCount); - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 0U, CONFIG_ADC_TEMP_CHANNEL, CONFIG_ADC_SAMPLE_TIME); - adc_regular_channel_config(CONFIG_ADC_INSTANCE, 1U, CONFIG_ADC_VREFINT_CHANNEL, CONFIG_ADC_SAMPLE_TIME); - adc_external_trigger_source_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE); - adc_external_trigger_config(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL, DISABLE); - adc_dma_mode_enable(CONFIG_ADC_INSTANCE); - - adc_tempsensor_vrefint_enable(); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - - adc_enable(CONFIG_ADC_INSTANCE); - delay_ms(CONFIG_ADC_STABILIZE_DELAY_MS); - adc_calibration_enable(CONFIG_ADC_INSTANCE); - adc_software_trigger_enable(CONFIG_ADC_INSTANCE, ADC_REGULAR_CHANNEL); - delay_ms(1U); - g_adc_dma_ready = 1U; -} - -/** - * @brief 查询 ADC DMA 循环缓存是否已完成首次有效填充。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示缓存已可用,返回 0 表示仍未准备好。 - */ -uint8_t adc_dma_ready(void) -{ - return g_adc_dma_ready; -} - -/** - * @brief 获取 ADC DMA 原始循环缓存只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const uint16_t* 返回长度为 2 的原始缓存指针,顺序为温度通道、VREF 通道。 - */ -const uint16_t *adc_dma_buffer_get(void) -{ - return (const uint16_t *)g_adc_dma_buffer; -} - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 在 DMA 缓存模式下,该函数优先返回已缓存的对应通道原始值;若通道不受支持则返回 0。 - */ -uint16_t adc_single_read(uint8_t channel) -{ - if(channel == CONFIG_ADC_TEMP_CHANNEL) { - return g_adc_dma_buffer[0]; - } - if(channel == CONFIG_ADC_VREFINT_CHANNEL) { - return g_adc_dma_buffer[1]; - } - return 0U; -} - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void) -{ - return adc_single_read(CONFIG_ADC_VREFINT_CHANNEL); -} - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void) -{ - return adc_single_read(CONFIG_ADC_TEMP_CHANNEL); -} - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当 vref_raw 为 0 时返回默认 3.3V,避免出现除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw) -{ - if(vref_raw == 0U) { - return CONFIG_ADC_DEFAULT_VDDA; - } - return (CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE * CONFIG_ADC_MAX_VALUE) / static_cast(vref_raw); -} - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda) -{ - const float sensor_voltage = (static_cast(temp_raw) * vdda) / CONFIG_ADC_MAX_VALUE; - return ((CONFIG_ADC_TEMP_V25 - sensor_voltage) / CONFIG_ADC_TEMP_AVG_SLOPE) + 25.0f; -} - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行任何数据写入。 - */ -void adc_collect_sample(adc_sample_t *sample) -{ - if(sample == nullptr) { - return; - } - - sample->temp_raw = adc_read_temp_raw(); - sample->vref_raw = adc_read_vref_raw(); - sample->vdda = adc_calculate_vdda(sample->vref_raw); - sample->temperature = adc_calculate_temperature(sample->temp_raw, sample->vdda); -} diff --git a/GD32E508_DCU_APP/device/CANFD.cpp b/GD32E508_DCU_APP/device/CANFD.cpp index 1f3846d..0a35cf4 100644 --- a/GD32E508_DCU_APP/device/CANFD.cpp +++ b/GD32E508_DCU_APP/device/CANFD.cpp @@ -8,36 +8,81 @@ #include "sys/config.h" namespace { -constexpr uint32_t kSlpGpio = GPIOA; -constexpr uint32_t kSlpPin = GPIO_PIN_8; - -struct CanFdTxBuffer { +struct TxFrame { can_trasnmit_message_struct tx_message; uint8_t payload[64]; - uint8_t valid; }; -CanFdTxBuffer s_txBuffer; +struct TxQueue { + TxFrame frames[4]; + uint8_t head; + uint8_t tail; + uint8_t count; +}; + +struct CanChannelConfig { + uint32_t canPeriph; + rcu_periph_enum canRcu; + uint32_t txPort; + uint32_t txPin; + uint32_t rxPort; + uint32_t rxPin; + uint32_t slpPort; + uint32_t slpPin; + IRQn_Type rx0Irq; + uint8_t filterNumber; +}; + +constexpr CanChannelConfig kChannels[] = { + { CAN0, RCU_CAN0, GPIOA, GPIO_PIN_12, GPIOA, GPIO_PIN_11, GPIOA, GPIO_PIN_8, CAN0_RX0_IRQn, 0U }, + { CAN1, RCU_CAN1, GPIOB, GPIO_PIN_12, GPIOB, GPIO_PIN_13, GPIOB, GPIO_PIN_14, CAN1_RX0_IRQn, 1U }, + { CAN2, RCU_CAN2, GPIOE, GPIO_PIN_1, GPIOE, GPIO_PIN_0, GPIOB, GPIO_PIN_9, CAN2_RX0_IRQn, 2U }, +}; + +constexpr size_t kChannelCount = sizeof(kChannels) / sizeof(kChannels[0]); +constexpr uint8_t kRxQueueDepth = 4U; +constexpr uint8_t kTxQueueDepth = 4U; } // namespace -CanFd::Diag CanFd::s_diag; -CanFd::RxFrame CanFd::s_rxFrame; +CanFd::Diag CanFd::s_diag{}; +CanFd::RxQueue CanFd::s_rxQueues[3]{}; +uint8_t CanFd::s_nextConsumeChannel = 0U; +static TxQueue s_txQueues[3]{}; +/** + * @brief 初始化三路 CANFD 相关 GPIO。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 为 CAN0/CAN1/CAN2 的 TX、RX 及收发器 SLP 控制脚统一完成 GPIO 时钟与模式配置。 + */ void CanFd::initGpio() { - rcu_periph_clock_enable(CONFIG_CAN_RCU); rcu_periph_clock_enable(RCU_GPIOA); + rcu_periph_clock_enable(RCU_GPIOB); + rcu_periph_clock_enable(RCU_GPIOE); rcu_periph_clock_enable(RCU_AF); - gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11); - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12); - gpio_init(kSlpGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, kSlpPin); + for(size_t i = 0; i < kChannelCount; ++i) { + const auto &ch = kChannels[i]; + gpio_init(ch.rxPort, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, ch.rxPin); + gpio_init(ch.txPort, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, ch.txPin); + gpio_init(ch.slpPort, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, ch.slpPin); + } } -void CanFd::filterAcceptAll() +/** + * @brief 为指定 CAN 控制器配置全接收过滤器。 + * @param[in] canPeriph 目标 CAN 外设实例。 + * @param[in] filterNumber 过滤器编号。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前使用 32 位 mask 模式放行全部报文,并统一进入 FIFO0。 + */ +void CanFd::filterAcceptAll(uint32_t canPeriph, uint8_t filterNumber) { can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; + can_filter.filter_number = filterNumber; can_filter.filter_mode = CAN_FILTERMODE_MASK; can_filter.filter_bits = CAN_FILTERBITS_32BIT; can_filter.filter_list_high = 0x0000U; @@ -46,10 +91,17 @@ void CanFd::filterAcceptAll() can_filter.filter_mask_low = 0x0000U; can_filter.filter_fifo_number = CAN_FIFO0; can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); + can_filter_init(canPeriph, &can_filter); } -void CanFd::initNominalTiming() +/** + * @brief 配置指定 CAN 控制器的标称仲裁段位时序。 + * @param[in] canPeriph 目标 CAN 外设实例。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前按 1 Mbps 仲裁段参数完成普通 CAN 初始化。 + */ +void CanFd::initNominalTiming(uint32_t canPeriph) { can_parameter_struct can_parameter{}; @@ -65,10 +117,17 @@ void CanFd::initNominalTiming() can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); + can_init(canPeriph, &can_parameter); } -void CanFd::initFdMode() +/** + * @brief 配置指定 CAN 控制器的 CAN FD 数据段参数。 + * @param[in] canPeriph 目标 CAN 外设实例。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 在 GD32E508 平台下启用 FD、BRS 与 TDC;非该平台则仅使能 FD 功能。 + */ +void CanFd::initFdMode(uint32_t canPeriph) { #ifdef GD32E508 can_fdframe_struct can_fd_parameter{}; @@ -88,30 +147,30 @@ void CanFd::initFdMode() can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); + can_fd_init(canPeriph, &can_fd_parameter); #else - can_fd_function_enable(CONFIG_CAN_INSTANCE); + can_fd_function_enable(canPeriph); #endif } +/** + * @brief 构造内部发送缓冲中的状态帧内容。 + * @param[in] status 指向状态载荷的指针。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前实现中状态帧构造逻辑已内联至 `enqueueTxFrame()`,此函数仅保留接口兼容性。 + */ void CanFd::buildStatusFrame(const StatusPayload *status) { + if(status == nullptr) { + return; + } + const int16_t temp_x100 = static_cast(status->temperature * 100.0f); const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &s_txBuffer.tx_message); - s_txBuffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - s_txBuffer.tx_message.tx_efid = 0U; - s_txBuffer.tx_message.tx_ff = CAN_FF_STANDARD; - s_txBuffer.tx_message.tx_ft = CAN_FT_DATA; - s_txBuffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - s_txBuffer.tx_message.fd_flag = ENABLE; - s_txBuffer.tx_message.fd_brs = ENABLE; - s_txBuffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = s_txBuffer.payload; + auto &frame = s_txQueues[0].frames[0]; + auto &p = frame.payload; p[0] = static_cast(status->temp_raw & 0xFFU); p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); p[2] = static_cast(status->vref_raw & 0xFFU); @@ -124,109 +183,345 @@ void CanFd::buildStatusFrame(const StatusPayload *status) p[9] = CONFIG_CAN_STATUS_TAG1; p[10] = CONFIG_CAN_STATUS_TAG2; p[11] = CONFIG_CAN_STATUS_TAG3; +} - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - s_txBuffer.tx_message.tx_data[i] = p[i]; +/** + * @brief 向指定 CAN 通道的发送 FIFO 入队一帧状态报文。 + * @param[in] channelIndex 目标 CAN 通道索引(0/1/2)。 + * @param[in] status 指向状态载荷的指针。 + * @param[out] 无。 + * @retval bool true 表示成功入队,false 表示参数无效或该通道发送队列已满。 + * @note 仅完成软件发送队列入队,不会立即触发硬件发送。 + */ +bool CanFd::enqueueTxFrame(uint8_t channelIndex, const StatusPayload *status) +{ + if(status == nullptr || channelIndex >= kChannelCount) { + return false; } - s_txBuffer.valid = 1U; -} -void CanFd::init() -{ - initGpio(); - setNormalMode(); - can_deinit(CONFIG_CAN_INSTANCE); - initNominalTiming(); - initFdMode(); - filterAcceptAll(); - - can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); - nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); - - s_rxFrame.valid = 0U; - s_txBuffer.valid = 0U; -} - -void CanFd::poll() -{ - /* 已由 CAN0_RX0_IRQHandler 中断驱动 */ -} - -void CanFd::prepareStatus(const StatusPayload *status) -{ - if(status == nullptr) { - s_txBuffer.valid = 0U; - return; + auto &queue = s_txQueues[channelIndex]; + if(queue.count >= kTxQueueDepth) { + s_diag.tx_drop_count++; + return false; } + buildStatusFrame(status); -} -void CanFd::sendPrepared() -{ - if(s_txBuffer.valid == 0U) return; - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &s_txBuffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - s_diag.tx_count++; - s_diag.last_payload_length = s_txBuffer.tx_message.tx_dlen; - s_diag.last_tx_id = s_txBuffer.tx_message.tx_sfid; - } else { - s_diag.error_count++; + auto &frame = queue.frames[queue.tail]; + can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &frame.tx_message); + frame.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; + frame.tx_message.tx_efid = 0U; + frame.tx_message.tx_ff = CAN_FF_STANDARD; + frame.tx_message.tx_ft = CAN_FT_DATA; + frame.tx_message.tx_dlen = CANFD_STATUS_DLEN; +#ifdef GD32E508 + frame.tx_message.fd_flag = ENABLE; + frame.tx_message.fd_brs = ENABLE; + frame.tx_message.fd_esi = CAN_ESI_DOMINANT; +#endif + + const auto &src = s_txQueues[0].frames[0].payload; + auto &p = frame.payload; + for(uint8_t j = 0; j < CANFD_STATUS_DLEN; ++j) { + p[j] = src[j]; + frame.tx_message.tx_data[j] = p[j]; } -} -bool CanFd::hasRxFrame() -{ - return s_rxFrame.valid != 0U; -} - -bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(s_rxFrame.valid == 0U) return false; - if(id) *id = s_rxFrame.id; - if(length) *length = s_rxFrame.length; - if(data) { for(uint8_t i = 0; i < s_rxFrame.length; ++i) data[i] = s_rxFrame.data[i]; } - s_rxFrame.valid = 0U; + queue.tail = static_cast((queue.tail + 1U) % kTxQueueDepth); + queue.count++; return true; } +/** + * @brief 初始化三路 CANFD 控制器、过滤器、中断与软件队列。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 初始化后默认将三路 TCAN1057A 收发器置为 Normal,并清零收发诊断状态。 + */ +void CanFd::init() +{ + s_diag = {}; + s_nextConsumeChannel = 0U; + + initGpio(); + + for(size_t i = 0; i < kChannelCount; ++i) { + const auto &ch = kChannels[i]; + rcu_periph_clock_enable(ch.canRcu); + gpio_bit_reset(ch.slpPort, ch.slpPin); /* STB=0 -> Normal */ + can_deinit(ch.canPeriph); + initNominalTiming(ch.canPeriph); + initFdMode(ch.canPeriph); + filterAcceptAll(ch.canPeriph, ch.filterNumber); + can_interrupt_enable(ch.canPeriph, CAN_INT_RFNE0); + nvic_irq_enable(ch.rx0Irq, 1U, static_cast(i)); + + s_rxQueues[i].head = 0U; + s_rxQueues[i].tail = 0U; + s_rxQueues[i].count = 0U; + s_txQueues[i].head = 0U; + s_txQueues[i].tail = 0U; + s_txQueues[i].count = 0U; + } + + s_nextConsumeChannel = 0U; +} + +/** + * @brief 执行兼容保留的 CAN 轮询入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前三路接收均由 RX0 中断驱动,该函数仅保留旧调用兼容性。 + */ +void CanFd::poll() +{ + /* 兼容保留:三通道接收已由 RX0 中断驱动 */ +} + +/** + * @brief 根据状态载荷为三路发送队列批量准备状态报文。 + * @param[in] status 指向状态载荷的指针;为空时直接返回。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前默认不会周期性调用;仅在外部显式触发发送测试或业务发送时使用。 + */ +void CanFd::prepareStatus(const StatusPayload *status) +{ + if(status == nullptr) { + return; + } + + for(size_t i = 0; i < kChannelCount; ++i) { + (void)enqueueTxFrame(static_cast(i), status); + } +} + +/** + * @brief 根据状态载荷仅为指定通道准备一帧状态报文。 + * @param[in] channelIndex 目标 CAN 通道索引(0/1/2)。 + * @param[in] status 指向状态载荷的指针;为空时返回失败。 + * @param[out] 无。 + * @retval bool true 表示成功入队,false 表示参数非法或发送队列已满。 + */ +bool CanFd::prepareStatusForChannel(uint8_t channelIndex, const StatusPayload *status) +{ + return enqueueTxFrame(channelIndex, status); +} + +/** + * @brief 将当前各通道已准备好的状态报文送入硬件邮箱发送。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前默认不会周期性调用;仅处理调用方显式准备过的发送队列内容。 + */ +void CanFd::sendPrepared() +{ + for(size_t i = 0; i < kChannelCount; ++i) { + auto &queue = s_txQueues[i]; + if(queue.count == 0U) { + continue; + } + + auto &frame = queue.frames[queue.head]; + const uint8_t mailbox = can_message_transmit(kChannels[i].canPeriph, &frame.tx_message); + if(mailbox != CAN_NOMAILBOX) { + s_diag.tx_count++; + s_diag.last_payload_length = frame.tx_message.tx_dlen; + s_diag.last_tx_id = frame.tx_message.tx_sfid; + s_diag.last_tx_channel = static_cast(i); + queue.head = static_cast((queue.head + 1U) % kTxQueueDepth); + queue.count--; + } else { + s_diag.error_count++; + } + } +} + +/** + * @brief 查询三路 CAN 通道是否存在待消费接收报文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示至少一条接收队列非空,false 表示当前三路均无待消费报文。 + */ +bool CanFd::hasRxFrame() +{ + for(size_t i = 0; i < kChannelCount; ++i) { + if(s_rxQueues[i].count != 0U) { + return true; + } + } + return false; +} + +/** + * @brief 轮转读取并消费一帧接收报文。 + * @param[in] 无。 + * @param[out] id 输出报文标识符;允许为空。 + * @param[out] data 输出报文数据缓存;允许为空。 + * @param[out] length 输出报文长度;允许为空。 + * @param[out] channel 输出报文来源通道号;允许为空。 + * @retval bool true 表示成功消费一帧报文,false 表示当前三路接收队列均为空。 + * @note 消费顺序采用从 `s_nextConsumeChannel` 开始的轮转扫描,避免长期偏向固定通道。 + */ +bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t *channel) +{ + RxFrame localFrame{}; + bool found = false; + + __disable_irq(); + for(size_t n = 0; n < kChannelCount; ++n) { + const uint8_t idx = static_cast((s_nextConsumeChannel + n) % kChannelCount); + auto &queue = s_rxQueues[idx]; + if(queue.count == 0U) { + continue; + } + + localFrame = queue.frames[queue.head]; + queue.head = static_cast((queue.head + 1U) % kRxQueueDepth); + queue.count--; + s_nextConsumeChannel = static_cast((idx + 1U) % kChannelCount); + found = true; + break; + } + __enable_irq(); + + if(!found) { + return false; + } + + if(channel) *channel = localFrame.channel; + if(id) *id = localFrame.id; + if(length) *length = localFrame.length; + if(data) { + for(uint8_t i = 0; i < localFrame.length; ++i) { + data[i] = localFrame.data[i]; + } + } + return true; +} + +/** + * @brief 获取 CANFD 诊断统计信息只读指针。 + * @param[in] 无。 + * @param[out] 无。 + * @retval const CanFd::Diag* 返回内部诊断统计结构体只读指针。 + */ const CanFd::Diag *CanFd::diag() { return &s_diag; } +/** + * @brief 将三路 TCAN1057A 收发器置为 Normal 模式。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 对所有通道统一将 SLP/STB 控制脚拉低。 + */ void CanFd::setNormalMode() { - gpio_bit_reset(kSlpGpio, kSlpPin); + for(size_t i = 0; i < kChannelCount; ++i) { + gpio_bit_reset(kChannels[i].slpPort, kChannels[i].slpPin); + } } +/** + * @brief 将三路 TCAN1057A 收发器置为 Silent 模式。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 对所有通道统一将 SLP/STB 控制脚拉高。 + */ void CanFd::setSilentMode() { - gpio_bit_set(kSlpGpio, kSlpPin); + for(size_t i = 0; i < kChannelCount; ++i) { + gpio_bit_set(kChannels[i].slpPort, kChannels[i].slpPin); + } } -void CanFd::onRx0Interrupt() +/** + * @brief 处理指定通道的 RX0 中断接收。 + * @param[in] channelIndex 目标 CAN 通道索引(0/1/2)。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 从对应控制器 FIFO0 取出一帧报文,更新诊断统计,并写入该通道软件接收队列。 + */ +void CanFd::handleRxInterrupt(uint8_t channelIndex) { - if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) return; + if(channelIndex >= kChannelCount) return; + const auto &ch = kChannels[channelIndex]; + + if(can_interrupt_flag_get(ch.canPeriph, CAN_INT_FLAG_RFL0) == RESET) return; can_receive_message_struct rx_message{}; can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); + can_message_receive(ch.canPeriph, CAN_FIFO0, &rx_message); s_diag.rx_count++; + s_diag.last_rx_channel = channelIndex; s_diag.last_payload_length = rx_message.rx_dlen; s_diag.last_rx_fd_flag = rx_message.fd_flag; s_diag.last_rx_brs = rx_message.fd_brs; s_diag.last_rx_esi = rx_message.fd_esi; s_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - s_rxFrame.id = s_diag.last_rx_id; - s_rxFrame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) - s_rxFrame.data[i] = rx_message.rx_data[i]; - s_rxFrame.valid = 1U; + auto &queue = s_rxQueues[channelIndex]; + if(queue.count >= kRxQueueDepth) { + s_diag.rx_drop_count++; + } else { + auto &frame = queue.frames[queue.tail]; + frame.channel = channelIndex; + frame.id = s_diag.last_rx_id; + frame.length = rx_message.rx_dlen; + for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { + frame.data[i] = rx_message.rx_data[i]; + } + queue.tail = static_cast((queue.tail + 1U) % kRxQueueDepth); + queue.count++; + } - can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); + can_interrupt_flag_clear(ch.canPeriph, CAN_INT_FLAG_RFL0); +} + +/** + * @brief CAN0 兼容中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 兼容保留入口,内部统一转调 `handleRxInterrupt(0U)`。 + */ +void CanFd::onRx0Interrupt() +{ + handleRxInterrupt(0U); } /* ----- 中断入口 C 包装 ------------------------------------------------- */ -extern "C" void CAN0_RX0_IRQHandler(void) { CanFd::onRx0Interrupt(); } \ No newline at end of file +/** + * @brief CAN0 RX0 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note C 向量包装函数,内部转调 `CanFd::handleRxInterrupt(0U)`。 + */ +extern "C" void CAN0_RX0_IRQHandler(void) { CanFd::handleRxInterrupt(0U); } + +/** + * @brief CAN1 RX0 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note C 向量包装函数,内部转调 `CanFd::handleRxInterrupt(1U)`。 + */ +extern "C" void CAN1_RX0_IRQHandler(void) { CanFd::handleRxInterrupt(1U); } + +/** + * @brief CAN2 RX0 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note C 向量包装函数,内部转调 `CanFd::handleRxInterrupt(2U)`。 + */ +extern "C" void CAN2_RX0_IRQHandler(void) { CanFd::handleRxInterrupt(2U); } diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_align_app b/GD32E508_DCU_APP/device/CANFD.cpp.bak_align_app deleted file mode 100644 index 8481d48..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_align_app +++ /dev/null @@ -1,278 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN 外设所需 GPIO 引脚。 - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOB); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); - gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - * @note 参考 APP 项目配置:仲裁段波特率为 1 Mbps,采样点约 80%。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = DISABLE; - can_parameter.trans_fifo_order = DISABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 参考 APP 项目配置: - * - 仲裁段保持 1 Mbps; - * - 数据段配置为 2 Mbps,采样点约 80%; - * - 发送时启用 BRS 后才会切到数据段速率。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = ENABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @note 若当前没有待接收报文,直接返回。 - */ -void canfd_poll(void) -{ - can_receive_message_struct rx_message{}; - - if(can_receive_message_length_get(CONFIG_CAN_INSTANCE, CAN_FIFO0) == 0U) { - return; - } - - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_can_isr b/GD32E508_DCU_APP/device/CANFD.cpp.bak_can_isr deleted file mode 100644 index 651b365..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_can_isr +++ /dev/null @@ -1,283 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN 外设所需 GPIO 引脚。 - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOB); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); - gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - * @note 参考 APP 项目配置:仲裁段波特率为 1 Mbps,采样点约 80%。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = ENABLE; - can_parameter.trans_fifo_order = ENABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 参考 APP 项目配置: - * - 仲裁段保持 1 Mbps; - * - 数据段配置为 2 Mbps,采样点约 80%; - * - 发送时启用 BRS 后才会切到数据段速率。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - can_fd_tdc_struct can_fd_tdc_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_tdc_parameter.tdc_filter = 0x04U; - can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; - can_fd_tdc_parameter.tdc_offset = 0x04U; - can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = ENABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @note 若当前没有待接收报文,直接返回。 - */ -void canfd_poll(void) -{ - can_receive_message_struct rx_message{}; - - if(can_receive_message_length_get(CONFIG_CAN_INSTANCE, CAN_FIFO0) == 0U) { - return; - } - - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrate b/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrate deleted file mode 100644 index 1246bc5..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrate +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN 外设所需 GPIO 引脚。 - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOB); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); - gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = DISABLE; - can_parameter.trans_fifo_order = DISABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_8TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_3TQ; - can_parameter.prescaler = CONFIG_CAN_NOMINAL_BAUD_PRESCALER; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 在 GD32E508 上启用 ISO 模式;非 GD32E508 平台仅启用 FD 功能。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = DISABLE; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 1U; - can_fd_parameter.data_resync_jump_width = 0U; - can_fd_parameter.data_time_segment_1 = 2U; - can_fd_parameter.data_time_segment_2 = 1U; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = CAN_BRS_DISABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @note 若当前没有待接收报文,直接返回。 - */ -void canfd_poll(void) -{ - can_receive_message_struct rx_message{}; - - if(can_receive_message_length_get(CONFIG_CAN_INSTANCE, CAN_FIFO0) == 0U) { - return; - } - - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrcu b/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrcu deleted file mode 100644 index 099c72e..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_canrcu +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN 外设所需 GPIO 引脚。 - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_INSTANCE); - rcu_periph_clock_enable(RCU_GPIOB); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); - gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = DISABLE; - can_parameter.trans_fifo_order = DISABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_8TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_3TQ; - can_parameter.prescaler = CONFIG_CAN_NOMINAL_BAUD_PRESCALER; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 在 GD32E508 上启用 ISO 模式;非 GD32E508 平台仅启用 FD 功能。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = DISABLE; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 1U; - can_fd_parameter.data_resync_jump_width = 0U; - can_fd_parameter.data_time_segment_1 = 2U; - can_fd_parameter.data_time_segment_2 = 1U; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = CAN_BRS_DISABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @note 若当前没有待接收报文,直接返回。 - */ -void canfd_poll(void) -{ - can_receive_message_struct rx_message{}; - - if(can_receive_message_length_get(CONFIG_CAN_INSTANCE, CAN_FIFO0) == 0U) { - return; - } - - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_hideimpl b/GD32E508_DCU_APP/device/CANFD.cpp.bak_hideimpl deleted file mode 100644 index 8014881..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_hideimpl +++ /dev/null @@ -1,225 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信模块实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { -constexpr uint32_t kSlpGpio = GPIOA; -constexpr uint32_t kSlpPin = GPIO_PIN_8; -} // namespace - -CanFd::Diag CanFd::s_diag; -CanFd::RxFrame CanFd::s_rxFrame; -CanFd::TxBuffer CanFd::s_txBuffer; - -void CanFd::initGpio() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOA); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11); - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12); - gpio_init(kSlpGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, kSlpPin); -} - -void CanFd::filterAcceptAll() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -void CanFd::initNominalTiming() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = ENABLE; - can_parameter.trans_fifo_order = ENABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -void CanFd::initFdMode() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - can_fd_tdc_struct can_fd_tdc_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_tdc_parameter.tdc_filter = 0x04U; - can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; - can_fd_tdc_parameter.tdc_offset = 0x04U; - can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -void CanFd::buildStatusFrame(const StatusPayload *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &s_txBuffer.tx_message); - s_txBuffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - s_txBuffer.tx_message.tx_efid = 0U; - s_txBuffer.tx_message.tx_ff = CAN_FF_STANDARD; - s_txBuffer.tx_message.tx_ft = CAN_FT_DATA; - s_txBuffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - s_txBuffer.tx_message.fd_flag = ENABLE; - s_txBuffer.tx_message.fd_brs = ENABLE; - s_txBuffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = s_txBuffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - s_txBuffer.tx_message.tx_data[i] = p[i]; - } - s_txBuffer.valid = 1U; -} - -void CanFd::init() -{ - initGpio(); - setNormalMode(); - can_deinit(CONFIG_CAN_INSTANCE); - initNominalTiming(); - initFdMode(); - filterAcceptAll(); - - can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); - nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); - - s_rxFrame.valid = 0U; - s_txBuffer.valid = 0U; -} - -void CanFd::poll() -{ - /* 已由 CAN0_RX0_IRQHandler 中断驱动 */ -} - -void CanFd::prepareStatus(const StatusPayload *status) -{ - if(status == nullptr) { - s_txBuffer.valid = 0U; - return; - } - buildStatusFrame(status); -} - -void CanFd::sendPrepared() -{ - if(s_txBuffer.valid == 0U) return; - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &s_txBuffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - s_diag.tx_count++; - s_diag.last_payload_length = s_txBuffer.tx_message.tx_dlen; - s_diag.last_tx_id = s_txBuffer.tx_message.tx_sfid; - } else { - s_diag.error_count++; - } -} - -bool CanFd::hasRxFrame() -{ - return s_rxFrame.valid != 0U; -} - -bool CanFd::consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(s_rxFrame.valid == 0U) return false; - if(id) *id = s_rxFrame.id; - if(length) *length = s_rxFrame.length; - if(data) { for(uint8_t i = 0; i < s_rxFrame.length; ++i) data[i] = s_rxFrame.data[i]; } - s_rxFrame.valid = 0U; - return true; -} - -const CanFd::Diag *CanFd::diag() -{ - return &s_diag; -} - -void CanFd::setNormalMode() -{ - gpio_bit_reset(kSlpGpio, kSlpPin); -} - -void CanFd::setSilentMode() -{ - gpio_bit_set(kSlpGpio, kSlpPin); -} - -void CanFd::onRx0Interrupt() -{ - if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) return; - - can_receive_message_struct rx_message{}; - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - - s_diag.rx_count++; - s_diag.last_payload_length = rx_message.rx_dlen; - s_diag.last_rx_fd_flag = rx_message.fd_flag; - s_diag.last_rx_brs = rx_message.fd_brs; - s_diag.last_rx_esi = rx_message.fd_esi; - s_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - s_rxFrame.id = s_diag.last_rx_id; - s_rxFrame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) - s_rxFrame.data[i] = rx_message.rx_data[i]; - s_rxFrame.valid = 1U; - - can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); -} - -/* ----- 中断入口 C 包装 ------------------------------------------------- */ -extern "C" void CAN0_RX0_IRQHandler(void) { CanFd::onRx0Interrupt(); } \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_oop b/GD32E508_DCU_APP/device/CANFD.cpp.bak_oop deleted file mode 100644 index 0c6674a..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_oop +++ /dev/null @@ -1,326 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { -constexpr uint32_t kCanSlpGpio = GPIOA; -constexpr uint32_t kCanSlpPin = GPIO_PIN_8; - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN0 外设所需 GPIO 引脚。 - * @note 按原理图连接关系配置: - * - PA12 -> CAN0_TX - * - PA11 -> CAN0_RX - * - PA8 -> CAN0_SLP(连接 TCAN1057A #0 模式控制脚) - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOA); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11); - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12); - gpio_init(kCanSlpGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, kCanSlpPin); -} - -/** - * @brief 将 TCAN1057A #0 置为正常工作模式。 - * @note 模式控制脚按 STB 语义处理:低电平为 Normal,高电平为 Silent。 - */ -inline void can_transceiver_normal_mode() -{ - gpio_bit_reset(kCanSlpGpio, kCanSlpPin); -} - -/** - * @brief 将 TCAN1057A #0 置为静默模式。 - * @note 静默模式下收发器不驱动总线显性位,可用于总线监听或受控隔离场景。 - */ -inline void can_transceiver_silent_mode() -{ - gpio_bit_set(kCanSlpGpio, kCanSlpPin); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - * @note 参考 APP 项目配置:仲裁段波特率为 1 Mbps,采样点约 80%。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = ENABLE; - can_parameter.trans_fifo_order = ENABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 参考 APP 项目配置: - * - 仲裁段保持 1 Mbps; - * - 数据段配置为 2 Mbps,采样点约 80%; - * - 发送时启用 BRS 后才会切到数据段速率。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - can_fd_tdc_struct can_fd_tdc_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_tdc_parameter.tdc_filter = 0x04U; - can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; - can_fd_tdc_parameter.tdc_offset = 0x04U; - can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = ENABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief CAN0 RX0 中断服务例程。 - * @note 在 CANFD 帧到达 FIFO0 时自动执行,将报文缓存到内部接收帧。 - */ -extern "C" void CAN0_RX0_IRQHandler(void) -{ - if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) { - return; - } - - can_receive_message_struct rx_message{}; - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; - - can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); -} - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数、接收过滤器与中断。 - * @note 启用 FIFO0 RX 中断替代轮询,TX 保持 mailbox 异步发送;GPIO 与原理图一致使用 PA11/PA12/PA8。 - * 其中 PA8 已封装为正常/静默两个模式控制函数,初始化时默认进入 Normal 模式。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_transceiver_normal_mode(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - - /* 使能 FIFO0 接收中断,替代轮询 */ - can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); - nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); - - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO(中断模式下退化为兼容空壳)。 - * @note 实际接收已由 CAN0_RX0_IRQHandler 以中断方式完成,此函数保留接口不破坏现有调用链。 - */ -void canfd_poll(void) -{ - /* 接收已由 CAN0_RX0_IRQHandler 中断驱动 */ -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_pa8mode b/GD32E508_DCU_APP/device/CANFD.cpp.bak_pa8mode deleted file mode 100644 index 5708b56..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_pa8mode +++ /dev/null @@ -1,319 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { -constexpr uint32_t kCanSlpGpio = GPIOA; -constexpr uint32_t kCanSlpPin = GPIO_PIN_8; - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN0 外设所需 GPIO 引脚。 - * @note 按原理图连接关系配置: - * - PA12 -> CAN0_TX - * - PA11 -> CAN0_RX - * - PA8 -> CAN0_SLP(连接 TCAN1057A #0 模式控制脚) - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOA); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11); - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12); - gpio_init(kCanSlpGpio, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, kCanSlpPin); -} - -/** - * @brief 将 TCAN1057A #0 置为正常工作模式。 - * @note 结合 TCAN1057A-Q1 产品资料:器件工作模式为 Normal / Silent, - * 当前原理图网络名虽然写作 CAN0_SLP,但本质是模式控制脚; - * 这里按 STB=0 -> Normal,STB=1 -> Silent 处理,因此 PA8 拉低进入正常模式。 - */ -inline void can_transceiver_normal_mode() -{ - gpio_bit_reset(kCanSlpGpio, kCanSlpPin); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - * @note 参考 APP 项目配置:仲裁段波特率为 1 Mbps,采样点约 80%。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = ENABLE; - can_parameter.trans_fifo_order = ENABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 参考 APP 项目配置: - * - 仲裁段保持 1 Mbps; - * - 数据段配置为 2 Mbps,采样点约 80%; - * - 发送时启用 BRS 后才会切到数据段速率。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - can_fd_tdc_struct can_fd_tdc_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_tdc_parameter.tdc_filter = 0x04U; - can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; - can_fd_tdc_parameter.tdc_offset = 0x04U; - can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = ENABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief CAN0 RX0 中断服务例程。 - * @note 在 CANFD 帧到达 FIFO0 时自动执行,将报文缓存到内部接收帧。 - */ -extern "C" void CAN0_RX0_IRQHandler(void) -{ - if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) { - return; - } - - can_receive_message_struct rx_message{}; - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; - - can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); -} - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数、接收过滤器与中断。 - * @note 启用 FIFO0 RX 中断替代轮询,TX 保持 mailbox 异步发送;GPIO 与原理图一致使用 PA11/PA12/PA8。 - * 其中 PA8 按 TCAN1057A 的模式控制脚处理:低电平为 Normal,高电平为 Silent。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_transceiver_normal_mode(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - - /* 使能 FIFO0 接收中断,替代轮询 */ - can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); - nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); - - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO(中断模式下退化为兼容空壳)。 - * @note 实际接收已由 CAN0_RX0_IRQHandler 以中断方式完成,此函数保留接口不破坏现有调用链。 - */ -void canfd_poll(void) -{ - /* 接收已由 CAN0_RX0_IRQHandler 中断驱动 */ -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/CANFD.cpp.bak_sch b/GD32E508_DCU_APP/device/CANFD.cpp.bak_sch deleted file mode 100644 index 8da69f4..0000000 --- a/GD32E508_DCU_APP/device/CANFD.cpp.bak_sch +++ /dev/null @@ -1,300 +0,0 @@ -/** - * @file CANFD.cpp - * @brief CANFD 通信外设初始化、收发与诊断实现。 - */ - -#include "main.h" -#include "device/canfd.h" -#include "sys/config.h" - -namespace { - -/** @brief 内部接收帧缓存结构。 */ -struct CanfdRxFrame { - uint32_t id = 0U; - uint8_t data[64] = {0}; - uint8_t length = 0U; - uint8_t valid = 0U; -}; - -/** @brief 内部发送帧缓存结构。 */ -struct CanfdTxBuffer { - can_trasnmit_message_struct tx_message{}; - uint8_t payload[64] = {0}; - uint8_t valid = 0U; -}; - -canfd_diag_t g_can_diag{}; -CanfdRxFrame g_rx_frame{}; -CanfdTxBuffer g_tx_buffer{}; - -/** - * @brief 初始化 CAN 外设所需 GPIO 引脚。 - */ -inline void can_gpio_init() -{ - rcu_periph_clock_enable(CONFIG_CAN_RCU); - rcu_periph_clock_enable(RCU_GPIOB); - rcu_periph_clock_enable(RCU_AF); - - gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); - gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE); -} - -/** - * @brief 配置 CAN 接收过滤器为接受所有报文。 - */ -inline void can_filter_accept_all() -{ - can_filter_parameter_struct can_filter{}; - can_filter.filter_number = 0U; - can_filter.filter_mode = CAN_FILTERMODE_MASK; - can_filter.filter_bits = CAN_FILTERBITS_32BIT; - can_filter.filter_list_high = 0x0000U; - can_filter.filter_list_low = 0x0000U; - can_filter.filter_mask_high = 0x0000U; - can_filter.filter_mask_low = 0x0000U; - can_filter.filter_fifo_number = CAN_FIFO0; - can_filter.filter_enable = ENABLE; - can_filter_init(CONFIG_CAN_INSTANCE, &can_filter); -} - -/** - * @brief 配置 CAN 标称位定时参数。 - * @note 参考 APP 项目配置:仲裁段波特率为 1 Mbps,采样点约 80%。 - */ -inline void can_nominal_init() -{ - can_parameter_struct can_parameter{}; - - can_struct_para_init(CAN_INIT_STRUCT, &can_parameter); - can_parameter.time_triggered = DISABLE; - can_parameter.auto_bus_off_recovery = ENABLE; - can_parameter.auto_wake_up = DISABLE; - can_parameter.auto_retrans = ENABLE; - can_parameter.rec_fifo_overwrite = ENABLE; - can_parameter.trans_fifo_order = ENABLE; - can_parameter.working_mode = CAN_NORMAL_MODE; - can_parameter.resync_jump_width = CAN_BT_SJW_1TQ; - can_parameter.time_segment_1 = CAN_BT_BS1_7TQ; - can_parameter.time_segment_2 = CAN_BT_BS2_2TQ; - can_parameter.prescaler = 6U; - can_init(CONFIG_CAN_INSTANCE, &can_parameter); -} - -/** - * @brief 配置 CANFD 可变速率模式参数。 - * @note 参考 APP 项目配置: - * - 仲裁段保持 1 Mbps; - * - 数据段配置为 2 Mbps,采样点约 80%; - * - 发送时启用 BRS 后才会切到数据段速率。 - */ -inline void can_fd_mode_init() -{ -#ifdef GD32E508 - can_fdframe_struct can_fd_parameter{}; - can_fd_tdc_struct can_fd_tdc_parameter{}; - - can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter); - can_fd_parameter.fd_frame = ENABLE; - can_fd_parameter.excp_event_detect = ENABLE; - can_fd_parameter.delay_compensation = ENABLE; - can_fd_tdc_parameter.tdc_filter = 0x04U; - can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET; - can_fd_tdc_parameter.tdc_offset = 0x04U; - can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter; - can_fd_parameter.iso_bosch = CAN_FDMOD_ISO; - can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE; - can_fd_parameter.data_prescaler = 6U; - can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ; - can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ; - can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ; - can_fd_init(CONFIG_CAN_INSTANCE, &can_fd_parameter); -#else - can_fd_function_enable(CONFIG_CAN_INSTANCE); -#endif -} - -/** - * @brief 根据状态载荷构造 CANFD 状态发送帧并置有效标志。 - * @param[in] status 指向状态载荷的指针;不为空时执行构造和置位。 - */ -inline void canfd_build_status_frame(const canfd_status_payload_t *status) -{ - const int16_t temp_x100 = static_cast(status->temperature * 100.0f); - const uint16_t vdda_x1000 = static_cast(status->vdda * 1000.0f); - - can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &g_tx_buffer.tx_message); - g_tx_buffer.tx_message.tx_sfid = CONFIG_CAN_STATUS_ID; - g_tx_buffer.tx_message.tx_efid = 0U; - g_tx_buffer.tx_message.tx_ff = CAN_FF_STANDARD; - g_tx_buffer.tx_message.tx_ft = CAN_FT_DATA; - g_tx_buffer.tx_message.tx_dlen = CANFD_STATUS_DLEN; -#ifdef GD32E508 - g_tx_buffer.tx_message.fd_flag = ENABLE; - g_tx_buffer.tx_message.fd_brs = ENABLE; - g_tx_buffer.tx_message.fd_esi = CAN_ESI_DOMINANT; -#endif - - auto &p = g_tx_buffer.payload; - p[0] = static_cast(status->temp_raw & 0xFFU); - p[1] = static_cast((status->temp_raw >> 8) & 0xFFU); - p[2] = static_cast(status->vref_raw & 0xFFU); - p[3] = static_cast((status->vref_raw >> 8) & 0xFFU); - p[4] = static_cast(temp_x100 & 0xFF); - p[5] = static_cast((temp_x100 >> 8) & 0xFF); - p[6] = static_cast(vdda_x1000 & 0xFFU); - p[7] = static_cast((vdda_x1000 >> 8) & 0xFFU); - p[8] = CONFIG_CAN_STATUS_TAG0; - p[9] = CONFIG_CAN_STATUS_TAG1; - p[10] = CONFIG_CAN_STATUS_TAG2; - p[11] = CONFIG_CAN_STATUS_TAG3; - - for(uint8_t i = 0; i < CANFD_STATUS_DLEN; ++i) { - g_tx_buffer.tx_message.tx_data[i] = p[i]; - } - g_tx_buffer.valid = 1U; -} -} // namespace - -/** - * @brief CAN0 RX0 中断服务例程。 - * @note 在 CANFD 帧到达 FIFO0 时自动执行,将报文缓存到内部接收帧。 - */ -extern "C" void CAN0_RX0_IRQHandler(void) -{ - if(can_interrupt_flag_get(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0) == RESET) { - return; - } - - can_receive_message_struct rx_message{}; - can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &rx_message); - can_message_receive(CONFIG_CAN_INSTANCE, CAN_FIFO0, &rx_message); - - g_can_diag.rx_count++; - g_can_diag.last_payload_length = rx_message.rx_dlen; - g_can_diag.last_rx_fd_flag = rx_message.fd_flag; - g_can_diag.last_rx_brs = rx_message.fd_brs; - g_can_diag.last_rx_esi = rx_message.fd_esi; - g_can_diag.last_rx_id = (rx_message.rx_ff == CAN_FF_STANDARD) ? rx_message.rx_sfid : rx_message.rx_efid; - - g_rx_frame.id = g_can_diag.last_rx_id; - g_rx_frame.length = rx_message.rx_dlen; - for(uint8_t i = 0; i < rx_message.rx_dlen; ++i) { - g_rx_frame.data[i] = rx_message.rx_data[i]; - } - g_rx_frame.valid = 1U; - - can_interrupt_flag_clear(CONFIG_CAN_INSTANCE, CAN_INT_FLAG_RFL0); -} - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数、接收过滤器与中断。 - * @note 启用 FIFO0 RX 中断替代轮询,TX 保持 mailbox 异步发送。 - */ -void canfd_init(void) -{ - can_gpio_init(); - can_deinit(CONFIG_CAN_INSTANCE); - can_nominal_init(); - can_fd_mode_init(); - can_filter_accept_all(); - - /* 使能 FIFO0 接收中断,替代轮询 */ - can_interrupt_enable(CONFIG_CAN_INSTANCE, CAN_INT_RFNE0); - nvic_irq_enable(CAN0_RX0_IRQn, 1U, 1U); - - g_rx_frame.valid = 0U; - g_tx_buffer.valid = 0U; -} - -/** - * @brief 轮询 CANFD 接收 FIFO(中断模式下退化为兼容空壳)。 - * @note 实际接收已由 CAN0_RX0_IRQHandler 以中断方式完成,此函数保留接口不破坏现有调用链。 - */ -void canfd_poll(void) -{ - /* 接收已由 CAN0_RX0_IRQHandler 中断驱动 */ -} - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status) -{ - if(status == nullptr) { - g_tx_buffer.valid = 0U; - return; - } - - canfd_build_status_frame(status); -} - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @note 若当前没有有效待发送报文,直接返回。 - */ -void canfd_send_prepared(void) -{ - if(g_tx_buffer.valid == 0U) { - return; - } - - const uint8_t mailbox = can_message_transmit(CONFIG_CAN_INSTANCE, &g_tx_buffer.tx_message); - if(mailbox != CAN_NOMAILBOX) { - g_can_diag.tx_count++; - g_can_diag.last_payload_length = g_tx_buffer.tx_message.tx_dlen; - g_can_diag.last_tx_id = g_tx_buffer.tx_message.tx_sfid; - } else { - g_can_diag.error_count++; - } -} - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @retval 非 0 存在待消费报文,0 无报文。 - */ -uint8_t canfd_has_rx_frame(void) -{ - return g_rx_frame.valid; -} - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval 1 成功消费一帧报文,0 当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length) -{ - if(g_rx_frame.valid == 0U) { - return 0U; - } - - if(id != nullptr) { - *id = g_rx_frame.id; - } - if(length != nullptr) { - *length = g_rx_frame.length; - } - if(data != nullptr) { - for(uint8_t i = 0; i < g_rx_frame.length; ++i) { - data[i] = g_rx_frame.data[i]; - } - } - - g_rx_frame.valid = 0U; - return 1U; -} - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @retval 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void) -{ - return &g_can_diag; -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/Timer.cpp b/GD32E508_DCU_APP/device/Timer.cpp index 343c384..cc90e03 100644 --- a/GD32E508_DCU_APP/device/Timer.cpp +++ b/GD32E508_DCU_APP/device/Timer.cpp @@ -8,6 +8,13 @@ #include "sys/task_manager.h" #include "sys/config.h" +/** + * @brief 配置用户调度定时器本体参数。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 使用 `CONFIG_SCHED_TIMER_*` 系列配置完成 TIMER2 的 100us 调度时基初始化。 + */ void SchedulerTimer::configureTimer() { timer_parameter_struct timer_initpara; @@ -28,18 +35,39 @@ void SchedulerTimer::configureTimer() timer_enable(CONFIG_SCHED_TIMER_INSTANCE); } +/** + * @brief 配置用户调度定时器对应的 NVIC。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 设置优先级分组,并为调度定时器中断向量配置抢占优先级与子优先级。 + */ void SchedulerTimer::configureNvic() { nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); nvic_irq_enable(CONFIG_SCHED_TIMER_IRQn, CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO, CONFIG_SCHED_TIMER_IRQ_SUB_PRIO); } +/** + * @brief 初始化用户调度定时器模块。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 依次完成定时器本体配置与 NVIC 中断配置。 + */ void SchedulerTimer::init() { configureTimer(); configureNvic(); } +/** + * @brief 用户调度定时器中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 响应更新中断,清除中断标志后推进一次 `TaskManager::tick100us()`。 + */ void SchedulerTimer::onInterrupt() { if(timer_interrupt_flag_get(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP) == RESET) return; @@ -48,4 +76,11 @@ void SchedulerTimer::onInterrupt() } /* ----- 中断入口 C 包装 ---------------------------------------------- */ -void TIMER2_IRQHandler(void) { SchedulerTimer::onInterrupt(); } \ No newline at end of file +/** + * @brief TIMER2 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note C 向量包装函数,内部转调 `SchedulerTimer::onInterrupt()`。 + */ +void TIMER2_IRQHandler(void) { SchedulerTimer::onInterrupt(); } diff --git a/GD32E508_DCU_APP/device/Timer.cpp.bak_dma b/GD32E508_DCU_APP/device/Timer.cpp.bak_dma deleted file mode 100644 index 45c6af3..0000000 --- a/GD32E508_DCU_APP/device/Timer.cpp.bak_dma +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file Timer.cpp - * @brief 用户定时器初始化与中断处理实现。 - */ - -#include "main.h" -#include "device/Timer.h" -#include "sys/task_manager.h" -#include "sys/config.h" - -/** - * @brief 配置定时器 2 参数:180MHz / 180 / 100 → 100us 中断周期。 - */ -static void timer2_config(void) -{ - timer_parameter_struct timer_initpara; - - rcu_periph_clock_enable(CONFIG_SCHED_TIMER_RCU); - timer_deinit(CONFIG_SCHED_TIMER_INSTANCE); - timer_struct_para_init(&timer_initpara); - - timer_initpara.prescaler = CONFIG_SCHED_TIMER_PRESCALER; - timer_initpara.alignedmode = TIMER_COUNTER_EDGE; - timer_initpara.counterdirection = TIMER_COUNTER_UP; - timer_initpara.period = CONFIG_SCHED_TIMER_PERIOD; - timer_initpara.clockdivision = TIMER_CKDIV_DIV1; - timer_init(CONFIG_SCHED_TIMER_INSTANCE, &timer_initpara); - - timer_interrupt_flag_clear(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP); - timer_interrupt_enable(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_UP); - timer_enable(CONFIG_SCHED_TIMER_INSTANCE); -} - -/** - * @brief 配置定时器 2 的中断优先级并使能中断。 - */ -static void timer2_nvic_config(void) -{ - nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); - nvic_irq_enable(CONFIG_SCHED_TIMER_IRQn, CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO, CONFIG_SCHED_TIMER_IRQ_SUB_PRIO); -} - -/** - * @brief 初始化用户定时器及其中断配置。 - * @note 当前用于建立 100us 基准节拍,驱动任务调度器时基。 - */ -void user_timer_init(void) -{ - timer2_config(); - timer2_nvic_config(); -} - -/** - * @brief 定时器 2 中断服务例程。 - * @note 每次计数溢出时清除标志并推进一次 100us 任务调度节拍。 - */ -void TIMER2_IRQHandler(void) -{ - if(timer_interrupt_flag_get(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP) == RESET) { - return; - } - - timer_interrupt_flag_clear(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP); - task_manager_tick_100us(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/Timer.cpp.bak_oop b/GD32E508_DCU_APP/device/Timer.cpp.bak_oop deleted file mode 100644 index 45c6af3..0000000 --- a/GD32E508_DCU_APP/device/Timer.cpp.bak_oop +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file Timer.cpp - * @brief 用户定时器初始化与中断处理实现。 - */ - -#include "main.h" -#include "device/Timer.h" -#include "sys/task_manager.h" -#include "sys/config.h" - -/** - * @brief 配置定时器 2 参数:180MHz / 180 / 100 → 100us 中断周期。 - */ -static void timer2_config(void) -{ - timer_parameter_struct timer_initpara; - - rcu_periph_clock_enable(CONFIG_SCHED_TIMER_RCU); - timer_deinit(CONFIG_SCHED_TIMER_INSTANCE); - timer_struct_para_init(&timer_initpara); - - timer_initpara.prescaler = CONFIG_SCHED_TIMER_PRESCALER; - timer_initpara.alignedmode = TIMER_COUNTER_EDGE; - timer_initpara.counterdirection = TIMER_COUNTER_UP; - timer_initpara.period = CONFIG_SCHED_TIMER_PERIOD; - timer_initpara.clockdivision = TIMER_CKDIV_DIV1; - timer_init(CONFIG_SCHED_TIMER_INSTANCE, &timer_initpara); - - timer_interrupt_flag_clear(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP); - timer_interrupt_enable(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_UP); - timer_enable(CONFIG_SCHED_TIMER_INSTANCE); -} - -/** - * @brief 配置定时器 2 的中断优先级并使能中断。 - */ -static void timer2_nvic_config(void) -{ - nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); - nvic_irq_enable(CONFIG_SCHED_TIMER_IRQn, CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO, CONFIG_SCHED_TIMER_IRQ_SUB_PRIO); -} - -/** - * @brief 初始化用户定时器及其中断配置。 - * @note 当前用于建立 100us 基准节拍,驱动任务调度器时基。 - */ -void user_timer_init(void) -{ - timer2_config(); - timer2_nvic_config(); -} - -/** - * @brief 定时器 2 中断服务例程。 - * @note 每次计数溢出时清除标志并推进一次 100us 任务调度节拍。 - */ -void TIMER2_IRQHandler(void) -{ - if(timer_interrupt_flag_get(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP) == RESET) { - return; - } - - timer_interrupt_flag_clear(CONFIG_SCHED_TIMER_INSTANCE, TIMER_INT_FLAG_UP); - task_manager_tick_100us(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/Timer.h b/GD32E508_DCU_APP/device/Timer.h index 5f25164..cab078a 100644 --- a/GD32E508_DCU_APP/device/Timer.h +++ b/GD32E508_DCU_APP/device/Timer.h @@ -7,12 +7,40 @@ */ class SchedulerTimer { public: + /** + * @brief 初始化用户调度定时器及其中断。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前用于建立 100us 基准节拍,驱动 TaskManager::tick100us()。 + */ static void init(); + + /** + * @brief TIMER2 中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 每次计数溢出时清除标志并调用 TaskManager::tick100us()。 + */ static void onInterrupt(); private: + /** + * @brief 配置 TIMER2 基本时序参数。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + */ static void configureTimer(); + + /** + * @brief 配置 TIMER2 的 NVIC 优先级。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + */ static void configureNvic(); }; -#endif /* DEVICE_TIMER_H */ +#endif /* DEVICE_TIMER_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/Timer.h.bak_oop b/GD32E508_DCU_APP/device/Timer.h.bak_oop deleted file mode 100644 index f0a5135..0000000 --- a/GD32E508_DCU_APP/device/Timer.h.bak_oop +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file Timer.h - * @brief 用户定时器初始化接口定义。 - */ -#ifndef DEVICE_TIMER_H -#define DEVICE_TIMER_H - -/** - * @brief 初始化用户定时器及其中断配置。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 当前用于建立 100us 基准节拍,驱动任务调度器时基。 - */ -void user_timer_init(void); - -#endif /* DEVICE_TIMER_H */ diff --git a/GD32E508_DCU_APP/device/adc.h b/GD32E508_DCU_APP/device/adc.h index f21d248..b29800b 100644 --- a/GD32E508_DCU_APP/device/adc.h +++ b/GD32E508_DCU_APP/device/adc.h @@ -14,30 +14,119 @@ public: * @note 保存外部 VIN_ADC、内部温度与内部参考电压的原始值,以及可直接使用的工程值。 */ struct Sample { - uint16_t vin_raw; /**< @brief 外部 VIN_ADC(PA6)原始 ADC 数值。 */ - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vin_adc_v; /**< @brief VIN_ADC 引脚处电压,单位 V(仅为分压后的 ADC 端电压)。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ + uint16_t vin_raw; /**< 外部 VIN_ADC(PA6)原始 ADC 数值。 */ + uint16_t temp_raw; /**< 内部温度通道原始 ADC 数值。 */ + uint16_t vref_raw; /**< 内部参考电压通道原始 ADC 数值。 */ + float vin_adc_v; /**< VIN_ADC 引脚处电压(分压后的 ADC 端电压),单位 V。 */ + float vdda; /**< 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ + float temperature; /**< 根据温度通道换算得到的芯片温度,单位 ℃。 */ }; + /** + * @brief 初始化 ADC 硬件、扫描通道与 DMA 循环缓存。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 完成 ADC 三通道扫描、DMA 循环搬运、PA6(VIN_ADC) 模拟输入配置以及内部通道校准。 + */ static void init(); + + /** + * @brief 查询 ADC DMA 缓存是否已完成首次有效填充。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示 DMA 循环缓存已可用,false 表示仍未准备好。 + */ static bool dmaReady(); + + /** + * @brief 获取 ADC DMA 原始循环缓存只读指针。 + * @param[in] 无。 + * @param[out] 无。 + * @retval const uint16_t* 返回长度为 \p kChannelCount 的原始缓存指针。 + * @note 缓冲区顺序为:VIN_ADC → 温度通道 → VREF 通道。 + */ static const uint16_t *dmaBuffer(); + + /** + * @brief 读取指定通道在 DMA 缓存中的原始 ADC 值。 + * @param[in] channel 目标 ADC 通道号。 + * @param[out] 无。 + * @retval uint16_t 对应通道原始值;不受支持的通道返回 0。 + */ static uint16_t readRaw(uint8_t channel); + + /** + * @brief 读取外部 VIN_ADC(PA6)通道原始值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t VIN_ADC 原始 ADC 数值。 + */ static uint16_t readVinRaw(); + + /** + * @brief 读取内部参考电压原始值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t 内部 VREFINT 通道原始 ADC 数值。 + */ static uint16_t readVrefRaw(); + + /** + * @brief 读取内部温度通道原始值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint16_t 内部温度通道原始 ADC 数值。 + */ static uint16_t readTempRaw(); + + /** + * @brief 根据 VIN_ADC 原始值与 VDDA 计算 ADC 引脚处电压。 + * @param[in] vinRaw VIN_ADC 通道原始 ADC 数值。 + * @param[in] vdda 当前 MCU 供电电压,单位 V。 + * @param[out] 无。 + * @retval float VIN_ADC 引脚电压,单位 V。 + * @note 当前仅计算分压后的 ADC 端电压;若需换算输入母线电压,需要补充完整分压比。 + */ static float calculateVinAdcVoltage(uint16_t vinRaw, float vdda); + + /** + * @brief 根据内部参考电压原始值计算 VDDA。 + * @param[in] vrefRaw 内部 VREFINT 通道原始 ADC 数值。 + * @param[out] 无。 + * @retval float 换算得到的 MCU 供电电压,单位 V。 + * @note 当 vrefRaw 为 0 时返回默认值 VDDA,避免除零异常。 + */ static float calculateVdda(uint16_t vrefRaw); + + /** + * @brief 根据温度原始值与 VDDA 计算芯片温度。 + * @param[in] tempRaw 内部温度通道原始 ADC 数值。 + * @param[in] vdda 当前 MCU 供电电压,单位 V。 + * @param[out] 无。 + * @retval float 换算得到的芯片温度,单位 ℃。 + */ static float calculateTemperature(uint16_t tempRaw, float vdda); + + /** + * @brief 采集一组完整 ADC 样本并完成工程值换算。 + * @param[in] sample 指向输出 Sample 的指针;允许为空。 + * @param[out] sample 当指针非空时,写入 VIN/温度/VREF 原始值与换算结果。 + * @retval 无返回值。 + * @note 当 sample 为 nullptr 时直接返回,不执行写操作。 + */ static void collectSample(Sample *sample); private: + /** + * @brief 初始化 ADC DMA 通道配置。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + */ static void initDma(); }; using adc_sample_t = Adc::Sample; -#endif /* DEVICE_ADC_H */ +#endif /* DEVICE_ADC_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/adc.h.bak_dma b/GD32E508_DCU_APP/device/adc.h.bak_dma deleted file mode 100644 index c3215a3..0000000 --- a/GD32E508_DCU_APP/device/adc.h.bak_dma +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef DEVICE_ADC_H -#define DEVICE_ADC_H - -#include - -/** - * @brief ADC 采样结果结构体。 - * @note 同时保存内部温度与内部参考电压的原始值及换算后的工程值。 - */ -typedef struct { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ -} adc_sample_t; - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 该函数完成 ADC 时钟、模式、校准以及内部通道使能。 - */ -void adc_hw_init(void); - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 函数内部会阻塞等待本次转换完成。 - */ -uint16_t adc_single_read(uint8_t channel); - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void); - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void); - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当输入为 0 时返回默认 3.3V,避免除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw); - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda); - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行写操作。 - */ -void adc_collect_sample(adc_sample_t *sample); - -#endif /* DEVICE_ADC_H */ diff --git a/GD32E508_DCU_APP/device/adc.h.bak_oop b/GD32E508_DCU_APP/device/adc.h.bak_oop deleted file mode 100644 index f2e6991..0000000 --- a/GD32E508_DCU_APP/device/adc.h.bak_oop +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef DEVICE_ADC_H -#define DEVICE_ADC_H - -#include - -/** - * @brief ADC 采样结果结构体。 - * @note 保存外部 VIN_ADC、内部温度与内部参考电压的原始值,以及可直接使用的工程值。 - */ -typedef struct { - uint16_t vin_raw; /**< @brief 外部 VIN_ADC(PA6)原始 ADC 数值。 */ - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vin_adc_v; /**< @brief VIN_ADC 引脚处电压,单位 V(仅为分压后的 ADC 端电压)。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ -} adc_sample_t; - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF/VIN_ADC 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 该函数完成 ADC 时钟、三通道扫描、DMA 循环缓存以及内部/外部采样通道使能。 - */ -void adc_hw_init(void); - -/** - * @brief 查询 ADC DMA 循环缓存是否已完成首次有效填充。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示缓存已可用,返回 0 表示仍未准备好。 - */ -uint8_t adc_dma_ready(void); - -/** - * @brief 获取 ADC DMA 原始循环缓存只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const uint16_t* 返回长度为 3 的原始缓存指针,顺序为 VIN_ADC、温度通道、VREF 通道。 - */ -const uint16_t *adc_dma_buffer_get(void); - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 在 DMA 缓存模式下,该函数优先返回已缓存的对应通道原始值;若通道不受支持则返回 0。 - */ -uint16_t adc_single_read(uint8_t channel); - -/** - * @brief 读取外部 VIN_ADC(PA6)通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 外部 VIN_ADC 通道的原始 ADC 值。 - */ -uint16_t adc_read_vin_raw(void); - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void); - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void); - -/** - * @brief 根据外部 VIN_ADC 原始值与 VDDA 计算 ADC 引脚处电压。 - * @param[in] vin_raw 外部 VIN_ADC 通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float VIN_ADC 引脚电压,单位 V。 - * @note 当前仅计算分压后的 ADC 端电压;若需换算输入母线电压,需要补充完整分压比。 - */ -float adc_calculate_vin_adc_voltage(uint16_t vin_raw, float vdda); - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当输入为 0 时返回默认 3.3V,避免除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw); - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda); - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入 VIN/温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行写操作。 - */ -void adc_collect_sample(adc_sample_t *sample); - -#endif /* DEVICE_ADC_H */ diff --git a/GD32E508_DCU_APP/device/adc.h.bak_sch b/GD32E508_DCU_APP/device/adc.h.bak_sch deleted file mode 100644 index eae2838..0000000 --- a/GD32E508_DCU_APP/device/adc.h.bak_sch +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef DEVICE_ADC_H -#define DEVICE_ADC_H - -#include - -/** - * @brief ADC 采样结果结构体。 - * @note 同时保存内部温度与内部参考电压的原始值及换算后的工程值。 - */ -typedef struct { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ -} adc_sample_t; - -/** - * @brief 初始化 ADC 硬件及内部温度/VREF 通道。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 该函数完成 ADC 时钟、双通道扫描、DMA 循环缓存以及内部通道使能。 - */ -void adc_hw_init(void); - -/** - * @brief 查询 ADC DMA 循环缓存是否已完成首次有效填充。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示缓存已可用,返回 0 表示仍未准备好。 - */ -uint8_t adc_dma_ready(void); - -/** - * @brief 获取 ADC DMA 原始循环缓存只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const uint16_t* 返回长度为 2 的原始缓存指针,顺序为温度通道、VREF 通道。 - */ -const uint16_t *adc_dma_buffer_get(void); - -/** - * @brief 执行指定通道的一次 ADC 单次采样。 - * @param[in] channel 待采样的 ADC 通道号。 - * @param[out] 无。 - * @retval uint16_t 指定通道的原始 ADC 采样值。 - * @note 在 DMA 缓存模式下,该函数优先返回已缓存的对应通道原始值;若通道不受支持则返回 0。 - */ -uint16_t adc_single_read(uint8_t channel); - -/** - * @brief 读取内部参考电压通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部参考电压通道的原始 ADC 值。 - */ -uint16_t adc_read_vref_raw(void); - -/** - * @brief 读取内部温度通道的原始 ADC 值。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint16_t 内部温度通道的原始 ADC 值。 - */ -uint16_t adc_read_temp_raw(void); - -/** - * @brief 根据内部参考电压原始值计算实际 VDDA。 - * @param[in] vref_raw 内部参考电压通道原始 ADC 数值。 - * @param[out] 无。 - * @retval float 换算得到的 VDDA 电压值,单位 V。 - * @note 当输入为 0 时返回默认 3.3V,避免除零异常。 - */ -float adc_calculate_vdda(uint16_t vref_raw); - -/** - * @brief 根据温度原始值与 VDDA 计算芯片温度。 - * @param[in] temp_raw 内部温度通道原始 ADC 数值。 - * @param[in] vdda 当前供电电压,单位 V。 - * @param[out] 无。 - * @retval float 换算得到的芯片温度,单位 ℃。 - */ -float adc_calculate_temperature(uint16_t temp_raw, float vdda); - -/** - * @brief 采集一组完整 ADC 样本并完成工程值换算。 - * @param[in] sample 指向输出样本结构体的指针;允许为空。 - * @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。 - * @retval 无返回值。 - * @note 当 sample 为 NULL 时函数直接返回,不执行写操作。 - */ -void adc_collect_sample(adc_sample_t *sample); - -#endif /* DEVICE_ADC_H */ diff --git a/GD32E508_DCU_APP/device/canfd.h b/GD32E508_DCU_APP/device/canfd.h index 3cf6778..63bd583 100644 --- a/GD32E508_DCU_APP/device/canfd.h +++ b/GD32E508_DCU_APP/device/canfd.h @@ -8,7 +8,7 @@ /** * @brief CANFD 通信模块。 - * @note 负责 GPIO/模式控制、波特率配置、异步接收缓存与状态帧发送。 + * @note 负责 GPIO/模式控制、波特率配置、异步接收缓存与按需发送能力。 */ class CanFd { public: @@ -17,15 +17,19 @@ public: * @note 记录发送、接收、错误计数以及最近一次收发报文的关键信息。 */ struct Diag { - uint32_t tx_count; /**< @brief 成功发送的报文计数。 */ - uint32_t rx_count; /**< @brief 成功接收的报文计数。 */ - uint32_t error_count; /**< @brief 发送失败或检测到的错误计数。 */ - uint32_t last_rx_id; /**< @brief 最近一次接收报文的标识符。 */ - uint32_t last_tx_id; /**< @brief 最近一次发送报文的标识符。 */ - uint8_t last_payload_length; /**< @brief 最近一次收发报文的数据长度。 */ - uint8_t last_rx_fd_flag; /**< @brief 最近一次接收报文的 FD 帧标志。 */ - uint8_t last_rx_brs; /**< @brief 最近一次接收报文的波特率切换标志。 */ - uint8_t last_rx_esi; /**< @brief 最近一次接收报文的错误状态指示位。 */ + uint32_t tx_count; /**< 成功发送的报文计数。 */ + uint32_t rx_count; /**< 成功接收的报文计数。 */ + uint32_t error_count; /**< 发送失败或检测到的错误计数。 */ + uint32_t rx_drop_count; /**< 接收 FIFO 满导致丢弃的报文计数。 */ + uint32_t tx_drop_count; /**< 发送 FIFO 满导致丢弃的报文计数。 */ + uint32_t last_rx_id; /**< 最近一次接收报文的标识符。 */ + uint32_t last_tx_id; /**< 最近一次发送报文的标识符。 */ + uint8_t last_rx_channel; /**< 最近一次接收报文所在的 CAN 通道号(0/1/2)。 */ + uint8_t last_tx_channel; /**< 最近一次发送报文所在的 CAN 通道号(0/1/2)。 */ + uint8_t last_payload_length; /**< 最近一次收发报文的数据长度。 */ + uint8_t last_rx_fd_flag; /**< 最近一次接收报文的 FD 帧标志。 */ + uint8_t last_rx_brs; /**< 最近一次接收报文的波特率切换标志。 */ + uint8_t last_rx_esi; /**< 最近一次接收报文的错误状态指示位。 */ }; /** @@ -33,42 +37,155 @@ public: * @note 当前保持协议兼容,仅包含温度与供电相关字段;VIN_ADC 单独在诊断打印中输出。 */ struct StatusPayload { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ + uint16_t temp_raw; /**< 内部温度通道原始 ADC 数值。 */ + uint16_t vref_raw; /**< 内部参考电压通道原始 ADC 数值。 */ + float vdda; /**< 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ + float temperature; /**< 根据温度通道换算得到的芯片温度,单位 ℃。 */ }; + /** + * @brief 初始化 CANFD 外设、GPIO、模式控制、过滤器与中断。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 初始化后默认进入 Normal 模式,并使能 3 路 CAN 控制器的 RX0 中断用于异步接收。 + */ static void init(); + + /** + * @brief 兼容保留的轮询接口,中断模式下为空壳。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 实际接收已由 CAN0/CAN1/CAN2 的 RX0 中断驱动。 + */ static void poll(); + + /** + * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文,并广播入队到 3 路发送 FIFO。 + * @param[in] status 指向 StatusPayload 的指针;为空时不入队。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前模块默认不会周期性调用该接口;仅在外部显式触发发送测试或业务发送时使用。 + */ static void prepareStatus(const StatusPayload *status); + + /** + * @brief 根据状态载荷仅向指定 CAN 通道的发送 FIFO 入队一帧状态报文。 + * @param[in] channelIndex 目标 CAN 通道号(0/1/2)。 + * @param[in] status 指向 StatusPayload 的指针;为空时不入队。 + * @param[out] 无。 + * @retval bool true 表示成功入队,false 表示通道非法或该通道发送 FIFO 已满。 + * @note 当前模块默认不会周期性调用该接口;仅在外部显式触发指定通道发送时使用。 + */ + static bool prepareStatusForChannel(uint8_t channelIndex, const StatusPayload *status); + + /** + * @brief 发送当前已准备好的 CANFD 状态报文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前模块默认不会周期性调用该接口;仅发送调用方显式准备过的报文;若队列为空则直接返回。 + */ static void sendPrepared(); + + /** + * @brief 查询 3 个 CAN 通道中是否存在尚未消费的接收报文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示至少有一路存在待消费报文,false 表示当前所有通道缓存为空。 + */ static bool hasRxFrame(); - static bool consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length); + + /** + * @brief 读取并消费最近一轮扫描到的某一路缓存接收帧。 + * @param[in] 无。 + * @param[out] id 输出报文标识符的指针;允许为空。 + * @param[out] data 输出报文数据缓存区指针;允许为空。 + * @param[out] length 输出报文数据长度的指针;允许为空。 + * @param[out] channel 输出报文来源的 CAN 通道号指针;允许为空。 + * @retval bool true 表示成功消费一帧报文,false 表示当前 3 路缓存均为空。 + * @note 每路通道各自保留最近一帧;消费顺序采用轮转扫描,避免长期偏向固定通道。 + */ + static bool consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length, uint8_t *channel = nullptr); + + /** + * @brief 获取 CANFD 诊断统计信息只读指针。 + * @param[in] 无。 + * @param[out] 无。 + * @retval const Diag* 指向内部诊断统计结构体的只读指针。 + */ static const Diag *diag(); + + /** + * @brief 将 TCAN1057A 收发器置为正常工作模式。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 模式控制脚按 STB 语义处理:低电平为 Normal,高电平为 Silent。 + */ static void setNormalMode(); + + /** + * @brief 将 TCAN1057A 收发器置为静默模式。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 静默模式下收发器不驱动总线显性位,可用于总线监听或受控隔离。 + */ static void setSilentMode(); + + /** + * @brief CAN0 兼容中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 兼容保留给 CAN0 中断包装使用;三路统一接收逻辑已收口到 handleRxInterrupt()。 + */ static void onRx0Interrupt(); + /** + * @brief 处理指定 CAN 通道的 RX0 中断接收。 + * @param[in] channelIndex CAN 通道索引(0/1/2)。 + * @param[out] 无。 + * @retval 无返回值。 + */ + static void handleRxInterrupt(uint8_t channelIndex); + private: struct RxFrame { + uint8_t channel; uint32_t id; - uint8_t data[64]; - uint8_t length; - uint8_t valid; + uint8_t data[64]; + uint8_t length; }; - static void initGpio(); - static void filterAcceptAll(); - static void initNominalTiming(); - static void initFdMode(); - static void buildStatusFrame(const StatusPayload *status); + struct RxQueue { + RxFrame frames[4]; + uint8_t head; + uint8_t tail; + uint8_t count; + }; - static Diag s_diag; - static RxFrame s_rxFrame; + /** @brief 初始化 CAN0/CAN1/CAN2 相关 GPIO。 */ + static void initGpio(); + /** @brief 为指定控制器配置全接收过滤器。 */ + static void filterAcceptAll(uint32_t canPeriph, uint8_t filterNumber); + /** @brief 配置指定控制器的 CAN 仲裁段标称位时序。 */ + static void initNominalTiming(uint32_t canPeriph); + /** @brief 配置指定控制器的 CAN FD 数据段位时序与 TDC。 */ + static void initFdMode(uint32_t canPeriph); + /** @brief 构造内部发送缓冲中的状态帧内容。 */ + static void buildStatusFrame(const StatusPayload *status); + /** @brief 向指定 CAN 通道的发送 FIFO 写入一帧状态报文。 */ + static bool enqueueTxFrame(uint8_t channelIndex, const StatusPayload *status); + + static Diag s_diag; + static RxQueue s_rxQueues[3]; + static uint8_t s_nextConsumeChannel; }; -using canfd_diag_t = CanFd::Diag; +using canfd_diag_t = CanFd::Diag; using canfd_status_payload_t = CanFd::StatusPayload; -#endif /* DEVICE_CANFD_H */ +#endif /* DEVICE_CANFD_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/canfd.h.bak_hideimpl b/GD32E508_DCU_APP/device/canfd.h.bak_hideimpl deleted file mode 100644 index e21157a..0000000 --- a/GD32E508_DCU_APP/device/canfd.h.bak_hideimpl +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef DEVICE_CANFD_H -#define DEVICE_CANFD_H - -#include - -/** @brief CANFD 状态报文的数据长度,单位字节。 */ -#define CANFD_STATUS_DLEN 12U - -/** - * @brief CANFD 通信模块。 - * @note 负责 GPIO/模式控制、波特率配置、异步接收缓存与状态帧发送。 - */ -class CanFd { -public: - /** - * @brief CANFD 运行诊断统计信息。 - * @note 记录发送、接收、错误计数以及最近一次收发报文的关键信息。 - */ - struct Diag { - uint32_t tx_count; /**< @brief 成功发送的报文计数。 */ - uint32_t rx_count; /**< @brief 成功接收的报文计数。 */ - uint32_t error_count; /**< @brief 发送失败或检测到的错误计数。 */ - uint32_t last_rx_id; /**< @brief 最近一次接收报文的标识符。 */ - uint32_t last_tx_id; /**< @brief 最近一次发送报文的标识符。 */ - uint8_t last_payload_length; /**< @brief 最近一次收发报文的数据长度。 */ - uint8_t last_rx_fd_flag; /**< @brief 最近一次接收报文的 FD 帧标志。 */ - uint8_t last_rx_brs; /**< @brief 最近一次接收报文的波特率切换标志。 */ - uint8_t last_rx_esi; /**< @brief 最近一次接收报文的错误状态指示位。 */ - }; - - /** - * @brief CANFD 状态发送载荷。 - * @note 当前保持协议兼容,仅包含温度与供电相关字段;VIN_ADC 单独在诊断打印中输出。 - */ - struct StatusPayload { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ - }; - - static void init(); - static void poll(); - static void prepareStatus(const StatusPayload *status); - static void sendPrepared(); - static bool hasRxFrame(); - static bool consumeRxFrame(uint32_t *id, uint8_t *data, uint8_t *length); - static const Diag *diag(); - static void setNormalMode(); - static void setSilentMode(); - static void onRx0Interrupt(); - -private: - struct RxFrame { - uint32_t id; - uint8_t data[64]; - uint8_t length; - uint8_t valid; - }; - - struct TxBuffer { - can_trasnmit_message_struct tx_message; - uint8_t payload[64]; - uint8_t valid; - }; - - static void initGpio(); - static void filterAcceptAll(); - static void initNominalTiming(); - static void initFdMode(); - static void buildStatusFrame(const StatusPayload *status); - - static Diag s_diag; - static RxFrame s_rxFrame; - static TxBuffer s_txBuffer; -}; - -using canfd_diag_t = CanFd::Diag; -using canfd_status_payload_t = CanFd::StatusPayload; - -#endif /* DEVICE_CANFD_H */ diff --git a/GD32E508_DCU_APP/device/canfd.h.bak_oop b/GD32E508_DCU_APP/device/canfd.h.bak_oop deleted file mode 100644 index f3cf947..0000000 --- a/GD32E508_DCU_APP/device/canfd.h.bak_oop +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file canfd.h - * @brief CANFD 通信接口、状态载荷与诊断信息定义。 - */ -#ifndef DEVICE_CANFD_H -#define DEVICE_CANFD_H - -#include - -/** @brief CANFD 状态报文的数据长度,单位字节。 */ -#define CANFD_STATUS_DLEN 12U - -/** - * @brief CANFD 运行诊断统计信息。 - * @note 记录发送、接收、错误计数以及最近一次收发报文的关键信息。 - */ -typedef struct { - uint32_t tx_count; /**< @brief 成功发送的报文计数。 */ - uint32_t rx_count; /**< @brief 成功接收的报文计数。 */ - uint32_t error_count; /**< @brief 发送失败或检测到的错误计数。 */ - uint32_t last_rx_id; /**< @brief 最近一次接收报文的标识符。 */ - uint32_t last_tx_id; /**< @brief 最近一次发送报文的标识符。 */ - uint8_t last_payload_length; /**< @brief 最近一次收发报文的数据长度。 */ - uint8_t last_rx_fd_flag; /**< @brief 最近一次接收报文的 FD 帧标志。 */ - uint8_t last_rx_brs; /**< @brief 最近一次接收报文的波特率切换标志。 */ - uint8_t last_rx_esi; /**< @brief 最近一次接收报文的错误状态指示位。 */ -} canfd_diag_t; - -/** - * @brief CANFD 状态发送载荷。 - * @note 用于封装供 CAN 状态帧发送的核心状态数据。当前保持协议兼容,仅包含温度与供电相关字段;VIN_ADC 单独在诊断打印中输出。 - */ -typedef struct { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ -} canfd_status_payload_t; - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void canfd_init(void); - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 若当前没有待接收报文,函数直接返回。 - */ -void canfd_poll(void); - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status); - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 若当前没有有效待发送报文,函数直接返回。 - */ -void canfd_send_prepared(void); - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示存在待消费报文,返回 0 表示没有待消费报文。 - */ -uint8_t canfd_has_rx_frame(void); - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval uint8_t 返回 1 表示成功消费一帧报文,返回 0 表示当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length); - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const canfd_diag_t* 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void); - -#endif /* DEVICE_CANFD_H */ diff --git a/GD32E508_DCU_APP/device/canfd.h.bak_sch b/GD32E508_DCU_APP/device/canfd.h.bak_sch deleted file mode 100644 index 9830943..0000000 --- a/GD32E508_DCU_APP/device/canfd.h.bak_sch +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file canfd.h - * @brief CANFD 通信接口、状态载荷与诊断信息定义。 - */ -#ifndef DEVICE_CANFD_H -#define DEVICE_CANFD_H - -#include - -/** @brief CANFD 状态报文的数据长度,单位字节。 */ -#define CANFD_STATUS_DLEN 12U - -/** - * @brief CANFD 运行诊断统计信息。 - * @note 记录发送、接收、错误计数以及最近一次收发报文的关键信息。 - */ -typedef struct { - uint32_t tx_count; /**< @brief 成功发送的报文计数。 */ - uint32_t rx_count; /**< @brief 成功接收的报文计数。 */ - uint32_t error_count; /**< @brief 发送失败或检测到的错误计数。 */ - uint32_t last_rx_id; /**< @brief 最近一次接收报文的标识符。 */ - uint32_t last_tx_id; /**< @brief 最近一次发送报文的标识符。 */ - uint8_t last_payload_length; /**< @brief 最近一次收发报文的数据长度。 */ - uint8_t last_rx_fd_flag; /**< @brief 最近一次接收报文的 FD 帧标志。 */ - uint8_t last_rx_brs; /**< @brief 最近一次接收报文的波特率切换标志。 */ - uint8_t last_rx_esi; /**< @brief 最近一次接收报文的错误状态指示位。 */ -} canfd_diag_t; - -/** - * @brief CANFD 状态发送载荷。 - * @note 用于封装温度与供电电压相关的状态数据,供状态帧打包发送。 - */ -typedef struct { - uint16_t temp_raw; /**< @brief 内部温度通道原始 ADC 数值。 */ - uint16_t vref_raw; /**< @brief 内部参考电压通道原始 ADC 数值。 */ - float vdda; /**< @brief 根据内部参考电压换算得到的 MCU 供电电压,单位 V。 */ - float temperature; /**< @brief 根据温度通道换算得到的芯片温度,单位 ℃。 */ -} canfd_status_payload_t; - -/** - * @brief 初始化 CANFD 外设、GPIO、波特率参数与接收过滤器。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void canfd_init(void); - -/** - * @brief 轮询 CANFD 接收 FIFO,并缓存最近收到的一帧数据。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 若当前没有待接收报文,函数直接返回。 - */ -void canfd_poll(void); - -/** - * @brief 根据状态载荷准备一帧待发送的 CANFD 状态报文。 - * @param[in] status 指向状态载荷的指针;为空时将清除待发送标志。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void canfd_prepare_status(const canfd_status_payload_t *status); - -/** - * @brief 发送已准备好的 CANFD 状态报文。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 若当前没有有效待发送报文,函数直接返回。 - */ -void canfd_send_prepared(void); - -/** - * @brief 查询是否存在尚未消费的接收报文。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint8_t 返回非 0 表示存在待消费报文,返回 0 表示没有待消费报文。 - */ -uint8_t canfd_has_rx_frame(void); - -/** - * @brief 读取并消费最近一次缓存的接收报文。 - * @param[out] id 输出报文标识符的指针;允许为空。 - * @param[out] data 输出报文数据缓存区指针;允许为空。 - * @param[out] length 输出报文数据长度的指针;允许为空。 - * @retval uint8_t 返回 1 表示成功消费一帧报文,返回 0 表示当前无有效缓存报文。 - */ -uint8_t canfd_consume_rx_frame(uint32_t *id, uint8_t *data, uint8_t *length); - -/** - * @brief 获取 CANFD 诊断统计信息只读指针。 - * @param[in] 无。 - * @param[out] 无。 - * @retval const canfd_diag_t* 指向内部诊断统计结构体的只读指针。 - */ -const canfd_diag_t *canfd_get_diag(void); - -#endif /* DEVICE_CANFD_H */ diff --git a/GD32E508_DCU_APP/device/temp_sensor.cpp b/GD32E508_DCU_APP/device/temp_sensor.cpp index ecae9ea..b49b30b 100644 --- a/GD32E508_DCU_APP/device/temp_sensor.cpp +++ b/GD32E508_DCU_APP/device/temp_sensor.cpp @@ -6,11 +6,25 @@ #include "device/adc.h" #include "device/temp_sensor.h" +/** + * @brief 初始化温度传感采样依赖模块。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前内部直接复用 `Adc::init()` 完成温度与参考电压采样链路初始化。 + */ void TempSensor::init() { Adc::init(); } +/** + * @brief 获取一组温度传感相关采样结果。 + * @param[in] data 指向输出采样结构体的指针。 + * @param[out] data 输出温度、VREF 与 VIN 相关采样结果;允许为空。 + * @retval 无返回值。 + * @note 当前内部直接转调 `Adc::collectSample()`。 + */ void TempSensor::sample(Data *data) { Adc::collectSample(data); diff --git a/GD32E508_DCU_APP/device/temp_sensor.cpp.bak_oop b/GD32E508_DCU_APP/device/temp_sensor.cpp.bak_oop deleted file mode 100644 index 31d5fad..0000000 --- a/GD32E508_DCU_APP/device/temp_sensor.cpp.bak_oop +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file temp_sensor.cpp - * @brief 温度传感采样实现。 - */ - -#include "device/adc.h" -#include "device/temp_sensor.h" - -/** - * @brief 初始化温度传感采样所需硬件资源。 - * @note 当前通过初始化 ADC 模块完成内部温度通道准备。 - */ -void temp_sensor_init(void) -{ - adc_hw_init(); -} - -/** - * @brief 采集一次温度传感样本并输出结果。 - * @param[out] data 指向输出样本结构体的指针;其语义与 adc_collect_sample() 一致。 - */ -void temp_sensor_sample(temp_sensor_data_t *data) -{ - adc_collect_sample(data); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/temp_sensor.h b/GD32E508_DCU_APP/device/temp_sensor.h index 03d3291..7c308e2 100644 --- a/GD32E508_DCU_APP/device/temp_sensor.h +++ b/GD32E508_DCU_APP/device/temp_sensor.h @@ -11,10 +11,25 @@ class TempSensor { public: using Data = Adc::Sample; + /** + * @brief 初始化温度采样依赖资源。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前通过调用 Adc::init() 完成内部通道准备。 + */ static void init(); + + /** + * @brief 采集一次温度相关样本。 + * @param[in] 无。 + * @param[out] data 指向输出 Data 结构体的指针。 + * @retval 无返回值。 + * @note 内部调用 Adc::collectSample() 填充完整 ADC 结果。 + */ static void sample(Data *data); }; using temp_sensor_data_t = TempSensor::Data; -#endif /* DEVICE_TEMP_SENSOR_H */ +#endif /* DEVICE_TEMP_SENSOR_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/temp_sensor.h.bak_oop b/GD32E508_DCU_APP/device/temp_sensor.h.bak_oop deleted file mode 100644 index 75712a4..0000000 --- a/GD32E508_DCU_APP/device/temp_sensor.h.bak_oop +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file temp_sensor.h - * @brief 温度传感采样接口定义。 - */ -#ifndef DEVICE_TEMP_SENSOR_H -#define DEVICE_TEMP_SENSOR_H - -#include -#include "device/adc.h" - -/** - * @brief 温度传感采样数据类型别名。 - * @note 复用 ADC 采样结果结构,统一保存温度与参考电压原始值及换算值。 - */ -typedef adc_sample_t temp_sensor_data_t; - -/** - * @brief 初始化温度传感采样所需硬件资源。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 当前通过初始化 ADC 模块完成内部温度通道准备。 - */ -void temp_sensor_init(void); - -/** - * @brief 采集一次温度传感样本并输出结果。 - * @param[out] data 指向输出样本结构体的指针;其语义与 adc_collect_sample() 一致。 - * @retval 无返回值。 - */ -void temp_sensor_sample(temp_sensor_data_t *data); - -#endif /* DEVICE_TEMP_SENSOR_H */ diff --git a/GD32E508_DCU_APP/device/usart0.cpp b/GD32E508_DCU_APP/device/usart0.cpp index 7336501..5846b03 100644 --- a/GD32E508_DCU_APP/device/usart0.cpp +++ b/GD32E508_DCU_APP/device/usart0.cpp @@ -10,34 +10,84 @@ uint8_t Usart0::s_txBuf[Usart0::kTxBufSize]; volatile uint16_t Usart0::s_txHead = 0U; volatile uint16_t Usart0::s_txTail = 0U; +volatile uint32_t Usart0::s_dropCount = 0U; +/** + * @brief 计算发送环形缓冲区中的下一个索引。 + * @param[in] idx 当前索引值。 + * @param[out] 无。 + * @retval uint16_t 返回环形缓冲区中的下一个索引。 + */ uint16_t Usart0::nextIndex(uint16_t idx) { return (idx + 1U) % kTxBufSize; } +/** + * @brief 判断 USART0 发送缓冲区是否已满。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示发送缓冲区已满,false 表示仍有可写空间。 + */ bool Usart0::isBufferFull() { return nextIndex(s_txHead) == s_txTail; } +/** + * @brief 判断 USART0 发送缓冲区是否为空。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示发送缓冲区为空,false 表示仍有待发数据。 + */ bool Usart0::isBufferEmpty() { return s_txHead == s_txTail; } -int Usart0::putChar(int ch, FILE *f) +/** + * @brief 以非阻塞方式向 USART0 发送缓冲写入一个字符。 + * @param[in] ch 待发送字符。 + * @param[out] 无。 + * @retval bool true 表示成功写入发送缓冲,false 表示缓冲已满而被丢弃。 + * @note 缓冲满时仅增加丢弃计数,不阻塞主流程。 + */ +bool Usart0::putCharNonBlocking(int ch) { - (void)f; uint16_t next = nextIndex(s_txHead); - while(next == s_txTail) { /* 缓冲满,忙等重试 */ } + if(next == s_txTail) { + s_dropCount++; + return false; + } s_txBuf[s_txHead] = static_cast(ch); s_txHead = next; usart_interrupt_enable(USART0, USART_INT_TBE); + return true; +} + +/** + * @brief 向 USART0 发送缓冲写入一个字符。 + * @param[in] ch 待发送字符。 + * @param[in] f 标准流指针。 + * @param[out] 无。 + * @retval int 返回写入缓冲的字符值。 + * @note 当前采用非阻塞写入策略;若缓冲已满则丢弃该字符但仍返回原字符值。 + */ +int Usart0::putChar(int ch, FILE *f) +{ + (void)f; + (void)putCharNonBlocking(ch); return ch; } +/** + * @brief USART0 中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 处理发送缓冲区的 TBE 中断驱动输出;当缓冲为空时自动关闭发送中断。 + */ void Usart0::onInterrupt() { if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_TBE) != RESET) { @@ -51,6 +101,13 @@ void Usart0::onInterrupt() } } +/** + * @brief 配置 USART0 对应 GPIO 引脚。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 将 PA9 配置为复用推挽发送脚,将 PA10 配置为浮空输入接收脚。 + */ void Usart0::configurePins() { rcu_periph_clock_enable(RCU_GPIOA); @@ -58,6 +115,13 @@ void Usart0::configurePins() gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); } +/** + * @brief 初始化 USART0 外设与中断。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 使用 `CONFIG_USART0_BAUDRATE` 配置串口参数,并使能 USART0 中断。 + */ void Usart0::init() { rcu_periph_clock_enable(RCU_USART0); @@ -73,5 +137,21 @@ void Usart0::init() } /* ----- 中断入口 / printf 重定向的 C 包装 --------------------------- */ +/** + * @brief 标准库 fputc 重定向入口。 + * @param[in] ch 待发送字符。 + * @param[in] f 标准流指针。 + * @param[out] 无。 + * @retval int 返回写入缓冲的字符值。 + * @note 该 C 包装函数内部转调 `Usart0::putChar()`。 + */ extern "C" int fputc(int ch, FILE *f) { return Usart0::putChar(ch, f); } -extern "C" void USART0_IRQHandler(void) { Usart0::onInterrupt(); } \ No newline at end of file + +/** + * @brief USART0 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 该 C 包装函数内部转调 `Usart0::onInterrupt()`。 + */ +extern "C" void USART0_IRQHandler(void) { Usart0::onInterrupt(); } diff --git a/GD32E508_DCU_APP/device/usart0.cpp.bak_oop b/GD32E508_DCU_APP/device/usart0.cpp.bak_oop deleted file mode 100644 index 7696620..0000000 --- a/GD32E508_DCU_APP/device/usart0.cpp.bak_oop +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file usart0.cpp - * @brief USART0 串口配置与 printf 重定向实现。 - * @note 使用 TX 中断 + 环形缓冲替代逐字节忙等 TBE,降低 CPU 占用。 - */ - -#include "main.h" -#include "device/usart0.h" -#include "sys/config.h" - -#define USARTx USART0 -#define USART_TX_BUF_SIZE 256U - -namespace { -uint8_t g_tx_buf[USART_TX_BUF_SIZE]; -volatile uint16_t g_tx_head = 0U; -volatile uint16_t g_tx_tail = 0U; - -inline uint16_t tx_buf_next(uint16_t idx) -{ - return (idx + 1U) % USART_TX_BUF_SIZE; -} - -inline bool tx_buf_full(void) -{ - return tx_buf_next(g_tx_head) == g_tx_tail; -} - -inline bool tx_buf_empty(void) -{ - return g_tx_head == g_tx_tail; -} -} // namespace - -/** - * @brief 重定向标准输出字符到 USART0。 - * @param[in] ch 待输出的字符。 - * @param[in] f 标准流指针;当前实现中未实际使用。 - * @retval 返回已发送的字符值。 - * @note 将字符写入环形发送缓冲,由 USART0 TXE 中断负责实际发送。 - */ -extern "C" int fputc(int ch, FILE *f) -{ - (void)f; - uint16_t next = tx_buf_next(g_tx_head); - - while(next == g_tx_tail) { - /* 缓冲满,忙等一小段时间后重试; - * 在 115200 波特率下通常不会发生 */ - } - g_tx_buf[g_tx_head] = static_cast(ch); - g_tx_head = next; - - /* 启动 TXE 中断以触发实际硬件发送 */ - usart_interrupt_enable(USARTx, USART_INT_TBE); - - return ch; -} - -/** - * @brief USART0 中断服务例程。 - * @note 处理 TXE 发送缓冲区空中断,从环形缓冲取下一字节发送。 - */ -extern "C" void USART0_IRQHandler(void) -{ - if(usart_interrupt_flag_get(USARTx, USART_INT_FLAG_TBE) != RESET) { - if(!tx_buf_empty()) { - usart_data_transmit(USARTx, g_tx_buf[g_tx_tail]); - g_tx_tail = tx_buf_next(g_tx_tail); - } - /* 缓冲已空,关 TXE 中断,等下次 fputc 再开 */ - if(tx_buf_empty()) { - usart_interrupt_disable(USARTx, USART_INT_TBE); - } - } -} - -/** - * @brief 配置 USART0 相关 GPIO 引脚。 - */ -void usart0_gpio_config(void) -{ - rcu_periph_clock_enable(RCU_GPIOA); - - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); -} - -/** - * @brief 配置并使能 USART0 外设。 - * @note 当前使用 8N1 格式,115200 波特率,收发同时使能。 - * 同步配置 NVIC 以便 TXE 中断驱动发送。 - */ -void usart0_config(void) -{ - rcu_periph_clock_enable(RCU_USART0); - - usart_deinit(USARTx); - usart_baudrate_set(USARTx, CONFIG_USART0_BAUDRATE); - usart_word_length_set(USARTx, USART_WL_8BIT); - usart_stop_bit_set(USARTx, USART_STB_1BIT); - usart_parity_config(USARTx, USART_PM_NONE); - usart_receive_config(USARTx, USART_RECEIVE_ENABLE); - usart_transmit_config(USARTx, USART_TRANSMIT_ENABLE); - usart_enable(USARTx); - - /* 使能 USART0 NVIC,用于 TXE 中断驱动发送 */ - nvic_irq_enable(USART0_IRQn, 2U, 0U); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/usart0.cpp.bak_txisr b/GD32E508_DCU_APP/device/usart0.cpp.bak_txisr deleted file mode 100644 index 1e51cc6..0000000 --- a/GD32E508_DCU_APP/device/usart0.cpp.bak_txisr +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file usart0.cpp - * @brief USART0 串口配置与 printf 重定向实现。 - */ - -#include "main.h" -#include "device/usart0.h" -#include "sys/config.h" - -#define USARTx USART0 - -/** - * @brief 重定向标准输出字符到 USART0。 - * @param[in] ch 待输出的字符。 - * @param[in] f 标准流指针;当前实现中未实际使用。 - * @retval 返回已发送的字符值。 - */ -extern "C" int fputc(int ch, FILE *f) -{ - (void)f; - while(RESET == usart_flag_get(USARTx, USART_FLAG_TBE)) { - } - usart_data_transmit(USARTx, (uint16_t)ch); - return ch; -} - -/** - * @brief 配置 USART0 相关 GPIO 引脚。 - */ -void usart0_gpio_config(void) -{ - rcu_periph_clock_enable(RCU_GPIOA); - - gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); - gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); -} - -/** - * @brief 配置并使能 USART0 外设。 - * @note 当前使用 8N1 格式,115200 波特率,收发同时使能。 - */ -void usart0_config(void) -{ - rcu_periph_clock_enable(RCU_USART0); - - usart_deinit(USARTx); - usart_baudrate_set(USARTx, CONFIG_USART0_BAUDRATE); - usart_word_length_set(USARTx, USART_WL_8BIT); - usart_stop_bit_set(USARTx, USART_STB_1BIT); - usart_parity_config(USARTx, USART_PM_NONE); - usart_receive_config(USARTx, USART_RECEIVE_ENABLE); - usart_transmit_config(USARTx, USART_TRANSMIT_ENABLE); - usart_enable(USARTx); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/usart0.h b/GD32E508_DCU_APP/device/usart0.h index 6c67c68..34fb834 100644 --- a/GD32E508_DCU_APP/device/usart0.h +++ b/GD32E508_DCU_APP/device/usart0.h @@ -6,24 +6,79 @@ /** * @brief USART0 串口模块。 - * @note 负责 GPIO 初始化、串口配置、TX 环形缓冲与中断驱动发送。 + * @note 负责 GPIO 初始化、外设配置、TX 环形缓冲与中断驱动发送。 */ class Usart0 { public: + /** + * @brief 配置 USART0 的 GPIO 引脚。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前配置为:PA9=TX(AF_PP)、PA10=RX(IN_FLOATING)。 + */ static void configurePins(); + + /** + * @brief 初始化 USART0 外设与 NVIC。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 使用 8N1 格式,收发使能,同步配置 NVIC 以便 TXE 中断驱动发送。 + */ static void init(); + + /** + * @brief 将字符写入 USART0 发送环形缓冲。 + * @param[in] ch 待发送字符。 + * @param[in] f 标准流指针,实际未使用。 + * @param[out] 无。 + * @retval int 返回已写入缓冲的字符值。 + * @note 新字符写入后自动启动 TXE 中断来推动实际硬件发送。 + */ static int putChar(int ch, FILE *f); + + /** + * @brief USART0 中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 在 TXE 产生时从环形缓冲取下一字节发送;缓冲空后关闭 TXE 中断。 + */ static void onInterrupt(); private: + /** + * @brief 获取环形缓冲下一索引。 + * @param[in] idx 当前索引。 + * @param[out] 无。 + * @retval uint16_t 下一索引值。 + */ static uint16_t nextIndex(uint16_t idx); + + /** + * @brief 判断环形发送缓冲是否已满。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示已满,false 表示可继续写入。 + */ static bool isBufferFull(); + + /** + * @brief 判断环形发送缓冲是否为空。 + * @param[in] 无。 + * @param[out] 无。 + * @retval bool true 表示空,false 表示仍有待发送数据。 + */ static bool isBufferEmpty(); + static bool putCharNonBlocking(int ch); + static constexpr uint16_t kTxBufSize = 256U; - static uint8_t s_txBuf[kTxBufSize]; + static volatile uint32_t s_dropCount; + static uint8_t s_txBuf[kTxBufSize]; static volatile uint16_t s_txHead; static volatile uint16_t s_txTail; }; -#endif /* DEVICE_USART0_H */ +#endif /* DEVICE_USART0_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/device/usart0.h.bak_oop b/GD32E508_DCU_APP/device/usart0.h.bak_oop deleted file mode 100644 index 1e5f910..0000000 --- a/GD32E508_DCU_APP/device/usart0.h.bak_oop +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file usart0.h - * @brief USART0 串口打印与基础配置接口定义。 - */ -#ifndef DEVICE_USART0_H -#define DEVICE_USART0_H - -/** - * @brief 配置 USART0 相关 GPIO 引脚。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void usart0_gpio_config(void); - -/** - * @brief 配置并使能 USART0 外设。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 当前串口参数由实现文件中的默认宏定义决定。 - */ -void usart0_config(void); - -#endif /* DEVICE_USART0_H */ diff --git a/GD32E508_DCU_APP/main.cpp b/GD32E508_DCU_APP/main.cpp index 5fff4d7..6b0df32 100644 --- a/GD32E508_DCU_APP/main.cpp +++ b/GD32E508_DCU_APP/main.cpp @@ -1,11 +1,20 @@ +/** + * @file main.cpp + * @brief 应用主入口与顶层流程实现。 + */ + #include "main.h" #include "sys/initial.h" +#include "sys/task_manager.h" #include "sys/task_runner.h" #include "sys/config.h" /** * @brief 打印应用启动横幅与系统时钟信息。 - * @note 该函数仅负责串口输出启动提示,不修改系统控制状态。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 该函数仅负责串口输出启动提示,不修改系统控制状态。 */ void App::printBanner() const { @@ -15,7 +24,10 @@ void App::printBanner() const /** * @brief 运行应用主循环。 + * @param[in] 无。 + * @param[out] 无。 * @retval int 固定返回 0;在嵌入式常驻循环场景下通常不会真正返回。 + * @note 完成系统初始化、任务运行时初始化和启动横幅输出后,持续执行任务分发循环。 */ int App::run() { @@ -25,11 +37,21 @@ int App::run() while(1) { TaskRunner::runPending(); + if(TaskManager::state().task_flags == 0U) { + __WFI(); + } } return 0; } +/** + * @brief 程序入口函数。 + * @param[in] 无。 + * @param[out] 无。 + * @retval int 返回应用主循环执行结果;在嵌入式常驻场景下通常不会返回。 + * @note 创建应用顶层对象并转入 `App::run()`。 + */ int main(void) { App app; diff --git a/GD32E508_DCU_APP/main.cpp.bak_config b/GD32E508_DCU_APP/main.cpp.bak_config deleted file mode 100644 index 95a6e28..0000000 --- a/GD32E508_DCU_APP/main.cpp.bak_config +++ /dev/null @@ -1,34 +0,0 @@ -#include "main.h" -#include "sys/initial.h" -#include "sys/task_runner.h" - -/** - * @brief 打印应用启动横幅与系统时钟信息。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 该函数仅负责串口输出启动提示,不修改系统控制状态。 - */ -static void app_banner(void) -{ - printf("\r\nGD32E508 DCU task scheduler start\r\n"); - printf("SystemCoreClock=%u Hz\r\n", SystemCoreClock); -} - -/** - * @brief 应用程序主入口函数。 - * @param[in] 无。 - * @param[out] 无。 - * @retval int 固定返回 0;在嵌入式常驻循环场景下通常不会真正返回。 - * @note 初始化硬件与任务运行环境后,进入永久任务执行循环。 - */ -int main(void) -{ - app_init(); - task_runner_init(); - app_banner(); - - while(1) { - task_runner_run_pending(); - } -} diff --git a/GD32E508_DCU_APP/main.cpp.bak_oop b/GD32E508_DCU_APP/main.cpp.bak_oop deleted file mode 100644 index c92b7fd..0000000 --- a/GD32E508_DCU_APP/main.cpp.bak_oop +++ /dev/null @@ -1,35 +0,0 @@ -#include "main.h" -#include "sys/initial.h" -#include "sys/task_runner.h" -#include "sys/config.h" - -/** - * @brief 打印应用启动横幅与系统时钟信息。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 该函数仅负责串口输出启动提示,不修改系统控制状态。 - */ -static void app_banner(void) -{ - printf("\r\n%s\r\n", APP_BANNER_TEXT); - printf("SystemCoreClock=%u Hz\r\n", SystemCoreClock); -} - -/** - * @brief 应用程序主入口函数。 - * @param[in] 无。 - * @param[out] 无。 - * @retval int 固定返回 0;在嵌入式常驻循环场景下通常不会真正返回。 - * @note 初始化硬件与任务运行环境后,进入永久任务执行循环。 - */ -int main(void) -{ - app_init(); - task_runner_init(); - app_banner(); - - while(1) { - task_runner_run_pending(); - } -} diff --git a/GD32E508_DCU_APP/main.h b/GD32E508_DCU_APP/main.h index f9773bc..60d0b6f 100644 --- a/GD32E508_DCU_APP/main.h +++ b/GD32E508_DCU_APP/main.h @@ -12,17 +12,17 @@ * @note 每个枚举值对应任务调度器中的一个任务位,用于驱动主循环中的任务分发。 */ enum system_task_t { - TASK_ADC_VREF_SAMPLE = 0, /**< @brief 采样 VIN/VREF 原始值任务。 */ - TASK_ADC_TEMP_SAMPLE, /**< @brief 采样内部温度通道原始值任务。 */ - TASK_ADC_PROCESS, /**< @brief 对 ADC 原始值进行电压与温度计算任务。 */ - TASK_CAN_RX_POLL, /**< @brief 兼容保留的 CANFD 接收轮询任务。 */ - TASK_CAN_RX_PARSE, /**< @brief 解析并消费已接收 CANFD 帧任务。 */ - TASK_CAN_TX_PREPARE, /**< @brief 准备 CANFD 状态发送帧任务。 */ - TASK_CAN_TX_SEND, /**< @brief 发送已准备好的 CANFD 帧任务。 */ - TASK_STATUS_LED, /**< @brief 状态灯维护任务。 */ - TASK_HEARTBEAT, /**< @brief 系统心跳维护任务。 */ - TASK_DIAGNOSTIC_PRINT, /**< @brief 诊断信息打印任务。 */ - TASK_COUNT /**< @brief 任务总数,用于边界或统计场景。 */ + TASK_ADC_VREF_SAMPLE = 0, /**< 采样 VIN/VREF 原始值任务。 */ + TASK_ADC_TEMP_SAMPLE, /**< 采样内部温度通道原始值任务。 */ + TASK_ADC_PROCESS, /**< 对 ADC 原始值进行电压与温度计算任务。 */ + TASK_CAN_RX_POLL, /**< 兼容保留的 CANFD 接收轮询任务。 */ + TASK_CAN_RX_PARSE, /**< 解析并消费已接收 CANFD 帧任务。 */ + TASK_CAN_TX_PREPARE, /**< 预留的 CANFD 发送准备任务,默认不主动置位。 */ + TASK_CAN_TX_SEND, /**< 预留的 CANFD 发送执行任务,默认不主动置位。 */ + TASK_STATUS_LED, /**< 状态灯维护任务。 */ + TASK_HEARTBEAT, /**< 系统心跳维护任务。 */ + TASK_DIAGNOSTIC_PRINT, /**< 诊断信息打印任务。 */ + TASK_COUNT /**< 任务总数,用于边界或统计场景。 */ }; /** @@ -30,12 +30,23 @@ enum system_task_t { * @note 保存各类节拍计数器与待执行任务标志位,由中断与主循环共享访问。 */ struct task_scheduler_t { - volatile uint32_t task_flags; /**< @brief 待执行任务位图,每一位对应一个任务。 */ - volatile uint32_t tick_100us; /**< @brief 100us 基准节拍累计计数。 */ - volatile uint32_t tick_1ms; /**< @brief 1ms 节拍累计计数。 */ - volatile uint32_t tick_10ms; /**< @brief 10ms 节拍累计计数。 */ - volatile uint32_t tick_100ms; /**< @brief 100ms 节拍累计计数。 */ - volatile uint32_t tick_1s; /**< @brief 1s 节拍累计计数。 */ + volatile uint32_t task_flags; /**< 待执行任务位图,每一位对应一个任务。 */ + volatile uint32_t tick_100us; /**< 100us 基准节拍累计计数。 */ + volatile uint32_t tick_1ms; /**< 1ms 节拍累计计数。 */ + volatile uint32_t tick_10ms; /**< 10ms 节拍累计计数。 */ + volatile uint32_t tick_100ms; /**< 100ms 节拍累计计数。 */ + /** @brief 1s 节拍累计计数。 */ + volatile uint32_t tick_1s; + /** @brief 调度分频计数:ADC VREF 采样。 */ + volatile uint16_t div_vref_sample; + /** @brief 调度分频计数:ADC 温度采样/处理。 */ + volatile uint16_t div_temp_sample; + /** @brief 调度分频计数:CAN 接收处理。 */ + volatile uint16_t div_can_rx; + /** @brief 调度分频计数:状态灯。 */ + volatile uint16_t div_can_tx; + /** @brief 调度分频计数:心跳与诊断打印。 */ + volatile uint16_t div_heartbeat; }; /** @@ -50,10 +61,22 @@ extern task_scheduler_t g_scheduler; */ class App { public: + /** + * @brief 运行应用主循环。 + * @param[in] 无。 + * @param[out] 无。 + * @retval int 固定返回 0;在嵌入式常驻循环场景下通常不会真正返回。 + */ int run(); private: + /** + * @brief 打印应用启动横幅与系统时钟信息。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + */ void printBanner() const; }; -#endif /* MAIN_H */ +#endif /* MAIN_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/main.h.bak_oop b/GD32E508_DCU_APP/main.h.bak_oop deleted file mode 100644 index b25cc70..0000000 --- a/GD32E508_DCU_APP/main.h.bak_oop +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MAIN_H -#define MAIN_H - -#include "RTE_Components.h" -#include CMSIS_device_header - -#include -#include - -/** - * @brief 系统任务枚举定义。 - * @note 每个枚举值对应任务调度器中的一个任务位,用于驱动主循环中的任务分发。 - */ -typedef enum { - TASK_ADC_VREF_SAMPLE = 0, /**< @brief 采样内部参考电压原始值任务。 */ - TASK_ADC_TEMP_SAMPLE, /**< @brief 采样内部温度通道原始值任务。 */ - TASK_ADC_PROCESS, /**< @brief 对 ADC 原始值进行电压与温度计算任务。 */ - TASK_CAN_RX_POLL, /**< @brief 轮询 CANFD 接收 FIFO 任务。 */ - TASK_CAN_RX_PARSE, /**< @brief 解析并消费已接收 CANFD 帧任务。 */ - TASK_CAN_TX_PREPARE, /**< @brief 准备 CANFD 状态发送帧任务。 */ - TASK_CAN_TX_SEND, /**< @brief 发送已准备好的 CANFD 帧任务。 */ - TASK_STATUS_LED, /**< @brief 状态灯维护任务。 */ - TASK_HEARTBEAT, /**< @brief 系统心跳维护任务。 */ - TASK_DIAGNOSTIC_PRINT, /**< @brief 诊断信息打印任务。 */ - TASK_COUNT /**< @brief 任务总数,用于边界或统计场景。 */ -} system_task_t; - -/** - * @brief 任务调度器状态结构体。 - * @note 该结构体保存各类节拍计数器与待执行任务标志位,由中断与主循环共享访问。 - */ -typedef struct { - volatile uint32_t task_flags; /**< @brief 待执行任务位图,每一位对应一个任务。 */ - volatile uint32_t tick_100us; /**< @brief 100us 基准节拍累计计数。 */ - volatile uint32_t tick_1ms; /**< @brief 1ms 节拍累计计数。 */ - volatile uint32_t tick_10ms; /**< @brief 10ms 节拍累计计数。 */ - volatile uint32_t tick_100ms; /**< @brief 100ms 节拍累计计数。 */ - volatile uint32_t tick_1s; /**< @brief 1s 节拍累计计数。 */ -} task_scheduler_t; - -/** - * @brief 全局任务调度器实例。 - * @note 由任务管理模块定义,由其他模块引用以观察或维护调度状态。 - */ -extern task_scheduler_t g_scheduler; - -#endif /* MAIN_H */ diff --git a/GD32E508_DCU_APP/sys/config.h b/GD32E508_DCU_APP/sys/config.h index 600f9cb..96478e3 100644 --- a/GD32E508_DCU_APP/sys/config.h +++ b/GD32E508_DCU_APP/sys/config.h @@ -76,4 +76,7 @@ /** @brief 调度基准节拍:心跳/诊断打印周期,单位 100us tick。 */ #define CONFIG_TASK_PERIOD_HEARTBEAT_TICKS 10000U + /** @brief UART 诊断打印级别:0=仅温度/电压,1=温度/电压+CAN 统计。 */ +#define CONFIG_UART_DIAG_LEVEL 1 + #endif /* SYS_CONFIG_H */ diff --git a/GD32E508_DCU_APP/sys/config.h.bak_canrate b/GD32E508_DCU_APP/sys/config.h.bak_canrate deleted file mode 100644 index 3fea9a4..0000000 --- a/GD32E508_DCU_APP/sys/config.h.bak_canrate +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file config.h - * @brief 应用级集中配置项定义。 - * @note 用于统一管理当前项目中可调的外设、时序、通信与算法常量。 - */ -#ifndef SYS_CONFIG_H -#define SYS_CONFIG_H - -/** @brief 应用启动横幅字符串。 */ -#define APP_BANNER_TEXT "GD32E508 DCU task scheduler start" - -/** @brief USART0 默认波特率。 */ -#define CONFIG_USART0_BAUDRATE 115200U - -/** @brief ADC 外设实例。 */ -#define CONFIG_ADC_INSTANCE ADC0 -/** @brief ADC 内部温度通道号。 */ -#define CONFIG_ADC_TEMP_CHANNEL ADC_CHANNEL_16 -/** @brief ADC 内部参考电压通道号。 */ -#define CONFIG_ADC_VREFINT_CHANNEL ADC_CHANNEL_17 -/** @brief ADC 满量程计数值。 */ -#define CONFIG_ADC_MAX_VALUE 4095.0f -/** @brief 内部参考电压典型值,单位 V。 */ -#define CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE 1.20f -/** @brief 温度传感器 25℃ 对应电压,单位 V。 */ -#define CONFIG_ADC_TEMP_V25 1.43f -/** @brief 温度传感器平均斜率,单位 V/℃。 */ -#define CONFIG_ADC_TEMP_AVG_SLOPE 0.0043f -/** @brief ADC 上电后稳定等待时间,单位 ms。 */ -#define CONFIG_ADC_STABILIZE_DELAY_MS 2U -/** @brief ADC 规则通道采样时间配置。 */ -#define CONFIG_ADC_SAMPLE_TIME ADC_SAMPLETIME_239POINT5 -/** @brief ADC 空输入保护时默认 VDDA,单位 V。 */ -#define CONFIG_ADC_DEFAULT_VDDA 3.3f - -/** @brief CAN 外设实例。 */ -#define CONFIG_CAN_INSTANCE CAN0 -/** @brief CAN 外设时钟使能枚举。 */ -#define CONFIG_CAN_RCU RCU_CAN0 -/** @brief CAN 状态报文标准帧 ID。 */ -#define CONFIG_CAN_STATUS_ID 0x321U -/** @brief CAN 标称波特率预分频值。 */ -#define CONFIG_CAN_NOMINAL_BAUD_PRESCALER 12U -/** @brief CAN 状态载荷中调试标识字符 0。 */ -#define CONFIG_CAN_STATUS_TAG0 0x43U -/** @brief CAN 状态载荷中调试标识字符 1。 */ -#define CONFIG_CAN_STATUS_TAG1 0x41U -/** @brief CAN 状态载荷中调试标识字符 2。 */ -#define CONFIG_CAN_STATUS_TAG2 0x4EU -/** @brief CAN 状态载荷中调试标识字符 3。 */ -#define CONFIG_CAN_STATUS_TAG3 0x46U - -/** @brief 用户调度定时器实例。 */ -#define CONFIG_SCHED_TIMER_INSTANCE TIMER2 -/** @brief 用户调度定时器中断号。 */ -#define CONFIG_SCHED_TIMER_IRQn TIMER2_IRQn -/** @brief 用户调度定时器时钟使能宏参数。 */ -#define CONFIG_SCHED_TIMER_RCU RCU_TIMER2 -/** @brief 用户调度定时器预分频值。 */ -#define CONFIG_SCHED_TIMER_PRESCALER 179U -/** @brief 用户调度定时器周期重装值。 */ -#define CONFIG_SCHED_TIMER_PERIOD 99U -/** @brief 用户调度定时器 NVIC 抢占优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO 1U -/** @brief 用户调度定时器 NVIC 子优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_SUB_PRIO 0U - -/** @brief 调度基准节拍:ADC VREF 采样周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS 5U -/** @brief 调度基准节拍:ADC 温度采样/处理周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS 10U -/** @brief 调度基准节拍:CAN 接收轮询/解析周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_RX_TICKS 100U -/** @brief 调度基准节拍:CAN 发送/状态灯周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_TX_TICKS 1000U -/** @brief 调度基准节拍:心跳/诊断打印周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_HEARTBEAT_TICKS 10000U - -#endif /* SYS_CONFIG_H */ diff --git a/GD32E508_DCU_APP/sys/config.h.bak_canrcu b/GD32E508_DCU_APP/sys/config.h.bak_canrcu deleted file mode 100644 index ec08ca5..0000000 --- a/GD32E508_DCU_APP/sys/config.h.bak_canrcu +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file config.h - * @brief 应用级集中配置项定义。 - * @note 用于统一管理当前项目中可调的外设、时序、通信与算法常量。 - */ -#ifndef SYS_CONFIG_H -#define SYS_CONFIG_H - -/** @brief 应用启动横幅字符串。 */ -#define APP_BANNER_TEXT "GD32E508 DCU task scheduler start" - -/** @brief USART0 默认波特率。 */ -#define CONFIG_USART0_BAUDRATE 115200U - -/** @brief ADC 外设实例。 */ -#define CONFIG_ADC_INSTANCE ADC0 -/** @brief ADC 内部温度通道号。 */ -#define CONFIG_ADC_TEMP_CHANNEL ADC_CHANNEL_16 -/** @brief ADC 内部参考电压通道号。 */ -#define CONFIG_ADC_VREFINT_CHANNEL ADC_CHANNEL_17 -/** @brief ADC 满量程计数值。 */ -#define CONFIG_ADC_MAX_VALUE 4095.0f -/** @brief 内部参考电压典型值,单位 V。 */ -#define CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE 1.20f -/** @brief 温度传感器 25℃ 对应电压,单位 V。 */ -#define CONFIG_ADC_TEMP_V25 1.43f -/** @brief 温度传感器平均斜率,单位 V/℃。 */ -#define CONFIG_ADC_TEMP_AVG_SLOPE 0.0043f -/** @brief ADC 上电后稳定等待时间,单位 ms。 */ -#define CONFIG_ADC_STABILIZE_DELAY_MS 2U -/** @brief ADC 规则通道采样时间配置。 */ -#define CONFIG_ADC_SAMPLE_TIME ADC_SAMPLETIME_239POINT5 -/** @brief ADC 空输入保护时默认 VDDA,单位 V。 */ -#define CONFIG_ADC_DEFAULT_VDDA 3.3f - -/** @brief CAN 外设实例。 */ -#define CONFIG_CAN_INSTANCE CAN0 -/** @brief CAN 状态报文标准帧 ID。 */ -#define CONFIG_CAN_STATUS_ID 0x321U -/** @brief CAN 标称波特率预分频值。 */ -#define CONFIG_CAN_NOMINAL_BAUD_PRESCALER 12U -/** @brief CAN 状态载荷中调试标识字符 0。 */ -#define CONFIG_CAN_STATUS_TAG0 0x43U -/** @brief CAN 状态载荷中调试标识字符 1。 */ -#define CONFIG_CAN_STATUS_TAG1 0x41U -/** @brief CAN 状态载荷中调试标识字符 2。 */ -#define CONFIG_CAN_STATUS_TAG2 0x4EU -/** @brief CAN 状态载荷中调试标识字符 3。 */ -#define CONFIG_CAN_STATUS_TAG3 0x46U - -/** @brief 用户调度定时器实例。 */ -#define CONFIG_SCHED_TIMER_INSTANCE TIMER2 -/** @brief 用户调度定时器中断号。 */ -#define CONFIG_SCHED_TIMER_IRQn TIMER2_IRQn -/** @brief 用户调度定时器时钟使能宏参数。 */ -#define CONFIG_SCHED_TIMER_RCU RCU_TIMER2 -/** @brief 用户调度定时器预分频值。 */ -#define CONFIG_SCHED_TIMER_PRESCALER 179U -/** @brief 用户调度定时器周期重装值。 */ -#define CONFIG_SCHED_TIMER_PERIOD 99U -/** @brief 用户调度定时器 NVIC 抢占优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO 1U -/** @brief 用户调度定时器 NVIC 子优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_SUB_PRIO 0U - -/** @brief 调度基准节拍:ADC VREF 采样周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS 5U -/** @brief 调度基准节拍:ADC 温度采样/处理周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS 10U -/** @brief 调度基准节拍:CAN 接收轮询/解析周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_RX_TICKS 100U -/** @brief 调度基准节拍:CAN 发送/状态灯周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_TX_TICKS 1000U -/** @brief 调度基准节拍:心跳/诊断打印周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_HEARTBEAT_TICKS 10000U - -#endif /* SYS_CONFIG_H */ diff --git a/GD32E508_DCU_APP/sys/config.h.bak_sch b/GD32E508_DCU_APP/sys/config.h.bak_sch deleted file mode 100644 index 33a88f7..0000000 --- a/GD32E508_DCU_APP/sys/config.h.bak_sch +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file config.h - * @brief 应用级集中配置项定义。 - * @note 用于统一管理当前项目中可调的外设、时序、通信与算法常量。 - */ -#ifndef SYS_CONFIG_H -#define SYS_CONFIG_H - -/** @brief 应用启动横幅字符串。 */ -#define APP_BANNER_TEXT "GD32E508 DCU task scheduler start" - -/** @brief USART0 默认波特率。 */ -#define CONFIG_USART0_BAUDRATE 115200U - -/** @brief ADC 外设实例。 */ -#define CONFIG_ADC_INSTANCE ADC0 -/** @brief ADC 内部温度通道号。 */ -#define CONFIG_ADC_TEMP_CHANNEL ADC_CHANNEL_16 -/** @brief ADC 内部参考电压通道号。 */ -#define CONFIG_ADC_VREFINT_CHANNEL ADC_CHANNEL_17 -/** @brief ADC 满量程计数值。 */ -#define CONFIG_ADC_MAX_VALUE 4095.0f -/** @brief 内部参考电压典型值,单位 V。 */ -#define CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE 1.20f -/** @brief 温度传感器 25℃ 对应电压,单位 V。 */ -#define CONFIG_ADC_TEMP_V25 1.43f -/** @brief 温度传感器平均斜率,单位 V/℃。 */ -#define CONFIG_ADC_TEMP_AVG_SLOPE 0.0043f -/** @brief ADC 上电后稳定等待时间,单位 ms。 */ -#define CONFIG_ADC_STABILIZE_DELAY_MS 2U -/** @brief ADC 规则通道采样时间配置。 */ -#define CONFIG_ADC_SAMPLE_TIME ADC_SAMPLETIME_239POINT5 -/** @brief ADC 空输入保护时默认 VDDA,单位 V。 */ -#define CONFIG_ADC_DEFAULT_VDDA 3.3f - -/** @brief CAN 外设实例。 */ -#define CONFIG_CAN_INSTANCE CAN0 -/** @brief CAN 外设时钟使能枚举。 */ -#define CONFIG_CAN_RCU RCU_CAN0 -/** @brief CAN 状态报文标准帧 ID。 */ -#define CONFIG_CAN_STATUS_ID 0x321U -/** @brief CAN 状态载荷中调试标识字符 0。 */ -#define CONFIG_CAN_STATUS_TAG0 0x43U -/** @brief CAN 状态载荷中调试标识字符 1。 */ -#define CONFIG_CAN_STATUS_TAG1 0x41U -/** @brief CAN 状态载荷中调试标识字符 2。 */ -#define CONFIG_CAN_STATUS_TAG2 0x4EU -/** @brief CAN 状态载荷中调试标识字符 3。 */ -#define CONFIG_CAN_STATUS_TAG3 0x46U - -/** @brief 用户调度定时器实例。 */ -#define CONFIG_SCHED_TIMER_INSTANCE TIMER2 -/** @brief 用户调度定时器中断号。 */ -#define CONFIG_SCHED_TIMER_IRQn TIMER2_IRQn -/** @brief 用户调度定时器时钟使能宏参数。 */ -#define CONFIG_SCHED_TIMER_RCU RCU_TIMER2 -/** @brief 用户调度定时器预分频值。 */ -#define CONFIG_SCHED_TIMER_PRESCALER 179U -/** @brief 用户调度定时器周期重装值。 */ -#define CONFIG_SCHED_TIMER_PERIOD 99U -/** @brief 用户调度定时器 NVIC 抢占优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO 1U -/** @brief 用户调度定时器 NVIC 子优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_SUB_PRIO 0U - -/** @brief 调度基准节拍:ADC VREF 采样周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS 5U -/** @brief 调度基准节拍:ADC 温度采样/处理周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS 10U -/** @brief 调度基准节拍:CAN 接收轮询/解析周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_RX_TICKS 100U -/** @brief 调度基准节拍:CAN 发送/状态灯周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_TX_TICKS 1000U -/** @brief 调度基准节拍:心跳/诊断打印周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_HEARTBEAT_TICKS 10000U - -#endif /* SYS_CONFIG_H */ diff --git a/GD32E508_DCU_APP/sys/config.h.bak_txisr b/GD32E508_DCU_APP/sys/config.h.bak_txisr deleted file mode 100644 index 33a88f7..0000000 --- a/GD32E508_DCU_APP/sys/config.h.bak_txisr +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file config.h - * @brief 应用级集中配置项定义。 - * @note 用于统一管理当前项目中可调的外设、时序、通信与算法常量。 - */ -#ifndef SYS_CONFIG_H -#define SYS_CONFIG_H - -/** @brief 应用启动横幅字符串。 */ -#define APP_BANNER_TEXT "GD32E508 DCU task scheduler start" - -/** @brief USART0 默认波特率。 */ -#define CONFIG_USART0_BAUDRATE 115200U - -/** @brief ADC 外设实例。 */ -#define CONFIG_ADC_INSTANCE ADC0 -/** @brief ADC 内部温度通道号。 */ -#define CONFIG_ADC_TEMP_CHANNEL ADC_CHANNEL_16 -/** @brief ADC 内部参考电压通道号。 */ -#define CONFIG_ADC_VREFINT_CHANNEL ADC_CHANNEL_17 -/** @brief ADC 满量程计数值。 */ -#define CONFIG_ADC_MAX_VALUE 4095.0f -/** @brief 内部参考电压典型值,单位 V。 */ -#define CONFIG_ADC_VREFINT_TYPICAL_VOLTAGE 1.20f -/** @brief 温度传感器 25℃ 对应电压,单位 V。 */ -#define CONFIG_ADC_TEMP_V25 1.43f -/** @brief 温度传感器平均斜率,单位 V/℃。 */ -#define CONFIG_ADC_TEMP_AVG_SLOPE 0.0043f -/** @brief ADC 上电后稳定等待时间,单位 ms。 */ -#define CONFIG_ADC_STABILIZE_DELAY_MS 2U -/** @brief ADC 规则通道采样时间配置。 */ -#define CONFIG_ADC_SAMPLE_TIME ADC_SAMPLETIME_239POINT5 -/** @brief ADC 空输入保护时默认 VDDA,单位 V。 */ -#define CONFIG_ADC_DEFAULT_VDDA 3.3f - -/** @brief CAN 外设实例。 */ -#define CONFIG_CAN_INSTANCE CAN0 -/** @brief CAN 外设时钟使能枚举。 */ -#define CONFIG_CAN_RCU RCU_CAN0 -/** @brief CAN 状态报文标准帧 ID。 */ -#define CONFIG_CAN_STATUS_ID 0x321U -/** @brief CAN 状态载荷中调试标识字符 0。 */ -#define CONFIG_CAN_STATUS_TAG0 0x43U -/** @brief CAN 状态载荷中调试标识字符 1。 */ -#define CONFIG_CAN_STATUS_TAG1 0x41U -/** @brief CAN 状态载荷中调试标识字符 2。 */ -#define CONFIG_CAN_STATUS_TAG2 0x4EU -/** @brief CAN 状态载荷中调试标识字符 3。 */ -#define CONFIG_CAN_STATUS_TAG3 0x46U - -/** @brief 用户调度定时器实例。 */ -#define CONFIG_SCHED_TIMER_INSTANCE TIMER2 -/** @brief 用户调度定时器中断号。 */ -#define CONFIG_SCHED_TIMER_IRQn TIMER2_IRQn -/** @brief 用户调度定时器时钟使能宏参数。 */ -#define CONFIG_SCHED_TIMER_RCU RCU_TIMER2 -/** @brief 用户调度定时器预分频值。 */ -#define CONFIG_SCHED_TIMER_PRESCALER 179U -/** @brief 用户调度定时器周期重装值。 */ -#define CONFIG_SCHED_TIMER_PERIOD 99U -/** @brief 用户调度定时器 NVIC 抢占优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_PREEMPT_PRIO 1U -/** @brief 用户调度定时器 NVIC 子优先级。 */ -#define CONFIG_SCHED_TIMER_IRQ_SUB_PRIO 0U - -/** @brief 调度基准节拍:ADC VREF 采样周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS 5U -/** @brief 调度基准节拍:ADC 温度采样/处理周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS 10U -/** @brief 调度基准节拍:CAN 接收轮询/解析周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_RX_TICKS 100U -/** @brief 调度基准节拍:CAN 发送/状态灯周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_CAN_TX_TICKS 1000U -/** @brief 调度基准节拍:心跳/诊断打印周期,单位 100us tick。 */ -#define CONFIG_TASK_PERIOD_HEARTBEAT_TICKS 10000U - -#endif /* SYS_CONFIG_H */ diff --git a/GD32E508_DCU_APP/sys/initial.cpp b/GD32E508_DCU_APP/sys/initial.cpp index 9f7f1f1..3ae2bbe 100644 --- a/GD32E508_DCU_APP/sys/initial.cpp +++ b/GD32E508_DCU_APP/sys/initial.cpp @@ -13,13 +13,19 @@ #include "sys/systick.h" #include "sys/task_manager.h" +/** + * @brief 执行应用级外设与调度初始化。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 依次完成 SysTick、USART0、ADC/温度采样、CANFD、任务管理器与调度定时器的启动。 + */ void AppInitializer::init() { SysTickTimer::initMs(); Usart0::configurePins(); Usart0::init(); TempSensor::init(); - while(!Adc::dmaReady()) { } CanFd::init(); TaskManager::init(); SchedulerTimer::init(); diff --git a/GD32E508_DCU_APP/sys/initial.cpp.bak_dma b/GD32E508_DCU_APP/sys/initial.cpp.bak_dma deleted file mode 100644 index 2eb750c..0000000 --- a/GD32E508_DCU_APP/sys/initial.cpp.bak_dma +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file initial.cpp - * @brief 应用启动初始化实现。 - */ - -#include "sys/initial.h" - -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "device/usart0.h" -#include "device/Timer.h" -#include "sys/systick.h" -#include "sys/task_manager.h" - -/** - * @brief 执行应用启动所需的底层模块初始化。 - * @note 初始化顺序:系统时基 → 串口 → 温度采集 → CAN 通信 → 任务调度 → 定时器。 - */ -void app_init(void) -{ - systick_config_ms(); - usart0_gpio_config(); - usart0_config(); - temp_sensor_init(); - canfd_init(); - task_manager_init(); - user_timer_init(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/initial.cpp.bak_fixinclude b/GD32E508_DCU_APP/sys/initial.cpp.bak_fixinclude deleted file mode 100644 index 2eb750c..0000000 --- a/GD32E508_DCU_APP/sys/initial.cpp.bak_fixinclude +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file initial.cpp - * @brief 应用启动初始化实现。 - */ - -#include "sys/initial.h" - -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "device/usart0.h" -#include "device/Timer.h" -#include "sys/systick.h" -#include "sys/task_manager.h" - -/** - * @brief 执行应用启动所需的底层模块初始化。 - * @note 初始化顺序:系统时基 → 串口 → 温度采集 → CAN 通信 → 任务调度 → 定时器。 - */ -void app_init(void) -{ - systick_config_ms(); - usart0_gpio_config(); - usart0_config(); - temp_sensor_init(); - canfd_init(); - task_manager_init(); - user_timer_init(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/initial.cpp.bak_oop b/GD32E508_DCU_APP/sys/initial.cpp.bak_oop deleted file mode 100644 index f923ed2..0000000 --- a/GD32E508_DCU_APP/sys/initial.cpp.bak_oop +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file initial.cpp - * @brief 应用启动初始化实现。 - */ - -#include "sys/initial.h" - -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "device/usart0.h" -#include "device/Timer.h" -#include "device/adc.h" -#include "sys/systick.h" -#include "sys/task_manager.h" - -/** - * @brief 执行应用启动所需的底层模块初始化。 - * @note 初始化顺序:系统时基 → 串口 → 温度采集 → CAN 通信 → 任务调度 → 定时器。 - */ -void app_init(void) -{ - systick_config_ms(); - usart0_gpio_config(); - usart0_config(); - temp_sensor_init(); - while(adc_dma_ready() == 0U) { - } - canfd_init(); - task_manager_init(); - user_timer_init(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/initial.cpp.bak_restore b/GD32E508_DCU_APP/sys/initial.cpp.bak_restore deleted file mode 100644 index 5fef8ca..0000000 --- a/GD32E508_DCU_APP/sys/initial.cpp.bak_restore +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file initial.cpp - * @brief 应用启动初始化实现。 - */ - -#include "initial.h" - -#include "../device/canfd.h" -#include "../device/temp_sensor.h" -#include "../device/usart0.h" -#include "../device/Timer.h" -#include "systick.h" -#include "task_manager.h" - -/** - * @brief 执行应用启动所需的底层模块初始化。 - * @note 初始化顺序:系统时基 → 串口 → 温度采集 → CAN 通信 → 任务调度 → 定时器。 - */ -void app_init(void) -{ - systick_config_ms(); - usart0_gpio_config(); - usart0_config(); - temp_sensor_init(); - canfd_init(); - task_manager_init(); - user_timer_init(); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/initial.h b/GD32E508_DCU_APP/sys/initial.h index 6c6e912..886c266 100644 --- a/GD32E508_DCU_APP/sys/initial.h +++ b/GD32E508_DCU_APP/sys/initial.h @@ -3,11 +3,18 @@ /** * @brief 应用初始化器。 - * @note 负责组织系统时基、串口、采样、通信、调度器等模块的启动顺序。 + * @note 负责按固定顺序组织系统时基、串口、采样、通信、调度器等底层模块启动。 */ class AppInitializer { public: + /** + * @brief 按固定顺序完成应用所有底层模块初始化。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 初始化顺序:SysTick → USART0 GPIO/外设 → 温度采样 → 等待 ADC DMA 就绪 → CANFD → 任务调度 → 调度定时器。 + */ static void init(); }; -#endif /* SYS_INITIAL_H */ +#endif /* SYS_INITIAL_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/initial.h.bak_oop b/GD32E508_DCU_APP/sys/initial.h.bak_oop deleted file mode 100644 index 9c7ae7d..0000000 --- a/GD32E508_DCU_APP/sys/initial.h.bak_oop +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file initial.h - * @brief 应用初始化入口接口定义。 - */ -#ifndef SYS_INITIAL_H -#define SYS_INITIAL_H - -/** - * @brief 执行应用启动所需的底层模块初始化。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 按既定顺序初始化系统时基、串口、采样、通信与任务调度相关模块。 - */ -void app_init(void); - -#endif /* SYS_INITIAL_H */ diff --git a/GD32E508_DCU_APP/sys/systick.cpp b/GD32E508_DCU_APP/sys/systick.cpp index 93d56a0..9ce059e 100644 --- a/GD32E508_DCU_APP/sys/systick.cpp +++ b/GD32E508_DCU_APP/sys/systick.cpp @@ -8,17 +8,38 @@ volatile uint32_t SysTickTimer::s_ms = 0U; +/** + * @brief SysTick 中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 每次 SysTick 中断到来时,将毫秒计数器自增 1。 + */ void SysTickTimer::onInterrupt() { s_ms++; } +/** + * @brief 执行毫秒级阻塞延时。 + * @param[in] ms 需要延时的毫秒数。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 基于 SysTick 维护的毫秒计数器忙等,适用于短时初始化等待。 + */ void SysTickTimer::delayMs(uint32_t ms) { uint32_t start = s_ms; while((s_ms - start) < ms) { } } +/** + * @brief 初始化 1ms SysTick 时基。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 先更新 `SystemCoreClock`,再按 1kHz 频率配置 SysTick。 + */ void SysTickTimer::initMs() { SystemCoreClockUpdate(); @@ -26,4 +47,11 @@ void SysTickTimer::initMs() } /* ----- 中断入口 C 包装 ---------------------------------------------- */ -void SysTick_Handler(void) { SysTickTimer::onInterrupt(); } \ No newline at end of file +/** + * @brief SysTick 中断向量入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note C 向量包装函数,内部转调 `SysTickTimer::onInterrupt()`。 + */ +void SysTick_Handler(void) { SysTickTimer::onInterrupt(); } diff --git a/GD32E508_DCU_APP/sys/systick.cpp.bak_fixinclude b/GD32E508_DCU_APP/sys/systick.cpp.bak_fixinclude deleted file mode 100644 index a8c2363..0000000 --- a/GD32E508_DCU_APP/sys/systick.cpp.bak_fixinclude +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file systick.cpp - * @brief SysTick 时基配置、中断处理与毫秒延时实现。 - */ - -#include "main.h" -#include "sys/systick.h" - -/** @brief 自启动后累计的系统节拍毫秒数。 */ -static volatile uint32_t systick_ms = 0U; - -/** - * @brief SysTick 中断服务例程,每毫秒递增一次节拍计数器。 - */ -void SysTick_Handler(void) -{ - systick_ms++; -} - -/** - * @brief 执行阻塞式毫秒延时。 - * @param[in] ms 需要延时的毫秒数。 - */ -void delay_ms(uint32_t ms) -{ - uint32_t start = systick_ms; - while((systick_ms - start) < ms) { - } -} - -/** - * @brief 配置 SysTick 为 1ms 系统节拍。 - */ -void systick_config_ms(void) -{ - SystemCoreClockUpdate(); - SysTick_Config(SystemCoreClock / 1000U); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/systick.cpp.bak_oop b/GD32E508_DCU_APP/sys/systick.cpp.bak_oop deleted file mode 100644 index a8c2363..0000000 --- a/GD32E508_DCU_APP/sys/systick.cpp.bak_oop +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file systick.cpp - * @brief SysTick 时基配置、中断处理与毫秒延时实现。 - */ - -#include "main.h" -#include "sys/systick.h" - -/** @brief 自启动后累计的系统节拍毫秒数。 */ -static volatile uint32_t systick_ms = 0U; - -/** - * @brief SysTick 中断服务例程,每毫秒递增一次节拍计数器。 - */ -void SysTick_Handler(void) -{ - systick_ms++; -} - -/** - * @brief 执行阻塞式毫秒延时。 - * @param[in] ms 需要延时的毫秒数。 - */ -void delay_ms(uint32_t ms) -{ - uint32_t start = systick_ms; - while((systick_ms - start) < ms) { - } -} - -/** - * @brief 配置 SysTick 为 1ms 系统节拍。 - */ -void systick_config_ms(void) -{ - SystemCoreClockUpdate(); - SysTick_Config(SystemCoreClock / 1000U); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/systick.cpp.bak_restore b/GD32E508_DCU_APP/sys/systick.cpp.bak_restore deleted file mode 100644 index 9b064b1..0000000 --- a/GD32E508_DCU_APP/sys/systick.cpp.bak_restore +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file systick.cpp - * @brief SysTick 时基配置、中断处理与毫秒延时实现。 - */ - -#include "../main.h" -#include "systick.h" - -/** @brief 自启动后累计的系统节拍毫秒数。 */ -static volatile uint32_t systick_ms = 0U; - -/** - * @brief SysTick 中断服务例程,每毫秒递增一次节拍计数器。 - */ -void SysTick_Handler(void) -{ - systick_ms++; -} - -/** - * @brief 执行阻塞式毫秒延时。 - * @param[in] ms 需要延时的毫秒数。 - */ -void delay_ms(uint32_t ms) -{ - uint32_t start = systick_ms; - while((systick_ms - start) < ms) { - } -} - -/** - * @brief 配置 SysTick 为 1ms 系统节拍。 - */ -void systick_config_ms(void) -{ - SystemCoreClockUpdate(); - SysTick_Config(SystemCoreClock / 1000U); -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/systick.h b/GD32E508_DCU_APP/sys/systick.h index 623a988..5e1fcfb 100644 --- a/GD32E508_DCU_APP/sys/systick.h +++ b/GD32E508_DCU_APP/sys/systick.h @@ -9,12 +9,34 @@ */ class SysTickTimer { public: + /** + * @brief 初始化 SysTick 为 1ms 系统节拍。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + */ static void initMs(); + + /** + * @brief 执行阻塞式毫秒延时。 + * @param[in] ms 需要延时的毫秒数。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 基于 1ms 中断递增的节拍计数器实现轮询延时。 + */ static void delayMs(uint32_t ms); + + /** + * @brief SysTick 中断处理入口。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 每毫秒递增内部节拍计数器。 + */ static void onInterrupt(); private: static volatile uint32_t s_ms; }; -#endif /* SYS_SYSTICK_H */ +#endif /* SYS_SYSTICK_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/systick.h.bak_oop b/GD32E508_DCU_APP/sys/systick.h.bak_oop deleted file mode 100644 index a0172a5..0000000 --- a/GD32E508_DCU_APP/sys/systick.h.bak_oop +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file systick.h - * @brief SysTick 时基配置与毫秒延时接口定义。 - */ -#ifndef SYS_SYSTICK_H -#define SYS_SYSTICK_H - -#include - -/** - * @brief 配置 SysTick 为 1ms 系统节拍。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void systick_config_ms(void); - -/** - * @brief 执行阻塞式毫秒延时。 - * @param[in] ms 需要延时的毫秒数。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void delay_ms(uint32_t ms); - -#endif /* SYS_SYSTICK_H */ diff --git a/GD32E508_DCU_APP/sys/task_manager.c.bak_20260510_0448 b/GD32E508_DCU_APP/sys/task_manager.c.bak_20260510_0448 deleted file mode 100644 index a853f4b..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.c.bak_20260510_0448 +++ /dev/null @@ -1,63 +0,0 @@ -#include "main.h" -#include "sys/task_manager.h" - -task_scheduler_t g_scheduler = {0}; - -void task_manager_init(void) -{ - g_scheduler.task_flags = 0U; - g_scheduler.tick_100us = 0U; - g_scheduler.tick_1ms = 0U; - g_scheduler.tick_10ms = 0U; - g_scheduler.tick_100ms = 0U; - g_scheduler.tick_1s = 0U; -} - -void task_manager_set(uint32_t task_mask) -{ - g_scheduler.task_flags |= task_mask; -} - -uint32_t task_manager_take_pending(void) -{ - uint32_t pending; - - __disable_irq(); - pending = g_scheduler.task_flags; - g_scheduler.task_flags &= ~pending; - __enable_irq(); - - return pending; -} - -void task_manager_tick_100us(void) -{ - g_scheduler.tick_100us++; - - if((g_scheduler.tick_100us % 5U) == 0U) { - task_manager_set(1UL << TASK_ADC_VREF_SAMPLE); - } - - if((g_scheduler.tick_100us % 10U) == 0U) { - g_scheduler.tick_1ms++; - task_manager_set((1UL << TASK_ADC_TEMP_SAMPLE) | - (1UL << TASK_ADC_PROCESS)); - } - - if((g_scheduler.tick_100us % 100U) == 0U) { - g_scheduler.tick_10ms++; - task_manager_set(1UL << TASK_CAN_POLL); - } - - if((g_scheduler.tick_100us % 1000U) == 0U) { - g_scheduler.tick_100ms++; - task_manager_set((1UL << TASK_CAN_REPORT) | - (1UL << TASK_STATUS_LED)); - } - - if((g_scheduler.tick_100us % 10000U) == 0U) { - g_scheduler.tick_1s++; - task_manager_set((1UL << TASK_HEARTBEAT) | - (1UL << TASK_DIAGNOSTIC_PRINT)); - } -} diff --git a/GD32E508_DCU_APP/sys/task_manager.cpp b/GD32E508_DCU_APP/sys/task_manager.cpp index e1f8d59..02d281c 100644 --- a/GD32E508_DCU_APP/sys/task_manager.cpp +++ b/GD32E508_DCU_APP/sys/task_manager.cpp @@ -9,6 +9,13 @@ task_scheduler_t g_scheduler = {0}; +/** + * @brief 初始化任务调度器内部状态。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 清零待执行任务位图以及所有分频节拍计数器。 + */ void TaskManager::init() { g_scheduler.task_flags = 0U; @@ -17,13 +24,32 @@ void TaskManager::init() g_scheduler.tick_10ms = 0U; g_scheduler.tick_100ms = 0U; g_scheduler.tick_1s = 0U; + g_scheduler.div_vref_sample = 0U; + g_scheduler.div_temp_sample = 0U; + g_scheduler.div_can_rx = 0U; + g_scheduler.div_can_tx = 0U; + g_scheduler.div_heartbeat = 0U; } +/** + * @brief 置位一个或多个待执行任务标志。 + * @param[in] taskMask 待置位的任务位图掩码。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 该操作不清除其他已存在的任务位。 + */ void TaskManager::set(uint32_t taskMask) { g_scheduler.task_flags |= taskMask; } +/** + * @brief 原子地取出当前所有待执行任务位图并清零。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint32_t 返回当前待执行任务位图。 + * @note 内部通过关中断实现对 `task_flags` 的原子交换。 + */ uint32_t TaskManager::takePending() { uint32_t pending; @@ -34,35 +60,54 @@ uint32_t TaskManager::takePending() return pending; } +/** + * @brief 推进一次 100us 调度节拍。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 按预设周期置位 ADC、CAN 接收、状态灯、心跳与诊断打印等任务。 + */ void TaskManager::tick100us() { g_scheduler.tick_100us++; - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS) == 0U) { + if(++g_scheduler.div_vref_sample >= CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS) { + g_scheduler.div_vref_sample = 0U; set(1UL << TASK_ADC_VREF_SAMPLE); } - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS) == 0U) { + if(++g_scheduler.div_temp_sample >= CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS) { + g_scheduler.div_temp_sample = 0U; g_scheduler.tick_1ms++; set((1UL << TASK_ADC_TEMP_SAMPLE) | (1UL << TASK_ADC_PROCESS)); } - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_CAN_RX_TICKS) == 0U) { + if(++g_scheduler.div_can_rx >= CONFIG_TASK_PERIOD_CAN_RX_TICKS) { + g_scheduler.div_can_rx = 0U; g_scheduler.tick_10ms++; set((1UL << TASK_CAN_RX_POLL) | (1UL << TASK_CAN_RX_PARSE)); } - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_CAN_TX_TICKS) == 0U) { + if(++g_scheduler.div_can_tx >= CONFIG_TASK_PERIOD_CAN_TX_TICKS) { + g_scheduler.div_can_tx = 0U; g_scheduler.tick_100ms++; - set((1UL << TASK_CAN_TX_PREPARE) | (1UL << TASK_CAN_TX_SEND) | (1UL << TASK_STATUS_LED)); + set(1UL << TASK_STATUS_LED); } - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_HEARTBEAT_TICKS) == 0U) { + if(++g_scheduler.div_heartbeat >= CONFIG_TASK_PERIOD_HEARTBEAT_TICKS) { + g_scheduler.div_heartbeat = 0U; g_scheduler.tick_1s++; set((1UL << TASK_HEARTBEAT) | (1UL << TASK_DIAGNOSTIC_PRINT)); } } +/** + * @brief 获取全局调度器状态对象引用。 + * @param[in] 无。 + * @param[out] 无。 + * @retval task_scheduler_t& 返回全局调度器状态对象引用。 + * @note 供调试或其他模块观察当前节拍与任务位图。 + */ task_scheduler_t &TaskManager::state() { return g_scheduler; diff --git a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_config b/GD32E508_DCU_APP/sys/task_manager.cpp.bak_config deleted file mode 100644 index 61bc513..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_config +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file task_manager.cpp - * @brief 任务标志调度与时基驱动实现。 - */ - -#include "main.h" -#include "sys/task_manager.h" - -task_scheduler_t g_scheduler = {0}; - -/** - * @brief 初始化任务管理器内部状态。 - */ -void task_manager_init(void) -{ - g_scheduler.task_flags = 0U; - g_scheduler.tick_100us = 0U; - g_scheduler.tick_1ms = 0U; - g_scheduler.tick_10ms = 0U; - g_scheduler.tick_100ms = 0U; - g_scheduler.tick_1s = 0U; -} - -/** - * @brief 设置一个或多个待执行任务标志。 - * @param[in] task_mask 待置位的任务位图掩码。 - */ -void task_manager_set(uint32_t task_mask) -{ - g_scheduler.task_flags |= task_mask; -} - -/** - * @brief 原子地取出当前所有待执行任务标志并清零。 - * @retval 返回当前待执行任务位图。 - */ -uint32_t task_manager_take_pending(void) -{ - uint32_t pending; - - __disable_irq(); - pending = g_scheduler.task_flags; - g_scheduler.task_flags &= ~pending; - __enable_irq(); - - return pending; -} - -/** - * @brief 推进一次 100us 调度节拍并按周期置位待执行任务。 - * @note 按 500us / 1ms / 10ms / 100ms / 1s 档次分别置位对应任务组。 - */ -void task_manager_tick_100us(void) -{ - g_scheduler.tick_100us++; - - if((g_scheduler.tick_100us % 5U) == 0U) { - task_manager_set(1UL << TASK_ADC_VREF_SAMPLE); - } - - if((g_scheduler.tick_100us % 10U) == 0U) { - g_scheduler.tick_1ms++; - task_manager_set((1UL << TASK_ADC_TEMP_SAMPLE) | - (1UL << TASK_ADC_PROCESS)); - } - - if((g_scheduler.tick_100us % 100U) == 0U) { - g_scheduler.tick_10ms++; - task_manager_set((1UL << TASK_CAN_RX_POLL) | - (1UL << TASK_CAN_RX_PARSE)); - } - - if((g_scheduler.tick_100us % 1000U) == 0U) { - g_scheduler.tick_100ms++; - task_manager_set((1UL << TASK_CAN_TX_PREPARE) | - (1UL << TASK_CAN_TX_SEND) | - (1UL << TASK_STATUS_LED)); - } - - if((g_scheduler.tick_100us % 10000U) == 0U) { - g_scheduler.tick_1s++; - task_manager_set((1UL << TASK_HEARTBEAT) | - (1UL << TASK_DIAGNOSTIC_PRINT)); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_fixinclude b/GD32E508_DCU_APP/sys/task_manager.cpp.bak_fixinclude deleted file mode 100644 index 61bc513..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_fixinclude +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file task_manager.cpp - * @brief 任务标志调度与时基驱动实现。 - */ - -#include "main.h" -#include "sys/task_manager.h" - -task_scheduler_t g_scheduler = {0}; - -/** - * @brief 初始化任务管理器内部状态。 - */ -void task_manager_init(void) -{ - g_scheduler.task_flags = 0U; - g_scheduler.tick_100us = 0U; - g_scheduler.tick_1ms = 0U; - g_scheduler.tick_10ms = 0U; - g_scheduler.tick_100ms = 0U; - g_scheduler.tick_1s = 0U; -} - -/** - * @brief 设置一个或多个待执行任务标志。 - * @param[in] task_mask 待置位的任务位图掩码。 - */ -void task_manager_set(uint32_t task_mask) -{ - g_scheduler.task_flags |= task_mask; -} - -/** - * @brief 原子地取出当前所有待执行任务标志并清零。 - * @retval 返回当前待执行任务位图。 - */ -uint32_t task_manager_take_pending(void) -{ - uint32_t pending; - - __disable_irq(); - pending = g_scheduler.task_flags; - g_scheduler.task_flags &= ~pending; - __enable_irq(); - - return pending; -} - -/** - * @brief 推进一次 100us 调度节拍并按周期置位待执行任务。 - * @note 按 500us / 1ms / 10ms / 100ms / 1s 档次分别置位对应任务组。 - */ -void task_manager_tick_100us(void) -{ - g_scheduler.tick_100us++; - - if((g_scheduler.tick_100us % 5U) == 0U) { - task_manager_set(1UL << TASK_ADC_VREF_SAMPLE); - } - - if((g_scheduler.tick_100us % 10U) == 0U) { - g_scheduler.tick_1ms++; - task_manager_set((1UL << TASK_ADC_TEMP_SAMPLE) | - (1UL << TASK_ADC_PROCESS)); - } - - if((g_scheduler.tick_100us % 100U) == 0U) { - g_scheduler.tick_10ms++; - task_manager_set((1UL << TASK_CAN_RX_POLL) | - (1UL << TASK_CAN_RX_PARSE)); - } - - if((g_scheduler.tick_100us % 1000U) == 0U) { - g_scheduler.tick_100ms++; - task_manager_set((1UL << TASK_CAN_TX_PREPARE) | - (1UL << TASK_CAN_TX_SEND) | - (1UL << TASK_STATUS_LED)); - } - - if((g_scheduler.tick_100us % 10000U) == 0U) { - g_scheduler.tick_1s++; - task_manager_set((1UL << TASK_HEARTBEAT) | - (1UL << TASK_DIAGNOSTIC_PRINT)); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_oop b/GD32E508_DCU_APP/sys/task_manager.cpp.bak_oop deleted file mode 100644 index eb9be32..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_oop +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file task_manager.cpp - * @brief 任务标志调度与时基驱动实现。 - */ - -#include "main.h" -#include "sys/task_manager.h" -#include "sys/config.h" - -task_scheduler_t g_scheduler = {0}; - -/** - * @brief 初始化任务管理器内部状态。 - */ -void task_manager_init(void) -{ - g_scheduler.task_flags = 0U; - g_scheduler.tick_100us = 0U; - g_scheduler.tick_1ms = 0U; - g_scheduler.tick_10ms = 0U; - g_scheduler.tick_100ms = 0U; - g_scheduler.tick_1s = 0U; -} - -/** - * @brief 设置一个或多个待执行任务标志。 - * @param[in] task_mask 待置位的任务位图掩码。 - */ -void task_manager_set(uint32_t task_mask) -{ - g_scheduler.task_flags |= task_mask; -} - -/** - * @brief 原子地取出当前所有待执行任务标志并清零。 - * @retval 返回当前待执行任务位图。 - */ -uint32_t task_manager_take_pending(void) -{ - uint32_t pending; - - __disable_irq(); - pending = g_scheduler.task_flags; - g_scheduler.task_flags &= ~pending; - __enable_irq(); - - return pending; -} - -/** - * @brief 推进一次 100us 调度节拍并按周期置位待执行任务。 - * @note 按 500us / 1ms / 10ms / 100ms / 1s 档次分别置位对应任务组。 - */ -void task_manager_tick_100us(void) -{ - g_scheduler.tick_100us++; - - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_VREF_SAMPLE_TICKS) == 0U) { - task_manager_set(1UL << TASK_ADC_VREF_SAMPLE); - } - - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_TEMP_SAMPLE_TICKS) == 0U) { - g_scheduler.tick_1ms++; - task_manager_set((1UL << TASK_ADC_TEMP_SAMPLE) | - (1UL << TASK_ADC_PROCESS)); - } - - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_CAN_RX_TICKS) == 0U) { - g_scheduler.tick_10ms++; - task_manager_set((1UL << TASK_CAN_RX_POLL) | - (1UL << TASK_CAN_RX_PARSE)); - } - - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_CAN_TX_TICKS) == 0U) { - g_scheduler.tick_100ms++; - task_manager_set((1UL << TASK_CAN_TX_PREPARE) | - (1UL << TASK_CAN_TX_SEND) | - (1UL << TASK_STATUS_LED)); - } - - if((g_scheduler.tick_100us % CONFIG_TASK_PERIOD_HEARTBEAT_TICKS) == 0U) { - g_scheduler.tick_1s++; - task_manager_set((1UL << TASK_HEARTBEAT) | - (1UL << TASK_DIAGNOSTIC_PRINT)); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_restore b/GD32E508_DCU_APP/sys/task_manager.cpp.bak_restore deleted file mode 100644 index c1e0c0f..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.cpp.bak_restore +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file task_manager.cpp - * @brief 任务标志调度与时基驱动实现。 - */ - -#include "../main.h" -#include "task_manager.h" - -task_scheduler_t g_scheduler = {0}; - -/** - * @brief 初始化任务管理器内部状态。 - */ -void task_manager_init(void) -{ - g_scheduler.task_flags = 0U; - g_scheduler.tick_100us = 0U; - g_scheduler.tick_1ms = 0U; - g_scheduler.tick_10ms = 0U; - g_scheduler.tick_100ms = 0U; - g_scheduler.tick_1s = 0U; -} - -/** - * @brief 设置一个或多个待执行任务标志。 - * @param[in] task_mask 待置位的任务位图掩码。 - */ -void task_manager_set(uint32_t task_mask) -{ - g_scheduler.task_flags |= task_mask; -} - -/** - * @brief 原子地取出当前所有待执行任务标志并清零。 - * @retval 返回当前待执行任务位图。 - */ -uint32_t task_manager_take_pending(void) -{ - uint32_t pending; - - __disable_irq(); - pending = g_scheduler.task_flags; - g_scheduler.task_flags &= ~pending; - __enable_irq(); - - return pending; -} - -/** - * @brief 推进一次 100us 调度节拍并按周期置位待执行任务。 - * @note 按 500us / 1ms / 10ms / 100ms / 1s 档次分别置位对应任务组。 - */ -void task_manager_tick_100us(void) -{ - g_scheduler.tick_100us++; - - if((g_scheduler.tick_100us % 5U) == 0U) { - task_manager_set(1UL << TASK_ADC_VREF_SAMPLE); - } - - if((g_scheduler.tick_100us % 10U) == 0U) { - g_scheduler.tick_1ms++; - task_manager_set((1UL << TASK_ADC_TEMP_SAMPLE) | - (1UL << TASK_ADC_PROCESS)); - } - - if((g_scheduler.tick_100us % 100U) == 0U) { - g_scheduler.tick_10ms++; - task_manager_set((1UL << TASK_CAN_RX_POLL) | - (1UL << TASK_CAN_RX_PARSE)); - } - - if((g_scheduler.tick_100us % 1000U) == 0U) { - g_scheduler.tick_100ms++; - task_manager_set((1UL << TASK_CAN_TX_PREPARE) | - (1UL << TASK_CAN_TX_SEND) | - (1UL << TASK_STATUS_LED)); - } - - if((g_scheduler.tick_100us % 10000U) == 0U) { - g_scheduler.tick_1s++; - task_manager_set((1UL << TASK_HEARTBEAT) | - (1UL << TASK_DIAGNOSTIC_PRINT)); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_manager.h b/GD32E508_DCU_APP/sys/task_manager.h index 8c37329..9390ae5 100644 --- a/GD32E508_DCU_APP/sys/task_manager.h +++ b/GD32E508_DCU_APP/sys/task_manager.h @@ -6,15 +6,53 @@ /** * @brief 任务调度管理器。 - * @note 负责维护节拍计数器与待执行任务位图。 + * @note 负责维护各类节拍计数器与待执行任务位图,由定时器中断与主循环共享访问。 */ class TaskManager { public: + /** + * @brief 初始化调度器内部状态。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 将所有节拍计数器和任务标志位清零。 + */ static void init(); + + /** + * @brief 推进一次 100us 调度节拍。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 由 TIMER2 ISR 调用;按周期分档置位 ADC/CAN/LED/心跳/诊断等任务标志。 + */ static void tick100us(); + + /** + * @brief 原子地取出当前所有待执行任务位图并清零。 + * @param[in] 无。 + * @param[out] 无。 + * @retval uint32_t 返回当前待执行任务位图。 + * @note 内部通过关中断保证原子性,供 TaskRunner 消费。 + */ static uint32_t takePending(); + + /** + * @brief 置位一个或多个待执行任务标志。 + * @param[in] taskMask 待置位的任务位图掩码。 + * @param[out] 无。 + * @retval 无返回值。 + */ static void set(uint32_t taskMask); + + /** + * @brief 获取全局调度器状态对象引用。 + * @param[in] 无。 + * @param[out] 无。 + * @retval task_scheduler_t& 全局调度器状态对象的引用。 + * @note 提供外部模块对调度状态的可观型访问。 + */ static task_scheduler_t &state(); }; -#endif /* SYS_TASK_MANAGER_H */ +#endif /* SYS_TASK_MANAGER_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_manager.h.bak_20260510_0448 b/GD32E508_DCU_APP/sys/task_manager.h.bak_20260510_0448 deleted file mode 100644 index 3c9c51a..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.h.bak_20260510_0448 +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SYS_TASK_MANAGER_H -#define SYS_TASK_MANAGER_H - -#include - -void task_manager_init(void); -void task_manager_tick_100us(void); -uint32_t task_manager_take_pending(void); -void task_manager_set(uint32_t task_mask); - -#endif /* SYS_TASK_MANAGER_H */ diff --git a/GD32E508_DCU_APP/sys/task_manager.h.bak_oop b/GD32E508_DCU_APP/sys/task_manager.h.bak_oop deleted file mode 100644 index 9b17811..0000000 --- a/GD32E508_DCU_APP/sys/task_manager.h.bak_oop +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file task_manager.h - * @brief 任务标志调度与时基驱动接口定义。 - */ -#ifndef SYS_TASK_MANAGER_H -#define SYS_TASK_MANAGER_H - -#include - -/** - * @brief 初始化任务管理器内部状态。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void task_manager_init(void); - -/** - * @brief 推进一次 100us 调度节拍并按周期置位待执行任务。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void task_manager_tick_100us(void); - -/** - * @brief 原子地取出当前所有待执行任务标志。 - * @param[in] 无。 - * @param[out] 无。 - * @retval uint32_t 返回当前待执行任务位图,并在内部清除对应标志。 - */ -uint32_t task_manager_take_pending(void); - -/** - * @brief 设置一个或多个待执行任务标志。 - * @param[in] task_mask 待置位的任务位图掩码。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void task_manager_set(uint32_t task_mask); - -#endif /* SYS_TASK_MANAGER_H */ diff --git a/GD32E508_DCU_APP/sys/task_runner.cpp b/GD32E508_DCU_APP/sys/task_runner.cpp index f59adba..c12affb 100644 --- a/GD32E508_DCU_APP/sys/task_runner.cpp +++ b/GD32E508_DCU_APP/sys/task_runner.cpp @@ -7,87 +7,181 @@ #include "device/adc.h" #include "device/canfd.h" #include "device/temp_sensor.h" +#include "sys/config.h" #include "sys/task_manager.h" #include "sys/task_runner.h" struct TaskRunner::Runtime { temp_sensor_data_t sample{}; - uint16_t last_vin_raw; - uint16_t last_vref_raw; - uint16_t last_temp_raw; - uint32_t last_rx_id; - uint8_t last_rx_len; - uint8_t last_rx_data[64]; + uint8_t last_rx_channel = 0U; + uint32_t last_rx_id = 0U; + uint8_t last_rx_len = 0U; + uint8_t last_rx_data[64] = {0}; }; TaskRunner::Runtime TaskRunner::s_runtime; +/** + * @brief 采样 VIN 与 VREF 原始 ADC 数值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 从 ADC DMA 缓冲中读取外部 VIN_ADC 与内部 VREFINT 通道最新值。 + */ void TaskRunner::taskAdcVrefSample() { - s_runtime.last_vin_raw = Adc::readVinRaw(); - s_runtime.last_vref_raw = Adc::readVrefRaw(); + Adc::collectSample(&s_runtime.sample); } +/** + * @brief 采样内部温度通道原始 ADC 数值。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 读取 ADC DMA 缓冲中的内部温度通道最新值。 + */ void TaskRunner::taskAdcTempSample() { - s_runtime.last_temp_raw = Adc::readTempRaw(); + Adc::collectSample(&s_runtime.sample); } +/** + * @brief 根据原始采样值计算工程量结果。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 输出 `vin_adc_v`、`vdda` 和 `temperature` 等可直接使用的工程值。 + */ void TaskRunner::taskAdcProcess() { - auto &s = s_runtime.sample; - s.vin_raw = s_runtime.last_vin_raw; - s.vref_raw = s_runtime.last_vref_raw; - s.temp_raw = s_runtime.last_temp_raw; - s.vdda = Adc::calculateVdda(s.vref_raw); - s.vin_adc_v = Adc::calculateVinAdcVoltage(s.vin_raw, s.vdda); - s.temperature = Adc::calculateTemperature(s.temp_raw, s.vdda); + /* 当前采样任务已直接调用 Adc::collectSample() 填充工程值。 + * 该处理任务保留为调度兼容入口,后续若重新拆分采样/换算阶段,可在此恢复。 */ + (void)s_runtime.sample; } +/** + * @brief 执行兼容保留的 CAN 接收轮询任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前三路 CANFD 接收已由 RX0 中断驱动,该任务仅保留接口兼容性。 + */ void TaskRunner::taskCanRxPoll() { CanFd::poll(); } -void TaskRunner::taskCanTxSend() { CanFd::sendPrepared(); } +/** + * @brief 执行预留的 CAN 发送执行任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前阶段不做周期性发送调度;若后续需要显式验证某一路发送能力,可由调用方先 prepare,再直接调用 `CanFd::sendPrepared()`。 + */ +void TaskRunner::taskCanTxSend() +{ + /* 当前阶段不做周期性发送调度。 + * 若后续需要显式验证某一路发送能力,可由调用方先 prepare,再直接调用 CanFd::sendPrepared()。 */ +} + +/** + * @brief 解析并消费一帧待处理的 CAN 接收报文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 若当前存在待消费报文,则更新最近一次接收的 ID、数据长度、数据内容与来源通道号。 + */ void TaskRunner::taskCanRxParse() { if(CanFd::hasRxFrame()) - CanFd::consumeRxFrame(&s_runtime.last_rx_id, s_runtime.last_rx_data, &s_runtime.last_rx_len); + CanFd::consumeRxFrame(&s_runtime.last_rx_id, s_runtime.last_rx_data, &s_runtime.last_rx_len, &s_runtime.last_rx_channel); } +/** + * @brief 执行预留的 CAN 发送准备任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前阶段三路 CANFD 仅要求底层收发能力可用,不做周期性业务状态广播;后续若需要恢复按通道发送,可在此处显式调用 `CanFd::prepareStatusForChannel()` 或 `CanFd::prepareStatus()`。 + */ void TaskRunner::taskCanTxPrepare() { - CanFd::StatusPayload status; - status.temp_raw = s_runtime.sample.temp_raw; - status.vref_raw = s_runtime.sample.vref_raw; - status.vdda = s_runtime.sample.vdda; - status.temperature = s_runtime.sample.temperature; - CanFd::prepareStatus(&status); + /* 当前阶段三路 CANFD 只要求底层收发能力可用,不做周期性业务状态广播。 + * 保留该任务入口,后续若需要恢复按通道发送,可在此处显式调用: + * CanFd::prepareStatusForChannel(channel, &status); + * 或: + * CanFd::prepareStatus(&status); + */ } +/** + * @brief 执行状态灯维护任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前仅保留任务入口,具体状态灯策略尚未实现。 + */ void TaskRunner::taskStatusLed() { /* 预留 */ } + +/** + * @brief 执行系统心跳维护任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 当前仅保留任务入口,后续可在此加入周期健康检查或轻量保活逻辑。 + */ void TaskRunner::taskHeartbeat() { /* 预留 */ } +/** + * @brief 输出当前温度、电压与 CAN 诊断信息。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 由 1 秒节拍触发,通过 UART 打印当前温度、电压,以及最近一次 CAN 接收与统计信息。 + */ void TaskRunner::taskDiagnosticPrint() { const auto *diag = CanFd::diag(); const auto &s = s_runtime.sample; - printf("vin_raw=%u, vin_adc=%.3f V, temp_raw=%u, vref_raw=%u, vdda=%.3f V, temp=%.2f C, rx_id=0x%08lX, rx_len=%u, can_tx=%lu, can_rx=%lu, can_err=%lu\r\n", - s.vin_raw, s.vin_adc_v, s.temp_raw, s.vref_raw, s.vdda, s.temperature, +#if (CONFIG_UART_DIAG_LEVEL == 0) + printf("temp=%.2f C, vdda=%.3f V, vin_adc=%.3f V\r\n", + s.temperature, + s.vdda, + s.vin_adc_v); +#else + printf("temp=%.2f C, vdda=%.3f V, vin_adc=%.3f V, rx_ch=%u, rx_id=0x%08lX, rx_len=%u, tx_ch=%u, can_tx=%lu, can_rx=%lu, can_drop=%lu, tx_drop=%lu, can_err=%lu\r\n", + s.temperature, + s.vdda, + s.vin_adc_v, + static_cast(s_runtime.last_rx_channel), static_cast(s_runtime.last_rx_id), static_cast(s_runtime.last_rx_len), + static_cast(diag->last_tx_channel), static_cast(diag->tx_count), static_cast(diag->rx_count), + static_cast(diag->rx_drop_count), + static_cast(diag->tx_drop_count), static_cast(diag->error_count)); +#endif } +/** + * @brief 初始化任务执行器运行时上下文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 执行一次完整 ADC 采样,并同步填充运行时缓存的原始值起点。 + */ void TaskRunner::init() { Adc::collectSample(&s_runtime.sample); - s_runtime.last_vin_raw = s_runtime.sample.vin_raw; - s_runtime.last_vref_raw = s_runtime.sample.vref_raw; - s_runtime.last_temp_raw = s_runtime.sample.temp_raw; } +/** + * @brief 执行当前所有已置位的待处理任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 先原子取出任务位图;若当前没有待处理任务则直接返回。 + */ void TaskRunner::runPending() { const uint32_t pending = TaskManager::takePending(); @@ -98,8 +192,6 @@ void TaskRunner::runPending() if(pending & (1UL << TASK_ADC_PROCESS)) taskAdcProcess(); if(pending & (1UL << TASK_CAN_RX_POLL)) taskCanRxPoll(); if(pending & (1UL << TASK_CAN_RX_PARSE)) taskCanRxParse(); - if(pending & (1UL << TASK_CAN_TX_PREPARE)) taskCanTxPrepare(); - if(pending & (1UL << TASK_CAN_TX_SEND)) taskCanTxSend(); if(pending & (1UL << TASK_STATUS_LED)) taskStatusLed(); if(pending & (1UL << TASK_HEARTBEAT)) taskHeartbeat(); if(pending & (1UL << TASK_DIAGNOSTIC_PRINT)) taskDiagnosticPrint(); diff --git a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_fixinclude b/GD32E508_DCU_APP/sys/task_runner.cpp.bak_fixinclude deleted file mode 100644 index 342188b..0000000 --- a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_fixinclude +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file task_runner.cpp - * @brief 任务执行器初始化与待执行任务分发实现。 - */ - -#include "main.h" -#include "device/adc.h" -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "sys/task_manager.h" -#include "sys/task_runner.h" - -namespace { -/** @brief 应用运行时上下文,保存各任务间共享的最新数据。 */ -struct AppRuntime { - temp_sensor_data_t sample{}; - uint16_t last_vref_raw = 0U; - uint16_t last_temp_raw = 0U; - uint32_t last_rx_id = 0U; - uint8_t last_rx_len = 0U; - uint8_t last_rx_data[64] = {0}; -}; - -AppRuntime g_app{}; - -/** - * @brief 采样内部参考电压原始值。 - */ -inline void task_adc_vref_sample() -{ - g_app.last_vref_raw = adc_read_vref_raw(); -} - -/** - * @brief 采样内部温度通道原始值。 - */ -inline void task_adc_temp_sample() -{ - g_app.last_temp_raw = adc_read_temp_raw(); -} - -/** - * @brief 根据采样原始值换算 VDDA 与芯片温度。 - */ -inline void task_adc_process() -{ - g_app.sample.vref_raw = g_app.last_vref_raw; - g_app.sample.temp_raw = g_app.last_temp_raw; - g_app.sample.vdda = adc_calculate_vdda(g_app.sample.vref_raw); - g_app.sample.temperature = adc_calculate_temperature(g_app.sample.temp_raw, g_app.sample.vdda); -} - -/** - * @brief 轮询 CANFD 接收 FIFO。 - */ -inline void task_can_rx_poll() -{ - canfd_poll(); -} - -/** - * @brief 解析并消费已接收的 CANFD 帧。 - */ -inline void task_can_rx_parse() -{ - if(canfd_has_rx_frame() != 0U) { - canfd_consume_rx_frame(&g_app.last_rx_id, g_app.last_rx_data, &g_app.last_rx_len); - } -} - -/** - * @brief 准备 CANFD 状态发送帧。 - */ -inline void task_can_tx_prepare() -{ - const canfd_status_payload_t status { - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - }; - canfd_prepare_status(&status); -} - -/** - * @brief 发送已准备好的 CANFD 帧。 - */ -inline void task_can_tx_send() -{ - canfd_send_prepared(); -} - -/** - * @brief 状态灯维护任务(当前为预留占位)。 - */ -inline void task_status_led() -{ -} - -/** - * @brief 系统心跳维护任务(当前为预留占位)。 - */ -inline void task_heartbeat() -{ -} - -/** - * @brief 诊断信息打印任务,输出当前所有运行时数据。 - */ -inline void task_diagnostic_print() -{ - const canfd_diag_t *diag = canfd_get_diag(); - - printf("temp_raw=%u, vref_raw=%u, vdda=%.3f V, temp=%.2f C, rx_id=0x%08lX, rx_len=%u, can_tx=%lu, can_rx=%lu, can_err=%lu\r\n", - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - static_cast(g_app.last_rx_id), - static_cast(g_app.last_rx_len), - static_cast(diag->tx_count), - static_cast(diag->rx_count), - static_cast(diag->error_count)); -} -} // namespace - -/** - * @brief 初始化任务执行器运行时上下文。 - * @note 执行一次初始采样,填充运行时数据起点。 - */ -void task_runner_init(void) -{ - adc_collect_sample(&g_app.sample); - g_app.last_vref_raw = g_app.sample.vref_raw; - g_app.last_temp_raw = g_app.sample.temp_raw; -} - -/** - * @brief 执行当前所有已置位的待处理任务。 - * @note 若当前没有待执行任务,直接返回。 - */ -void task_runner_run_pending(void) -{ - const uint32_t pending = task_manager_take_pending(); - if(pending == 0U) { - return; - } - - if((pending & (1UL << TASK_ADC_VREF_SAMPLE)) != 0U) { - task_adc_vref_sample(); - } - if((pending & (1UL << TASK_ADC_TEMP_SAMPLE)) != 0U) { - task_adc_temp_sample(); - } - if((pending & (1UL << TASK_ADC_PROCESS)) != 0U) { - task_adc_process(); - } - if((pending & (1UL << TASK_CAN_RX_POLL)) != 0U) { - task_can_rx_poll(); - } - if((pending & (1UL << TASK_CAN_RX_PARSE)) != 0U) { - task_can_rx_parse(); - } - if((pending & (1UL << TASK_CAN_TX_PREPARE)) != 0U) { - task_can_tx_prepare(); - } - if((pending & (1UL << TASK_CAN_TX_SEND)) != 0U) { - task_can_tx_send(); - } - if((pending & (1UL << TASK_STATUS_LED)) != 0U) { - task_status_led(); - } - if((pending & (1UL << TASK_HEARTBEAT)) != 0U) { - task_heartbeat(); - } - if((pending & (1UL << TASK_DIAGNOSTIC_PRINT)) != 0U) { - task_diagnostic_print(); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_oop b/GD32E508_DCU_APP/sys/task_runner.cpp.bak_oop deleted file mode 100644 index eb2f9a1..0000000 --- a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_oop +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @file task_runner.cpp - * @brief 任务执行器初始化与待执行任务分发实现。 - */ - -#include "main.h" -#include "device/adc.h" -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "sys/task_manager.h" -#include "sys/task_runner.h" - -namespace { -/** @brief 应用运行时上下文,保存各任务间共享的最新数据。 */ -struct AppRuntime { - temp_sensor_data_t sample{}; - uint16_t last_vin_raw = 0U; - uint16_t last_vref_raw = 0U; - uint16_t last_temp_raw = 0U; - uint32_t last_rx_id = 0U; - uint8_t last_rx_len = 0U; - uint8_t last_rx_data[64] = {0}; -}; - -AppRuntime g_app{}; - -/** - * @brief 采样内部参考电压原始值。 - */ -inline void task_adc_vref_sample() -{ - g_app.last_vin_raw = adc_read_vin_raw(); - g_app.last_vref_raw = adc_read_vref_raw(); -} - -/** - * @brief 采样内部温度通道原始值。 - */ -inline void task_adc_temp_sample() -{ - g_app.last_temp_raw = adc_read_temp_raw(); -} - -/** - * @brief 根据采样原始值换算 VDDA 与芯片温度。 - */ -inline void task_adc_process() -{ - g_app.sample.vin_raw = g_app.last_vin_raw; - g_app.sample.vref_raw = g_app.last_vref_raw; - g_app.sample.temp_raw = g_app.last_temp_raw; - g_app.sample.vdda = adc_calculate_vdda(g_app.sample.vref_raw); - g_app.sample.vin_adc_v = adc_calculate_vin_adc_voltage(g_app.sample.vin_raw, g_app.sample.vdda); - g_app.sample.temperature = adc_calculate_temperature(g_app.sample.temp_raw, g_app.sample.vdda); -} - -/** - * @brief 轮询 CANFD 接收 FIFO。 - */ -inline void task_can_rx_poll() -{ - canfd_poll(); -} - -/** - * @brief 解析并消费已接收的 CANFD 帧。 - */ -inline void task_can_rx_parse() -{ - if(canfd_has_rx_frame() != 0U) { - canfd_consume_rx_frame(&g_app.last_rx_id, g_app.last_rx_data, &g_app.last_rx_len); - } -} - -/** - * @brief 准备 CANFD 状态发送帧。 - */ -inline void task_can_tx_prepare() -{ - const canfd_status_payload_t status { - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - }; - canfd_prepare_status(&status); -} - -/** - * @brief 发送已准备好的 CANFD 帧。 - */ -inline void task_can_tx_send() -{ - canfd_send_prepared(); -} - -/** - * @brief 状态灯维护任务(当前为预留占位)。 - */ -inline void task_status_led() -{ -} - -/** - * @brief 系统心跳维护任务(当前为预留占位)。 - */ -inline void task_heartbeat() -{ -} - -/** - * @brief 诊断信息打印任务,输出当前所有运行时数据。 - */ -inline void task_diagnostic_print() -{ - const canfd_diag_t *diag = canfd_get_diag(); - - printf("vin_raw=%u, vin_adc=%.3f V, temp_raw=%u, vref_raw=%u, vdda=%.3f V, temp=%.2f C, rx_id=0x%08lX, rx_len=%u, can_tx=%lu, can_rx=%lu, can_err=%lu\r\n", - g_app.sample.vin_raw, - g_app.sample.vin_adc_v, - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - static_cast(g_app.last_rx_id), - static_cast(g_app.last_rx_len), - static_cast(diag->tx_count), - static_cast(diag->rx_count), - static_cast(diag->error_count)); -} -} // namespace - -/** - * @brief 初始化任务执行器运行时上下文。 - * @note 执行一次初始采样,填充运行时数据起点。 - */ -void task_runner_init(void) -{ - adc_collect_sample(&g_app.sample); - g_app.last_vin_raw = g_app.sample.vin_raw; - g_app.last_vref_raw = g_app.sample.vref_raw; - g_app.last_temp_raw = g_app.sample.temp_raw; -} - -/** - * @brief 执行当前所有已置位的待处理任务。 - * @note 若当前没有待执行任务,直接返回。 - */ -void task_runner_run_pending(void) -{ - const uint32_t pending = task_manager_take_pending(); - if(pending == 0U) { - return; - } - - if((pending & (1UL << TASK_ADC_VREF_SAMPLE)) != 0U) { - task_adc_vref_sample(); - } - if((pending & (1UL << TASK_ADC_TEMP_SAMPLE)) != 0U) { - task_adc_temp_sample(); - } - if((pending & (1UL << TASK_ADC_PROCESS)) != 0U) { - task_adc_process(); - } - if((pending & (1UL << TASK_CAN_RX_POLL)) != 0U) { - task_can_rx_poll(); - } - if((pending & (1UL << TASK_CAN_RX_PARSE)) != 0U) { - task_can_rx_parse(); - } - if((pending & (1UL << TASK_CAN_TX_PREPARE)) != 0U) { - task_can_tx_prepare(); - } - if((pending & (1UL << TASK_CAN_TX_SEND)) != 0U) { - task_can_tx_send(); - } - if((pending & (1UL << TASK_STATUS_LED)) != 0U) { - task_status_led(); - } - if((pending & (1UL << TASK_HEARTBEAT)) != 0U) { - task_heartbeat(); - } - if((pending & (1UL << TASK_DIAGNOSTIC_PRINT)) != 0U) { - task_diagnostic_print(); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_restore b/GD32E508_DCU_APP/sys/task_runner.cpp.bak_restore deleted file mode 100644 index e709cf1..0000000 --- a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_restore +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file task_runner.cpp - * @brief 任务执行器初始化与待执行任务分发实现。 - */ - -#include "../main.h" -#include "../device/adc.h" -#include "../device/canfd.h" -#include "../device/temp_sensor.h" -#include "task_manager.h" -#include "task_runner.h" - -namespace { -/** @brief 应用运行时上下文,保存各任务间共享的最新数据。 */ -struct AppRuntime { - temp_sensor_data_t sample{}; - uint16_t last_vref_raw = 0U; - uint16_t last_temp_raw = 0U; - uint32_t last_rx_id = 0U; - uint8_t last_rx_len = 0U; - uint8_t last_rx_data[64] = {0}; -}; - -AppRuntime g_app{}; - -/** - * @brief 采样内部参考电压原始值。 - */ -inline void task_adc_vref_sample() -{ - g_app.last_vref_raw = adc_read_vref_raw(); -} - -/** - * @brief 采样内部温度通道原始值。 - */ -inline void task_adc_temp_sample() -{ - g_app.last_temp_raw = adc_read_temp_raw(); -} - -/** - * @brief 根据采样原始值换算 VDDA 与芯片温度。 - */ -inline void task_adc_process() -{ - g_app.sample.vref_raw = g_app.last_vref_raw; - g_app.sample.temp_raw = g_app.last_temp_raw; - g_app.sample.vdda = adc_calculate_vdda(g_app.sample.vref_raw); - g_app.sample.temperature = adc_calculate_temperature(g_app.sample.temp_raw, g_app.sample.vdda); -} - -/** - * @brief 轮询 CANFD 接收 FIFO。 - */ -inline void task_can_rx_poll() -{ - canfd_poll(); -} - -/** - * @brief 解析并消费已接收的 CANFD 帧。 - */ -inline void task_can_rx_parse() -{ - if(canfd_has_rx_frame() != 0U) { - canfd_consume_rx_frame(&g_app.last_rx_id, g_app.last_rx_data, &g_app.last_rx_len); - } -} - -/** - * @brief 准备 CANFD 状态发送帧。 - */ -inline void task_can_tx_prepare() -{ - const canfd_status_payload_t status { - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - }; - canfd_prepare_status(&status); -} - -/** - * @brief 发送已准备好的 CANFD 帧。 - */ -inline void task_can_tx_send() -{ - canfd_send_prepared(); -} - -/** - * @brief 状态灯维护任务(当前为预留占位)。 - */ -inline void task_status_led() -{ -} - -/** - * @brief 系统心跳维护任务(当前为预留占位)。 - */ -inline void task_heartbeat() -{ -} - -/** - * @brief 诊断信息打印任务,输出当前所有运行时数据。 - */ -inline void task_diagnostic_print() -{ - const canfd_diag_t *diag = canfd_get_diag(); - - printf("temp_raw=%u, vref_raw=%u, vdda=%.3f V, temp=%.2f C, rx_id=0x%08lX, rx_len=%u, can_tx=%lu, can_rx=%lu, can_err=%lu\r\n", - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - static_cast(g_app.last_rx_id), - static_cast(g_app.last_rx_len), - static_cast(diag->tx_count), - static_cast(diag->rx_count), - static_cast(diag->error_count)); -} -} // namespace - -/** - * @brief 初始化任务执行器运行时上下文。 - * @note 执行一次初始采样,填充运行时数据起点。 - */ -void task_runner_init(void) -{ - adc_collect_sample(&g_app.sample); - g_app.last_vref_raw = g_app.sample.vref_raw; - g_app.last_temp_raw = g_app.sample.temp_raw; -} - -/** - * @brief 执行当前所有已置位的待处理任务。 - * @note 若当前没有待执行任务,直接返回。 - */ -void task_runner_run_pending(void) -{ - const uint32_t pending = task_manager_take_pending(); - if(pending == 0U) { - return; - } - - if((pending & (1UL << TASK_ADC_VREF_SAMPLE)) != 0U) { - task_adc_vref_sample(); - } - if((pending & (1UL << TASK_ADC_TEMP_SAMPLE)) != 0U) { - task_adc_temp_sample(); - } - if((pending & (1UL << TASK_ADC_PROCESS)) != 0U) { - task_adc_process(); - } - if((pending & (1UL << TASK_CAN_RX_POLL)) != 0U) { - task_can_rx_poll(); - } - if((pending & (1UL << TASK_CAN_RX_PARSE)) != 0U) { - task_can_rx_parse(); - } - if((pending & (1UL << TASK_CAN_TX_PREPARE)) != 0U) { - task_can_tx_prepare(); - } - if((pending & (1UL << TASK_CAN_TX_SEND)) != 0U) { - task_can_tx_send(); - } - if((pending & (1UL << TASK_STATUS_LED)) != 0U) { - task_status_led(); - } - if((pending & (1UL << TASK_HEARTBEAT)) != 0U) { - task_heartbeat(); - } - if((pending & (1UL << TASK_DIAGNOSTIC_PRINT)) != 0U) { - task_diagnostic_print(); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_sch b/GD32E508_DCU_APP/sys/task_runner.cpp.bak_sch deleted file mode 100644 index 342188b..0000000 --- a/GD32E508_DCU_APP/sys/task_runner.cpp.bak_sch +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file task_runner.cpp - * @brief 任务执行器初始化与待执行任务分发实现。 - */ - -#include "main.h" -#include "device/adc.h" -#include "device/canfd.h" -#include "device/temp_sensor.h" -#include "sys/task_manager.h" -#include "sys/task_runner.h" - -namespace { -/** @brief 应用运行时上下文,保存各任务间共享的最新数据。 */ -struct AppRuntime { - temp_sensor_data_t sample{}; - uint16_t last_vref_raw = 0U; - uint16_t last_temp_raw = 0U; - uint32_t last_rx_id = 0U; - uint8_t last_rx_len = 0U; - uint8_t last_rx_data[64] = {0}; -}; - -AppRuntime g_app{}; - -/** - * @brief 采样内部参考电压原始值。 - */ -inline void task_adc_vref_sample() -{ - g_app.last_vref_raw = adc_read_vref_raw(); -} - -/** - * @brief 采样内部温度通道原始值。 - */ -inline void task_adc_temp_sample() -{ - g_app.last_temp_raw = adc_read_temp_raw(); -} - -/** - * @brief 根据采样原始值换算 VDDA 与芯片温度。 - */ -inline void task_adc_process() -{ - g_app.sample.vref_raw = g_app.last_vref_raw; - g_app.sample.temp_raw = g_app.last_temp_raw; - g_app.sample.vdda = adc_calculate_vdda(g_app.sample.vref_raw); - g_app.sample.temperature = adc_calculate_temperature(g_app.sample.temp_raw, g_app.sample.vdda); -} - -/** - * @brief 轮询 CANFD 接收 FIFO。 - */ -inline void task_can_rx_poll() -{ - canfd_poll(); -} - -/** - * @brief 解析并消费已接收的 CANFD 帧。 - */ -inline void task_can_rx_parse() -{ - if(canfd_has_rx_frame() != 0U) { - canfd_consume_rx_frame(&g_app.last_rx_id, g_app.last_rx_data, &g_app.last_rx_len); - } -} - -/** - * @brief 准备 CANFD 状态发送帧。 - */ -inline void task_can_tx_prepare() -{ - const canfd_status_payload_t status { - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - }; - canfd_prepare_status(&status); -} - -/** - * @brief 发送已准备好的 CANFD 帧。 - */ -inline void task_can_tx_send() -{ - canfd_send_prepared(); -} - -/** - * @brief 状态灯维护任务(当前为预留占位)。 - */ -inline void task_status_led() -{ -} - -/** - * @brief 系统心跳维护任务(当前为预留占位)。 - */ -inline void task_heartbeat() -{ -} - -/** - * @brief 诊断信息打印任务,输出当前所有运行时数据。 - */ -inline void task_diagnostic_print() -{ - const canfd_diag_t *diag = canfd_get_diag(); - - printf("temp_raw=%u, vref_raw=%u, vdda=%.3f V, temp=%.2f C, rx_id=0x%08lX, rx_len=%u, can_tx=%lu, can_rx=%lu, can_err=%lu\r\n", - g_app.sample.temp_raw, - g_app.sample.vref_raw, - g_app.sample.vdda, - g_app.sample.temperature, - static_cast(g_app.last_rx_id), - static_cast(g_app.last_rx_len), - static_cast(diag->tx_count), - static_cast(diag->rx_count), - static_cast(diag->error_count)); -} -} // namespace - -/** - * @brief 初始化任务执行器运行时上下文。 - * @note 执行一次初始采样,填充运行时数据起点。 - */ -void task_runner_init(void) -{ - adc_collect_sample(&g_app.sample); - g_app.last_vref_raw = g_app.sample.vref_raw; - g_app.last_temp_raw = g_app.sample.temp_raw; -} - -/** - * @brief 执行当前所有已置位的待处理任务。 - * @note 若当前没有待执行任务,直接返回。 - */ -void task_runner_run_pending(void) -{ - const uint32_t pending = task_manager_take_pending(); - if(pending == 0U) { - return; - } - - if((pending & (1UL << TASK_ADC_VREF_SAMPLE)) != 0U) { - task_adc_vref_sample(); - } - if((pending & (1UL << TASK_ADC_TEMP_SAMPLE)) != 0U) { - task_adc_temp_sample(); - } - if((pending & (1UL << TASK_ADC_PROCESS)) != 0U) { - task_adc_process(); - } - if((pending & (1UL << TASK_CAN_RX_POLL)) != 0U) { - task_can_rx_poll(); - } - if((pending & (1UL << TASK_CAN_RX_PARSE)) != 0U) { - task_can_rx_parse(); - } - if((pending & (1UL << TASK_CAN_TX_PREPARE)) != 0U) { - task_can_tx_prepare(); - } - if((pending & (1UL << TASK_CAN_TX_SEND)) != 0U) { - task_can_tx_send(); - } - if((pending & (1UL << TASK_STATUS_LED)) != 0U) { - task_status_led(); - } - if((pending & (1UL << TASK_HEARTBEAT)) != 0U) { - task_heartbeat(); - } - if((pending & (1UL << TASK_DIAGNOSTIC_PRINT)) != 0U) { - task_diagnostic_print(); - } -} \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_runner.h b/GD32E508_DCU_APP/sys/task_runner.h index 6870bcd..959f098 100644 --- a/GD32E508_DCU_APP/sys/task_runner.h +++ b/GD32E508_DCU_APP/sys/task_runner.h @@ -7,23 +7,48 @@ */ class TaskRunner { public: + /** + * @brief 初始化任务执行器运行时上下文。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 执行一次初始 ADC 采样,填充运行时数据的起点。 + */ static void init(); + + /** + * @brief 执行当前所有已置位的待处理任务。 + * @param[in] 无。 + * @param[out] 无。 + * @retval 无返回值。 + * @note 若当前没有待执行任务,直接返回。 + */ static void runPending(); private: struct Runtime; static Runtime s_runtime; + /** @brief 采样 VIN/VREF 原始值。 */ static void taskAdcVrefSample(); + /** @brief 采样内部温度原始值。 */ static void taskAdcTempSample(); + /** @brief 根据采样值计算工程量。 */ static void taskAdcProcess(); + /** @brief 兼容保留的 CAN 轮询任务。 */ static void taskCanRxPoll(); + /** @brief 解析并消费接收帧。 */ static void taskCanRxParse(); + /** @brief 预留的 CAN 发送准备任务;当前不主动生成周期业务帧。 */ static void taskCanTxPrepare(); + /** @brief 预留的 CAN 发送执行任务;当前仅保留接口,不参与周期调度。 */ static void taskCanTxSend(); + /** @brief 状态灯维护任务(当前预留)。 */ static void taskStatusLed(); + /** @brief 心跳维护任务(当前预留)。 */ static void taskHeartbeat(); + /** @brief 诊断打印任务。 */ static void taskDiagnosticPrint(); }; -#endif /* SYS_TASK_RUNNER_H */ +#endif /* SYS_TASK_RUNNER_H */ \ No newline at end of file diff --git a/GD32E508_DCU_APP/sys/task_runner.h.bak_oop b/GD32E508_DCU_APP/sys/task_runner.h.bak_oop deleted file mode 100644 index 13c3530..0000000 --- a/GD32E508_DCU_APP/sys/task_runner.h.bak_oop +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file task_runner.h - * @brief 任务执行器初始化与待执行任务分发接口定义。 - */ -#ifndef SYS_TASK_RUNNER_H -#define SYS_TASK_RUNNER_H - -/** - * @brief 初始化任务执行器运行时上下文。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - */ -void task_runner_init(void); - -/** - * @brief 执行当前所有已置位的待处理任务。 - * @param[in] 无。 - * @param[out] 无。 - * @retval 无返回值。 - * @note 若当前没有待执行任务,函数直接返回。 - */ -void task_runner_run_pending(void); - -#endif /* SYS_TASK_RUNNER_H */ diff --git a/GD32E508_DCU_APP/README.md b/README.md similarity index 100% rename from GD32E508_DCU_APP/README.md rename to README.md