diff --git a/src/shared/drivers/adc/InternalADC.cpp b/src/shared/drivers/adc/InternalADC.cpp
index 6312b2d9aa93587f41cf6fa000bdb759fd8dc8e4..abc344d4190b8d831daa315a390073e46327b385 100644
--- a/src/shared/drivers/adc/InternalADC.cpp
+++ b/src/shared/drivers/adc/InternalADC.cpp
@@ -41,22 +41,46 @@
 #endif
 
 #if defined(STM32F407xx) || defined(STM32F205xx)
-#define AUX_CH InternalADC::CH16
+#define TEMP_CH InternalADC::CH16
+#define VBAT_CH InternalADC::CH18
 #define VBAT_DIV 2.0f
 #elif defined(STM32F429xx) || defined(STM32F767xx) || defined(STM32F769xx)
-#define AUX_CH InternalADC::CH18
+#define TEMP_CH InternalADC::CH18
+#define VBAT_CH InternalADC::CH18
+#define SINGLE_AUX_CHANNEL
 #define VBAT_DIV 4.0f
 #endif
 
+#ifndef WITHOUT_CALIBRATION
+namespace InternalADCConsts
+{
+// Factory calibration values
+// Read "Temperature sensor characteristics" chapter in the datasheet
+static const float voltage30 =
+    static_cast<float>(*TEMP30_CAL_VALUE) * 3.3 / 4095;
+static const float voltage110 =
+    static_cast<float>(*TEMP110_CAL_VALUE) * 3.3 / 4095;
+static const float slope = (voltage110 - voltage30) / (TEMP110 - TEMP30);
+}  // namespace InternalADCConsts
+#endif
+
 namespace Boardcore
 {
 
-InternalADC::InternalADC(ADC_TypeDef* adc, const float supplyVoltage)
-    : adc(adc), supplyVoltage(supplyVoltage)
+InternalADC::InternalADC(ADC_TypeDef* adc) : adc(adc)
 {
     resetRegisters();
     ClockUtils::enablePeripheralClock(adc);
 
+    // Set the clock divider for the analog circuitry to the highest value (/8).
+    // Currently there is no need to speed up ADC reading. For this reason we
+    // use the safest setting.
+    // If it will need to be changed you need to check the datasheet for the
+    // maximum frequency the analog circuitry supports and compare it with the
+    // parent clock (APB2). Also you need to take into account the sampling time
+    // for the temperature sensor.
+    ADC->CCR |= ADC_CCR_ADCPRE_1 | ADC_CCR_ADCPRE_0;
+
     for (int i = 0; i < CH_NUM; i++)
     {
         channelsEnabled[i]   = false;
@@ -82,7 +106,7 @@ bool InternalADC::selfTest() { return true; }
 
 InternalADCData InternalADC::sampleImpl()
 {
-    for (int i = 0; i < CH_NUM; i++)
+    for (int i = 0; i < CH16; i++)
     {
         if (channelsEnabled[i])
         {
@@ -90,28 +114,28 @@ InternalADCData InternalADC::sampleImpl()
         }
     }
 
-    // Prepare the auxiliary channel for the next sample
-    if (vbatLastRead)
-    {
-        vbatVoltageRawValue = channelsRawValues[AUX_CH];
+    /**
+     * The temperature and vbat sensors are enabled and then disabled. If left
+     * enabled they somehow disrupt other channels measurements. I did not find
+     * description of this behaviour anywhere but observed it during testing.
+     *
+     * Also the temperature sensors has a startup time of 10us. 12us is used
+     * because during test 10us were not enough.
+     */
 
-        if (tempEnabled)
-        {
-            ADC->CCR &= ~ADC_CCR_VBATE;
-            ADC->CCR |= ADC_CCR_TSVREFE;
-            vbatLastRead = false;
-        }
-    }
-    else
+    if (tempEnabled)
     {
-        temperatureRawValue = channelsRawValues[AUX_CH];
+        ADC->CCR |= ADC_CCR_TSVREFE;
+        miosix::delayUs(12);
+        temperatureRawValue = readChannel(static_cast<Channel>(TEMP_CH));
+        ADC->CCR &= ~ADC_CCR_TSVREFE;
+    }
 
-        if (vbatEnabled)
-        {
-            ADC->CCR |= ADC_CCR_VBATE;
-            ADC->CCR &= ~ADC_CCR_TSVREFE;
-            vbatLastRead = true;
-        }
+    if (vbatEnabled)
+    {
+        ADC->CCR |= ADC_CCR_VBATE;
+        vbatVoltageRawValue = readChannel(static_cast<Channel>(VBAT_CH));
+        ADC->CCR &= ~ADC_CCR_VBATE;
     }
 
     timestamp = TimestampTimer::getTimestamp();
@@ -135,60 +159,66 @@ void InternalADC::disableChannel(Channel channel)
 void InternalADC::enableTemperature(SampleTime sampleTime)
 {
     tempEnabled = true;
-
-    ADC->CCR &= ~ADC_CCR_VBATE;
-    ADC->CCR |= ADC_CCR_TSVREFE;
-    vbatLastRead = false;
-
-    enableChannel(AUX_CH, sampleTime);
+    enableChannel(TEMP_CH, sampleTime);
 }
 
-void InternalADC::disableTemperature() { tempEnabled = false; }
+void InternalADC::disableTemperature()
+{
+    tempEnabled = false;
+    if (!vbatEnabled || TEMP_CH != VBAT_CH)
+        disableChannel(TEMP_CH);
+}
 
 void InternalADC::enableVbat(SampleTime sampleTime)
 {
     vbatEnabled = true;
-
-    ADC->CCR |= ADC_CCR_VBATE;
-    ADC->CCR &= ~ADC_CCR_TSVREFE;
-    vbatLastRead = true;
-
-    enableChannel(AUX_CH, sampleTime);
+    enableChannel(VBAT_CH, sampleTime);
 }
 
-void InternalADC::disableVbat() { vbatEnabled = false; }
+void InternalADC::disableVbat()
+{
+    vbatEnabled = false;
+    if (!tempEnabled || TEMP_CH != VBAT_CH)
+        disableChannel(VBAT_CH);
+}
 
 InternalADCData InternalADC::getVoltage(Channel channel)
 {
     return {timestamp, channel,
-            channelsRawValues[channel] * supplyVoltage / RESOLUTION};
+            channelsRawValues[channel] * V_DDA_VOLTAGE / RESOLUTION};
 }
 
 TemperatureData InternalADC::getTemperature()
 {
     TemperatureData data;
     data.temperatureTimestamp = timestamp;
-    data.temperature = temperatureRawValue * supplyVoltage / RESOLUTION;
+
+    if (temperatureRawValue != 0)
+    {
+        data.temperature = temperatureRawValue * V_DDA_VOLTAGE / RESOLUTION;
 
 #ifdef WITHOUT_CALIBRATION
-    // Default conversion
-    data.temperature = ((data.temperature - 0.76) / 0.0025) + 25;
+        // Default conversion
+        data.temperature = ((data.temperature - 0.76) / 0.0025) + 25;
 #else
-    // Factory calibration
-    // Read "Temperature sensor characteristics" chapter in the datasheet
-    float voltage30  = static_cast<float>(*TEMP30_CAL_VALUE) * 3.3 / 4095;
-    float voltage110 = static_cast<float>(*TEMP110_CAL_VALUE) * 3.3 / 4095;
-    float slope      = (voltage110 - voltage30) / (TEMP110 - TEMP30);
-    data.temperature = ((data.temperature - voltage30) / slope) + TEMP30;
+        // Factory calibration
+        data.temperature = ((data.temperature - InternalADCConsts::voltage30) /
+                            InternalADCConsts::slope) +
+                           TEMP30;
 #endif
+    }
+    else
+    {
+        data.temperature = 0;
+    }
 
     return data;
 }
 
 InternalADCData InternalADC::getVbatVoltage()
 {
-    return {timestamp, AUX_CH,
-            vbatVoltageRawValue * supplyVoltage / RESOLUTION * VBAT_DIV};
+    return {timestamp, VBAT_CH,
+            vbatVoltageRawValue * V_DDA_VOLTAGE / RESOLUTION * VBAT_DIV};
 }
 
 inline void InternalADC::resetRegisters()
@@ -225,7 +255,7 @@ inline void InternalADC::setChannelSampleTime(Channel channel,
     }
 }
 
-float InternalADC::readChannel(Channel channel)
+uint16_t InternalADC::readChannel(Channel channel)
 {
     // Assuming that ADC_SQR1_L remains 0 (1 conversion)
 
diff --git a/src/shared/drivers/adc/InternalADC.h b/src/shared/drivers/adc/InternalADC.h
index 1968132cdfc09a31eb2cfc7df044703698296b64..276b35b6d1e8c0de6893470be9689c6971a07b86 100644
--- a/src/shared/drivers/adc/InternalADC.h
+++ b/src/shared/drivers/adc/InternalADC.h
@@ -93,7 +93,7 @@ public:
      * @brief Resets the ADC configuration and automatically enables the
      * peripheral clock.
      */
-    explicit InternalADC(ADC_TypeDef* adc, const float supplyVoltage = 3.3);
+    explicit InternalADC(ADC_TypeDef* adc);
 
     ~InternalADC();
 
@@ -133,20 +133,18 @@ private:
 
     void setChannelSampleTime(Channel channel, SampleTime sampleTime);
 
-    float readChannel(Channel channel);
+    uint16_t readChannel(Channel channel);
 
     ADC_TypeDef* adc;
-    const float supplyVoltage;
 
     bool channelsEnabled[CH_NUM];
-    bool tempEnabled  = false;
-    bool vbatEnabled  = false;
-    bool vbatLastRead = false;
-
-    float channelsRawValues[CH_NUM];
-    float temperatureRawValue = 0;
-    float vbatVoltageRawValue = 0;
-    uint64_t timestamp        = 0;
+    bool tempEnabled = false;
+    bool vbatEnabled = false;
+
+    uint16_t channelsRawValues[CH_NUM];
+    uint16_t temperatureRawValue = 0;
+    uint16_t vbatVoltageRawValue = 0;
+    uint64_t timestamp           = 0;
 
     static constexpr int RESOLUTION = 4095;  ///< 12 bits
 };
diff --git a/src/tests/drivers/test-internal-adc.cpp b/src/tests/drivers/test-internal-adc.cpp
index e4da6359da6feb10f247d34947455025e0f6526c..33bf23cc7e409d2b97c5ca9db4398854d1c93b50 100644
--- a/src/tests/drivers/test-internal-adc.cpp
+++ b/src/tests/drivers/test-internal-adc.cpp
@@ -27,33 +27,29 @@
 using namespace miosix;
 using namespace Boardcore;
 
+GpioPin ch5(GPIOA_BASE, 5);
+GpioPin ch6(GPIOA_BASE, 6);
+
 int main()
 {
-    // Set the clock divider for the analog circuitry (/8)
-    ADC->CCR |= ADC_CCR_ADCPRE_0 | ADC_CCR_ADCPRE_1;
-    // In this case I've set the maximum value, check the datasheet for the
-    // maximum frequency the analog circuitry supports and compare it with the
-    // parent clock
-
-    InternalADC adc(ADC1, 3.3);
-    adc.enableChannel(InternalADC::CH5);  // PF7
-    adc.enableChannel(InternalADC::CH6);  // PF8
+    ch5.mode(Mode::INPUT_ANALOG);
+    ch6.mode(Mode::INPUT_ANALOG);
+
+    InternalADC adc(ADC1);
+    adc.enableChannel(InternalADC::CH5);  // PA5
+    adc.enableChannel(InternalADC::CH6);  // PA6
     adc.enableTemperature();
     adc.enableVbat();
     adc.init();
 
-    printf("Configuration completed\n");
-
     while (true)
     {
         adc.sample();
 
-        printf(
-            "CH5: %1.3f\tCH6: %1.3f\tCH18: %1.3f\tTemp: %1.3f\tVbat: %1.3f\n",
-            adc.getVoltage(InternalADC::CH5).voltage,
-            adc.getVoltage(InternalADC::CH6).voltage,
-            adc.getVoltage(InternalADC::CH18).voltage,
-            adc.getTemperature().temperature, adc.getVbatVoltage().voltage);
+        printf("CH5: %1.3f\tCH6: %1.3f\tTemp: %1.3f\tVbat: %1.3f\n",
+               adc.getVoltage(InternalADC::CH5).voltage,
+               adc.getVoltage(InternalADC::CH6).voltage,
+               adc.getTemperature().temperature, adc.getVbatVoltage().voltage);
 
         delayMs(1000);
     }