cancel
Showing results for 
Search instead for 
Did you mean: 

ADC in continuous mode only reading once

RPape.1
Associate II

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);
}

0 REPLIES 0