ST意法半导体
直播中

xymbmcu

12年用户 1025经验值
擅长:可编程逻辑
私信 关注
[问答]

怎样去解决STM32H743 ADC随机跳过样本的问题呢

我有一个设置,我通过 DMA1 S0 从 ADC1 读取到 RAM2 中的循环缓冲区。问题是它随机跳过样本。我将缓冲区初始化为一个已知的错误值,这样我就可以看到缓冲区中的某些地址没有被覆盖。如果我将正弦输入输入,本文底部的图片就是我得到的结果。顶部的扁平线是预初始化数据。正弦波中的间隙每次都不在同一个地方。间隙以 8 个样本或 8 个样本的倍数为一组。
我开始以连续模式运行 ADC,但现在从定时器触发。用于触发 ADC1 的定时器是运行在 16.384kHz 的 LPtiM1。我只有一个等级。
我故意将内存缓冲区放在 0x30000000 以避免总线与 cpu 冲突。
我正在运行带有 freertos 设置的 CUBEMX。我试过禁用所有其他活动。唯一的 cpu 活动是空闲循环和一个挂起的任务。系统节拍定时器中断将以 1kHz 的频率触发。
我试过将数据缓冲区放在 0x24000000,同样的事情。将它向上移动到 0x30002710....同样的事情。
我在循环和正常模式下尝试过 DMA。一样。同样,启用它的 DMA fifo 也没有任何区别。
我在 ADC 上使用模拟看门狗,所以我尝试将其关闭。同样的结果。
我最初(现在仍然需要)使用双常规同步模式转换两个通道 ADC1 和 ADC2。我关闭了 ADC2 进行测试,但这没有帮助。当它打开时,ADC2 将跳过的数据放在完全相同的位置。这并不奇怪,因为每个样本只有一个字的 dma 传输,ADC2 在前 16 位,ADC1 在后 16 位。
据我所见,ADC 触发没有停止或错过,因为正弦波中没有明显的不连续性。来自 ADC 的 DMA 触发必须发生,因为即使没有传输数据,DMA 目标地址也会递增。它似乎指向 DMA 问题。就像 DMA 或其他东西有一条弱地址线,所以 DMA 认为它已经写入了数据,但没有传输任何数据。
对于专家...我将在此处包括一些 MX 生成的代码:
  • 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_DIV8;
  •   hadc1.Init.Resolution = ADC_RESOLUTION_16B;
  •   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 = ENABLE;
  •   hadc1.Init.NbrOfDiscConversion = 1;
  •   hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_LPTIM1_OUT;
  •   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  •   hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
  •   hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  •   hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  •   hadc1.Init.OversamplingMode = ENABLE;
  •   hadc1.Init.Oversampling.Ratio = 8;
  •   hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_3;
  •   hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
  •   hadc1.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
  •   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_8CYCLES_5;
  •   sConfig.SingleDiff = ADC_DIFFERENTIAL_ENDED;
  •   sConfig.OffsetNumber = ADC_OFFSET_NONE;
  •   sConfig.Offset = 0;
  •   sConfig.OffsetSignedSaturation = DISABLE;
  •   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   /* USER CODE BEGIN ADC1_Init 2 */
  •   /* USER CODE END ADC1_Init 2 */
  • }
  • void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
  • {
  •   GPIO_InitTypeDef GPIO_InitStruct = {0};
  •   if(adcHandle->Instance==ADC1)
  •   {
  •   /* USER CODE BEGIN ADC1_MspInit 0 */
  •   /* USER CODE END ADC1_MspInit 0 */
  •     /* ADC1 clock enable */
  •     __HAL_RCC_ADC12_CLK_ENABLE();
  •     __HAL_RCC_GPIOA_CLK_ENABLE();
  •     /**ADC1 GPIO Configuration
  •     PA6     ------> ADC1_INP3
  •     PA7     ------> ADC1_INN3
  •     */
  •     GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
  •     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  •     GPIO_InitStruct.Pull = GPIO_NOPULL;
  •     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  •     /* ADC1 DMA Init */
  •     /* ADC1 Init */
  •     hdma_adc1.Instance = DMA1_Stream0;
  •     hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
  •     hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
  •     hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
  •     hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
  •     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  •     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  •     hdma_adc1.Init.Mode = DMA_NORMAL;
  •     hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
  •     hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  •     if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
  •     {
  •       Error_Handler();
  •     }
  •     __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
  •     /* ADC1 interrupt Init */
  •     HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
  •     HAL_NVIC_EnableIRQ(ADC_IRQn);
  •   /* USER CODE BEGIN ADC1_MspInit 1 */
  •   /* USER CODE END ADC1_MspInit 1 */
  •   }
  • void MX_DMA_Init(void)
  • {
  •   /* DMA controller clock enable */
  •   __HAL_RCC_DMA1_CLK_ENABLE();
  •   /* DMA interrupt init */
  •   /* DMA1_Stream0_IRQn interrupt configuration */
  •   HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 0);
  •   HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  • }
