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.
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.
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.

| Reference | Exact part or value | Job in this design |
|---|---|---|
| U1 | Analog Devices MAX31855KASA+T, SOIC-8 | K-type conversion, internal reference-temperature measurement and fault reporting. |
| C1 | KEMET C0805C104K5RACTU, 100 nF, 50 V, X7R, 0805 | Local supply bypass, with short connections to U1 VCC and ground. The dielectric code identifies a temperature-dependent ceramic family. |
| C2 | KEMET C0805C103J5GACTU, 10 nF, 50 V, ±5%, C0G, 0805 | Differential input filter directly between the two probe nets; C0G identifies a stable ceramic temperature characteristic. |
| R1 | Vishay CRCW080510K0FKEA, 10 kΩ, ±1% | Holds chip select inactive while the Pico starts. |
| J1 / J2 | Samtec TSW-105-07-G-S / TSW-102-07-G-S, 2.54 mm pitch | Five 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 terminal | Original Pico connection | Meaning |
|---|---|---|
| 1, 3V3 | Physical pin 36, 3V3 OUT | Only module supply. |
| 2, GND | Physical pin 23, ground | Common logic reference. |
| 3, SCK | Physical pin 24, GP18 | Serial clock. |
| 4, CS_N | Physical pin 22, GP17 | Active-low selection. |
| 5, SO | Physical pin 21, GP16 | Converter 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.
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.
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.

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.
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.
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.
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?
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.