bsp_V8M_YY_adc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #include "board.h"
  2. #include "hpm_adc12_drv.h"
  3. #include "bsp_V8M_YY_adc.h"
  4. #include "test.h"
  5. // 一共28路adc被4个ad控制器使用 20 路给12位ad012 8路给16位ad
  6. // hpm6750没有内置的参考电压 外部一般接3.3vadc参考电压
  7. // 经2026/03/13 测试 DMA+序列的转发模式对12位ad行不通 测试多次 分别试过ad012 且用官方例程跑过 此时 单次触发 周期触发都是可以的
  8. // 必须使用同一个ADC控制器 不然要配置多个dma控制 通道可以配置的不同
  9. //
  10. static const float vref_voltage = 3.30f; /* HPM6750没有内部VREF电压 */
  11. #define ADC12_VALUE_MAX (0xFFF)
  12. #define ADC_VOLTAGE_DIVIDER_RATIO (22.0f) /* 22:1分压 */
  13. #define AD_VALUE_AVERAGE_NUM 50 // 均值滤波长度
  14. #define AD_CHANNEL_NUM 5
  15. #define ADC12_CORE BOARD_RUNNING_CORE // HPM_CORE0
  16. #define ADC12_SEQ_START_POS 0
  17. #define ADC12_CH_SAMPLE_CYCLE (20U)
  18. #define ADC12 HPM_ADC0
  19. #define ADC12_IRQ IRQn_ADC0
  20. #define ADC_CLK_NAME clock_adc0
  21. #define ADC12_CHANEL_1 0
  22. #define ADC12_CHANEL_2 1
  23. #define ADC12_CHANEL_3 2
  24. #define ADC12_CHANEL_4 3
  25. #define ADC12_CHANEL_5 7
  26. #define ADC12_CHANEL_6 // 没有内置vref
  27. /* ADC通道定义 */
  28. static uint8_t adc_channels[AD_CHANNEL_NUM] = {
  29. ADC12_CHANEL_1, /* 通道1: (飞控供电通道) */
  30. ADC12_CHANEL_2, /* 通道2: (AD1INPUT) */
  31. ADC12_CHANEL_3, /* 通道3: (AD2INPUT) */
  32. ADC12_CHANEL_4, /* 通道4: (AD3INPUT) */
  33. ADC12_CHANEL_5, /* 通道5: (AD4INPUT) */
  34. };
  35. /* DMA缓冲区 - 使用非缓存区并确保对齐 */
  36. #define ADC_DMA_BUFFER_SIZE (AD_VALUE_AVERAGE_NUM * AD_CHANNEL_NUM)
  37. ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(ADC_SOC_DMA_ADDR_ALIGNMENT) static uint32_t adc_dma_buffer[ADC_DMA_BUFFER_SIZE];
  38. /* 处理后的ADC值数组 */
  39. static uint16_t adValueBuffer[AD_VALUE_AVERAGE_NUM][AD_CHANNEL_NUM];
  40. /* 电压计算结果 */
  41. static float adVoltage_BeforCalib[AD_CHANNEL_NUM] = {0.0f};
  42. /**
  43. * 从DMA缓冲区提取数据
  44. */
  45. static void extract_adc_from_dma(void)
  46. {
  47. adc12_seq_dma_data_t *dma_data = (adc12_seq_dma_data_t *)adc_dma_buffer;
  48. uint32_t idx = 0;
  49. for (uint32_t sample = 0; sample < AD_VALUE_AVERAGE_NUM; sample++) {
  50. for (uint32_t ch = 0; ch < AD_CHANNEL_NUM; ch++) {
  51. idx = sample * AD_CHANNEL_NUM + ch;
  52. ///* 检查cycle_bit有效性 这个只是检查本次adc搬运的数据是否是最新的,对于检测电压的均值滤波来说没有意义*/
  53. //if (dma_data[idx].cycle_bit == 0) {
  54. // adValueBuffer[sample][ch] = 0xFFFF; /* 无效数据标记 */
  55. // continue;
  56. //}
  57. // 有效性检查
  58. if (dma_data[idx].adc_ch != adc_channels[ch]) {
  59. printf("警告:通道不匹配 - 预期通道%d,实际通道%d\n",
  60. adc_channels[ch], dma_data[idx].adc_ch);
  61. }
  62. //printf("Sequence Mode - %s - ", "ADC12");
  63. //printf("Cycle Bit: %02d - ", dma_data[idx].cycle_bit);
  64. //printf("Sequence Number:%02d - ", dma_data[idx].seq_num);
  65. //printf("ADC Channel: %02d - ", dma_data[idx].adc_ch);
  66. //printf("Result: 0x%04x\n", dma_data[idx].result);
  67. /* 提取纯ADC结果 */
  68. adValueBuffer[sample][ch] = dma_data[idx].result;
  69. /* 可选:验证通道号 */
  70. if (dma_data[idx].adc_ch != adc_channels[ch]) {
  71. /* 通道不匹配,但数据可能仍然有效 */
  72. }
  73. }
  74. }
  75. }
  76. static void HPM_ADC0_IO_0_5_config(void)
  77. {
  78. HPM_IOC->PAD[IOC_PAD_PE14].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 0
  79. HPM_IOC->PAD[IOC_PAD_PE15].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 1
  80. HPM_IOC->PAD[IOC_PAD_PE18].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 2
  81. HPM_IOC->PAD[IOC_PAD_PE17].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 3
  82. HPM_IOC->PAD[IOC_PAD_PE21].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK; // 7
  83. }
  84. static hpm_stat_t init_common_config(adc12_conversion_mode_t conv_mode)
  85. {
  86. adc12_config_t cfg;
  87. /* initialize an ADC instance */
  88. adc12_get_default_config(&cfg);
  89. cfg.res = adc12_res_12_bits;
  90. cfg.conv_mode = conv_mode;
  91. cfg.diff_sel = adc12_sample_signal_single_ended; // 单端
  92. cfg.adc_clk_div = adc12_clock_divider_3;
  93. cfg.sel_sync_ahb = (clk_adc_src_ahb0 == clock_get_source(ADC_CLK_NAME)) ? true : false;
  94. cfg.wait_dis = true; // 是否需要读取adc值后再开启下次转换 true不需要
  95. if (cfg.conv_mode == adc12_conv_mode_sequence ||
  96. cfg.conv_mode == adc12_conv_mode_preemption) {
  97. cfg.adc_ahb_en = true; // 启用dma 必须开启此项
  98. }
  99. /* adc12 initialization */
  100. hpm_stat_t stat = adc12_init(ADC12, &cfg);
  101. if (stat != status_success) {
  102. printf("adc init fail\r\n");
  103. }
  104. return stat;
  105. }
  106. static void init_sequence_config(void)
  107. {
  108. adc12_seq_config_t seq_cfg;
  109. adc12_dma_config_t dma_cfg;
  110. adc12_channel_config_t ch_cfg;
  111. hpm_stat_t stat;
  112. /* get a default channel config */
  113. adc12_get_channel_default_config(&ch_cfg);
  114. /* initialize an ADC channel */
  115. ch_cfg.diff_sel = adc12_sample_signal_single_ended;
  116. ch_cfg.sample_cycle = ADC12_CH_SAMPLE_CYCLE;
  117. for (uint32_t i = 0; i < sizeof(adc_channels); i++) {
  118. ch_cfg.ch = adc_channels[i]; // 初始化对应的adc通道
  119. adc12_init_channel(ADC12, &ch_cfg);
  120. printf("adc channel %d init\r\n", ch_cfg.ch );
  121. }
  122. /* Set a sequence config */
  123. seq_cfg.seq_len = sizeof(adc_channels); // 序列长度
  124. seq_cfg.restart_en = true; // 重启序列转换
  125. seq_cfg.cont_en = true; // adc通道持续转换 按照序列匹配的顺序
  126. seq_cfg.hw_trig_en = false;// 软件触发
  127. seq_cfg.sw_trig_en = true;
  128. for (int i = 0; i < seq_cfg.seq_len; i++) { // 从第一个序列开始
  129. seq_cfg.queue[i].seq_int_en = false; // 关中断
  130. seq_cfg.queue[i].ch = adc_channels[i]; // 序列对应的通道
  131. printf("seq_cfg_ch %d\r\n", seq_cfg.queue[i].ch);
  132. }
  133. /* Initialize a sequence */
  134. stat = adc12_set_seq_config(ADC12, &seq_cfg);
  135. if(stat != status_success)
  136. {
  137. printf("adc12 seq config fail\r\n");
  138. }
  139. /* Set a DMA config */
  140. dma_cfg.start_addr = (uint32_t *)core_local_mem_to_sys_address(ADC12_CORE, (uint32_t)adc_dma_buffer);
  141. dma_cfg.buff_len_in_4bytes = ADC_DMA_BUFFER_SIZE; // 设置dma传输的buffer 最大4096
  142. dma_cfg.stop_en = false; // 传输完成后不停止
  143. dma_cfg.stop_pos = 0; // 传输停止位置
  144. /* Initialize DMA for the sequence mode */
  145. stat = adc12_init_seq_dma(ADC12, &dma_cfg);
  146. if(stat != status_success)
  147. {
  148. printf("adc12 dma config fail\r\n");
  149. }
  150. }
  151. /**
  152. * ADC初始化
  153. */
  154. void V8M_YY_ADC1_Init(void)
  155. {
  156. /* 1. IO、时钟配置*/
  157. HPM_ADC0_IO_0_5_config();
  158. /* Configure the ADC clock from AHB (@200MHz by default)*/
  159. clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
  160. /* 2. 通用配置*/
  161. if(init_common_config(adc12_conv_mode_sequence) != status_success)
  162. {
  163. printf("adc12 common config error\r\n");
  164. }
  165. /* 3. 序列 DMA配置*/
  166. init_sequence_config();
  167. board_delay_ms(20);
  168. /* 4. 启动转换 */
  169. if(adc12_trigger_seq_by_sw(ADC12) != status_success)
  170. {
  171. printf("seq soft trig fail\r\n");
  172. }
  173. printf("ADC初始化完成\n");
  174. }
  175. /**
  176. * 更新电压值 - 从DMA缓冲区读取并计算
  177. */
  178. void V8M_YY_ADC_UpdateVoltage(void)
  179. {
  180. uint32_t sum[AD_CHANNEL_NUM] = {0};
  181. uint32_t valid_count[AD_CHANNEL_NUM] = {0};
  182. float adAverageValue[AD_CHANNEL_NUM] = {0.0f};
  183. /* 从DMA缓冲区提取数据 */
  184. extract_adc_from_dma();
  185. /* 计算每个通道的平均值 */
  186. for (uint8_t ch = 0; ch < AD_CHANNEL_NUM; ch++) {
  187. sum[ch] = 0;
  188. valid_count[ch] = 0;
  189. for (uint8_t sample = 0; sample < AD_VALUE_AVERAGE_NUM; sample++) {
  190. // if (adValueBuffer[sample][ch] != 0xFFFF) { // valid_count 有效值计数
  191. sum[ch] += adValueBuffer[sample][ch];
  192. valid_count[ch]++;
  193. // }
  194. }
  195. if (valid_count[ch] > 0) {
  196. adAverageValue[ch] = (float)sum[ch] / valid_count[ch];
  197. } else {
  198. adAverageValue[ch] = 0.0f;
  199. }
  200. }
  201. /* 使用内部参考电压校准 没有内部参考电压*/
  202. /* 计算外部通道电压(22倍分压) */
  203. for (int ch = 0; ch < AD_CHANNEL_NUM; ch++) {
  204. adVoltage_BeforCalib[ch] = adAverageValue[ch] / ADC12_VALUE_MAX * vref_voltage * ADC_VOLTAGE_DIVIDER_RATIO;
  205. }
  206. /* 重新启动ADC转换 连续转换不需要重新启动*/
  207. // adc12_trigger_seq_by_sw(ADC12);
  208. }
  209. /**
  210. * 获取电压值
  211. */
  212. float V8M_YY_Voltage_GetVolt(V8M_YY_ADC_ChannelType voltageChannel)
  213. {
  214. float voltage = 0.0f;
  215. switch (voltageChannel)
  216. {
  217. case V8M_YY_AD_CHANNEL_MC:
  218. voltage = adVoltage_BeforCalib[0];
  219. break;
  220. case V8M_YY_AD_CHANNEL_AD1INPUT:
  221. case V8M_YY_AD_CHANNEL_AD2INPUT:
  222. case V8M_YY_AD_CHANNEL_AD3INPUT:
  223. case V8M_YY_AD_CHANNEL_AD4INPUT:
  224. voltage = adVoltage_BeforCalib[voltageChannel];
  225. break;
  226. //case V8M_YY_AD_CHANNEL_ADVREF:
  227. // voltage = adVoltage_BeforCalib[voltageChannel];
  228. // break;
  229. default:
  230. break;
  231. }
  232. return voltage;
  233. }
  234. /* adc dma+序列 demo 2026/3/18 测试完成*/
  235. #ifdef ADC_TEST
  236. /**
  237. * @brief 简洁版打印所有ADC通道
  238. */
  239. static void V8M_YY_Voltage_PrintAllSimple(void)
  240. {
  241. // 通道名称数组
  242. const char *channel_names[] = {
  243. "MC", "AD1", "AD2", "AD3", "AD4"
  244. };
  245. printf("=== ADC电压值 ===\n");
  246. // 循环打印6个通道
  247. for (int i = 0; i < 5; i++) {
  248. float voltage = V8M_YY_Voltage_GetVolt(i);
  249. printf("通道%d(%s): %.3f V\n", i, channel_names[i], voltage);
  250. }
  251. }
  252. static void debug_adc_config(void)
  253. {
  254. printf("ADC配置调试信息:\n");
  255. printf("AD_CHANNEL_NUM: %d\n", AD_CHANNEL_NUM);
  256. printf("配置的通道:");
  257. for (int i = 0; i < AD_CHANNEL_NUM; i++) {
  258. printf("%d ", adc_channels[i]);
  259. }
  260. printf("\n");
  261. // 检查DMA缓冲区地址
  262. printf("DMA缓冲区地址: 0x%x\n", (uint32_t)adc_dma_buffer);
  263. printf("DMA缓冲区大小: %d 字节\n", sizeof(adc_dma_buffer));
  264. // 读取ADC状态寄存器
  265. printf("ADC状态: 0x%x\n", ADC12->SEQ_DMA_CFG);
  266. }
  267. void v8m_yy_adc_test(void)
  268. {
  269. V8M_YY_ADC1_Init();
  270. debug_adc_config();
  271. while(1)
  272. {
  273. V8M_YY_ADC_UpdateVoltage();
  274. V8M_YY_Voltage_PrintAllSimple();
  275. }
  276. }
  277. #endif