cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with the ADC measurement with DMA and RTC

CCuev.1
Associate

HI

I have a problem. I want to measure 4 channels of the ADC every 20 seconds (this is more time but for now it is like this for testing) through an RTC interrupt, then print by the serial terminal.
What happens is that it shows me the reading every 20 seconds but all the channels are always at 0.

Config ADC1 and DMA

 

void  ADC1_DMA_Init(void)
{
	    __HAL_RCC_ADC1_CLK_ENABLE();
	    ADC_ChannelConfTypeDef sConfig = {0};
	    hadc1.Instance = ADC1;
	    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
	    hadc1.Init.ContinuousConvMode = DISABLE;
	    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
	    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	    hadc1.Init.DiscontinuousConvMode = ENABLE;
	    hadc1.Init.NbrOfDiscConversion = ADC_BUFF_SIZE;
	    hadc1.Init.NbrOfConversion = ADC_BUFF_SIZE;
	    if (HAL_ADC_Init(&hadc1) != HAL_OK)
	    {
		    Error_Handler();
	    }
	    
	    HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);
	    HAL_NVIC_EnableIRQ(ADC1_IRQn);
	    
	    sConfig.Channel = ADC_CHANNEL_10;
	    sConfig.Rank = ADC_REGULAR_RANK_1;
	    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
	    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	    {
		    Error_Handler();
	    }
	    sConfig.Channel = ADC_CHANNEL_11;
	    sConfig.Rank = ADC_REGULAR_RANK_2;
	    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
	    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	    {
		    Error_Handler();
	    }
	    sConfig.Channel = ADC_CHANNEL_1;
	    sConfig.Rank = ADC_REGULAR_RANK_3;
	    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
	    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	    {
		    Error_Handler();
	    }

	    sConfig.Channel = ADC_CHANNEL_4;
	    sConfig.Rank = ADC_REGULAR_RANK_4;
	    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
	    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	    {
		    Error_Handler();
	    }
	    
	    __HAL_RCC_DMA1_CLK_ENABLE();
	    hdma_adc1.Instance = DMA1_Channel1;
	    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_HALFWORD;
	    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
	    hdma_adc1.Init.Mode = DMA_NORMAL;
	    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
	    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
	    {
		    Error_Handler();
	    }
	    __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
	    __HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TC);
	    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
	    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
	    ADC_Enable(&hadc1);
}

 

 

stm32f1xx_it.c

 

void  DMA1_Channel1_IRQHandler(void)
{
    if (__HAL_DMA_GET_FLAG(&hdma_adc1, DMA_IT_TC) !=  0x00u)
    {
	    __HAL_DMA_CLEAR_FLAG(&hdma_adc1, DMA_IT_TC);
    }
}
...
void  ADC1_2_IRQHandler(void)
{
    if (__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC))
    {
	    __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC);
    }
}
...
void  RTC_Alarm_IRQHandler(void)
{
    if (__HAL_RTC_ALARM_GET_FLAG(&hrtc, RTC_IT_ALRA) != (uint32_t)RESET)
	{
    	HAL_ADCEx_Calibration_Start(&hadc1);
    	HAL_ADC_Start_DMA(&hadc1, (uint32_t  *)&adcValue, ADC_BUFF_SIZE);
    	results.Cbat = adcValue[0];
    	results.Csol = adcValue[1];
    	results.Vbat = adcValue[2];
    	results.Vsol = adcValue[3];

    	myprintf("\nVbat: %-5d Vsol: %-5d Cbat: %-5d Csol: %-5d\n", results.Vbat, results.Vsol, results.Cbat, results.Csol);
    	HAL_ADC_Stop_DMA(&hadc1);

    	HAL_RTC_GetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, FORMAT_BIN);
    	sAlarm.AlarmTime.Seconds  =  sAlarm.AlarmTime.Seconds  +  0x20;
    	HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BIN);
    	__HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_IT_ALRA);
    	__HAL_RTC_ALARM_EXTI_CLEAR_FLAG();
	 }
}

 

 

uint16_t adcValue[4];

In DMA1_Channel1_IRQHandler and ADC1_2_IRQHandler I have no code. In RTC_Alarm_IRQHandler is where I start the ADC conversion and save the data in the adcValue buffer, then pass it to a structure and display it on the serial terminal.
myprintf is a function to print by UART1.

I am programming a stm32f103rct6 microcontroller with platformio.

Result obtained by serial terminal every 20 seconds:
Vbat: 0 Vsol: 0 Cbat: 0 Csol: 0

 

1 REPLY 1
TDK
Guru

Wait for DMA to complete before using its values. DMA happens in the background.

If you feel a post has answered your question, please click "Accept as Solution".