我有一个设置,我通过 DMA1 S0 从 ADC1 读取到 RAM2 中的循环缓冲区。问题是它随机跳过样本。我将缓冲区初始化为一个已知的错误值,这样我就可以看到缓冲区中的某些地址没有被覆盖。如果我将正弦输入输入,本文底部的图片就是我得到的结果。顶部的扁平线是预初始化数据。正弦波中的间隙每次
都不在同一个地方。间隙以 8 个样本或 8 个样本的倍数为一组。
我开始以连续模式运行 ADC,但现在从定时器触发。用于触发 ADC1 的定时器是运行在 16.384kHz 的 LP
tiM1。我只有一个等级。
我故意将内存缓冲区放在 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
0