cancel
Showing results for 
Search instead for 
Did you mean: 

Having trouble with ADC sequencing STM32H7

CLeo.1
Senior II

Hi everyone, hope everyone is doing well

I am trying to setup the STM32H743ZI's ADC for a 5 channel Continuous scan. The 5 scans will be used for

The Input voltage - Channel 0

The Input Current - Channel 1

The output Voltage - Chanel 2

The output Current - Channel 3

Internal Temperature Sensor - Channel 18

Essentially I just want the ADC to continuously scan these 5 channels and have the DMA transfer it into a buffer so it can be read by software. The way I want to read the buffers is via Polling as I am using a RTOS.

The problem I am having is that the EOS flag for the ADC and the DMA1 TC4 flag is setting but the data is not transferring into the DMA buffer. I see the data shifting around in the DR register in the ADC3 however.

I double checked the DMA, the memory address is within the right region of memory for the DMA to see. I have no idea what's happening has I never really use the ADC for a sequential scan before.

I was hopping if anyone can see if I mis-setup or if I have to do something. For example I am not using interrupts as I mention I am using polling, however I am using the DMA. Do I need to still enable the DMA4 TC interrupt still? Etc etc. I just want the ADC to scan forever along side the DMA transferring data and I poll in whenever I want.

Any suggestions are appreciated

The Low Level register that setups GPIO, DMA, ADC

void ADC_helper_function::enable(int * RxBuffer) {
 
	LL_DMA_InitTypeDef     ADC_Config_DMA;
	LL_GPIO_InitTypeDef    ADC_Config_GPIO;
	LL_ADC_InitTypeDef     ADC_Config_init;
	LL_ADC_REG_InitTypeDef ADC_Config_REG;
 
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOC);
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOF);
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_ADC3);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
 
	LL_ADC_StructInit(&ADC_Config_init);
	LL_ADC_REG_StructInit(&ADC_Config_REG);
	LL_GPIO_StructInit(&ADC_Config_GPIO);
	LL_DMA_StructInit(&ADC_Config_DMA);
 
	//Configure GPIOA
	ADC_Config_GPIO.Mode       = LL_GPIO_MODE_ANALOG;
	ADC_Config_GPIO.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	ADC_Config_GPIO.Pin        = LL_GPIO_PIN_2 | LL_GPIO_PIN_3;
	ADC_Config_GPIO.Pull       = LL_GPIO_PULL_UP;
	ADC_Config_GPIO.Speed      = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	LL_GPIO_Init(GPIOC, &ADC_Config_GPIO);
 
	//Configure GPIOC
	ADC_Config_GPIO.Mode       = LL_GPIO_MODE_ANALOG;
	ADC_Config_GPIO.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	ADC_Config_GPIO.Pin        = LL_GPIO_PIN_9 | LL_GPIO_PIN_7;
	ADC_Config_GPIO.Pull       = LL_GPIO_PULL_UP;
	ADC_Config_GPIO.Speed      = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	LL_GPIO_Init(GPIOF, &ADC_Config_GPIO);
 
	ADC_Config_DMA.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
	ADC_Config_DMA.FIFOMode = LL_DMA_FIFOMODE_DISABLE;
	ADC_Config_DMA.MemBurst = LL_DMA_MBURST_SINGLE;
	ADC_Config_DMA.MemoryOrM2MDstAddress = (uint32_t)RxBuffer;
	ADC_Config_DMA.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
	ADC_Config_DMA.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
	ADC_Config_DMA.Mode = LL_DMA_MODE_CIRCULAR;
	ADC_Config_DMA.NbData = 5;
	ADC_Config_DMA.PeriphBurst = LL_DMA_PBURST_SINGLE;
	ADC_Config_DMA.PeriphOrM2MSrcAddress = (uint32_t)&ADC1->DR;
	ADC_Config_DMA.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_WORD;
	ADC_Config_DMA.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
	ADC_Config_DMA.PeriphRequest = LL_DMAMUX1_REQ_ADC3;
	ADC_Config_DMA.Priority = LL_DMA_PRIORITY_LOW;
 
	//Interrupt: DMA
	LL_DMA_Init(DMA1, LL_DMA_STREAM_4, &ADC_Config_DMA);
 
	//Configure ADC
	ADC_Config_init.LeftBitShift    = LL_ADC_LEFT_BIT_SHIFT_NONE;
	ADC_Config_init.LowPowerMode    = LL_ADC_LP_MODE_NONE;
	ADC_Config_init.Resolution      = LL_ADC_RESOLUTION_16B;
	LL_ADC_Init(ADC3, &ADC_Config_init);
 
	ADC_Config_REG.ContinuousMode   = LL_ADC_REG_CONV_CONTINUOUS;
	ADC_Config_REG.DataTransferMode = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	ADC_Config_REG.Overrun          = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
	ADC_Config_REG.SequencerLength  =  LL_ADC_REG_SEQ_SCAN_ENABLE_5RANKS;
	ADC_Config_REG.TriggerSource    =  LL_ADC_REG_TRIG_SOFTWARE;
	LL_ADC_REG_Init(ADC3, &ADC_Config_REG);
 
	LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_0);
	LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_1);
	LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_2);
	LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_3);
	LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_5, LL_ADC_CHANNEL_TEMPSENSOR);
 
	LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_1 | LL_ADC_CHANNEL_2 | LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
 
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_0 | LL_ADC_CHANNEL_1 | LL_ADC_CHANNEL_2 | LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_1CYCLE_5);
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_387CYCLES_5);
 
	LL_ADC_SetCommonPathInternalCh(ADC3_COMMON, LL_ADC_PATH_INTERNAL_TEMPSENSOR);
 
	LL_ADC_DisableDeepPowerDown(ADC3);
 
	LL_RCC_PLL2_SetM(4);
	LL_RCC_PLL2_SetN(9);
	LL_RCC_PLL2_SetP(4);
	LL_RCC_PLL2_SetFRACN(6144);
	LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_8_16);
	LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
	LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLL2P);
	LL_RCC_PLL2FRACN_Enable();
	LL_RCC_PLL2P_Enable();
	LL_RCC_PLL2_Enable();
	while ((LL_RCC_PLL2_IsReady == 0)) {
 
	}
 
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_4);
	LL_ADC_EnableInternalRegulator(ADC3);
	LL_ADC_Enable(ADC3);
	LL_ADC_REG_StartConversion(ADC3);
}

The task that polls for the ADC buffer

void ADC::ADC_Daemon(void * parameter) {
 
	int tempSensor = 0;
 
	while(1) {
		vTaskDelay(ADC_Checkin_Interval/portTICK_PERIOD_MS);
 
		if ((LL_ADC_IsActiveFlag_EOS(ADC3)) && (LL_DMA_IsActiveFlag_TC4(DMA1))) {
 
			tempSensor = dataStructure->getRxBuffer()[3];
			LL_ADC_ClearFlag_EOS(ADC3);
			LL_DMA_ClearFlag_TC4(DMA1);
		}
 
	}
}

13 REPLIES 13

Perfect going to try it. Ill let you know

I finally got the HAL example working and you're right, I get around the same mV as well for temperature sensor. However the only difference I could find is that the Calibration register is actually filled in, where even though I initiated the ADC calibration theres still nothing in the ADC Calibration register.

Got the calibration fully working now ( I see the value within the register) However value is still completely off.

Okay, I found the cause but not the fix. The ADC3->DR register is holding the right value, but for whatever reason the transfer from the DR register into the memory buffer used via DMA is completely different. For example.

Inside ADC3->DR = 0x3084 inside Buffer = 0x5F