2021-10-28 06:43 PM
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);
}
}
}
Solved! Go to Solution.
2021-10-31 08:48 PM
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;
2021-10-28 07:47 PM
the first suggestion (easy to do) is, to check if STM32H7 Cube FW lib has similar example, and do some update following the example.
2021-10-30 04:07 PM
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?
2021-10-31 12:04 AM
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.
2021-10-31 06:58 PM
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.
2021-10-31 07:19 PM
Thank you for the response.
2021-10-31 08:48 PM
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;
2021-10-31 09:14 PM
in case the values of temp sensor is completely wrong, 2 points may be checked:
2021-11-01 04:06 PM
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.
2021-11-01 07:36 PM
I just try example in STM32Cube_FW_H7_V1.9.0 -> Projects\NUCLEO-H743ZI\Examples\ADC\ADC_InternalChannelConversion, and it (ADC_CHANNEL_VREFINT) works for me, I get 1221~1224mV for VREFINT. I modify to ADC_CHANNEL_TEMPSENSOR, and 624~629mV seen at room temperature 25~30 degree C.