Skip to main content
Pilous Droip
Senior
November 19, 2021
Question

H7 read temperature from ADC

  • November 19, 2021
  • 25 replies
  • 3988 views

H friends,

I'm trying to read adc3, a temperature sensor from stm32h753. But something is wrong. Because I didn't get any interruptions. Can anyone help?

void MX_ADC3_Init(void) {
 LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP);
 
 /* Peripheral clock enable */
 LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_ADC3);
 
 if (LL_ADC_IsDeepPowerDownEnabled(ADC3) != 0UL)
 LL_ADC_DisableDeepPowerDown(ADC3);
 
 if (LL_ADC_IsInternalRegulatorEnabled(ADC3) == 0UL) {
 LL_ADC_EnableInternalRegulator(ADC3);
 __IO uint32_t wait_loop_index = 0UL;
 wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL))) + 1000;
 while (wait_loop_index != 0UL) {
 wait_loop_index--;
 }
 }
 
 LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_CLOCK_ASYNC_DIV2);
 LL_ADC_SetResolution(ADC3, LL_ADC_RESOLUTION_16B);
 LL_ADC_REG_SetSequencerLength(ADC3, LL_ADC_REG_SEQ_SCAN_ENABLE_10RANKS);
 LL_ADC_SetLowPowerMode(ADC3, LL_ADC_LP_MODE_NONE);
 LL_ADC_REG_SetContinuousMode(ADC3, LL_ADC_REG_CONV_CONTINUOUS);
 LL_ADC_REG_SetSequencerDiscont(ADC3, LL_ADC_REG_SEQ_DISCONT_DISABLE);
 LL_ADC_REG_SetTriggerSource(ADC3, LL_ADC_REG_TRIG_SOFTWARE);
 LL_ADC_REG_SetDataTransferMode(ADC3, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
 LL_ADC_REG_SetOverrun(ADC3, LL_ADC_REG_OVR_DATA_OVERWRITTEN);
 LL_ADC_SetOverSamplingScope(ADC3, LL_ADC_OVS_DISABLE);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_TEMPSENSOR);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_387CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_SetOffset(ADC3, LL_ADC_OFFSET_1, LL_ADC_CHANNEL_TEMPSENSOR, 0);
 
 LL_ADC_EnableIT_EOS(ADC3); // End of regular sequence of conversions IR enable
 LL_ADC_EnableIT_EOC(ADC3); // End of conversion IR enable
}
 
void init_DMA_ADC(void) {
 
 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
 
 LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
 LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE);
 LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);
 LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
 LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_CIRCULAR);
 LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_PBURST_SINGLE);
 LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);
 LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
 LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_ADC3);
 LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_HIGH);
 
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_1, (uint32_t) (&ADC3->DR));
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_1, (uint32_t)tempSensor);
 
 LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1);
}
 
