Files
DCU_APP/GD32E508_DCU_APP/device/ADC.cpp.bak_oop
T
cbb 4b8b47bc9b feat: 添加GD32E508 DCU应用工程的初始结构
- 新增完整的CMSIS解决方案配置,包含AC6/GCC/IAR/CLANG编译器支持
- 添加项目配置文件,定义了设备层、系统层、应用层的模块结构
- 配置ARM::CMSIS和GigaDevice::GD32E50x_DFP软件包依赖
- 创建多层代码架构:应用入口(main)、系统层(sys)、设备层(device)
- 实现任务管理系统,包含任务调度器和任务执行器分离设计
- 集成ADC、CANFD、定时器、串口、温度采样等核心功能模块
- 添加详细的README文档说明项目结构和代码组织方式
- 配置AC6链接脚本和运行时环境文件
- 设置Git忽略规则以排除编译产物和临时文件
2026-05-10 17:28:14 +08:00

219 lines
7.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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<float>(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<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 当指针非空时,写入 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);
}