cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 + Zephyr: ADC + DMA giving wrong (low) values for Internal temperature, VBAT, VREF

DhirajThakur
Associate II

Hi,

we are using ADC with DMA for internal ADC channel like internal Temperature sensor, VBAT, VREF but we are facing issue related to accuracy please help me on this Configuration:

ADC channel:

   adc_channel_config_t ADC3_temp_config = {
        .channel       = ADC_CHANNEL_TEMPSENSOR,
        .rank          = ADC_REGULAR_RANK_8,
        .sampling_time = ADC_SAMPLETIME_810CYCLES_5,
    };
   adc_channel_config_t ADC3_vbat_config = {
        .channel       = ADC_CHANNEL_VBAT,
        .rank          = ADC_REGULAR_RANK_9,
        .sampling_time = ADC_SAMPLETIME_8CYCLES_5,
    };
        uC_AtoD_HAL::adc_channel_config_t ADC3_vref_config = {
        .channel       = ADC_CHANNEL_VREFINT,
        .rank          = ADC_REGULAR_RANK_10,
        .sampling_time = ADC_SAMPLETIME_8CYCLES_5,
};
 
DMA :
dma_channel_config_t ADC3_dma_config = {
        .channel = 2, // Channel 0 - ADC1, Channel 1 - ADC2, Channel 2 - ADC3, In H7 this parameter is used as a
                      // instance number
        .stream          = DMA1_Stream3,
        .src_data_width  = DMA_PDATAALIGN_WORD,
        .dest_data_width = DMA_MDATAALIGN_WORD
    };
 
ADC register for internal:
    ADC_Common_TypeDef *adc_common = ADC3_COMMON_REGISTER(pADC3Handler);
    adc_common->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN | ADC_CCR_VBATEN;
 
Code:
For temperature:
#define TS_CAL1_TEMP 30.0f
#define TS_CAL2_TEMP 110.0f
#define TS_CAL1_ADDR ((uint16_t*)0x1FF1E820) // 30°C
#define TS_CAL2_ADDR ((uint16_t*)0x1FF1E840) // 110°C
uint16_t TS_CAL1 = *TS_CAL1_ADDR;
uint16_t TS_CAL2 = *TS_CAL2_ADDR;
LOG_DBG("TS_CAL1: %d, TS_CAL2: %d\n", TS_CAL1, TS_CAL2);
uint32_t TS_DATA = 0;
for (int i = 0; i < NUM_OF_CHANNEL_BUFFERS_ADC3; i++)
{
TS_DATA += MCUTemperature[i];
}
TS_DATA = TS_DATA / NUM_OF_CHANNEL_BUFFERS_ADC3;

float McuTemperature = 
(float_t)(((TS_CAL2_TEMP - TS_CAL1_TEMP) / (float_t)(TS_CAL2 - TS_CAL1)) * (TS_DATA - TS_CAL1)) + TS_CAL1_TEMP;
 
For Vref:
#define VREFIN_CAL ((uint16_t*)0x1FF1E860)
uint16_t Vrefin_Cal_Value = *VREFIN_CAL;
uint32_t VREF_DATA = 0;
for (int i = 0; i < NUM_OF_CHANNEL_BUFFERS_ADC3; i++)
{
VREF_DATA += Vrefint_volt[i];
}
VREF_DATA = VREF_DATA / NUM_OF_CHANNEL_BUFFERS_ADC3;
float vref = 3.3 * (Vrefin_Cal_Value /VREF_DATA );
vref = (vref / 65535) * VREF_DATA;
 
for Vbat:
    uint32_t Vbat_DATA = 0;
    for (int i = 0; i < NUM_OF_CHANNEL_BUFFERS_ADC3; i++)
    {
      Vbat_DATA += BatteryVoltage[i];
    }
    Vbat_DATA = Vbat_DATA / NUM_OF_CHANNEL_BUFFERS_ADC3;

   LOG_DBG("Vbat Raw count : %d\n",Vbat_DATA );

  BatteryVoltage = (Vbat_DATA * 4.0 * 3.3) / 65535.0;
 
Please let me know any configuration is miss 
Thanks in Advance
 


5 REPLIES 5
TDK
Super User

A few things:

  • Are you calibrating the ADC before using it? You need to.
  • What chip are you using?
  • What raw ADC values do you get?
  • What vbat//vrefint/temperature values do you get and, if not obvious, why do you think they're incorrect?
  • You're using 130 for the upper end temperature instead of 110 as the comments say.
If you feel a post has answered your question, please click "Accept as Solution".

