当前位置:   article > 正文

STM32+DMA多路+ADCHAL库函数+cubemax配置+部分解释_stm32hal adcdma

stm32hal adcdma

1.DMA有很多类型:BDMA、MDMA、DMA。这里配置的是DAM和BDMA。

——用到的外设:ADC多路通道BDMA。

——ADC1的11路,ADC2的7路,ADC3的10路,总共使用ADC28路。

——ADC1和ADC2使用DMA传输,ADC3使用BDMA传输。

——芯片:STM32H723ZGT6型号。

2.STM32Cubemax配置

——新建工程——选择对应芯片类型

——选择对应芯片——STM32H723ZGT6型号——

——选yes——

——配置管脚——28路管脚——ADC1/ADC2/ADC3对应管脚——

——配置对应ADC选项——以ADC1为例子,配置11路ADC的DMA采样——其他ADC也相应配置。

——ADC3和ADC1有点不同,需要注意——

——配置其他选项——RCC和NVIC。

——配置时钟——目前配置的是13.5MHZ的ADC时钟。

——生成文件——

——最后生成文件就可以编辑程序了——

3.编辑程序需要添加的程序

——在adc.c文件下添加代码

  1. /* USER CODE BEGIN 1 */
  2. void adc_init(void)//在adc.c文件下插入写到/* USER CODE BEGIN 1 */下和/* USER CODE END 1 */中间
  3. {
  4. MX_ADC1_Init(); //初始化调用放这里, 确保在MX_DMA_Init()初始化后面
  5. MX_ADC2_Init(); //初始化调用放这里, 确保在MX_DMA_Init()初始化后面
  6. MX_ADC3_Init(); //在MX_BDMA_Init()初始化后面
  7. //HAL_Delay(100); //有地方说这里可以等等电压稳定后再校准
  8. if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)
  9. {
  10. Error_Handler();
  11. }
  12. if (HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)
  13. {
  14. Error_Handler();
  15. }
  16. if (HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK)
  17. {
  18. Error_Handler();
  19. }
  20. if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_dmabuff, adc1_buff_Size) != HAL_OK)
  21. {
  22. Error_Handler();
  23. }
  24. if (HAL_ADC_Start_DMA(&hadc2, (uint32_t *)adc2_dmabuff, adc2_buff_Size) != HAL_OK)
  25. {
  26. Error_Handler();
  27. }
  28. if (HAL_ADC_Start_DMA(&hadc3, (uint32_t *)adc3_dmabuff, adc3_buff_Size) != HAL_OK)
  29. {
  30. Error_Handler();
  31. }
  32. }
  33. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
  34. {
  35. if(hadc->Instance == ADC1) {
  36. // flag0++;
  37. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_dmabuff[0], adc1_buff_Size);
  38. }else if(hadc->Instance == ADC2) {
  39. // flag1++;
  40. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2_dmabuff[0], adc2_buff_Size);
  41. }
  42. else if(hadc->Instance == ADC3) {
  43. // flag2++;
  44. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc3_dmabuff[0], adc3_buff_Size);
  45. }
  46. }
  47. //ADC的DMA的完成中断回调
  48. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
  49. {
  50. uint8_t j;
  51. j=1;
  52. ADC.flag_adc1=j;
  53. ADC.flag_adc2=j;
  54. ADC.flag_adc3=j;
  55. if(hadc->Instance == ADC1) {
  56. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_dmabuff[adc1_buff_Size/2], adc1_buff_Size);
  57. // HAL_ADC_Stop_DMA(&hadc1);//add//sxq3.13
  58. } else if(hadc->Instance == ADC2) {
  59. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc2_dmabuff[adc2_buff_Size/2], adc2_buff_Size);
  60. // HAL_ADC_Stop_DMA(&hadc2);//add//sxq3.13
  61. }else if(hadc->Instance == ADC3) {
  62. SCB_InvalidateDCache_by_Addr((uint32_t *) &adc3_dmabuff[adc3_buff_Size/2], adc3_buff_Size);
  63. // HAL_ADC_Stop_DMA(&hadc3);//add//sxq3.13
  64. }
  65. }
  66. void Scan_ADC(void)
  67. {
  68. uint32_t j;
  69. SCB_DisableDCache();
  70. if(ADC.flag_adc1==1){ //判断是不是ADC1进入的中断回调
  71. for(j=0;j<adc1_buff_Size;j++){
  72. ADC1_VALUE[j]=adc1_dmabuff[j];
  73. ADC.ADC1_V[j]=(float)(ADC1_VALUE[j]*3.3/65536.0);
  74. }
  75. ADC.flag_adc1=0;
  76. }
  77. if(ADC.flag_adc2==1)
  78. {
  79. for(j=0;j<adc2_buff_Size;j++){
  80. ADC2_VALUE[j]=adc2_dmabuff[j];
  81. ADC.ADC2_V[j]=(float)(ADC2_VALUE[j]*3.3/65536.0);
  82. }
  83. ADC.flag_adc2=0;
  84. }
  85. if(ADC.flag_adc3==1)
  86. {
  87. for(j=0;j<adc3_buff_Size;j++){
  88. ADC3_VALUE[j]=adc3_dmabuff[j];
  89. ADC.ADC3_V[j]=(float)(ADC3_VALUE[j]*3.3/4096.0);
  90. }
  91. ADC.flag_adc3=0;
  92. }
  93. SCB_EnableDCache();
  94. }
  95. /* USER CODE END 1 */

