diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 38852e8975cdd4496e36f965293a27bcdfb38140..dc630721eef6582109b785e60a3cefa307d246cf 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -8,7 +8,7 @@
             "defines": [
                 "DEBUG",
                 "_ARCH_CORTEXM4_STM32F4",
-                "_BOARD_STM32F407VG_STM32F4DISCOVERY",
+                "_BOARD_STM32F4DISCOVERY",
                 "_MIOSIX_BOARDNAME=stm32f407vg_stm32f4discovery",
                 "HSE_VALUE=8000000",
                 "SYSCLK_FREQ_168MHz=168000000",
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 499e63fbe0bc2fbf8adf05ba283e4de56d1fb77a..caa4ff15bf38b4658d34a4bf0af6745b62d54e44 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,246 +1,264 @@
 {
-    "cmake.configureSettings": {
-        "CMAKE_C_COMPILER_LAUNCHER": "ccache",
-        "CMAKE_CXX_COMPILER_LAUNCHER": "ccache"
-    },
-    "cmake.parallelJobs": 1,
-    "files.associations": {
-        "sstream": "cpp",
-        "format": "cpp",
-        "any": "cpp",
-        "array": "cpp",
-        "atomic": "cpp",
-        "bit": "cpp",
-        "*.tcc": "cpp",
-        "bitset": "cpp",
-        "cctype": "cpp",
-        "chrono": "cpp",
-        "clocale": "cpp",
-        "cmath": "cpp",
-        "codecvt": "cpp",
-        "complex": "cpp",
-        "condition_variable": "cpp",
-        "cstdarg": "cpp",
-        "cstddef": "cpp",
-        "cstdint": "cpp",
-        "cstdio": "cpp",
-        "cstdlib": "cpp",
-        "cstring": "cpp",
-        "ctime": "cpp",
-        "cwchar": "cpp",
-        "cwctype": "cpp",
-        "deque": "cpp",
-        "list": "cpp",
-        "map": "cpp",
-        "set": "cpp",
-        "unordered_map": "cpp",
-        "vector": "cpp",
-        "exception": "cpp",
-        "algorithm": "cpp",
-        "functional": "cpp",
-        "iterator": "cpp",
-        "memory": "cpp",
-        "memory_resource": "cpp",
-        "numeric": "cpp",
-        "optional": "cpp",
-        "random": "cpp",
-        "ratio": "cpp",
-        "regex": "cpp",
-        "string": "cpp",
-        "string_view": "cpp",
-        "system_error": "cpp",
-        "tuple": "cpp",
-        "type_traits": "cpp",
-        "utility": "cpp",
-        "fstream": "cpp",
-        "future": "cpp",
-        "initializer_list": "cpp",
-        "iomanip": "cpp",
-        "iosfwd": "cpp",
-        "iostream": "cpp",
-        "istream": "cpp",
-        "limits": "cpp",
-        "mutex": "cpp",
-        "new": "cpp",
-        "ostream": "cpp",
-        "shared_mutex": "cpp",
-        "stdexcept": "cpp",
-        "streambuf": "cpp",
-        "thread": "cpp",
-        "cinttypes": "cpp",
-        "typeindex": "cpp",
-        "typeinfo": "cpp",
-        "variant": "cpp",
-        "__config": "cpp",
-        "__threading_support": "cpp",
-        "__mutex_base": "cpp",
-        "__tree": "cpp",
-        "locale": "cpp",
-        "__bit_reference": "cpp",
-        "__bits": "cpp",
-        "__debug": "cpp",
-        "__errc": "cpp",
-        "__functional_base": "cpp",
-        "__hash_table": "cpp",
-        "__locale": "cpp",
-        "__node_handle": "cpp",
-        "__nullptr": "cpp",
-        "__split_buffer": "cpp",
-        "__string": "cpp",
-        "__tuple": "cpp",
-        "ios": "cpp",
-        "queue": "cpp",
-        "stack": "cpp",
-        "__functional_03": "cpp",
-        "filesystem": "cpp",
-        "unordered_set": "cpp",
-        "hash_map": "cpp",
-        "valarray": "cpp",
-        "ranges": "cpp",
-        "compare": "cpp",
-        "concepts": "cpp",
-        "core": "cpp",
-        "iterativelinearsolvers": "cpp",
-        "pastixsupport": "cpp",
-        "superlusupport": "cpp",
-        "adolcforward": "cpp",
-        "alignedvector3": "cpp",
-        "bvh": "cpp",
-        "fft": "cpp",
-        "iterativesolvers": "cpp",
-        "mprealsupport": "cpp",
-        "matrixfunctions": "cpp",
-        "nonlinearoptimization": "cpp",
-        "openglsupport": "cpp",
-        "polynomials": "cpp",
-        "autodiff": "cpp",
-        "sparseextra": "cpp",
-        "specialfunctions": "cpp"
-    },
-    "cSpell.words": [
-        "aelf",
-        "airbrakes",
-        "Airbrakes",
-        "Alessandro",
-        "AMSL",
-        "atthr",
-        "AVDD",
-        "Baro",
-        "boardcore",
-        "Boardcorev",
-        "boudrate",
-        "Corigliano",
-        "CORTEXM",
-        "cpitch",
-        "cppcheck",
-        "croll",
-        "cwise",
-        "cyaw",
-        "DATABUS",
-        "deleteme",
-        "DMEIE",
-        "Doxyfile",
-        "doxygen",
-        "DRDY",
-        "Duca",
-        "Ecompass",
-        "Eigen",
-        "elfs",
-        "Erbetta",
-        "Fatt",
-        "Fatttr",
-        "fedetft's",
-        "fiprintf",
-        "Gatttr",
-        "getdetahstate",
-        "GNSS",
-        "Gpio",
-        "GPIOA",
-        "GPIOB",
-        "GPIOC",
-        "GPIOD",
-        "GPIOE",
-        "GPIOF",
-        "GPIOG",
-        "GPIOS",
-        "gpstr",
-        "Hatt",
-        "HSCMAND",
-        "HSCMRNN",
-        "HWMAPPING",
-        "IDLEIE",
-        "irqn",
-        "irqv",
-        "Kalman",
-        "Katt",
-        "kbps",
-        "ldrex",
-        "leds",
-        "LIFCR",
-        "logdecoder",
-        "Luca",
-        "MEKF",
-        "MINC",
-        "miosix",
-        "mkdir",
-        "mosfet",
-        "mosi",
-        "MPXHZ",
-        "Musso",
-        "NATT",
-        "NBAR",
-        "NDTR",
-        "NGPS",
-        "NMAG",
-        "NMEA",
-        "NMEKF",
-        "nord",
-        "NVIC",
-        "peripehral",
-        "PINC",
-        "Pitot",
-        "Plin",
-        "Qgbw",
-        "Qget",
-        "Qhandle",
-        "Qput",
-        "Qwait",
-        "Qwakeup",
-        "Riccardo",
-        "RXNE",
-        "RXNEIE",
-        "sats",
-        "Satt",
-        "sdio",
-        "SDRAM",
-        "spitch",
-        "sqdip",
-        "sqtrp",
-        "sroll",
-        "SSCDANN",
-        "SSCDRRN",
-        "stof",
-        "syaw",
-        "TCIE",
-        "TEIE",
-        "Terraneo",
-        "testsuite",
-        "TSCPP",
-        "Ublox",
-        "UBXACK",
-        "UBXGPS",
-        "UBXNAV",
-        "Unsync",
-        "upcounter",
-        "USART",
-        "vbat",
-        "velnord",
-        "vout",
-        "vsense",
-        "Xbee",
-        "xnord",
-        "yned"
-    ],
-    "cSpell.language": "en",
-    "cSpell.enabled": true
+        "cmake.configureSettings": {
+                "CMAKE_C_COMPILER_LAUNCHER": "ccache",
+                "CMAKE_CXX_COMPILER_LAUNCHER": "ccache"
+        },
+        "cmake.parallelJobs": 1,
+        "files.associations": {
+                "sstream": "cpp",
+                "format": "cpp",
+                "any": "cpp",
+                "array": "cpp",
+                "atomic": "cpp",
+                "bit": "cpp",
+                "*.tcc": "cpp",
+                "bitset": "cpp",
+                "cctype": "cpp",
+                "chrono": "cpp",
+                "clocale": "cpp",
+                "cmath": "cpp",
+                "codecvt": "cpp",
+                "complex": "cpp",
+                "condition_variable": "cpp",
+                "cstdarg": "cpp",
+                "cstddef": "cpp",
+                "cstdint": "cpp",
+                "cstdio": "cpp",
+                "cstdlib": "cpp",
+                "cstring": "cpp",
+                "ctime": "cpp",
+                "cwchar": "cpp",
+                "cwctype": "cpp",
+                "deque": "cpp",
+                "list": "cpp",
+                "map": "cpp",
+                "set": "cpp",
+                "unordered_map": "cpp",
+                "vector": "cpp",
+                "exception": "cpp",
+                "algorithm": "cpp",
+                "functional": "cpp",
+                "iterator": "cpp",
+                "memory": "cpp",
+                "memory_resource": "cpp",
+                "numeric": "cpp",
+                "optional": "cpp",
+                "random": "cpp",
+                "ratio": "cpp",
+                "regex": "cpp",
+                "string": "cpp",
+                "string_view": "cpp",
+                "system_error": "cpp",
+                "tuple": "cpp",
+                "type_traits": "cpp",
+                "utility": "cpp",
+                "fstream": "cpp",
+                "future": "cpp",
+                "initializer_list": "cpp",
+                "iomanip": "cpp",
+                "iosfwd": "cpp",
+                "iostream": "cpp",
+                "istream": "cpp",
+                "limits": "cpp",
+                "mutex": "cpp",
+                "new": "cpp",
+                "ostream": "cpp",
+                "shared_mutex": "cpp",
+                "stdexcept": "cpp",
+                "streambuf": "cpp",
+                "thread": "cpp",
+                "cinttypes": "cpp",
+                "typeindex": "cpp",
+                "typeinfo": "cpp",
+                "variant": "cpp",
+                "__config": "cpp",
+                "__threading_support": "cpp",
+                "__mutex_base": "cpp",
+                "__tree": "cpp",
+                "locale": "cpp",
+                "__bit_reference": "cpp",
+                "__bits": "cpp",
+                "__debug": "cpp",
+                "__errc": "cpp",
+                "__functional_base": "cpp",
+                "__hash_table": "cpp",
+                "__locale": "cpp",
+                "__node_handle": "cpp",
+                "__nullptr": "cpp",
+                "__split_buffer": "cpp",
+                "__string": "cpp",
+                "__tuple": "cpp",
+                "ios": "cpp",
+                "queue": "cpp",
+                "stack": "cpp",
+                "__functional_03": "cpp",
+                "filesystem": "cpp",
+                "unordered_set": "cpp",
+                "hash_map": "cpp",
+                "valarray": "cpp",
+                "ranges": "cpp",
+                "compare": "cpp",
+                "concepts": "cpp",
+                "core": "cpp",
+                "iterativelinearsolvers": "cpp",
+                "pastixsupport": "cpp",
+                "superlusupport": "cpp",
+                "adolcforward": "cpp",
+                "alignedvector3": "cpp",
+                "bvh": "cpp",
+                "fft": "cpp",
+                "iterativesolvers": "cpp",
+                "mprealsupport": "cpp",
+                "matrixfunctions": "cpp",
+                "nonlinearoptimization": "cpp",
+                "openglsupport": "cpp",
+                "polynomials": "cpp",
+                "autodiff": "cpp",
+                "sparseextra": "cpp",
+                "specialfunctions": "cpp"
+        },
+        "cSpell.words": [
+                "ADCPRE",
+                "ADON",
+                "aelf",
+                "airbrakes",
+                "Airbrakes",
+                "Alessandro",
+                "AMSL",
+                "atthr",
+                "AVDD",
+                "Baro",
+                "boardcore",
+                "Boardcorev",
+                "boudrate",
+                "Corigliano",
+                "CORTEXM",
+                "cpitch",
+                "cppcheck",
+                "croll",
+                "cwise",
+                "cyaw",
+                "DATABUS",
+                "deleteme",
+                "DMEIE",
+                "Doxyfile",
+                "doxygen",
+                "DRDY",
+                "Duca",
+                "Ecompass",
+                "Eigen",
+                "elfs",
+                "Erbetta",
+                "Fatt",
+                "Fatttr",
+                "fedetft's",
+                "fiprintf",
+                "Gatttr",
+                "getdetahstate",
+                "GNSS",
+                "Gpio",
+                "GPIOA",
+                "GPIOB",
+                "GPIOC",
+                "GPIOD",
+                "GPIOE",
+                "GPIOF",
+                "GPIOG",
+                "GPIOS",
+                "gpstr",
+                "Hatt",
+                "HIFCR",
+                "HISR",
+                "HSCMAND",
+                "HSCMRNN",
+                "HWMAPPING",
+                "IDLEIE",
+                "irqn",
+                "irqv",
+                "JEOC",
+                "JOFR",
+                "JSQR",
+                "JSWSTART",
+                "Kalman",
+                "Katt",
+                "kbps",
+                "ldrex",
+                "leds",
+                "LIFCR",
+                "LISR",
+                "logdecoder",
+                "Luca",
+                "Matteo",
+                "MEKF",
+                "microcontrollers",
+                "MINC",
+                "miosix",
+                "mkdir",
+                "mosfet",
+                "mosi",
+                "MPXHZ",
+                "Musso",
+                "NATT",
+                "NBAR",
+                "NDTR",
+                "NGPS",
+                "Nidasio",
+                "NMAG",
+                "NMEA",
+                "NMEKF",
+                "nord",
+                "NVIC",
+                "peripehral",
+                "Piazzolla",
+                "PINC",
+                "Pitot",
+                "Plin",
+                "Qgbw",
+                "Qget",
+                "Qhandle",
+                "Qput",
+                "Qwait",
+                "Qwakeup",
+                "Riccardo",
+                "RXNE",
+                "RXNEIE",
+                "sats",
+                "Satt",
+                "sdio",
+                "SDRAM",
+                "smpr",
+                "SMPR",
+                "spitch",
+                "sqdip",
+                "sqtrp",
+                "sroll",
+                "SSCDANN",
+                "SSCDRRN",
+                "stof",
+                "SWSTART",
+                "syaw",
+                "TCIE",
+                "TCIF",
+                "TEIE",
+                "Terraneo",
+                "testsuite",
+                "TSCPP",
+                "TSVREFE",
+                "Ublox",
+                "UBXACK",
+                "UBXGPS",
+                "UBXNAV",
+                "Unsync",
+                "upcounter",
+                "USART",
+                "vbat",
+                "velnord",
+                "vout",
+                "vsense",
+                "Xbee",
+                "xnord",
+                "yned"
+        ],
+        "cSpell.language": "en",
+        "cSpell.enabled": true
 }
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7a55228cdd5d6724a274cd40f0c6d7947d04f0e..cdbc08614f50f7d21b57c0a4f332df58e4477b91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -178,7 +178,7 @@ add_executable(test-general-purpose-timer src/tests/drivers/timer/test-general-p
 sbs_target(test-general-purpose-timer stm32f429zi_stm32f4discovery)
 
 add_executable(test-internal-adc src/tests/drivers/test-internal-adc.cpp)
-sbs_target(test-internal-adc stm32f429zi_skyward_death_stack_x)
+sbs_target(test-internal-adc stm32f407vg_stm32f4discovery)
 
 add_executable(test-internal-adc-dma src/tests/drivers/test-internal-adc-dma.cpp)
 sbs_target(test-internal-adc-dma stm32f429zi_stm32f4discovery)
@@ -231,6 +231,9 @@ sbs_target(test-xbee-snd stm32f429zi_stm32f4discovery)
 add_executable(test-usart src/tests/drivers/usart/test-usart.cpp)
 sbs_target(test-usart stm32f407vg_stm32f4discovery)
 
+add_executable(test-internal-temp src/tests/drivers/test-internal-temp.cpp)
+sbs_target(test-internal-temp stm32f407vg_stm32f4discovery)
+
 #-----------------------------------------------------------------------------#
 #                               Tests - Events                                #
 #-----------------------------------------------------------------------------#
diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake
index 3c6806988b9fcf80a1a9bce82c4536b4ae40033f..120f7bc5e0143d8e5cb78cd3c578603ca66f844e 100644
--- a/cmake/boardcore.cmake
+++ b/cmake/boardcore.cmake
@@ -43,6 +43,7 @@ foreach(OPT_BOARD ${BOARDS})
         ${SBS_BASE}/src/shared/diagnostic/PrintLogger.cpp
 
         # Drivers
+        ${SBS_BASE}/src/shared/drivers/adc/InternalTemp.cpp
         ${SBS_BASE}/src/shared/drivers/adc/InternalADC.cpp
         ${SBS_BASE}/src/shared/drivers/canbus/Canbus.cpp
         ${SBS_BASE}/src/shared/drivers/canbus/CanInterrupt.cpp
diff --git a/src/shared/drivers/adc/InternalADC.cpp b/src/shared/drivers/adc/InternalADC.cpp
index 5599223012b51872d29bec8cfdee357fa9fb0f33..737b2b6bc040925b2f7268ebc6154edcb17f25b3 100644
--- a/src/shared/drivers/adc/InternalADC.cpp
+++ b/src/shared/drivers/adc/InternalADC.cpp
@@ -72,9 +72,7 @@ InternalADC::InternalADC(ADC_TypeDef* adc, const float supplyVoltage,
 
     // Init indexMap
     for (auto i = 0; i < CH_NUM; i++)
-    {
         indexMap[i] = -1;
-    }
 }
 
 InternalADC::~InternalADC()
@@ -90,13 +88,13 @@ bool InternalADC::init()
     adc->CR2 |= ADC_CR2_ADON;
 
     // Set single conversion mode
-    adc->CR2 &= ~ADC_CR2_CONT;
+    // adc->CR2 &= ~ADC_CR2_CONT;
 
     // Set scan mode
-    adc->CR1 |= ADC_CR1_SCAN;
+    // adc->CR1 |= ADC_CR1_SCAN;
 
     // Data alignment
-    adc->CR2 &= ~ADC_CR2_ALIGN;  // right
+    // adc->CR2 &= ~ADC_CR2_ALIGN;  // right
 
     if (isUsingDMA)
     {
@@ -130,33 +128,22 @@ bool InternalADC::init()
     return true;
 }
 
-bool InternalADC::enableChannel(Channel channel)
-{
-    return enableChannel(channel, CYCLES_3);
-}
-
 bool InternalADC::enableChannel(Channel channel, SampleTime sampleTime)
 {
     // Check channel number
     if (channel < CH0 || channel >= CH_NUM)
-    {
         return false;
-    }
 
     // Add channel to the sequence
     if (!isUsingDMA)
     {
         if (!addInjectedChannel(channel))
-        {
             return false;
-        }
     }
     else
     {
         if (!addRegularChannel(channel))
-        {
             return false;
-        }
 
         // Update the DMA number of data
         dmaStream->NDTR = activeChannels;
@@ -168,6 +155,52 @@ bool InternalADC::enableChannel(Channel channel, SampleTime sampleTime)
     return true;
 }
 
+bool InternalADC::addRegularChannel(Channel channel)
+{
+    // Check active channels number
+    if (activeChannels >= 16)
+        return false;
+
+    // Add the channel to the sequence
+    volatile uint32_t* sqrPtr;
+    switch (activeChannels / 6)
+    {
+        case 1:
+            sqrPtr = &(adc->SQR2);
+            break;
+        case 2:
+            sqrPtr = &(adc->SQR1);
+            break;
+        default:
+            sqrPtr = &(adc->SQR3);
+    }
+    *sqrPtr = channel << ((activeChannels % 6) * 5);
+
+    // Update the channels number in the register
+    adc->SQR1 &= ~ADC_SQR1_L;
+    adc->SQR1 |= activeChannels << 20;
+
+    // Save the index of the channel in the ADC's regular sequence
+    indexMap[channel] = activeChannels;
+
+    // Update the counter
+    activeChannels++;
+
+    return true;
+}
+
+ADCData InternalADC::readChannel(Channel channel, SampleTime sampleTime)
+{
+    setChannelSampleTime(channel, sampleTime);
+    startRegularConversion();
+
+    while (!(adc->SR & ADC_SR_EOC))
+        ;
+
+    return {TimestampTimer::getTimestamp(), channel,
+            static_cast<uint16_t>(adc->DR) * supplyVoltage / RESOLUTION};
+}
+
 InternalADCData InternalADC::getVoltage(Channel channel)
 {
     float voltage = 0;
@@ -219,14 +252,14 @@ InternalADCData InternalADC::sampleImpl()
 
         // This should trigger the DMA stream for each channel's conversion
 
-        // Wait for tranfer end
+        // Wait for transfer end
         while (!(*statusReg & (transferCompleteMask | transferErrorMask)))
             ;
 
         // Clear the transfer complete flag
         *clearFlagReg |= transferCompleteMask;
 
-        // If and error has occurred (probaly due to a higher priority stream)
+        // If and error has occurred (probably due to a higher priority stream)
         // don't update the timestamp, the values should not have been updated
         if (*statusReg & transferErrorMask)
         {
@@ -244,6 +277,8 @@ InternalADCData InternalADC::sampleImpl()
     return lastSample;
 }
 
+float InternalADC::getSupplyVoltage() { return supplyVoltage; }
+
 inline void InternalADC::resetRegisters()
 {
     // Reset the ADC configuration
@@ -277,9 +312,7 @@ inline bool InternalADC::addInjectedChannel(Channel channel)
 {
     // Check active channels number
     if (activeChannels >= 4)
-    {
         return false;
-    }
 
     // Add the channel to the sequence, starting from position 4
     adc->JSQR |= channel << (15 - activeChannels * 5);
@@ -292,9 +325,7 @@ inline bool InternalADC::addInjectedChannel(Channel channel)
     for (auto i = 0; i < CH_NUM; i++)
     {
         if (indexMap[i] >= 0)
-        {
             indexMap[i]++;
-        }
     }
 
     // Set this channel index to 0
@@ -306,53 +337,15 @@ inline bool InternalADC::addInjectedChannel(Channel channel)
     return true;
 }
 
-inline bool InternalADC::addRegularChannel(Channel channel)
-{
-    // Check active channels number
-    if (activeChannels >= 16)
-    {
-        return false;
-    }
-
-    // Add the channel to the sequence
-    volatile uint32_t* sqrPtr;
-    switch (activeChannels % 6)
-    {
-        case 1:
-            sqrPtr = &(adc->SQR3);
-            break;
-        case 2:
-            sqrPtr = &(adc->SQR2);
-            break;
-        default:
-            sqrPtr = &(adc->SQR1);
-    }
-    *sqrPtr = channel << ((activeChannels % 6) * 5);
-
-    // Update the channels number in the register
-    adc->SQR1 |= activeChannels << 20;
-
-    // Save the index of the channel in the ADC's regular sequence
-    indexMap[channel] = activeChannels;
-
-    // Update the counter
-    activeChannels++;
-
-    return true;
-}
-
 inline void InternalADC::setChannelSampleTime(Channel channel,
                                               SampleTime sampleTime)
 {
     volatile uint32_t* smprPtr;
     if (channel <= 9)
-    {
         smprPtr = &(adc->SMPR2);
-    }
     else
-    {
         smprPtr = &(adc->SMPR1);
-    }
+
     *smprPtr = sampleTime << (channel * 3);
 }
 
diff --git a/src/shared/drivers/adc/InternalADC.h b/src/shared/drivers/adc/InternalADC.h
index 662419e817ef60eb8622b6326af3ad5f11bf3f72..ab0498619a7447080ab2efa4c6c6b7c53438e73b 100644
--- a/src/shared/drivers/adc/InternalADC.h
+++ b/src/shared/drivers/adc/InternalADC.h
@@ -90,6 +90,9 @@ public:
         CH13,
         CH14,
         CH15,
+        CH16,
+        CH17,
+        CH18,
         CH_NUM
     };
 
@@ -127,9 +130,14 @@ public:
      */
     bool init() override;
 
-    bool enableChannel(Channel channel);
+    /**
+     * @brief Make a regular conversion for the specified channel.
+     */
+    ADCData readChannel(Channel channel, SampleTime sampleTime = CYCLES_3);
+
+    bool enableChannel(Channel channel, SampleTime sampleTime = CYCLES_3);
 
-    bool enableChannel(Channel channel, SampleTime sampleTime);
+    bool addRegularChannel(Channel channel);
 
     InternalADCData getVoltage(Channel channel);
 
@@ -137,6 +145,8 @@ public:
 
     InternalADCData sampleImpl() override;
 
+    float getSupplyVoltage();
+
 private:
     inline void resetRegisters();
 
@@ -146,8 +156,6 @@ private:
 
     inline bool addInjectedChannel(Channel channel);
 
-    inline bool addRegularChannel(Channel channel);
-
     inline void setChannelSampleTime(Channel channel, SampleTime sampleTime);
 
     ADC_TypeDef* adc;
@@ -168,7 +176,7 @@ private:
      * We'll use up to 4 injected channel by default and up to 16 channels when
      * using DMA.
      *
-     * The differentiation is necessary because whitout DMA it is much simplier
+     * The differentiation is necessary because whiteout DMA it is much simpler
      * to use injected channel for multichannel readings. Otherwise we would
      * need to handle each channel's end of conversion interrupt or go through
      */
@@ -182,7 +190,7 @@ private:
     volatile uint32_t* clearFlagReg;
 
     static constexpr int INJECTED_CHANNEL_N = 4;
-    static constexpr int RESOLUTION         = 4096;  ///< 12 bits
+    static constexpr int RESOLUTION         = 4095;  ///< 12 bits
 };
 
 }  // namespace Boardcore
diff --git a/src/shared/drivers/adc/InternalTemp.cpp b/src/shared/drivers/adc/InternalTemp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e6c15b2fc9629145d82ac9a6cb4f7fe6c63dcfec
--- /dev/null
+++ b/src/shared/drivers/adc/InternalTemp.cpp
@@ -0,0 +1,84 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Authors: Giulia Ghirardini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "InternalTemp.h"
+
+#ifdef _ARCH_CORTEXM4_STM32F4
+#define TEMP30_CAL_VALUE ((uint16_t*)((uint32_t)0x1FFF7A2C))
+#define TEMP110_CAL_VALUE ((uint16_t*)((uint32_t)0x1FFF7A2E))
+#define TEMP30 30
+#define TEMP110 110
+#endif
+
+namespace Boardcore
+{
+
+InternalTemp::InternalTemp(InternalADC::SampleTime sampleTime,
+                           const float supplyVoltage)
+    : adc(ADC1, supplyVoltage), sampleTime(sampleTime)
+{
+}
+
+bool InternalTemp::init()
+{
+    bool result = adc.init();
+
+#if defined(_BOARD_STM32F4DISCOVERY) || defined(_ARCH_CORTEXM3_STM32F2)
+    adc.addRegularChannel(InternalADC::CH16);
+#else
+    adc.addRegularChannel(InternalADC::CH18);
+#endif
+
+    ADC->CCR &= ~ADC_CCR_VBATE;
+    ADC->CCR |= ADC_CCR_TSVREFE;
+
+    return result;
+}
+
+bool InternalTemp::selfTest() { return adc.selfTest(); }
+
+InternalTempData InternalTemp::sampleImpl()
+{
+#if defined(_BOARD_STM32F4DISCOVERY) || defined(_ARCH_CORTEXM3_STM32F2)
+    auto adcData = adc.readChannel(InternalADC::CH16, sampleTime);
+#else
+    auto adcData = adc.readChannel(InternalADC::CH18, sampleTime);
+#endif
+
+    InternalTempData data;
+    data.temperatureTimestamp = adcData.voltageTimestamp;
+
+#ifdef _ARCH_CORTEXM3_STM32F2
+    // Default conversion
+    data.temperature = ((adcData.voltage - 0.76) / 0.0025) + 25;
+#else
+    // Factory calibration
+    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 = ((adcData.voltage - voltage30) / slope) + TEMP30;
+#endif
+
+    return data;
+}
+
+}  // namespace Boardcore
diff --git a/src/shared/drivers/adc/InternalTemp.h b/src/shared/drivers/adc/InternalTemp.h
new file mode 100644
index 0000000000000000000000000000000000000000..a66e32cafa0283ee463a82c0d8c7be4b3efa99a3
--- /dev/null
+++ b/src/shared/drivers/adc/InternalTemp.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Authors: Giulia Ghirardini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+#include <drivers/adc/InternalADC.h>
+
+#include "InternalTempData.h"
+
+namespace Boardcore
+{
+
+class InternalTemp : public Sensor<InternalTempData>
+{
+public:
+    explicit InternalTemp(
+        InternalADC::SampleTime sampleTime = InternalADC::CYCLES_480,
+        const float supplyVoltage          = 5.0);
+
+    bool init() override;
+
+    bool selfTest() override;
+
+    InternalTempData sampleImpl() override;
+
+    // InternalTempData addRegularChannel(InternalADC::Channel channel);
+
+private:
+    InternalADC adc;
+    InternalADC::SampleTime sampleTime;
+};
+
+}  // namespace Boardcore
diff --git a/src/shared/drivers/adc/InternalTempData.h b/src/shared/drivers/adc/InternalTempData.h
new file mode 100644
index 0000000000000000000000000000000000000000..96f709033d5cdcadb60b4d3e53f19d2da7901b90
--- /dev/null
+++ b/src/shared/drivers/adc/InternalTempData.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2021 Skyward Experimental Rocketry
+ * Author: Alberto Nidasio
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <sensors/SensorData.h>
+
+namespace Boardcore
+{
+
+struct InternalTempData : public TemperatureData
+{
+    InternalTempData() : TemperatureData{0, 0} {}
+
+    static std::string header() { return "timestamp,temperature\n"; }
+
+    void print(std::ostream& os) const
+    {
+        os << temperatureTimestamp << "," << temperature << "\n";
+    }
+};
+
+}  // namespace Boardcore
diff --git a/src/tests/drivers/test-internal-temp.cpp b/src/tests/drivers/test-internal-temp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23fd7844a83f5ae4978d26f092253f76067814e3
--- /dev/null
+++ b/src/tests/drivers/test-internal-temp.cpp
@@ -0,0 +1,44 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Authors: Giulia Ghirardini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <drivers/adc/InternalTemp.h>
+#include <drivers/timer/TimestampTimer.h>
+#include <miosix.h>
+#include <utils/ClockUtils.h>
+
+using namespace Boardcore;
+
+int main()
+{
+    ADC->CCR |= ADC_CCR_ADCPRE_0 | ADC_CCR_ADCPRE_1;
+
+    InternalTemp temp(InternalADC::CYCLES_480, 3.0);
+    temp.init();
+
+    for (;;)
+    {
+        temp.sample();
+        printf("Temperature: %2.3f\n", temp.getLastSample().temperature);
+
+        miosix::delayMs(1000);
+    }
+}