Search code examples
stm32offsetadcmcu

STM32 ADC Offset voltage problem. ADC starts from 0.05V instead of 0V


I am working with STM32H743ZI for GPIO, I2C, SPI, ADC. I want to read analog voltage from 8 different channel of ADC1. My code works properly, but there is offset voltage that i dont want to.

I am reading the ADC value by connecting the voltage I give from the DC power supply to the ADC pins of the STM32H743ZI.

Below you can see power supply voltages and read ADC value.

DC Supply ADC 0V 0.04 0.5V 0.54V 1.5V 1.55V 3V 3.05V .........

Here is my code...

HAL_ADC_Start(&hadc1);

ADC_ChannelConfTypeDef sConfig = {0};


                sConfig.Channel = ADC_CHANNEL_2;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_2 = HAL_ADC_GetValue(&hadc1);



                sConfig.Channel = ADC_CHANNEL_3;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_3 = HAL_ADC_GetValue(&hadc1);



                sConfig.Channel = ADC_CHANNEL_4;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_4 = HAL_ADC_GetValue(&hadc1);


                sConfig.Channel = ADC_CHANNEL_5;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_5 = HAL_ADC_GetValue(&hadc1);

                sConfig.Channel = ADC_CHANNEL_6;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_6 = HAL_ADC_GetValue(&hadc1);


                sConfig.Channel = ADC_CHANNEL_7;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_7 = HAL_ADC_GetValue(&hadc1);


                sConfig.Channel = ADC_CHANNEL_8;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_8 = HAL_ADC_GetValue(&hadc1);


                sConfig.Channel = ADC_CHANNEL_9;
                HAL_ADC_ConfigChannel(&hadc1, &sConfig);
                HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
                raw_9 = HAL_ADC_GetValue(&hadc1);


                HAL_ADC_Stop(&hadc1);


                  ADC_2[0] = (int)(raw_2 / 256);
                  ADC_2[1] = (int)(raw_2 % 256);

                  ADC_3[0] = (int)(raw_3 / 256);
                  ADC_3[1] = (int)(raw_3 % 256);

                  ADC_4[0] = (int)(raw_4 / 256);
                  ADC_4[1] = (int)(raw_4 % 256);

                  ADC_5[0] = (int)(raw_5 / 256);
                  ADC_5[1] = (int)(raw_5 % 256);

                  ADC_6[0] = (int)(raw_6 / 256);
                  ADC_6[1] = (int)(raw_6 % 256);

                  ADC_7[0] = (int)(raw_7 / 256);
                  ADC_7[1] = (int)(raw_7 % 256);

                  ADC_8[0] = (int)(raw_8 / 256);
                  ADC_8[1] = (int)(raw_8 % 256);

                  ADC_9[0] = (int)(raw_9 / 256);
                  ADC_9[1] = (int)(raw_9 % 256);

I found a solution by subtracting the estimated offset values ​​from the read value but I believe there is a better solution.


                if(raw_2 < 4045 && raw_2 >= 993) raw_2 -= 50;
                else if(raw_2 <= 993 && raw_2 >= 0) raw_2 -= 62;

                if(raw_3 < 4045 && raw_3 >= 993) raw_3 -= 50;
                else if(raw_3 <= 993 && raw_3 >= 0) raw_3 -= 62;

                if(raw_4 < 4045 && raw_4 >= 993) raw_4 -= 50;
                else if(raw_4 <= 993 && raw_4 >= 0) raw_4 -= 62;

                if(raw_5 < 4045 && raw_5 >= 993) raw_5 -= 50;
                else if(raw_5 <= 993 && raw_5 >= 0) raw_5 -= 62;

                if(raw_6 < 4045 && raw_6 >= 993) raw_6 -= 50;
                else if(raw_6 <= 993 && raw_6 >= 0) raw_6 -= 62;

                if(raw_7 < 4045 && raw_7 >= 993) raw_7 -= 50;
                else if(raw_7 <= 993 && raw_7 >= 0) raw_7 -= 62;

                if(raw_8 < 4045 && raw_8 >= 993) raw_8 -= 50;
                else if(raw_8 <= 993 && raw_8 >= 0) raw_8 -= 62;

                if(raw_9 < 4045 && raw_9 >= 993) raw_9 -= 50;
                else if(raw_9 <= 993 && raw_9 >= 0) raw_9 -= 62;`your text` 

Solution

  • I had exactly the same problem with the STM32H7. When connecting the ADC pin to GND, I would receive (16 bit) values around 900, which equals 0.05V.

    As pmacfarlane suggested, I tried calibrating the ADC. I place the following line in my code, after I initilize the ADC, but before I start the ADC conversion.

      HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
    

    After this change my ADC would now read values around 90 (~0.005) when connected to GND. Not 0, but given that this ADC is effectively 14 bit instead of 16 bit, this is pretty okay.

    Note that I'm using the ADC_SINGLE_ENDED parameter because I'm using my ADC in single-ended configuration. Besides the ADC_CALIB_OFFSET mode there is also another ADC_CALIB_OFFSET_LINEARITY mode, which gave me a similar result (This one is probably used to fix linearity issues).