cancel
Showing results for 
Search instead for 
Did you mean: 

H7 read temperature from ADC

Pilous Droip
Senior

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

25 REPLIES 25
GwenoleB
ST Employee

Hi!

First of all, take care ADC3 is a 12-bit resolution 😉

Do you know at which frequency your ADC is working ?

Thank you,

Gwénolé

Pilous Droip
Senior

Yes. I set 12 Bit. You are right. Thanks.

And my clock for ADC3 is 50MHz, from PLL2P.

Here is my new logs. Where is changed resolution from 16b to 12bit.

adc=2, tempVal=0x2e1, temp=21
dma=1, tempVal=0x2e1, temp=21
adc=2, tempVal=0x2e1, temp=21
dma=1, tempVal=0x2e1, temp=21
adc=2, tempVal=0x2e1, temp=21
dma=1, tempVal=0x2e1, temp=21
adc=2, tempVal=0x2e1, temp=21
dma=1, tempVal=0x2e1, temp=21
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
......many 30......
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x303, temp=30
dma=1, tempVal=0x303, temp=30
adc=2, tempVal=0x2ef, temp=25
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
...many 19 ......
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
adc=2, tempVal=0x2dc, temp=19
dma=1, tempVal=0x2dc, temp=19
.... many 19.....
adc=2, tempVal=0x2e5, temp=22
dma=1, tempVal=0x2e5, temp=22
adc=2, tempVal=0x2e5, temp=22
dma=1, tempVal=0x2e5, temp=22
adc=2, tempVal=0x2e5, temp=22
dma=1, tempVal=0x2e5, temp=22
adc=2, tempVal=0x2e5, temp=22
dma=1, tempVal=0x2e5, temp=22
adc=2, tempVal=0x2e5, temp=22
dma=1, tempVal=0x2e5, temp=22
....many 22.....
adc=2, tempVal=0x2ee, temp=25
dma=1, tempVal=0x2ee, temp=25
adc=2, tempVal=0x2ee, temp=25
dma=1, tempVal=0x2ee, temp=25
adc=2, tempVal=0x2ee, temp=25
dma=1, tempVal=0x2ee, temp=25
adc=2, tempVal=0x2dd, temp=19
dma=1, tempVal=0x2dd, temp=19
adc=2, tempVal=0x2dd, temp=19
dma=1, tempVal=0x2ec, temp=24
adc=2, tempVal=0x2ec, temp=24

Pilous Droip
Senior

I reduced the resolution from 16b to 12b. And I let the temperature work out for a while. Here is the chart. It can be seen that it is completely wrong. I have a PCB in the office, where the temperature is about 24 deg.

uint32_t temp;
if (adc_flag >= 1){
	 adc_flag = 0;
}
 
if (dma_flag == 1){
        temp = __LL_ADC_CALC_TEMPERATURE(VDD_VALUE, tempSensor[0], LL_ADC_RESOLUTION_12B);
         UARTPrint("dma=%d, tempVal=0x%02x, temp=%d", dma_flag, tempSensor[0], temp);
         dma_flag = 0;
}

 Figure chart: yellow is temperature in degree.

0693W00000GYOWmQAP.png

Pilous Droip
Senior

Now I play with frequency of ADC. And my set is:

    /* PLL3 pro ADC -> ADC3 CLOCK = 20 MHz */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    PeriphClkInitStruct.PLL3.PLL3M = 4;
    PeriphClkInitStruct.PLL3.PLL3N = 100;
    PeriphClkInitStruct.PLL3.PLL3P = 2;
    PeriphClkInitStruct.PLL3.PLL3Q = 2;
    PeriphClkInitStruct.PLL3.PLL3R = 10;
    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) / 10 = 20MHz

My init ADC I set:

void BSP_ADC_init(void) {
    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_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC3), LL_ADC_CLOCK_ASYNC_DIV1);
    LL_ADC_SetResolution(ADC3, LL_ADC_RESOLUTION_12B);
    LL_ADC_REG_SetSequencerLength(ADC3, LL_ADC_REG_SEQ_SCAN_DISABLE);
    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
}

And now I have tempVal from DMA zero.

dma=1, tempVal=0x00, temp=-216
dma=1, tempVal=0x00, temp=-216

And when I go back to 50MHz, the ADC value is back .... I found BoosMode in the datasheet. I tried it, but it didn't help ...

GwenoleB
ST Employee

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).

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.

GwenoleB
ST Employee
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.

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

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.