——在adc.c文件中需要注意的地方需要添加代码——在void MX_ADC3_Init(void)结尾的用户可以添加的代码区域添加上。

  1. /* USER CODE BEGIN ADC3_Init 2 */
  2. //ADD FOR adc3 the //ADC3只能使用BDMA ,数据访问的区域有限定,在0x38000000之后;
  3. /** Initializes and configures the Region and the memory to be protected */
  4. MPU_Region_InitTypeDef MPU_InitStruct = {0};;
  5. MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  6. MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  7. MPU_InitStruct.BaseAddress = 0x38000000;
  8. MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
  9. MPU_InitStruct.SubRegionDisable = 0x0;
  10. MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  11. MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  12. MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  13. MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  14. MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  15. MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  16. HAL_MPU_ConfigRegion(&MPU_InitStruct);
  17. /* USER CODE END ADC3_Init 2 */

——还有一个值得注意的地方——在adc.h中需要添加代码——这一步是因为BDMA的特殊,在D3区域,看参考手册可以知道D3区域地址在0x38000000。需要改变一下它的地址

  1. /* USER CODE BEGIN Includes */
  2. typedef struct {//配置使用的ADC数据存储区域结构体
  3. volatile uint32_t flag_adc1;
  4. volatile uint32_t flag_adc2;
  5. volatile uint32_t flag_adc3;
  6. float ADC1_V[adc1_buff_Size];
  7. float ADC2_V[adc2_buff_Size];
  8. float ADC3_V[adc3_buff_Size];
  9. }ADC_VALUE;
  10. ADC_VALUE ADC;
  11. extern ADC_VALUE ADC;
  12. volatile uint16_t ADC1_VALUE[adc1_buff_Size];
  13. volatile uint16_t ADC2_VALUE[adc2_buff_Size];
  14. volatile uint16_t ADC3_VALUE[adc3_buff_Size];
  15. //32字节对齐(地址+大小)
  16. //adc1_data指定到 AXI SRAM 的0x24000000
  17. //adc3_data指定到 SRAM4 的0x38000000
  18. ALIGN_32BYTES (uint16_t adc1_dmabuff[adc1_buff_Size]) __attribute__((section(".ARM.__at_0x24000080")));
  19. ALIGN_32BYTES (uint16_t adc2_dmabuff[adc2_buff_Size]) __attribute__((section(".ARM.__at_0x24000060")));
  20. ALIGN_32BYTES (uint16_t adc3_dmabuff[adc3_buff_Size]) __attribute__((section(".ARM.__at_0x38000000")));
  21. /* USER CODE END Includes */
  22. extern ADC_HandleTypeDef hadc1;
  23. extern ADC_HandleTypeDef hadc2;
  24. extern ADC_HandleTypeDef hadc3;
  25. /* USER CODE BEGIN Private defines */
  26. /* USER CODE END Private defines */
  27. void MX_ADC1_Init(void);
  28. void MX_ADC2_Init(void);
  29. void MX_ADC3_Init(void);
  30. /* USER CODE BEGIN Prototypes */
  31. void adc_init(void);//头文件声明
  32. void Scan_ADC(void);//头文件声明

——在主函数里头添加代码——

——最后编译一下,有些数据错误警告处理一下,主要流程就是这样,然后观察数组变化,

如果源头0x38000000数组里头变了,而使用的中间传递数组没变,

有可能是使用的Dcache的原因,找到程序中使能Dceche注释掉,即SCB_EnbleDCache();又或者其他你自己编写使能的函数注释掉,看能不能解决。如果没有,

看对应ADC的数据寄存器有没有变化,如果改变了,说明ADC调试通了,主要逻辑层面或者内存数据处理的问题。

如果寄存器没有变化,可能你ADC都没调通,需要重新调配。

以上仅仅属于本人学习心得,可供学习参考,禁止商用~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/753080
推荐阅读
相关标签
  

闽ICP备14008679号