| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- #include "board.h"
- #include "hpm_adc12_drv.h"
- #include "bsp_V8M_YY_adc.h"
- #include "test.h"
- // 一共28路adc被4个ad控制器使用 20 路给12位ad012 8路给16位ad
- // hpm6750没有内置的参考电压 外部一般接3.3vadc参考电压
- // 经2026/03/13 测试 DMA+序列的转发模式对12位ad行不通 测试多次 分别试过ad012 且用官方例程跑过 此时 单次触发 周期触发都是可以的
- // 必须使用同一个ADC控制器 不然要配置多个dma控制 通道可以配置的不同
- //
- static const float vref_voltage = 3.30f; /* HPM6750没有内部VREF电压 */
- #define ADC12_VALUE_MAX (0xFFF)
- #define ADC_VOLTAGE_DIVIDER_RATIO (22.0f) /* 22:1分压 */
- #define AD_VALUE_AVERAGE_NUM 50 // 均值滤波长度
- #define AD_CHANNEL_NUM 5
- #define ADC12_CORE BOARD_RUNNING_CORE // HPM_CORE0
- #define ADC12_SEQ_START_POS 0
- #define ADC12_CH_SAMPLE_CYCLE (20U)
- #define ADC12 HPM_ADC0
- #define ADC12_IRQ IRQn_ADC0
- #define ADC_CLK_NAME clock_adc0
- #define ADC12_CHANEL_1 0
- #define ADC12_CHANEL_2 1
- #define ADC12_CHANEL_3 2
- #define ADC12_CHANEL_4 3
- #define ADC12_CHANEL_5 7
- #define ADC12_CHANEL_6 // 没有内置vref
- /* ADC通道定义 通道定义一定是字节*/
- static uint8_t adc_channels[AD_CHANNEL_NUM] = {
- ADC12_CHANEL_1, /* 通道1: (飞控供电通道) */
- ADC12_CHANEL_2, /* 通道2: (AD1INPUT) */
- ADC12_CHANEL_3, /* 通道3: (AD2INPUT) */
- ADC12_CHANEL_4, /* 通道4: (AD3INPUT) */
- ADC12_CHANEL_5, /* 通道5: (AD4INPUT) */
- };
- /* DMA缓冲区 - 使用非缓存区并确保对齐 */
- #define ADC_DMA_BUFFER_SIZE (AD_VALUE_AVERAGE_NUM * AD_CHANNEL_NUM)
- ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(ADC_SOC_DMA_ADDR_ALIGNMENT) static uint32_t adc_dma_buffer[ADC_DMA_BUFFER_SIZE];
- /* 处理后的ADC值数组 */
- static uint16_t adValueBuffer[AD_VALUE_AVERAGE_NUM][AD_CHANNEL_NUM];
- /* 电压计算结果 */
- static float adVoltage_BeforCalib[AD_CHANNEL_NUM] = {0.0f};
- /**
- * 从DMA缓冲区提取数据
- */
- static void extract_adc_from_dma(void)
- {
- adc12_seq_dma_data_t *dma_data = (adc12_seq_dma_data_t *)adc_dma_buffer;
- uint32_t idx = 0;
-
- for (uint32_t sample = 0; sample < AD_VALUE_AVERAGE_NUM; sample++) {
- for (uint32_t ch = 0; ch < AD_CHANNEL_NUM; ch++) {
- idx = sample * AD_CHANNEL_NUM + ch;
-
- ///* 检查cycle_bit有效性 这个只是检查本次adc搬运的数据是否是最新的,对于检测电压的均值滤波来说没有意义*/
- //if (dma_data[idx].cycle_bit == 0) {
- // adValueBuffer[sample][ch] = 0xFFFF; /* 无效数据标记 */
- // continue;
- //}
- // 有效性检查
- if (dma_data[idx].adc_ch != adc_channels[ch]) {
- printf("警告:通道不匹配 - 预期通道%d,实际通道%d\n",
- adc_channels[ch], dma_data[idx].adc_ch);
- }
- //printf("Sequence Mode - %s - ", "ADC12");
- //printf("Cycle Bit: %02d - ", dma_data[idx].cycle_bit);
- //printf("Sequence Number:%02d - ", dma_data[idx].seq_num);
- //printf("ADC Channel: %02d - ", dma_data[idx].adc_ch);
- //printf("Result: 0x%04x\n", dma_data[idx].result);
-
- /* 提取纯ADC结果 */
- adValueBuffer[sample][ch] = dma_data[idx].result;
-
- /* 可选:验证通道号 */
- if (dma_data[idx].adc_ch != adc_channels[ch]) {
- /* 通道不匹配,但数据可能仍然有效 */
- }
- }
- }
- }
- static void HPM_ADC0_IO_0_5_config(void)
- {
- HPM_IOC->PAD[IOC_PAD_PE14].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 0
- HPM_IOC->PAD[IOC_PAD_PE15].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 1
- HPM_IOC->PAD[IOC_PAD_PE18].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 2
- HPM_IOC->PAD[IOC_PAD_PE17].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 3
- HPM_IOC->PAD[IOC_PAD_PE21].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 7
- }
- static hpm_stat_t init_common_config(adc12_conversion_mode_t conv_mode)
- {
- adc12_config_t cfg;
- /* initialize an ADC instance */
- adc12_get_default_config(&cfg);
- cfg.res = adc12_res_12_bits;
- cfg.conv_mode = conv_mode;
- cfg.diff_sel = adc12_sample_signal_single_ended; // 单端
- cfg.adc_clk_div = adc12_clock_divider_3;
- cfg.sel_sync_ahb = (clk_adc_src_ahb0 == clock_get_source(ADC_CLK_NAME)) ? true : false;
- cfg.wait_dis = true; // 是否需要读取adc值后再开启下次转换 true不需要
- if (cfg.conv_mode == adc12_conv_mode_sequence ||
- cfg.conv_mode == adc12_conv_mode_preemption) {
- cfg.adc_ahb_en = true; // 启用dma 必须开启此项
- }
- /* adc12 initialization */
- hpm_stat_t stat = adc12_init(ADC12, &cfg);
- if (stat != status_success) {
- printf("adc init fail\r\n");
-
- }
- return stat;
- }
- static void init_sequence_config(void)
- {
- adc12_seq_config_t seq_cfg;
- adc12_dma_config_t dma_cfg;
- adc12_channel_config_t ch_cfg;
- hpm_stat_t stat;
- /* get a default channel config */
- adc12_get_channel_default_config(&ch_cfg);
-
- /* initialize an ADC channel */
- ch_cfg.diff_sel = adc12_sample_signal_single_ended;
- ch_cfg.sample_cycle = ADC12_CH_SAMPLE_CYCLE;
- for (uint32_t i = 0; i < sizeof(adc_channels); i++) {
- ch_cfg.ch = adc_channels[i]; // 初始化对应的adc通道
- adc12_init_channel(ADC12, &ch_cfg);
- printf("adc channel %d init\r\n", ch_cfg.ch );
- }
- /* Set a sequence config */
- seq_cfg.seq_len = sizeof(adc_channels); // 序列长度
- seq_cfg.restart_en = true; // 重启序列转换
- seq_cfg.cont_en = true; // adc通道持续转换 按照序列匹配的顺序
- seq_cfg.hw_trig_en = false;// 软件触发
- seq_cfg.sw_trig_en = true;
- for (int i = 0; i < seq_cfg.seq_len; i++) { // 从第一个序列开始
- seq_cfg.queue[i].seq_int_en = false; // 关中断
- seq_cfg.queue[i].ch = adc_channels[i]; // 序列对应的通道
- printf("seq_cfg_ch %d\r\n", seq_cfg.queue[i].ch);
- }
- /* Initialize a sequence */
- stat = adc12_set_seq_config(ADC12, &seq_cfg);
- if(stat != status_success)
- {
- printf("adc12 seq config fail\r\n");
-
- }
- /* Set a DMA config */
- dma_cfg.start_addr = (uint32_t *)core_local_mem_to_sys_address(ADC12_CORE, (uint32_t)adc_dma_buffer);
- dma_cfg.buff_len_in_4bytes = ADC_DMA_BUFFER_SIZE; // 设置dma传输的buffer 最大4096
- dma_cfg.stop_en = false; // 传输完成后不停止
- dma_cfg.stop_pos = 0; // 传输停止位置
- /* Initialize DMA for the sequence mode */
- stat = adc12_init_seq_dma(ADC12, &dma_cfg);
- if(stat != status_success)
- {
- printf("adc12 dma config fail\r\n");
-
- }
- }
- /**
- * ADC初始化
- */
- void V8M_YY_ADC1_Init(void)
- {
- /* 1. IO、时钟配置*/
- static bool adc_is_init = false;
- if(!adc_is_init)
- {
- HPM_ADC0_IO_0_5_config();
- /* Configure the ADC clock from AHB (@200MHz by default)*/
- clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
- /* 2. 通用配置*/
- if(init_common_config(adc12_conv_mode_sequence) != status_success)
- {
- printf("adc12 common config error\r\n");
- }
- /* 3. 序列 DMA配置*/
- init_sequence_config();
- board_delay_ms(20);
- /* 4. 启动转换 */
- if(adc12_trigger_seq_by_sw(ADC12) != status_success)
- {
- printf("seq soft trig fail\r\n");
- }
-
- printf("ADC初始化完成\n");
- }
-
- }
- /**
- * 更新电压值 - 从DMA缓冲区读取并计算
- */
- void V8M_YY_ADC_UpdateVoltage(void)
- {
- uint32_t sum[AD_CHANNEL_NUM] = {0};
- uint32_t valid_count[AD_CHANNEL_NUM] = {0};
- float adAverageValue[AD_CHANNEL_NUM] = {0.0f};
-
-
- /* 从DMA缓冲区提取数据 */
- extract_adc_from_dma();
-
- /* 计算每个通道的平均值 */
- for (uint8_t ch = 0; ch < AD_CHANNEL_NUM; ch++) {
- sum[ch] = 0;
- valid_count[ch] = 0;
-
- for (uint8_t sample = 0; sample < AD_VALUE_AVERAGE_NUM; sample++) {
- // if (adValueBuffer[sample][ch] != 0xFFFF) { // valid_count 有效值计数
- sum[ch] += adValueBuffer[sample][ch];
- valid_count[ch]++;
- // }
- }
-
- if (valid_count[ch] > 0) {
- adAverageValue[ch] = (float)sum[ch] / valid_count[ch];
- } else {
- adAverageValue[ch] = 0.0f;
- }
- }
-
- /* 使用内部参考电压校准 没有内部参考电压*/
-
- /* 计算外部通道电压(22倍分压) */
- for (int ch = 0; ch < AD_CHANNEL_NUM; ch++) {
- adVoltage_BeforCalib[ch] = adAverageValue[ch] / ADC12_VALUE_MAX * vref_voltage * ADC_VOLTAGE_DIVIDER_RATIO;
- }
-
- /* 重新启动ADC转换 连续转换不需要重新启动*/
- // adc12_trigger_seq_by_sw(ADC12);
- }
- /**
- * 获取电压值
- */
- float V8M_YY_Voltage_GetVolt(V8M_YY_ADC_ChannelType voltageChannel)
- {
- float voltage = 0.0f;
- switch (voltageChannel)
- {
- case V8M_YY_AD_CHANNEL_MC:
- voltage = adVoltage_BeforCalib[0];
- break;
- case V8M_YY_AD_CHANNEL_AD1INPUT:
- case V8M_YY_AD_CHANNEL_AD2INPUT:
- case V8M_YY_AD_CHANNEL_AD3INPUT:
- case V8M_YY_AD_CHANNEL_AD4INPUT:
- voltage = adVoltage_BeforCalib[voltageChannel];
- break;
- //case V8M_YY_AD_CHANNEL_ADVREF:
- // voltage = adVoltage_BeforCalib[voltageChannel];
- // break;
- default:
- break;
- }
- return voltage;
- }
- /* adc dma+序列 demo 2026/3/18 测试完成*/
- #ifdef ADC_TEST
- /**
- * @brief 简洁版打印所有ADC通道
- */
- static void V8M_YY_Voltage_PrintAllSimple(void)
- {
- // 通道名称数组
- const char *channel_names[] = {
- "MC", "AD1", "AD2", "AD3", "AD4"
- };
-
- printf("=== ADC电压值 ===\n");
-
- // 循环打印6个通道
- for (int i = 0; i < 5; i++) {
- float voltage = V8M_YY_Voltage_GetVolt(i);
- printf("通道%d(%s): %.3f V\n", i, channel_names[i], voltage);
- }
- }
- static void debug_adc_config(void)
- {
- printf("ADC配置调试信息:\n");
- printf("AD_CHANNEL_NUM: %d\n", AD_CHANNEL_NUM);
- printf("配置的通道:");
- for (int i = 0; i < AD_CHANNEL_NUM; i++) {
- printf("%d ", adc_channels[i]);
- }
- printf("\n");
-
- // 检查DMA缓冲区地址
- printf("DMA缓冲区地址: 0x%x\n", (uint32_t)adc_dma_buffer);
- printf("DMA缓冲区大小: %d 字节\n", sizeof(adc_dma_buffer));
-
- // 读取ADC状态寄存器
- printf("ADC状态: 0x%x\n", ADC12->SEQ_DMA_CFG);
- }
- void v8m_yy_adc_test(void)
- {
- V8M_YY_ADC1_Init();
- debug_adc_config();
- while(1)
- {
- V8M_YY_ADC_UpdateVoltage();
- V8M_YY_Voltage_PrintAllSimple();
- }
-
- }
- #endif
|