OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6353|回复: 6

求助:STM32F4 单通道ADC + DMA采集出现问题

[复制链接]

11

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2019-5-15
在线时间
34 小时
发表于 2023-1-12 15:40:59 | 显示全部楼层 |阅读模式
10金钱
求助:STM32F4 ADC + DMA出现问题,只进入一次中断。我现在需求是:只需要采集单个通道PC1的模拟值,程序用CUBE生成的,可以确定的是,PC1对应的ADC通道号,和DMA通道是正确的,但是只会进去一次DMA2_Stream2_IRQHandler中断,然后程序卡死在HAL_ADC_IRQHandler函数。运行不到ADC2_Value[1] = HAL_ADC_GetValue(&hadc2);这地方.
有调过ADC+DMA的,比较熟的帮忙指教下,那个配置有问题,或者测试程序有问题,谢谢!

主函数如下:
  MX_DMA_Init();
  MX_ADC2_Init();

   HAL_ADC_Start_DMA(&hadc2,&ADC2_Value[1],1);//开启ADC终端转换
  while(1)
{
   .....
   .....
   .....
    ADC2_Value[1] = HAL_ADC_GetValue(&hadc2);

}


配置程序如下:
/* ADC2 init function */
void MX_ADC2_Init(void)
{

  /* USER CODE BEGIN ADC2_Init 0 */

  /* USER CODE END ADC2_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC2_Init 1 */

  /* USER CODE END ADC2_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = DISABLE;
  hadc2.Init.ContinuousConvMode = ENABLE;//ENABLE:开启连续转换模式
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DMAContinuousRequests = ENABLE;//ENABLE:开启连续转换模式
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;//ADC_EOC_SEQ_CONV:单通道转换完成就进入中断  ADC_EOC_SINGLE_CONV
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */

  /* USER CODE END ADC2_Init 2 */

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  if(adcHandle->Instance==ADC2)//
  {
  /* USER CODE BEGIN ADC2_MspInit 0 */

  /* USER CODE END ADC2_MspInit 0 */
    /* ADC2 clock enable */
    __HAL_RCC_ADC2_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC2 GPIO Configuration
    PC1     ------> ADC2_IN11
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* ADC2 DMA Init */
    /* ADC2 Init */
    hdma_adc2.Instance = DMA2_Stream2;
    hdma_adc2.Init.Channel = DMA_CHANNEL_1;
    hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc2.Init.MemInc = DMA_MINC_DISABLE;//因为是单通道采集,所以取消 memory增长的配置
    hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc2.Init.Mode = DMA_NORMAL;
    hdma_adc2.Init.Priority = DMA_PRIORITY_LOW;
    hdma_adc2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_adc2) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc2);

  /* USER CODE BEGIN ADC2_MspInit 1 */

  /* USER CODE END ADC2_MspInit 1 */
  }
  else
  {

  }
}

/**
  * Enable DMA controller clock
  */
void MX_DMA_Init(void)//用于ADC2采集
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);

}

void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC2)
  {
  /* USER CODE BEGIN ADC2_MspDeInit 0 */

  /* USER CODE END ADC2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC2_CLK_DISABLE();

    /**ADC2 GPIO Configuration
    PC1     ------> ADC2_IN11
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);

    /* ADC2 DMA DeInit */
    HAL_DMA_DeInit(adcHandle->DMA_Handle);
  /* USER CODE BEGIN ADC2_MspDeInit 1 */

  /* USER CODE END ADC2_MspDeInit 1 */
  }
  else
  {

  }
}

void DMA2_Stream2_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream2_IRQn 0 */

  /* USER CODE END DMA2_Stream2_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc2);
  /* USER CODE BEGIN DMA2_Stream2_IRQn 1 */

  /* USER CODE END DMA2_Stream2_IRQn 1 */
}



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-1-12 16:55:55 | 显示全部楼层
你用了DMA为什么还要取ADC数据寄存器的值,还要进ADC中断?你ADC配置的是软件触发,在程序哪里触发ADC了?
回复

使用道具 举报

11

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2019-5-15
在线时间
34 小时
 楼主| 发表于 2023-1-13 10:27:54 | 显示全部楼层