void enable_adc_interrupt(void) {
 
 NVIC_SetPriority(ADC3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
 NVIC_EnableIRQ(ADC3_IRQn);
}
 
void enable_dma_interrupt(void) {
 
 NVIC_SetPriority(DMA1_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
 NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
 
void enable_ADC(void)
{
 LL_ADC_Enable(ADC3);
 while (LL_ADC_IsEnabled(ADC3) == 0UL);
}
 
void start_ADC(uint32_t size)
{
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, size);
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
 LL_ADC_REG_StartConversion(ADC3);
}
 
void DMA1_Stream1_IRQHandler(void) {
 if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
 LL_DMA_ClearFlag_TC1(DMA1);
 
 dma_flag = 1;
 }
}
 
void ADC3_IRQHandler(void) {
 
 if(LL_ADC_IsActiveFlag_EOC(ADC3) || LL_ADC_IsActiveFlag_EOS(ADC3) ){
 
 LL_ADC_ClearFlag_EOC(ADC3);
 LL_ADC_ClearFlag_EOS(ADC3);
 
 adc_flag = 1;
 }
}

i call it in my main:

MX_ADC3_Init();
init_DMA_ADC();
enable_adc_interrupt();
enable_dma_interrupt();
enable_ADC();
start_ADC(2); // 2 for 2x half word

And in while ufnction I have condition:

if ((adc_flag == 1) || (dma_flag == 1)){
 
 adc_flag = 0;
 dma_flag = 0;
 
 // breakpoint here
}

my studing material is datasheet, reference manual and internet...

https://www.st.com/resource/en/datasheet/stm32h753ii.pdf

https://www.st.com/resource/en/reference_manual/dm00314099-stm32h742-stm32h743-753-and-stm32h750-value-line-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

This topic has been closed for replies.

25 replies

ST Employee
November 22, 2021

Hi,

This is a non sense for me.

I will try to run your script on my side, maybe I missed something with your configuration.

There is no issue with your frequency setup. The minimum ADC sampling time required for Temp sensor is 9µs. This constraint is already reached with your current configuration (PLL2P @50MHz).

Pilous Droip
Senior
November 22, 2021

I found 1 mistake:

void enable_ADC(void)
{
 LL_ADC_Enable(ADC3);
 while (LL_ADC_IsEnabled(ADC3) == 0UL);
 
 LL_ADC_StartCalibration(ADC3 , LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED );
 while (LL_ADC_IsCalibrationOnGoing(ADC3) == 0UL);
}

I had in LL_ADC_StartCalibration LL_ADC_DIFFERENTIAL_ENDED. I'm replacing LL_ADC_SINGLE_ENDED, but the error is still here.

ST Employee
November 22, 2021
LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_387CYCLES_5);

For ADC3, the sampling time need to be replaced by LL_ADC_SAMPLINGTIME_ADC3_247CYCLES_5

On other hand, can you confirm that bit TSEN is set to 1 ? It's located in ADC3_CCr register bit 23.

Pilous Droip
Senior
November 22, 2021

A can't set time to 247CYCLES_5. I don't have it in my ll file.

#define LL_ADC_SAMPLINGTIME_1CYCLE_5 (0x00000000UL) /*!< Sampling time 1.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_2CYCLES_5 ( ADC_SMPR2_SMP10_0) /*!< Sampling time 2.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_8CYCLES_5 ( ADC_SMPR2_SMP10_1 ) /*!< Sampling time 8.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_16CYCLES_5 ( ADC_SMPR2_SMP10_1 | ADC_SMPR2_SMP10_0) /*!< Sampling time 16.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_32CYCLES_5 (ADC_SMPR2_SMP10_2 ) /*!< Sampling time 32.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_64CYCLES_5 (ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_0) /*!< Sampling time 64.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_387CYCLES_5 (ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_1 ) /*!< Sampling time 387.5 ADC clock cycles */
#define LL_ADC_SAMPLINGTIME_810CYCLES_5 (ADC_SMPR2_SMP10_2 | ADC_SMPR2_SMP10_1 | ADC_SMPR2_SMP10_0) /*!< Sampling time 810.5 ADC clock cycles */

And when I look into my registers, bit TSEN I don't see. Interesting. But in my eclipse aplication it has name VSENSEEN. And it is set to 0.

https://www.st.com/resource/en/reference_manual/dm00314099-stm32h742-stm32h743-753-and-stm32h750-value-line-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf#page=1042

0693W00000GYSI0QAP.png

ST Employee
November 22, 2021

I'm sorry I took the wrong reference manual...Sampling time doesn't need to be change...

Try to force this bit just before starting your ADC and see if there is any change. It seems that the TempSensor is not enable.

Pilous Droip
Senior
November 23, 2021

So today I added another channel. And I think adc is working badly in my setup.

Here is complete code:

Clock source

PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
 PeriphClkInitStruct.PLL3.PLL3M = 4;
 PeriphClkInitStruct.PLL3.PLL3N = 100;
 PeriphClkInitStruct.PLL3.PLL3P = 2;
 PeriphClkInitStruct.PLL3.PLL3Q = 2;
 PeriphClkInitStruct.PLL3.PLL3R = 4;
 PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1;
 PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
 PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
 PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL3; // R output = ((8MHz / 4) * 100) / 4 = 50MHz

