MAX31855K: A Plausible Temperature Frame Can Still Have the Wrong Cold Junction

This is an unbuilt Tricky Circuit module design and a repeatable experiment. The supplied decoder has host computer tests. Target firmware execution, assembled-board behavior and calibrated temperature accuracy have not been verified. Native schematic and PCB review are recorded separately.

What this module is meant to teach

A thermocouple joins two different metal alloys at its sensing tip. It produces a small voltage related to the temperature difference between that tip and the places where its wires meet the measuring circuit. It does not send an absolute temperature over a wire. Cold-junction compensation means measuring the temperature of those reference connections and using it to interpret the thermocouple voltage. “Cold” names the reference end; it need not be colder than the probe.

The Analog Devices MAX31855K performs that compensation and reports a digital result. This project deliberately separates three questions: did the serial frame have a plausible format, did the converter report a wiring fault, and was its internal temperature a good representation of the actual reference junctions? A good answer to the first question does not establish the other two. Moving a warm finger near the input connector can be more revealing than printing additional decimal places.

The exact converter is MAX31855KASA+T, the K-type version in the eight-pin narrow small-outline integrated-circuit package, abbreviated SOIC. The final T denotes tape-and-reel packaging, not a different thermocouple type. Do not silently substitute a J-, T- or other letter version. The linked Product Information Notice PIN 2571A, dated 20 April 2026, concerns shipping boxes for specified moisture-sensitivity-level-one reel shipments. It describes no change to fit, form, function, quality or reliability; it is not an electrical pinout erratum.

The complete module and its boundaries

This board has no regulator and no voltage translator. Supply it with the original Raspberry Pi Pico's regulated 3.3 V output. The converter's operating supply range is 3.0–3.6 V; a connector marked VCC on an unrelated marketplace board does not prove that board accepts 5 V. Keep this module and all its serial connections in one 3.3 V domain. Here ground is the shared electrical reference for the logic and supply, not a connection to either thermocouple wire.

MAX31855KASA+T physical pins 2 T-minus and 3 T-plus connect to a two-pin probe header and a 10 nanofarad differential capacitor. Pin 4 receives 3.3 volts with a 100 nanofarad bypass to pin 1 ground. Pins 5 SCK, 6 chip select and 7 serial output reach a five-pin host header. A 10 kilohm resistor pulls chip select to 3.3 volts, while pin 8 is explicitly unconnected.
Original functional schematic. Repeated 3V3 and ground symbols name the same source and return; the two probe nets remain separate from ground. Editable SVG · Full-size PNG.
ReferenceExact part or valueJob in this design
U1Analog Devices MAX31855KASA+T, SOIC-8K-type conversion, internal reference-temperature measurement and fault reporting.
C1KEMET C0805C104K5RACTU, 100 nF, 50 V, X7R, 0805Local supply bypass, with short connections to U1 VCC and ground. The dielectric code identifies a temperature-dependent ceramic family.
C2KEMET C0805C103J5GACTU, 10 nF, 50 V, ±5%, C0G, 0805Differential input filter directly between the two probe nets; C0G identifies a stable ceramic temperature characteristic.
R1Vishay CRCW080510K0FKEA, 10 kΩ, ±1%Holds chip select inactive while the Pico starts.
J1 / J2Samtec TSW-105-07-G-S / TSW-102-07-G-S, 2.54 mm pitchFive host connections and two explicitly labelled probe connections.

U1 pin 1 is GND, 2 is T−, 3 is T+, 4 is VCC, 5 is SCK, 6 is active-low chip select, 7 is serial output and 8 is do not connect. Keep pin 8 isolated. Do not connect T− to ground to make the drawing look tidier. Use an ungrounded, electrically isolated K-type probe for this experiment. A grounded-junction probe or a tip touching a conductive grounded vessel changes the input conditions.

J2 pin 1 is T− and pin 2 is T+. For K-type thermocouple alloys these are the negative Alumel and positive Chromel connections. Check the probe supplier's markings; national color conventions differ. Ordinary copper header contacts introduce transitions from thermocouple alloy to copper. Their temperatures must be close to the converter's reference temperature for the compensation assumption to work. This is a low-temperature teaching fixture, not a qualified high-temperature connector system.

J1 terminalOriginal Pico connectionMeaning
1, 3V3Physical pin 36, 3V3 OUTOnly module supply.
2, GNDPhysical pin 23, groundCommon logic reference.
3, SCKPhysical pin 24, GP18Serial clock.
4, CS_NPhysical pin 22, GP17Active-low selection.
5, SOPhysical pin 21, GP16Converter output to controller input.

