Skip to main content
Visitor II
February 27, 2023
Question

ADC in continuous mode only reading once

  • February 27, 2023
  • 0 replies
  • 1152 views

I am trying to read data using ADC1 continuously and copy it into a buffer via DMA.

However, the data is only read and copied once (seemingly correctly), and afterwards nothing happens anymore (data in buffer does not change, ADC1_IRQHandler() is not called anymore).

If I set a breakpoint somewhere in the program, the value of the ADC_CFGR register equals 2147495944, i. e. the DMNGT bits are both 0. Shouldn't they be both 1, as I enabled DMA Circular Mode?

As you can see in the code, the MX_DMA_Init() function is called before HAL_ADC_Init(), which was seemingly a bug in earlier versions of STM32CubeIDE (see this thread: How to enable ADC continuous mode with DMA? (st.com)).

I already tried setting the DMNGT bits manually and also tried setting the ADSTART bit manually in the ADC1_IRQHandler() on EOC interrupt, but both did not work.

I am using an STM32MP153AAB3 on a custom board.

The relevant parts of code look like this (I left out unrelated things, timer inits etc. for the sake of clarity):

main.cpp:

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
IPCC_HandleTypeDef hipcc;
 
static MyAdc myAdc(ADC1, ADC_CHANNEL_12, &hadc1);
static MyMeasurement myMeasurement{&myAdc};
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_IPCC_Init(void);
 
/* 
... 
*/
 
int main(void)
{
 /* USER CODE BEGIN 1 */
 /* USER CODE END 1 */
 
 /* MCU Configuration--------------------------------------------------------*/
 
 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();
 
 /* USER CODE BEGIN Init */
 
 /* USER CODE END Init */
 
 if(IS_ENGINEERING_BOOT_MODE())
 {
 /* Configure the system clock */
 SystemClock_Config();
 }
 else
 {
 /* IPCC initialisation */
 MX_IPCC_Init();
 }
 
 /* USER CODE BEGIN SysInit */
 
 /* USER CODE END SysInit */
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 /* USER CODE BEGIN 2 */
 
 MX_DMA_Init();
 myMeasurement.init();
 
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 
	/* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */
}
 
 
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
 RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;
 RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE;
 RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL4.PLLSource = RCC_PLL4SOURCE_HSI;
 RCC_OscInitStruct.PLL4.PLLM = 4;
 RCC_OscInitStruct.PLL4.PLLN = 25;
 RCC_OscInitStruct.PLL4.PLLP = 2;
 RCC_OscInitStruct.PLL4.PLLQ = 2;
 RCC_OscInitStruct.PLL4.PLLR = 4;
 RCC_OscInitStruct.PLL4.PLLRGE = RCC_PLL4IFRANGE_1;
 RCC_OscInitStruct.PLL4.PLLFRACV = 0;
 RCC_OscInitStruct.PLL4.PLLMODE = RCC_PLL_INTEGER;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 
 /** RCC Clock Config
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_ACLK
 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
 |RCC_CLOCKTYPE_PCLK3|RCC_CLOCKTYPE_PCLK4
 |RCC_CLOCKTYPE_PCLK5;
 RCC_ClkInitStruct.AXISSInit.AXI_Clock = RCC_AXISSOURCE_HSI;
 RCC_ClkInitStruct.AXISSInit.AXI_Div = RCC_AXI_DIV1;
 RCC_ClkInitStruct.MCUInit.MCU_Clock = RCC_MCUSSOURCE_HSI;
 RCC_ClkInitStruct.MCUInit.MCU_Div = RCC_MCU_DIV1;
 RCC_ClkInitStruct.APB4_Div = RCC_APB4_DIV1;
 RCC_ClkInitStruct.APB5_Div = RCC_APB5_DIV1;
 RCC_ClkInitStruct.APB1_Div = RCC_APB1_DIV1;
 RCC_ClkInitStruct.APB2_Div = RCC_APB2_DIV1;
 RCC_ClkInitStruct.APB3_Div = RCC_APB3_DIV1;
 
 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
}
 
/**
 * Enable DMA controller clock
 */
static void MX_DMA_Init(void)
{
 
 /* DMA controller clock enable */
 __HAL_RCC_DMAMUX_CLK_ENABLE();
 __HAL_RCC_DMA2_CLK_ENABLE();
 
 /* DMA interrupt init */
 /* DMA2_Stream0_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 
}

MyMeasurement.cpp:

MyMeasurement::MyMeasurement(MyAdc* myAdc)
{
 this->myAdc= myAdc;
}
 
void MyMeasurement::init()
{
 myAdc->Init();
 myAdc->Start();
}

MyAdc.cpp:

MyAdc::MyAdc(ADC_TypeDef* adc, uint32_t adcChannel, ADC_HandleTypeDef* adcHandle)
{
 this->adcChannel = adcChannel;
 this->adcHandle = adcHandle;
 
 /** Common config
 */
 adcHandle->Instance = adc;
 adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
 adcHandle->Init.Resolution = ADC_RESOLUTION_12B;
 adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
 adcHandle->Init.EOCSelection = ADC_EOC_SEQ_CONV;
 adcHandle->Init.LowPowerAutoWait = DISABLE;
 adcHandle->Init.ContinuousConvMode = ENABLE;
 adcHandle->Init.NbrOfConversion = 1;
 adcHandle->Init.DiscontinuousConvMode = DISABLE;
 adcHandle->Init.NbrOfDiscConversion = 1;
 adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START;
 adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 adcHandle->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
 adcHandle->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
 adcHandle->Init.OversamplingMode = DISABLE;
}
 
void MyAdc::Init(void)
{
 ASSERT(HAL_ADC_DeInit(adcHandle) == HAL_OK);
 ASSERT(HAL_ADC_Init(adcHandle) == HAL_OK);
 
 /** Configure the ADC multi-mode
 */
 ADC_MultiModeTypeDef multimode = {0};
 multimode.Mode = ADC_MODE_INDEPENDENT; // multi-mode disabled
 ASSERT(HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) == HAL_OK);
 
 /** Configure Regular Channel
 */
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = adcChannel;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5; 
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 
 HAL_ADC_ConfigChannel(adcHandle, &sConfig);
 
 /* Run the ADC calibration in single-ended mode */
 ASSERT(HAL_ADCEx_Calibration_Start(adcHandle, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) == HAL_OK);
 
 // enable End of Conversion interrupt (call ADC1_IRQHandler at the end of each conversion)
 SET_BIT(adcHandle->Instance->IER, ADC_IER_EOCIE);
}
 
void MyAdc::Start()
{
 ASSERT(HAL_ADC_Start_DMA(adcHandle, (uint32_t*) &samplingData[0], BUFFER_SIZE) == HAL_OK);
}

    This topic has been closed for replies.