enable ADC

void ADC_init(void) {
 //LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLL3R);
 
 LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
 /* PF10 ------> ADC3_INP6 */
 GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
 GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
 LL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
 LL_AHB1_GRP1_ForceReset(LL_AHB1_GRP1_PERIPH_ADC12);
 LL_AHB4_GRP1_ForceReset(LL_AHB4_GRP1_PERIPH_ADC3);
 __NOP();__NOP();__NOP();__NOP();
 LL_AHB1_GRP1_ReleaseReset(LL_AHB1_GRP1_PERIPH_ADC12);
 LL_AHB4_GRP1_ReleaseReset(LL_AHB4_GRP1_PERIPH_ADC3);
 
 /* Peripheral clock enable */
 LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_ADC3);
 
 if (LL_ADC_IsDeepPowerDownEnabled(ADC3) != 0UL)
 LL_ADC_DisableDeepPowerDown(ADC3);
 
 if (LL_ADC_IsInternalRegulatorEnabled(ADC3) == 0UL) {
 LL_ADC_EnableInternalRegulator(ADC3);
 __IO uint32_t wait_loop_index = 0UL;
 wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL))) + 1000;
 while (wait_loop_index != 0UL) {
 wait_loop_index--;
 }
 }
 
 LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_CLOCK_ASYNC_DIV1);
 LL_ADC_SetBoostMode(ADC3, LL_ADC_BOOST_MODE_50MHZ);
 
 LL_ADC_SetResolution(ADC3, LL_ADC_RESOLUTION_12B);
 LL_ADC_SetLowPowerMode(ADC3, LL_ADC_LP_MODE_NONE);
 
 LL_ADC_REG_SetTriggerSource(ADC3, LL_ADC_REG_TRIG_SOFTWARE);
 LL_ADC_REG_SetSequencerLength(ADC3, LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS);
 LL_ADC_REG_SetSequencerDiscont(ADC3, LL_ADC_REG_SEQ_DISCONT_DISABLE);
 LL_ADC_REG_SetContinuousMode(ADC3, LL_ADC_REG_CONV_CONTINUOUS); 
 LL_ADC_REG_SetDataTransferMode(ADC3, LL_ADC_REG_DMA_TRANSFER_UNLIMITED); 
 LL_ADC_REG_SetOverrun(ADC3, LL_ADC_REG_OVR_DATA_OVERWRITTEN); 
 LL_ADC_SetOverSamplingScope(ADC3, LL_ADC_OVS_DISABLE);
 
 LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_MULTI_INDEPENDENT);
 
 LL_ADC_INJ_SetQueueMode(ADC3, LL_ADC_INJ_QUEUE_DISABLE);
 // turn on all (PDF page 1042 RM0433 Rev7 and for use in future)
 // The software is allowed to write this bits only when the ADCs are disabled (ADCAL=0, JADSTART=0, ADSTART=0, ADSTP=0, ADDIS=0 and ADEN=0).
 LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_PATH_INTERNAL_VREFINT | LL_ADC_PATH_INTERNAL_TEMPSENSOR | LL_ADC_PATH_INTERNAL_VBAT);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_6);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SAMPLINGTIME_8CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_TEMPSENSOR);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_810CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_EnableIT_EOS(ADC3); // End of regular sequence of conversions IR enable
 LL_ADC_EnableIT_EOC(ADC3); // End of conversion IR enable
}

Enable DMA

void DMA_init(void) {
 
 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
 
 LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_1);
 LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE);
 LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);
 LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
 LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_CIRCULAR);
 LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_PBURST_SINGLE);
 LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);
 LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
 LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_ADC3);
 LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_HIGH);
 
 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_1, LL_ADC_DMA_GetRegAddr(ADC3, LL_ADC_DMA_REG_REGULAR_DATA));
 LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_1, (uint32_t) tempSensor);
 
 LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1);
}

Enable interrupts:

void ADC_EnableInterrupt(void) {
 NVIC_SetPriority(ADC3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1, 0));
 NVIC_EnableIRQ(ADC3_IRQn);
}
 
