cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743ZI ADC + DMA sampling data acting quite strange

CLeo.1
Senior II

Hi everyone, hope all of you are doing well.

Posting here again about the ADC. I finally got the ADC out of that over run situation and now ready to acquire data!

The way the ADC is setup is by having 4 channels using Pins setup as continuous scanning

PC2 = Channel 0 for ADC 3 Rank 0

PC3 = Channel 1 for ADC 3 Rank 1

PF9 = Channel 2 for ADC 3 Rank 2

PF7 = Channel 3 for ADC 3 Rank 3

and internal temperature sensor = Channel 12 for ADC 3

I am essentially polling for the DMA1 Stream 4 Transfer Complete 4 flag, once this is done I know that the ADC has done all 5 sequential reads, however when I get into the array or even the data there's either nonsense data or zeros. The channels that read zero I have tried hooking up those pins to VDD and it still reads zero. I notice in the ADC3->DR there's a lot of activity going.

What I have tried thus far is, changing DMA to one shot mode, behavior is the same.

I am not sure what's going as it seems to look like the DMA is not transferring from ADC3->DR properly into its memory buffer. The buffer being used is in the x2400 region of memory and there's no error flag set for either DMA1 or ADC3.

ADC, GPIO, Low Level driver initialization

LL_DMA_InitTypeDef       ADC_Config_DMA;
	LL_GPIO_InitTypeDef      ADC_Config_GPIO;
	LL_ADC_InitTypeDef       ADC_Config_Init;
	LL_ADC_CommonInitTypeDef ADC_Config_CommonInit;
	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_CommonStructInit(&ADC_Config_CommonInit);
	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_DOWN;
	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_DOWN;
	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_HALFWORD;
	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)&ADC3->DR;
	ADC_Config_DMA.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_HALFWORD;
	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);
 
	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_CommonInit.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
	ADC_Config_CommonInit.MultiDMATransfer = LL_ADC_MULTI_REG_DMA_EACH_ADC;
	ADC_Config_CommonInit.Multimode = LL_ADC_MULTI_INDEPENDENT;
	LL_ADC_CommonInit(ADC3_COMMON, &ADC_Config_CommonInit);
 
	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_PRESERVED;
	ADC_Config_REG.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
	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_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_0);
 
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_0, LL_ADC_SAMPLINGTIME_810CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_810CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_810CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_810CYCLES_5);
	LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_810CYCLES_5);
 
	LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_0, LL_ADC_SINGLE_ENDED);
	LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_1, LL_ADC_SINGLE_ENDED);
	LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_2, LL_ADC_SINGLE_ENDED);
	LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
 
	LL_ADC_SetCommonPathInternalCh(ADC3_COMMON, LL_ADC_PATH_INTERNAL_TEMPSENSOR);
	LL_ADC_SetBoostMode(ADC3, LL_ADC_BOOST_MODE_50MHZ);
	LL_ADC_SetLowPowerMode(ADC3, LL_ADC_LP_MODE_NONE);
	//LL_ADC_SetOffsetSignedSaturation(ADC3, LL_ADC_OFFSET_4, LL_ADC_OFFSET_SIGNED_SATURATION_ENABLE);
	//LL_ADC_SetDataRightShift(ADC3, LL_ADC_OFFSET_4, LL_ADC_OFFSET_RSHIFT_ENABLE);
 
	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();
 
	LL_ADC_StartCalibration(ADC3, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);
	while (LL_ADC_IsCalibrationOnGoing(ADC3));
 
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_4);
	LL_ADC_DisableDeepPowerDown(ADC3);
	LL_ADC_EnableInternalRegulator(ADC3);
	LL_ADC_ClearFlag_ADRDY(ADC3);
	LL_ADC_Enable(ADC3);
	while (LL_ADC_IsActiveFlag_ADRDY(ADC3) == 0);
	LL_ADC_ClearFlag_ADRDY(ADC3);
	LL_ADC_REG_StartConversion(ADC3);

ADC Task to read 5 channels

void ADC::ADC_Daemon(void * parameter) {
 
	int tempSensor = 0;
	int inputVoltage = 0;
	int inputCurrent = 0;
	int outputVoltage = 0;
	int outputCurrent = 0;
 
	while(1) {
		vTaskDelay(ADC_Checkin_Interval / portTICK_PERIOD_MS);
 
		if (LL_DMA_IsActiveFlag_TC4(DMA1)) {
 
			inputVoltage = dataStructure->getRxBuffer()[0];
			inputCurrent = dataStructure->getRxBuffer()[1];
 
			outputVoltage = dataStructure->getRxBuffer()[2];
			outputCurrent = dataStructure->getRxBuffer()[3];
 
			tempSensor = (TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP)/(*TEMPSENSOR_CAL2_ADDR - *TEMPSENSOR_CAL1_ADDR) * dataStructure->getRxBuffer()[4] + 30;
			LL_DMA_ClearFlag_TC4(DMA1);
		}
	}
}

Data within the buffer once Transfer Completed flag 4 from the DMA1 is triggered. Just pure nonsense data. The pins are pull down and not in used but here there's some kind of voltage.

0693W00000GW7jBQAT.jpg

20 REPLIES 20
CLeo.1
Senior II

Fixed the issue for the analog pins for not reading the voltage properly.

Fix:

LL_ADC_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_0);

LL_ADC_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_1);

LL_ADC_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_2);

LL_ADC_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_3);

LL_ADC_SetChannelPreSelection(ADC3, LL_ADC_CHANNEL_TEMPSENSOR);

I dont know why this is the way to initialize the ADC as I thought the ranks you pick them will decide which channel to sample through. I also thought setChannelPreSelection was to choose which ADC channel gets sampled first. Anyways adding all the ADC channels you are going to use into setChannelPreSelection works.