General-purpose input/output, shortened to GPIO, is a configurable digital pin. The GP number in code is not the Pico's physical pin number. The firmware also configures GP19 for the hardware serial peripheral interface, SPI, but that controller-output wire is left unconnected: this converter is read-only. Never attach it to an input thermocouple terminal.

Place the reference junction before routing the clock

The 35 × 25 mm PCB, or printed circuit board, is arranged with the probe connector on the left, converter in the quiet central area and host connector on the right. Keep the probe pair short and adjacent, with C2 beside the converter inputs. Keep the supply capacitor close to its actual supply and ground pins. Preserve an isothermal region—an area at nearly one temperature—around the reference connections and converter. A grounded copper region can help spread temperature, but it must not connect the T− net electrically to ground.

A power indicator, regulator or nearby load resistor would warm this small area, so this revision omits them. Do not route a motor current or switching-power return through it. The proposed SOIC pads are a design candidate derived from the package outline and still need native mechanical and assembly review; a tidy local drawing is not a manufactured-fit result. The prototype has no reverse-polarity protection or isolated input channel.

What the numbers mean

The thermocouple field is a signed fourteen-bit integer multiplied by 0.25 °C. An analog-to-digital converter, ADC, represents an analog quantity as a number with finite steps. A 0.25 °C step is resolution, not a claim of ±0.25 °C accuracy. The internal-temperature field has twelve signed bits with 0.0625 °C steps. Four printed decimal places preserve that binary step; they do not imply four-decimal-place physical accuracy.

For example, a thermocouple field of 100 represents 25.00 °C. The fourteen-bit field 0x3FFF represents −1 quarter-degree, or −0.25 °C, rather than a huge positive temperature. The decoder checks the reserved bits and consistency between the aggregate fault flag and the open/short detail bits before returning a temperature. A fault frame leaves temperature columns empty. Retaining a previous numeric temperature there would make a wiring fault look like a stable bath.

A 32-bit MAX31855 serial frame is divided into signed thermocouple temperature, reserved and aggregate fault bits, signed internal temperature, another reserved bit and three fault-detail bits. A conceptual chip-select interval encloses 32 clocks, followed by a high interval when results may update.
Original protocol explanation and constructed numerical examples. This is not an oscilloscope capture. Editable SVG · Full-size PNG.

The converter can take up to 200 ms for its first thermocouple result after power-up and up to 100 ms per subsequent conversion. The program waits 250 ms initially and between reads, with chip select high outside the short transfer. However, the frame has no conversion sequence counter, device identity or cyclic redundancy check, CRC. Reading slowly and receiving plausible bits cannot prove exact data age or even identify a disconnected output that happens to read all zeroes. The timestamp is the time the software observed a frame.

Complete Pico MicroPython observer

Use the original RP2040 Pico and its MicroPython firmware. MicroPython is Python implemented for microcontrollers; CPython is the ordinary desktop interpreter used for the decoder tests here. Copy this complete file to the Pico, inspect the wiring first, then run it from the serial console. The SPI clock request is 1 MHz, mode 0. Most-significant-bit-first means the highest-weight bit arrives first. A finally block releases chip select even if the bus raises an exception.

"""Pico/MAX31855K frame observer. Import on CPython to test the real decoder.

No device identity, CRC, conversion-age or calibrated-temperature claim.
"""


def signed(value, bits):
    if bits < 1 or not 0 <= value < (1 << bits):
        raise ValueError("unsigned field outside width")
    return value - (1 << bits) if value & (1 << (bits - 1)) else value


def decode_frame(frame):
    if not isinstance(frame, (bytes, bytearray)) or len(frame) != 4:
        raise ValueError("exactly four bytes required")
    raw = int.from_bytes(frame, "big")
    faults = raw & 7
    summary = bool(raw & (1 << 16))
    if raw & ((1 << 17) | (1 << 3)):
        return {"state": "invalid_frame", "raw": raw, "reason": "reserved_bit"}
    if summary != bool(faults):
        return {"state": "invalid_frame", "raw": raw, "reason": "fault_mismatch"}
    if faults:
        names = tuple(name for mask, name in ((1, "open"), (2, "short_gnd"),
                      (4, "short_vcc")) if faults & mask)
        return {"state": "fault", "raw": raw, "faults": names}
    return {"state": "frame_ok", "raw": raw,
            "thermocouple_C": signed((raw >> 18) & 0x3fff, 14) * 0.25,
            "internal_C": signed((raw >> 4) & 0xfff, 12) * 0.0625,
            "identity_or_age_verified": False}