void DMA_EnableInterrupt(void) {
 NVIC_SetPriority(DMA1_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1, 0));
 NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}

Enable ADC and start ADC

int32_t ADC_enable(void) {
 LL_ADC_Enable(ADC3);
 while (LL_ADC_IsEnabled(ADC3) == 0UL)
 ;
 
 LL_ADC_StartCalibration(ADC3, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);
 
 int32_t timeout = 0xFFFFFF;
 
 while ((LL_ADC_IsCalibrationOnGoing(ADC3) == 0UL) && (--timeout >= 0))
 ;
 
 return timeout;
}
 
void ADC_start(void) {
 LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, (uint32_t) (sizeof(tempSensor) / sizeof(uint16_t)));
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
 LL_ADC_REG_StartConversion(ADC3);
}

And convert values from adc

uint32_t BSP_GetMCUTemperature(void){
 return __LL_ADC_CALC_TEMPERATURE(3300, tempSensor[1], LL_ADC_RESOLUTION_12B);
}
 
uint32_t GetPF10Voltage(void){
 return __LL_ADC_CALC_DATA_TO_VOLTAGE(3300, tempSensor[0], LL_ADC_RESOLUTION_12B);
}

ISR

void DMA1_Stream1_IRQHandler(void) {
 if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
 LL_DMA_ClearFlag_TC1(DMA1);
 }
}
 
void ADC3_IRQHandler(void) {
 
 if (LL_ADC_IsActiveFlag_EOC(ADC3)) {
 LL_ADC_ClearFlag_EOC(ADC3);
 }
 
 if (LL_ADC_IsActiveFlag_EOS(ADC3)) {
 LL_ADC_ClearFlag_EOS(ADC3);
 }
}

I have a potentiometer on the PF10 pin. But the value does not change when it changes position.

Now I test it on: NUCLEO-H743ZI2 (NUH743ZI$AT1).

Pilous Droip
Senior
November 24, 2021

I'm rewriting my code ... But it's worse than before. :face_with_steam_from_nose:

I create one init function:

void ADC_init(void) {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_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 GPIOF
 ADC_Config_GPIO.Mode = LL_GPIO_MODE_ANALOG;
 ADC_Config_GPIO.Pin = LL_GPIO_PIN_10;
 ADC_Config_GPIO.Pull = LL_GPIO_PULL_NO;
 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) tempSensor;
 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 = ADC3_NUM_CHANNEL; // now set 2 for PF10 and internal temp
 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_1, &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(__LL_ADC_COMMON_INSTANCE(ADC3), &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_OVERWRITTEN;
 ADC_Config_REG.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
 ADC_Config_REG.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS;
 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_6);
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_TEMPSENSOR);
 
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SAMPLINGTIME_810CYCLES_5);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_810CYCLES_5);
 
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_PATH_INTERNAL_TEMPSENSOR | LL_ADC_PATH_INTERNAL_VREFINT | LL_ADC_PATH_INTERNAL_VBAT);
 LL_ADC_SetBoostMode(ADC3, LL_ADC_BOOST_MODE_25MHZ); // Boost mode is configured for 20Mhz < frequency <= 25Mhz
 LL_ADC_SetLowPowerMode(ADC3, LL_ADC_LP_MODE_NONE);
 
 LL_RCC_PLL3_SetM(4);
 LL_RCC_PLL3_SetN(100);
 LL_RCC_PLL3_SetP(2);
 LL_RCC_PLL3_SetQ(2);
 LL_RCC_PLL3_SetR(9);
 LL_RCC_PLL3_SetFRACN(0); // ((8.000.000 / 4) x 100) / 9 = 22,222222 MHz
 LL_RCC_PLL3_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_8_16);
 LL_RCC_PLL3_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
 LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLL3R);
 LL_RCC_PLL3FRACN_Enable();
 LL_RCC_PLL3R_Enable();
 LL_RCC_PLL3_Enable();
 
 LL_ADC_EnableIT_EOS(ADC3); // End of regular sequence of conversions IR enable
 LL_ADC_EnableIT_EOC(ADC3); // End of conversion IR enable
 LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1);
 
 LL_ADC_StartCalibration(ADC3, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);
 while (LL_ADC_IsCalibrationOnGoing(ADC3))
 ;
 
 LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1);
 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);
}

