bsp_V8M_YY_adc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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. static bool adc_is_init = false;
  158. if(!adc_is_init)
  159. {
  160. HPM_ADC0_IO_0_5_config();
  161. /* Configure the ADC clock from AHB (@200MHz by default)*/
  162. clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
  163. /* 2. 通用配置*/
  164. if(init_common_config(adc12_conv_mode_sequence) != status_success)
  165. {
  166. printf("adc12 common config error\r\n");
  167. }
  168. /* 3. 序列 DMA配置*/
  169. init_sequence_config();
  170. board_delay_ms(20);
  171. /* 4. 启动转换 */
  172. if(adc12_trigger_seq_by_sw(ADC12) != status_success)
  173. {
  174. printf("seq soft trig fail\r\n");
  175. }
  176. printf("ADC初始化完成\n");
  177. }
  178. }
  179. /**
  180. * 更新电压值 - 从DMA缓冲区读取并计算
  181. */
  182. void V8M_YY_ADC_UpdateVoltage(void)
  183. {
  184. uint32_t sum[AD_CHANNEL_NUM] = {0};
  185. uint32_t valid_count[AD_CHANNEL_NUM] = {0};
  186. float adAverageValue[AD_CHANNEL_NUM] = {0.0f};
  187. /* 从DMA缓冲区提取数据 */
  188. extract_adc_from_dma();
  189. /* 计算每个通道的平均值 */
  190. for (uint8_t ch = 0; ch < AD_CHANNEL_NUM; ch++) {
  191. sum[ch] = 0;
  192. valid_count[ch] = 0;
  193. for (uint8_t sample = 0; sample < AD_VALUE_AVERAGE_NUM; sample++) {
  194. // if (adValueBuffer[sample][ch] != 0xFFFF) { // valid_count 有效值计数
  195. sum[ch] += adValueBuffer[sample][ch];
  196. valid_count[ch]++;
  197. // }
  198. }
  199. if (valid_count[ch] > 0) {
  200. adAverageValue[ch] = (float)sum[ch] / valid_count[ch];
  201. } else {
  202. adAverageValue[ch] = 0.0f;
  203. }
  204. }
  205. /* 使用内部参考电压校准 没有内部参考电压*/
  206. /* 计算外部通道电压(22倍分压) */
  207. for (int ch = 0; ch < AD_CHANNEL_NUM; ch++) {
  208. adVoltage_BeforCalib[ch] = adAverageValue[ch] / ADC12_VALUE_MAX * vref_voltage * ADC_VOLTAGE_DIVIDER_RATIO;
  209. }
  210. /* 重新启动ADC转换 连续转换不需要重新启动*/
  211. // adc12_trigger_seq_by_sw(ADC12);
  212. }
  213. /**
  214. * 获取电压值
  215. */
  216. float V8M_YY_Voltage_GetVolt(V8M_YY_ADC_ChannelType voltageChannel)
  217. {
  218. float voltage = 0.0f;
  219. switch (voltageChannel)
  220. {
  221. case V8M_YY_AD_CHANNEL_MC:
  222. voltage = adVoltage_BeforCalib[0];
  223. break;
  224. case V8M_YY_AD_CHANNEL_AD1INPUT:
  225. case V8M_YY_AD_CHANNEL_AD2INPUT:
  226. case V8M_YY_AD_CHANNEL_AD3INPUT:
  227. case V8M_YY_AD_CHANNEL_AD4INPUT:
  228. voltage = adVoltage_BeforCalib[voltageChannel];
  229. break;
  230. //case V8M_YY_AD_CHANNEL_ADVREF:
  231. // voltage = adVoltage_BeforCalib[voltageChannel];
  232. // break;
  233. default:
  234. break;
  235. }
  236. return voltage;
  237. }
  238. /* adc dma+序列 demo 2026/3/18 测试完成*/
  239. #ifdef ADC_TEST
  240. /**
  241. * @brief 简洁版打印所有ADC通道
  242. */
  243. static void V8M_YY_Voltage_PrintAllSimple(void)
  244. {
  245. // 通道名称数组
  246. const char *channel_names[] = {
  247. "MC", "AD1", "AD2", "AD3", "AD4"
  248. };
  249. printf("=== ADC电压值 ===\n");
  250. // 循环打印6个通道
  251. for (int i = 0; i < 5; i++) {
  252. float voltage = V8M_YY_Voltage_GetVolt(i);
  253. printf("通道%d(%s): %.3f V\n", i, channel_names[i], voltage);
  254. }
  255. }
  256. static void debug_adc_config(void)
  257. {
  258. printf("ADC配置调试信息:\n");
  259. printf("AD_CHANNEL_NUM: %d\n", AD_CHANNEL_NUM);
  260. printf("配置的通道:");
  261. for (int i = 0; i < AD_CHANNEL_NUM; i++) {
  262. printf("%d ", adc_channels[i]);
  263. }
  264. printf("\n");
  265. // 检查DMA缓冲区地址
  266. printf("DMA缓冲区地址: 0x%x\n", (uint32_t)adc_dma_buffer);
  267. printf("DMA缓冲区大小: %d 字节\n", sizeof(adc_dma_buffer));
  268. // 读取ADC状态寄存器
  269. printf("ADC状态: 0x%x\n", ADC12->SEQ_DMA_CFG);
  270. }
  271. void v8m_yy_adc_test(void)
  272. {
  273. V8M_YY_ADC1_Init();
  274. debug_adc_config();
  275. while(1)
  276. {
  277. V8M_YY_ADC_UpdateVoltage();
  278. V8M_YY_Voltage_PrintAllSimple();
  279. }
  280. }
  281. #endif