定时器设置
  • void MX_LPTIM1_Init(void)
  • {
  •   /* USER CODE BEGIN LPTIM1_Init 0 */
  •   /* USER CODE END LPTIM1_Init 0 */
  •   /* USER CODE BEGIN LPTIM1_Init 1 */
  •   /* USER CODE END LPTIM1_Init 1 */
  •   hlptim1.Instance = LPTIM1;
  •   hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
  •   hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
  •   hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
  •   hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
  •   hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
  •   hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
  •   hlptim1.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO;
  •   hlptim1.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO;
  •   if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
  •   {
  •     Error_Handler();
  •   }
  •   /* USER CODE BEGIN LPTIM1_Init 2 */
  •   /* USER CODE END LPTIM1_Init 2 */
  • }
  • void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef* lptimHandle)
  • {
  •   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  •   if(lptimHandle->Instance==LPTIM1)
  •   {
  •   /* USER CODE BEGIN LPTIM1_MspInit 0 */
  •   /* USER CODE END LPTIM1_MspInit 0 */
  •   /** Initializes the peripherals clock
  •   */
  •     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  •     PeriphClkInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
  •     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  •     {
  •       Error_Handler();
  •     }
  •     /* LPTIM1 clock enable */
  •     __HAL_RCC_LPTIM1_CLK_ENABLE();
  •   /* USER CODE BEGIN LPTIM1_MspInit 1 */
  •   /* USER CODE END LPTIM1_MspInit 1 */
  •   }
  • }
我开始采样的代码:
  •         // Interrupt if the DMA can't keep up with the ADC
  •         // If this occurs the DMA is blocked until the overrun is flag is cleared
  •         __HAL_ADC_ENABLE_IT(hadc1, ADC_IT_OVR);
  •         // Interrupt if the DMA experiences issues getting the data written
  •         __HAL_DMA_ENABLE_IT(hadc1->DMA_Handle, DMA_IT_TE);
  •         __HAL_DMA_ENABLE_IT(hadc1->DMA_Handle, DMA_IT_DME);
  •         result = HAL_DMA_RegisterCallback(hadc1->DMA_Handle, HAL_DMA_XFER_ERROR_CB_ID, DMA_transfer_error_callback);
  •         if(result != HAL_OK)
  •         {
  •                 log_error("Couldn't register DMA transfer error callback, code = %d",(int)result);
  •         }
  •         result = HAL_DMA_RegisterCallback(hadc1->DMA_Handle, HAL_DMA_XFER_ABORT_CB_ID, DMA_abort_callback);
  •         if(result != HAL_OK)
  •         {
  •                 log_error("Couldn't register DMA Abort callback, code = %d",(int)result);
  •         }
  •         // Clear the watchdog flag to make sure we don't get a spurious hit
  •         __HAL_ADC_CLEAR_FLAG(hadc1, ADC_FLAG_AWD1);
  •         while((hadc1->Instance->ISR) & (0x1 << 7))
  •         {
  •                 __HAL_ADC_CLEAR_FLAG(hadc1, ADC_FLAG_AWD1);
  •         }
  •         //Start the ADCs
  •         result = HAL_ADC_Start_DMA(hadc1, (uint32_t *)analog_dma_buffer , ANALOGUE_SENSOR_BUFFER_SIZE);
  •         if(result != HAL_OK)
  •         {
  •                 log_error("Couldn't start  ADC, code = %d",(int)result);
  •                 retval = result;
  •         }
  •         result = HAL_LPTIM_Counter_Start(&hlptim1, 2);
  •         if(result != HAL_OK)
  •         {
  •                 log_error("Couldn't start adc timer, code = %d",(int)result);
  •                 retval = result;
  •         }
在过去的几天里,我学到了很多关于 STM32 ADC 的知识,比我真正希望的要多!我已经尝试了我能想到的一切,但在这方面没有取得任何进展。有没有人对其他要检查的内容有任何想法?我唯一的其他选择是尝试放弃 DMA 并返回到基于中断的方案。但我正在尝试 DMA,因为 CPU 确实需要忙于做其他事情。
CubeMX 版本 6.3.0 RC5



回帖(1)

刘柳

2022-12-21 10:34:53
我禁用了 dcache,这就是我所看到的。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分