def read_frame(spi, chip_select):
    """Always release CS, including a bus exception. Caller waits while CS high."""
    chip_select.value(0)
    try:
        return decode_frame(spi.read(4))
    finally:
        chip_select.value(1)


def run():
    from machine import Pin, SPI
    import time
    cs = Pin(17, Pin.OUT, value=1)
    spi = SPI(0, baudrate=1_000_000, polarity=0, phase=0, bits=8,
              firstbit=SPI.MSB, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
    # GP19/MOSI is configured by SPI0 but NOT connected to this read-only module.
    time.sleep_ms(250)  # datasheet maximum initial conversion is 200 ms
    print("observed_ms,state,thermocouple_C,internal_C,raw_hex,detail")
    try:
        while True:
            observed = time.ticks_ms()
            try:
                result = read_frame(spi, cs)
                raw = "%08x" % result["raw"]
                if result["state"] == "frame_ok":
                    print("%d,frame_ok,%.2f,%.4f,%s,identity_and_age_unknown" %
                          (observed, result["thermocouple_C"], result["internal_C"], raw))
                else:
                    detail = "+".join(result.get("faults", (result.get("reason", "unknown"),)))
                    print("%d,%s,,,%s,%s" % (observed, result["state"], raw, detail))
            except (OSError, ValueError) as error:
                print("%d,read_error,,,,%s" % (observed, str(error).replace(",", ";")))
            # Temperature/fault data update only while CS is high. These are
            # observation timestamps; read spacing cannot prove conversion age.
            time.sleep_ms(250)
    finally:
        cs.value(1)
        spi.deinit()


if __name__ == "__main__":
    run()

Download the program, real host tests, diagrams, contract and blank worksheet. Run python3 test_actual_program.py in the extracted folder on a computer to exercise the delivered decoder. Its fourteen test methods cover signed values, all fault combinations, inconsistent flags, reserved bits, short reads and chip-select cleanup. They do not execute the Pico SPI peripheral, establish sensor presence or substitute for a target test.

A bench sequence that keeps observations honest

  1. With all power disconnected, inspect the exact U1 marking and orientation, connector numbering and isolated pin 8. Check continuity from each header terminal to the intended device pin, including both sides of the differential capacitor. Check for accidental continuity from either probe input to ground.
  2. Connect only the Pico and module. Power the Pico from its normal USB cable; USB means Universal Serial Bus. Measure the module supply before starting acquisition. Do not add a second supply to its 3V3 header.
  3. Leave the dry module, connector and probe at a stable room temperature. Record both reported temperatures, frame status, supply voltage and a separate reference reading with its uncertainty. Do not fill the blank worksheet with the calculated examples.
  4. Move only the probe tip into gently stirred ice water, then room-temperature water and warm water below 60 °C. Keep the electronics and wire transitions dry. Wait for a stable trend instead of comparing two changing sensors at arbitrary timestamps.
  5. Return the probe and module to a stable environment. Gently warm the input connector area with a nearby finger without touching bare conductors. Watch whether reported probe temperature moves while the separate bath reference remains stable. Repeat by warming the converter region. Record the actual direction and settling time; no response has been measured for this design.
  6. Disconnect power, remove the probe, then power up and observe the open-circuit status after the initial interval. Restore the probe only with power removed. The short-to-ground and short-to-supply decoder tests are constructed software cases, not instructions to apply arbitrary voltages to probe pins.

For interpretation, use a first-order compensation thought experiment. If the reference contacts are at 25 °C, the die is at 35 °C and the tip remains fixed, using the die as a contact-temperature estimate can introduce roughly a +10 °C bias. Real thermocouple nonlinearity and gradients make this an illustration, not a calibration equation. Improve thermal placement before trying to cancel a changing offset in software.

Challenge: plausible zeroes after a loose wire

The module cable comes loose and the program reports a format-plausible frame containing 0.00 °C for both fields with no fault bit. Does the fault decoder prove that the probe is working?

Show the reasoning

No. The decoder validates relationships within the bits it received. All-zero data satisfies those relationships but carries no device identity or freshness evidence. Stop interpreting it as a temperature until supply, continuity and the serial output are checked. A real open probe with a powered, communicating converter is a different condition from an absent converter output.

For another example of separating a timing model from an actual observation, see the published ATtiny85 clock and piezo experiment. The same discipline applies here: a correct arithmetic result does not establish a correct physical reference.

Primary sources