Other functions are: enable interrupts and get value

void ADC_EnableInterrupt(void) {
 
 NVIC_SetPriority(ADC3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 2, 0));
 NVIC_EnableIRQ(ADC3_IRQn);
}
 
void DMA_EnableInterrupt(void) {
 
 NVIC_SetPriority(DMA1_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 2, 0));
 NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
 
uint32_t GetMCUTemperature(void){
 return __LL_ADC_CALC_TEMPERATURE(3300, tempSensor[1], LL_ADC_RESOLUTION_16B);
}
 
uint32_t GetPF10Voltage(void){
 return __LL_ADC_CALC_DATA_TO_VOLTAGE(3300, tempSensor[0], LL_ADC_RESOLUTION_16B);
}

Interrupt handler:

void DMA1_Stream1_IRQHandler(void) {
 if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
 LL_DMA_ClearFlag_TC1(DMA1);
 
 dma_flag = 1;
 }
}
 
void ADC3_IRQHandler(void) {
 
 if (LL_ADC_IsActiveFlag_EOC(ADC3)) {
 LL_ADC_ClearFlag_EOC(ADC3);
 
 adc_flag = 1;
 }
 
 if (LL_ADC_IsActiveFlag_EOS(ADC3)) {
 LL_ADC_ClearFlag_EOS(ADC3);
 adc_flag = 2;
 }
}

Variable for reading

#define DMA_BUFFER __attribute__ ((section (".sram1"),aligned(32)))
#define ADC3_NUM_CHANNEL 2
 
volatile DMA_BUFFER uint16_t tempSensor[ADC3_NUM_CHANNEL] = { 0 };

In main, I call every one second:

if (adc_flag > 0) {
 InfoPrint("adc_flag: %d", adc_flag);
 adc_flag = 0;
}
 
if (dma_flag > 0) {
 InfoPrint("dma_flag: %d", dma_flag);
 dma_flag = 0;
}
 
UARTprint("pf10 = %d, temp = %d", BSP_GetPF10Voltage(), BSP_GetMCUTemperature());

And my outpu is here:

adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216
adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216
adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216
adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216
adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216
adc_flag: 2
dma_flag: 1
pf10 = 2538, temp = -216

And I see that interrupts work, but continuous measurement doesn't work.

0693W00000GYiiiQAD.png

Pilous Droip
Senior
November 29, 2021

I'm approaching a solution. In some pdf I read about DCache. So I tried to update my code:

