硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1672|回复: 9
收起左侧

[ADC] STM32H7 adc采样值有异常

[复制链接]

1

主题

4

回帖

7

积分

新手上路

积分
7
发表于 2024-11-25 15:06:04 | 显示全部楼层 |阅读模式
adc1和adc2均使用adc+dma的方式传输数据,都是独立的,两个adc各有1个通道,都由tim2定时触发,频率2M;dma使用半传输完成中断,每个adc有两个buffer,长度为100,交替存储数据;adc1使用dma1_stream0,adc2使用dma1_stream1,但是dma1_stream1中断没有开,在dma1_stream0中断中拷取两个adc的值,异常值刚好就是每100个点左右就会出现,求各位大佬看看。

adc1的配置:

void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
  LL_ADC_SetBoostMode(hadc1.Instance,LL_ADC_BOOST_MODE_50MHZ);

  /* USER CODE END ADC1_Init 2 */

}



adc2的配置:

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 */

  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_18;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC2_Init 2 */
  LL_ADC_SetBoostMode(hadc2.Instance,LL_ADC_BOOST_MODE_50MHZ);
  /* USER CODE END ADC2_Init 2 */

}



tim2的配置:

void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 11;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 9;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}



dma_stream0中断拷贝数据的部分代码:


if(__HAL_DMA_GET_FLAG(&hdma_adc1,DMA_FLAG_TCIF0_4)!=RESET)
    {
        __HAL_DMA_CLEAR_FLAG(&hdma_adc1,DMA_FLAG_TCIF0_4);//清除DMA传输完成中断标志位  
        if(g_adc1dma_first_flag==0xaa)
        {
            if (DMA1_Stream0->CR &(1 << 19))//buf0已满,正常处理buf1
            {
                memcpy((void *)&TrwaveSample[0][tw_sit],AdcDmaBuf0_0,sizeof(uint16_t)*ADCDMA_LEN);
                memcpy((void *)&TrwaveSample[1][tw_sit],AdcDmaBuf1_0,sizeof(uint16_t)*ADCDMA_LEN);         
                g_TwaveSave_sit++;
                if(g_TwaveSave_sit >= TWAVESAMPLE_SITMAX)
                {
                    g_TwaveSave_sit = 0;
                }               
            }
            else //buf1已满,正常处理buf0
            {
                memcpy((void *)&TrwaveSample[0][tw_sit],AdcDmaBuf0_1,sizeof(uint16_t)*ADCDMA_LEN);
                memcpy((void *)&TrwaveSample[1][tw_sit],AdcDmaBuf1_1,sizeof(uint16_t)*ADCDMA_LEN);
                g_TwaveSave_sit++;
                if(g_TwaveSave_sit >= TWAVESAMPLE_SITMAX)
                {
                    g_TwaveSave_sit = 0;
                }      
            }
        }
        else
        {
            g_adc1dma_first_flag=0xaa;
            return;
        }
    /*以下为数据处理*/
}



adc不加信号时的波形
12.png





回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
发表于 2024-11-25 16:04:39 | 显示全部楼层
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;这里改大一点试一下。
回复

使用道具 举报

1

主题

4

回帖

7

积分

新手上路

积分
7
 楼主| 发表于 2024-11-25 17:12:04 | 显示全部楼层
lzf 发表于 2024-11-25 16:04
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;这里改大一点试一下。

试过了,不行
回复

使用道具 举报

1

主题

4

回帖

7

积分

新手上路

积分
7
 楼主| 发表于 2024-11-25 18:31:54 | 显示全部楼层
lzf 发表于 2024-11-25 16:04
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;这里改大一点试一下。

试过了,不行
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-11-26 07:55:28 | 显示全部楼层
这种情况有必要两个中断都打开,因为都是用的DMA1,那么就有个优先级仲裁的问题,如果实在仅想开启一个的话,可以配置DMA优先级,仅开启优先级低的中断,看看是不是好点。

另外使用DMA,注意MPU/Cache问题。
回复

使用道具 举报

1

主题

4

回帖

7

积分

新手上路

积分
7
 楼主| 发表于 2024-11-26 10:23:34 | 显示全部楼层
eric2013 发表于 2024-11-26 07:55
这种情况有必要两个中断都打开,因为都是用的DMA1,那么就有个优先级仲裁的问题,如果实在仅想开启一个的话 ...

开两个中断所需要的时间会加倍,数据会处理不过来,所以不能开两个;把stream0的优先级调到比stream1低还是没什么效果。

dma优先级配置:
void MX_DMA_Init(void)
{

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

  /* DMA interrupt init */
  /* DMA1_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  /* DMA1_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
  /* DMA1_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 7, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
  /* DMA1_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 3, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 9, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  /* DMA2_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 11, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);

}

mpu的配置如下:
void MPU_Config(void)
{
        MPU_Region_InitTypeDef MPU_InitStruct;

        /* 禁止 MPU */
        HAL_MPU_Disable();

        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x24000000;
        MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE; /* 使用了DMA把cache关闭,否则会出现数据不连续现象 */
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;       
//        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
//        MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

        HAL_MPU_ConfigRegion(&MPU_InitStruct);
       
       
        /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x60000000;
        MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;       
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;        /* 不能用MPU_ACCESS_CACHEABLE;会出现2次CS、WE信号 */
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
       
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
        HAL_MPU_ConfigRegion(&MPU_InitStruct);

        /*使能 MPU */
        HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-11-27 08:09:35 | 显示全部楼层
nanfeng 发表于 2024-11-26 10:23
开两个中断所需要的时间会加倍,数据会处理不过来,所以不能开两个;把stream0的优先级调到比stream1低还 ...

缓冲加大下,双缓冲的每个缓冲搞到2K,这样两个中断分别处理肯定没问题,这样每次中断都有1ms的时间,足够两个中断使用了
回复

使用道具 举报

0

主题

23

回帖

23

积分

新手上路

积分
23
发表于 2024-11-27 13:52:32 | 显示全部楼层
我猜你模拟信号要么是直接进入ADC管脚,要么是运放BUFFER一样进入,没有加KICKBACK抑制电路。或者你的VDDA和VREF不干净,可以看一下VREF的波形。
回复

使用道具 举报

1

主题

4

回帖

7

积分

新手上路

积分
7
 楼主| 发表于 2024-11-29 16:09:38 | 显示全部楼层
eric2013 发表于 2024-11-27 08:09
缓冲加大下,双缓冲的每个缓冲搞到2K,这样两个中断分别处理肯定没问题,这样每次中断都有1ms的时间,足 ...

找到原因了,是memcpy的问题,放在dma中断中,会对adc采样有影响,放到定时器中断中就正常了
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-11-30 06:51:18 | 显示全部楼层
nanfeng 发表于 2024-11-29 16:09
找到原因了,是memcpy的问题,放在dma中断中,会对adc采样有影响,放到定时器中断中就正常了

谢谢告知最终原因。
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 06:09 , Processed in 0.045038 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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