diff --git a/src/shared/sensors/MAX31855/MAX31855.h b/src/shared/sensors/MAX31855/MAX31855.h
index 2c5fb8067b12eec4bf015539d34927ffd6fa8a45..62be42ab10eabb7c66a507c9d67449cbc92eec01 100644
--- a/src/shared/sensors/MAX31855/MAX31855.h
+++ b/src/shared/sensors/MAX31855/MAX31855.h
@@ -29,6 +29,17 @@
 namespace Boardcore
 {
 
+/**
+ * @brief MAX31855 thermocouple sensor driver.
+ *
+ * The MAX31855 performs cold-junction compensation and digitizes the signal
+ * from a K, J, N, T, S, R, or E type thermocouple depending on the selected
+ * product variant. The data is output in  a signed 14-bit, SPI-compatible,
+ * read-only format. This converter resolves temperatures to 0.25°C, allows
+ * readings as high as +1800°C and as low as -270°C, and exhibits thermocouple
+ * accuracy of ±2°C for temperatures ranging from -200°C to +700°C for K-type
+ * thermocouples.
+ */
 class MAX31855 : public Sensor<TemperatureData>
 {
 public:
diff --git a/src/shared/sensors/MAX31856/MAX31856.cpp b/src/shared/sensors/MAX31856/MAX31856.cpp
index 325e1ac8aaad44ce19d95db2c63db613fc5e8d80..ad1d5475980f62eea2eb31e4df99e49778081b53 100644
--- a/src/shared/sensors/MAX31856/MAX31856.cpp
+++ b/src/shared/sensors/MAX31856/MAX31856.cpp
@@ -49,6 +49,9 @@ bool MAX31856::init()
     // Set thermocouple type
     setThermocoupleType(type);
 
+    // Reset the cold junction offset
+    setColdJunctionOffset(0);
+
     // Enable continuous conversion mode
     spi.writeRegister(CR0, CR0_CMODE);
 
@@ -81,46 +84,44 @@ void MAX31856::setThermocoupleType(ThermocoupleType type)
     spi.writeRegister(CR1, static_cast<uint8_t>(type));
 }
 
-TemperatureData MAX31856::sampleImpl()
+void MAX31856::setColdJunctionOffset(float offset)
 {
-    int32_t sample;
+    SPITransaction spi{slave};
+    spi.writeRegister(CJTO,
+                      static_cast<int8_t>(offset * 1 / CJ_TEMP_LSB_VALUE));
+}
 
-    {
-        SPITransaction spi{slave};
-        sample = spi.readRegister24(LTCBH);
-    }
+MAX31856Data MAX31856::sampleImpl()
+{
+    SPITransaction spi{slave};
+    int16_t cjRaw = spi.readRegister16(CJTH);
+    int32_t tcRaw = spi.readRegister24(LTCBH);
 
-    TemperatureData result{};
+    MAX31856Data result;
     result.temperatureTimestamp = TimestampTimer::getTimestamp();
 
-    // Sign extension
-    sample = sample << 8;
-    sample = sample >> (8 + 5);
-
-    // Convert the integer and decimal part separately
-    result.temperature = static_cast<float>(sample) * 0.007812;
+    // The register has:
+    // - A leading sign bit (which is actually two's complement)
+    // - The other 18 bits
+    // - 5 unused trailing bits
 
-    return result;
-}
-
-TemperatureData MAX31856::readInternalTemperature()
-{
-    uint16_t sample[2];
-
-    {
-        SPITransaction spi{slave};
-        spi.read16(sample, sizeof(sample));
-    }
+    // Since the 24 bit registers value is stored into a 32 bit variable, first
+    // we make a left shift to move the sign bit in the 31st bit, and then a
+    // right shift to remove the unused bits.
+    // This automatically extends the sign
+    tcRaw = tcRaw << 8;
+    tcRaw = tcRaw >> (8 + 5);
 
-    TemperatureData result{};
-    result.temperatureTimestamp = TimestampTimer::getTimestamp();
+    // Here we just make a right shift as the sign bit is already in the 15th
+    // bit. This will also perform the sign extension like in sampleImpl()
+    cjRaw = cjRaw >> 4;
 
-    // Extract data bits
-    sample[1] = sample[1] >> 4;
+    // Convert the raw value into temperature
+    result.temperature = static_cast<float>(tcRaw) * TC_TEMP_LSB_VALUE;
 
-    // Convert the integer and decimal part separately
-    result.temperature = static_cast<float>(sample[1] >> 4);
-    result.temperature += static_cast<float>(sample[1] & 0xF) * 0.0625;
+    // Convert the raw value into temperature
+    result.coldJunctionTemperature =
+        static_cast<float>(cjRaw) * CJ_TEMP_LSB_VALUE;
 
     return result;
 }
diff --git a/src/shared/sensors/MAX31856/MAX31856.h b/src/shared/sensors/MAX31856/MAX31856.h
index 97fbd817e8eb3e13766eaea09c847c644a836c4a..7e04e481a5b820ccc2fb37597419cea2b341394a 100644
--- a/src/shared/sensors/MAX31856/MAX31856.h
+++ b/src/shared/sensors/MAX31856/MAX31856.h
@@ -26,10 +26,25 @@
 #include <drivers/spi/SPIDriver.h>
 #include <sensors/Sensor.h>
 
+#include "MAX31856Data.h"
+
 namespace Boardcore
 {
 
-class MAX31856 : public Sensor<TemperatureData>
+/**
+ * @brief MAX31855 thermocouple sensor driver.
+ *
+ * The MAX31856 performs cold-junction compensation and digitizes the signal
+ * from any type of thermocouple. This converter resolves temperatures to
+ * 0.0078125°C, allows readings as high as +1800°C and as low as -210°C
+ * (depending on thermocouple type), and exhibits thermocouple voltage
+ * measurement accuracy of ±0.15%. The thermocouple inputs are protected against
+ * over voltage conditions up to ±45V. A lookup table (LUT) stores linearity
+ * correction data for several types of thermocouples (K, J, N, R, S, T, E, and
+ * B). Line frequency filtering of 50Hz and 60Hz is included, as is thermocouple
+ * fault detection
+ */
+class MAX31856 : public Sensor<MAX31856Data>
 {
 public:
     enum class ThermocoupleType : uint8_t
@@ -63,13 +78,10 @@ public:
 
     void setThermocoupleType(ThermocoupleType type);
 
-    /**
-     * @brief Read the device internal temperature (cold junction).
-     */
-    TemperatureData readInternalTemperature();
+    void setColdJunctionOffset(float offset);
 
 private:
-    TemperatureData sampleImpl() override;
+    MAX31856Data sampleImpl() override;
 
     SPISlave slave;
     ThermocoupleType type;
@@ -99,6 +111,9 @@ private:
     static constexpr uint8_t CR0_CMODE     = 0x1 << 7;
     static constexpr uint8_t CR0_OCFAULT_0 = 0x1 << 4;
     static constexpr uint8_t SR_OPEN       = 0x1 << 0;
+
+    static constexpr float TC_TEMP_LSB_VALUE = 0.007812;  // [°C]
+    static constexpr float CJ_TEMP_LSB_VALUE = 0.0625;    // [°C]
 };
 
 }  // namespace Boardcore
diff --git a/src/shared/sensors/MAX31856/MAX31856Data.h b/src/shared/sensors/MAX31856/MAX31856Data.h
new file mode 100644
index 0000000000000000000000000000000000000000..ebd5742eb02c1a6d117ec4e061d08187b4141a0f
--- /dev/null
+++ b/src/shared/sensors/MAX31856/MAX31856Data.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2023 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 <utils/Debug.h>
+
+#include <cstdio>
+#include <map>
+
+#include "sensors/SensorData.h"
+
+namespace Boardcore
+{
+
+struct MAX31856Data : public TemperatureData
+{
+    float coldJunctionTemperature;
+
+    MAX31856Data() : MAX31856Data{0, 0.0, 0.0} {}
+
+    MAX31856Data(uint64_t temperatureTimestamp, float temperature)
+        : MAX31856Data(temperatureTimestamp, temperature, 0)
+    {
+    }
+
+    MAX31856Data(uint64_t temperatureTimestamp, float temperature,
+                 float coldJunctionTemperature)
+        : TemperatureData{temperatureTimestamp, temperature},
+          coldJunctionTemperature(coldJunctionTemperature)
+    {
+    }
+
+    static std::string header()
+    {
+        return "temperatureTimestamp,temperature,coldJunctionTemperature\n";
+    }
+
+    void print(std::ostream& os) const
+    {
+        os << temperatureTimestamp << "," << temperature << ","
+           << coldJunctionTemperature << "\n";
+    }
+};
+
+}  // namespace Boardcore
\ No newline at end of file
diff --git a/src/tests/sensors/test-max31856.cpp b/src/tests/sensors/test-max31856.cpp
index 8cf44008d1929c29f87cdfbb14ca5f131fc5fb58..6d4a3edd655e93480c365ce5f258f72d7be9fa82 100644
--- a/src/tests/sensors/test-max31856.cpp
+++ b/src/tests/sensors/test-max31856.cpp
@@ -60,13 +60,23 @@ int main()
         printf("The thermocouple is connected\n");
     }
 
+    // Wait for one sample to be made
+    Thread::sleep(100);
+
+    // Set cold junction offset
+    // This should set the cold junction temperature to 25°
+    sensor.sample();
+    auto sample = sensor.getLastSample();
+    sensor.setColdJunctionOffset(sample.coldJunctionTemperature - 25);
+    printf("Offset: %f\n", sample.coldJunctionTemperature - 25);
+
     while (true)
     {
         sensor.sample();
-        TemperatureData sample = sensor.getLastSample();
+        sample = sensor.getLastSample();
 
-        printf("\r\e[0K[%.2f] %.2f", sample.temperatureTimestamp / 1e6,
-               sample.temperature);
+        printf("[%.2f] %f %f\n", sample.temperatureTimestamp / 1e6,
+               sample.temperature, sample.coldJunctionTemperature);
 
         Thread::sleep(100);
     }