SCB_InvalidateDCache_by_Addr((uint32_t*) tempSensor, (uint32_t) (sizeof(tempSensor) / sizeof(uint16_t)));
UartPrint("TEMP=%d; PF10=%d; VREF=%d", GetMCUTemperature(), GetPF10Voltage(), GetVrefVoltage
 
 
// Using function for read temps and voltages
uint32_t GetMCUTemperature(void) {
 return __LL_ADC_CALC_TEMPERATURE(3300, tempSensor[0], LL_ADC_RESOLUTION_16B);
}
 
uint32_t GetPF10Voltage(void) {
 return __LL_ADC_CALC_DATA_TO_VOLTAGE(3300, tempSensor[1], LL_ADC_RESOLUTION_16B);
}
 
uint32_t GetVrefVoltage(void) {
 return __LL_ADC_CALC_DATA_TO_VOLTAGE(3300, tempSensor[2], LL_ADC_RESOLUTION_16B);
}

I used a freezer before starting the MCU. Now I have a problem with the PF10 value. This value is not measured.

The time in ms is given in parentheses.

[02011] TEMP=24; PF10=580; VREF=1269
[03016] TEMP=27; PF10=598; VREF=1268
[04021] TEMP=28; PF10=591; VREF=1268
[05026] TEMP=27; PF10=578; VREF=1269
[06031] TEMP=29; PF10=593; VREF=1269
[07036] TEMP=31; PF10=571; VREF=1269
[08041] TEMP=34; PF10=587; VREF=1269
[09046] TEMP=37; PF10=571; VREF=1270
[10051] TEMP=40; PF10=570; VREF=1269
[11056] TEMP=42; PF10=606; VREF=1271
[12061] TEMP=44; PF10=609; VREF=1270
[13066] TEMP=45; PF10=605; VREF=1271
[14071] TEMP=46; PF10=605; VREF=1270
[15076] TEMP=48; PF10=623; VREF=1270
[16081] TEMP=48; PF10=617; VREF=1270
[17086] TEMP=49; PF10=626; VREF=1269
[18091] TEMP=49; PF10=635; VREF=1271
[19096] TEMP=49; PF10=634; VREF=1271
[20101] TEMP=51; PF10=612; VREF=1270
[21106] TEMP=51; PF10=611; VREF=1270
[22111] TEMP=51; PF10=604; VREF=1270
[23116] TEMP=52; PF10=612; VREF=1270
[24121] TEMP=52; PF10=614; VREF=1270
[25126] TEMP=52; PF10=620; VREF=1271

Here is my init ADC

void ADC_Init(void) {
 // clock is set to 50MHz
 LL_GPIO_InitTypeDef GPIO_InitStruct = { 0 };
 
 LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOF);
 /* PF10 ------> ADC3_INP6 */
 GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
 GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
 LL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
 LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLL3R);
 
 /* Peripheral clock enable */
 LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_ADC3);
 
 if (LL_ADC_IsDeepPowerDownEnabled(ADC3) != 0UL)
 LL_ADC_DisableDeepPowerDown(ADC3);
 
 if (LL_ADC_IsInternalRegulatorEnabled(ADC3) == 0UL) {
 LL_ADC_EnableInternalRegulator(ADC3);
 __IO uint32_t wait_loop_index = 0UL;
 wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL))) + 1000;
 while (wait_loop_index != 0UL) {
 wait_loop_index--;
 }
 }
 
 LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_PATH_INTERNAL_TEMPSENSOR | LL_ADC_PATH_INTERNAL_VREFINT | LL_ADC_PATH_INTERNAL_VBAT);
 LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_CLOCK_ASYNC_DIV1);
 LL_ADC_SetResolution(ADC3, LL_ADC_RESOLUTION_16B);
 LL_ADC_REG_SetSequencerLength(ADC3, LL_ADC_REG_SEQ_SCAN_ENABLE_3RANKS);
 LL_ADC_SetLowPowerMode(ADC3, LL_ADC_LP_MODE_NONE);
 LL_ADC_REG_SetContinuousMode(ADC3, LL_ADC_REG_CONV_CONTINUOUS);
 LL_ADC_REG_SetSequencerDiscont(ADC3, LL_ADC_REG_SEQ_DISCONT_DISABLE);
 LL_ADC_REG_SetTriggerSource(ADC3, LL_ADC_REG_TRIG_SOFTWARE);
 LL_ADC_REG_SetDataTransferMode(ADC3, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
 LL_ADC_REG_SetOverrun(ADC3, LL_ADC_REG_OVR_DATA_OVERWRITTEN);
 LL_ADC_SetOverSamplingScope(ADC3, LL_ADC_OVS_DISABLE);
 
 LL_ADC_SetBoostMode(ADC3, LL_ADC_BOOST_MODE_50MHZ);
 
 LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_MULTI_INDEPENDENT);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_TEMPSENSOR);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_387CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_6);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SAMPLINGTIME_8CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_6, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_REG_SetSequencerRanks(ADC3, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_VREFINT);
 LL_ADC_SetChannelSamplingTime(ADC3, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_64CYCLES_5);
 LL_ADC_SetChannelSingleDiff(ADC3, LL_ADC_CHANNEL_VREFINT, LL_ADC_SINGLE_ENDED);
 
 LL_ADC_EnableIT_EOS(ADC3); // End of regular sequence of conversions IR enable
 
}