Are you calibrating the ADC before using it? You need to.

ANS: Yes

What chip are you using?

ANS: STM32H743ZIVET6

What raw ADC values do you get?

ANS: During debugging we could read the below calibration values and ADC raw count.

TS_CAL2 = 16287, TS_CAL1 = 12805.

Temperature raw count = 2877

Vbat raw count = 2760

 

You're using 130 for the upper end temperature instead of 110 as the comments say.

ANS:

#define TS_CAL1_TEMP 30.0f
#define TS_CAL2_TEMP 110.0f
 
What vbat//vrefint/temperature values do you get and, if not obvious, why do you think they're incorrect?
ANS:
We are using 16bit ADC 
For temperature,

As per the Datasheet of STM32H743ZI, an internal MCU temperature sensor connected to ADC3_INP18 channel is factory calibrated and below are the calibration values stored into the MCU internal Flash.

DhirajThakur_0-1749794370052.jpeg

 

Below formula will be used for actual temperature calculation. Where TS_DATA is the actual temperature sensor output value converted by ADC. also mention this formula in code above 

DhirajThakur_1-1749794370053.jpeg

 

At room temperature, it is expected to get the value of TS_DATA between TS_CAL1 & TS_CAL2 or near around TS_CAL1.  But we are getting TS_DATA = 2877 & calculated temperature = -198.098

For Vbat,

ADC count for Vbat/4  = 2760, formula used to calculate battery volt = 4 * 3.3 * Vbat raw count / 65535 , where 4 is multiplying factor for ADC count Vbat /4,  3.3 V is VDDA, 65535 is for 16 bit ADC resolution.

Hence Calculated Vbat = 0.56V

Measured Vbat pin voltage on STM32H743ZI Nucleo board is 3.25V. 

 

Are you calibrating the ADC before using it? You need to.

ANS: Yes

What chip are you using?

ANS: STM32H743ZIVET6

What raw ADC values do you get?

ANS: During debugging we could read the below calibration values and ADC raw count.

TS_CAL2 = 16287, TS_CAL1 = 12805.

Temperature raw count = 2877

Vbat raw count = 2760

 

You're using 130 for the upper end temperature instead of 110 as the comments say.

ANS:

#define TS_CAL1_TEMP 30.0f
#define TS_CAL2_TEMP 110.0f
 
What vbat//vrefint/temperature values do you get and, if not obvious, why do you think they're incorrect?
ANS:
We are using 16bit ADC 
For temperature,

As per the Datasheet of STM32H743ZI, an internal MCU temperature sensor connected to ADC3_INP18 channel is factory calibrated and below are the calibration values stored into the MCU internal Flash.

DhirajThakur_0-1749796419620.jpeg

 

 

Below formula will be used for actual temperature calculation. Where TS_DATA is the actual temperature sensor output value converted by ADC. also mention this formula in code above 

DhirajThakur_1-1749796419603.jpeg

 

 

At room temperature, it is expected to get the value of TS_DATA between TS_CAL1 & TS_CAL2 or near around TS_CAL1.  But we are getting TS_DATA = 2877 & calculated temperature = -198.098

For Vbat,

ADC count for Vbat/4  = 2760, formula used to calculate battery volt = 4 * 3.3 * Vbat raw count / 65535 , where 4 is multiplying factor for ADC count Vbat /4,  3.3 V is VDDA, 65535 is for 16 bit ADC resolution.

Hence Calculated Vbat = 0.56V

Measured Vbat pin voltage on STM32H743ZI Nucleo board is 3.25V. 

Sarra.S
ST Employee

Hello @DhirajThakur

Since the issue is related to TS_DATA value (very low), and this value is converted by ADC, most probably the issue is related to the ADC configuration; try using a longer sampling time for the internal temperature sensor.

Another thing is in your formula: Vbat= 4 * 3.3 * Vbat raw count / 65535 where VDDA= 3.3 

Depending on the package VDDA can be internally connected to Vref+ or not, could you specify the package you're using! 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

TDK
Super User

> ADC_REGULAR_RANK_8

If converting 3 channels, they should be on ranks 1-3. Or maybe 0-2, not sure if it's base 0 or 1.

I have to believe the issue is in how the ADC is being configured. Doesn't look like you're using HAL. Ensure the SQRx registers point to the correct channels.

> ADC_SAMPLETIME_8CYCLES_5

Unlikely to be long enough for VREFINT or VBAT. Required sampling duration is in the datasheet.

If you feel a post has answered your question, please click "Accept as Solution".