1、你用了DMA为什么还要取ADC数据寄存器的值----关于这点,我是在网上找的资料,连续转换模式的话,只需要调用一次HAL_ADC_Start_DMA开启DMA,后面只需要循环HAL_ADC_GetValue来读取值就是了吧?比如我要连续读取10次,怎么读取每次的值?程序配置与使用参考的是连接的这篇文章:https://blog.csdn.net/weixin_46158019/article/details/109717279
2、ADC中断我不知道是怎么产生的,按我的配置也没配置中断啊,也没执行HAL_ADC_Start_IT这类的函数。程序运行它的执行路径是DMA2_Stream2_IRQHandler------>HAL_ADC_ConvCpltCallback,HAL_ADC_ConvCpltCallback这个函数我程序没做任何处理,然后程序就一直执行ADC_IRQHandler,后面也不会再进去HAL_ADC_ConvCpltCallback函数了。
void ADC_IRQHandler(void)
{
  /* USER CODE BEGIN ADC_IRQn 0 */

  /* USER CODE END ADC_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC_IRQn 1 */

  /* USER CODE END ADC_IRQn 1 */
}
需要怎么修改帮忙指正下,谢谢!
回复

使用道具 举报

11

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2019-5-15
在线时间
34 小时
 楼主| 发表于 2023-1-13 10:29:13 | 显示全部楼层
阿侑kevin 发表于 2023-1-12 16:55
你用了DMA为什么还要取ADC数据寄存器的值,还要进ADC中断?你ADC配置的是软件触发,在程序哪里触发ADC了?


1、你用了DMA为什么还要取ADC数据寄存器的值----关于这点,我是在网上找的资料,连续转换模式的话,只需要调用一次HAL_ADC_Start_DMA开启DMA,后面只需要循环HAL_ADC_GetValue来读取值就是了吧?比如我要连续读取10次,怎么读取每次的值?程序配置与使用参考的是连接的这篇文章:https://blog.csdn.net/weixin_46158019/article/details/109717279
2、ADC中断我不知道是怎么产生的,按我的配置也没配置中断啊,也没执行HAL_ADC_Start_IT这类的函数。程序运行它的执行路径是DMA2_Stream2_IRQHandler------>HAL_ADC_ConvCpltCallback,HAL_ADC_ConvCpltCallback这个函数我程序没做任何处理,然后程序就一直执行ADC_IRQHandler,后面也不会再进去HAL_ADC_ConvCpltCallback函数了。
void ADC_IRQHandler(void)
{
  /* USER CODE BEGIN ADC_IRQn 0 */

  /* USER CODE END ADC_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC_IRQn 1 */

  /* USER CODE END ADC_IRQn 1 */
}
需要怎么修改帮忙指正下,谢谢!
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-1-13 11:07:02 | 显示全部楼层
chenshuibing 发表于 2023-1-13 10:29
1、你用了DMA为什么还要取ADC数据寄存器的值----关于这点,我是在网上找的资料,连续转换模式的话,只 ...

1、ADC+DMA的意义是每次ADC转换完成后DMA都会把ADC值搬运到指定的地方,不需要你自己取值
2、ADC配置中用的是软件触发ADC(ADC_SOFTWARE_START),但是代码中没有看到触发ADC的操作HAL_ADC_Start,既然设置了软件触发那无论是单次转换还是连续转换都需要手动触发ADC
3、ADC只进一次中断是因为ADC_EOC_SINGLE_CONV,改成ADC_EOC_SEQ_CONV
回复

使用道具 举报

11

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2019-5-15
在线时间
34 小时
 楼主| 发表于 2023-1-13 11:53:55 | 显示全部楼层
阿侑kevin 发表于 2023-1-13 11:07
1、ADC+DMA的意义是每次ADC转换完成后DMA都会把ADC值搬运到指定的地方,不需要你自己取值
2、ADC配置中 ...

按照您的提示,  在HAL_ADC_Start_DMA前增加HAL_ADC_Start(&hadc2);
  HAL_ADC_Start_DMA(&hadc2,&ADC2_Value[0],1);//开启ADC终端转换;
效果是一样的,程序进不去
while(1)里面
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-1-13 16:47:51 | 显示全部楼层
chenshuibing 发表于 2023-1-13 11:53
按照您的提示,  在HAL_ADC_Start_DMA前增加HAL_ADC_Start(&hadc2);
  HAL_ADC_Start_DMA(&hadc2,&ADC2_ ...

进不了while是停在哪了?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-24 20:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表