Skip to main content
CLeo.1
Senior II
October 29, 2021
Solved

Having trouble with ADC sequencing STM32H7

  • October 29, 2021
  • 3 replies
  • 3578 views

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

This topic has been closed for replies.
Best answer by CLeo.1

Found the error. ADC is no longer OVR and DMA is transferring data. However the values of temp sensor is completely wrong

Issue:

ADC_Config_DMA.PeriphOrM2MSrcAddress = (uint32_t)&ADC1->DR;

FIx:

ADC_Config_DMA.PeriphOrM2MSrcAddress = (uint32_t)&ADC3->DR;

3 replies

jiangfan
ST Employee
October 29, 2021

the first suggestion (easy to do) is, to check if STM32H7 Cube FW lib has similar example, and do some update following the example.

CLeo.1
CLeo.1Author
Senior II
October 30, 2021

Thank you for your reply. I have tried every example it didnt work for me. I have also tried using interrupts and didnt work. However I noticed that the Over run flag is being triggered on the ADC3 side. This could be the cause as to why it stops running. But why does it trigger?

thundertronics.com
Visitor II
October 31, 2021

I've tested H7s ADC back and forth and it works seamlessly with multiple channels and injected conversions, though I did not used LL drivers. 1) Ensure that DMA is initialized before ADC; 2) Ensure that DMA can access particular RAM address. If it still does not work, create simple project using full HAL and find the difference between LL one. It is probably that RxBuffer located in RAM which is not accessible by DMA, or DMA/ADC initialization somewhere performed in wrong order.

jiangfan
ST Employee
November 1, 2021

I agree with this idea, to check DMA operation, ADC_DR => buffer_RAM should be checked. still, I suggest to compare with DMA example(s) in​ STM32H7 Cube FW lib.

CLeo.1
CLeo.1AuthorBest answer
Senior II
November 1, 2021

Found the error. ADC is no longer OVR and DMA is transferring data. However the values of temp sensor is completely wrong

Issue:

ADC_Config_DMA.PeriphOrM2MSrcAddress = (uint32_t)&ADC1->DR;

FIx:

ADC_Config_DMA.PeriphOrM2MSrcAddress = (uint32_t)&ADC3->DR;

jiangfan
ST Employee
November 1, 2021

in case the values of temp sensor is completely wrong, 2 points may be checked:

  • the sequence may not be the expected one. that is, input is channel A,B,C,D,E, but output (to buffer RAM) may be B,C,D,E,A
  • better to use longest sample time
CLeo.1
CLeo.1Author
Senior II
November 1, 2021

Issue is actually rooting more than just the temperature sensor. I've made a new thread as this was more geared towards the over run issue with the ADC.

I want to understand point 1 more, as I am having troubles piecing it together.

Point 2, I have tried the slowest cycle and lowering the ADC clock as well, no avail.