feat: 添加GD32E508 DCU应用工程的初始结构

- 新增完整的CMSIS解决方案配置,包含AC6/GCC/IAR/CLANG编译器支持
- 添加项目配置文件,定义了设备层、系统层、应用层的模块结构
- 配置ARM::CMSIS和GigaDevice::GD32E50x_DFP软件包依赖
- 创建多层代码架构:应用入口(main)、系统层(sys)、设备层(device)
- 实现任务管理系统,包含任务调度器和任务执行器分离设计
- 集成ADC、CANFD、定时器、串口、温度采样等核心功能模块
- 添加详细的README文档说明项目结构和代码组织方式
- 配置AC6链接脚本和运行时环境文件
- 设置Git忽略规则以排除编译产物和临时文件
This commit is contained in:
cbb
2026-05-10 17:28:14 +08:00
commit 4b8b47bc9b
116 changed files with 36659 additions and 0 deletions
+182
View File
@@ -0,0 +1,182 @@
#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<float>(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<float>(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);
}