SpaceCommsKit — https://spacecommskit.com
Version 1.0
This is a companion to the SCK-PBL-1 User Guide. The User Guide tells you what's on the board and how to talk to it. This page is different: it's a record of real problems found during bring-up of this board, exactly how each one was tracked down, and what the actual fix turned out to be — including a couple of cases where the obvious suspect was wrong and the real bug was hiding somewhere nobody was looking.
If you're building on this board and hit a symptom that sounds like anything below, start here. It'll likely save you the time it took us to find it the first time.
The board's altimeter is an MS5611-01BA03 barometric pressure sensor. It measures air pressure and reports it over I2C along with a set of factory calibration numbers; the firmware combines the two using a formula from the sensor's datasheet to produce a pressure reading in hPa (hectopascals — the standard unit for atmospheric pressure; sea-level pressure is typically around 1013 hPa) and a derived altitude.
On a brand-new, fully assembled board, the very first pressure readings out of this sensor were consistently around 1970–1973 hPa — roughly double normal atmospheric pressure at ground level. Temperature readings from the same sensor looked completely normal throughout. The mismatch was stable and repeatable, not noisy or occasional.
Why this took a while Every individual step below was a reasonable thing to check given what was known at the time, and each one came back clean. That's actually the useful part of this story: a long list of "not the problem" is often what it takes to find something that's genuinely unusual, and it's worth reading through even though the real answer turns out to be short.
| Suspected cause | How it was tested | Result |
|---|---|---|
| Corrupted calibration data | Reverse-derived all six calibration coefficients by hand from the sensor's own printed output and checked them against normal MS5611 factory ranges | All six were realistic, genuine values — not corrupted |
| Formula implemented wrong | Re-ran the datasheet's compensation formula by hand using the sensor's own logged numbers | The arithmetic matched exactly, given those inputs |
| Sealed pressure port | Physically inspected the sensor package for shipping tape/film over the two pressure ports | Both ports open, no seal present |
| Power pins wired wrong | Measured supply (VDD), protocol-select (PS), and ground (GND) pins directly with a multimeter | All three measured exactly correct |
| I2C wiring wrong | Traced SDA/SCL connections against the schematic and confirmed pull-up resistor values | Correctly wired, standard pull-ups |
| ADC conversion read too early | Widened the conversion wait time well past the datasheet's stated minimum | Reduced reading-to-reading noise, but did not move the actual offset |
| Sensor hadn't finished settling after reflow soldering | Checked the manufacturer's own soldering guidance, which recommends 48 hours of rest after the last solder step before trusting readings | Board was already well past that window |
| A specific "reserved" pin wired to the wrong rail | Physically reworked the board to tie the pin to ground per the datasheet's reference circuit, retested | No change in the reading — directly disproven |
| One defective sensor | Swapped in a second, then a third physically different sensor (different manufacturing date, opposite end of the same reel), retested each | All three produced the same wrong reading — rules out a single bad part |
The detail that cracked it: the wrong reading wasn't random or vague, it was landing at almost exactly double the correct pressure — 2.00×, to four significant figures, confirmed against an independently measured reference reading and reproduced across three different physical sensors. A clean, precise ratio like that is the signature of a units or scaling error, not a hardware fault — random defects don't converge on an exact multiplier.
Cross-checking the firmware's compensation math against a trusted, independent open-source MS5611 library turned up the real issue: the MS5611 sensor family has two different sets of internal math constants depending on the exact chip variant, and this firmware had been using the wrong set — every one of four constants was set to a value meant for a closely related sensor, not this one. Using the wrong constants doesn't cause an error or a crash; it just silently computes a pressure that's exactly double what it should be, for any sensor, every time.
Root cause Four shift constants in the pressure compensation formula were using values from a related sensor variant instead of the genuine MS5611 datasheet values. This inflated the computed pressure by exactly 2× on every reading, regardless of which physical sensor was attached — which is exactly why swapping sensors never changed anything.
# Wrong (silently doubled every pressure reading):
OFF = C2 * (1 << 17) + (C4 * dT) // (1 << 6)
SENS = C1 * (1 << 16) + (C3 * dT) // (1 << 7)
# Correct:
OFF = C2 * (1 << 16) + (C4 * dT) // (1 << 7)
SENS = C1 * (1 << 15) + (C3 * dT) // (1 << 8)
After the fix, pressure readings matched an independently measured reference value to within normal sensor accuracy, and computed altitude finally agreed with GPS altitude for the first time in the investigation.
The onboard GPS module needs to be switched from its default "Portable" navigation mode into "Airborne" mode to track altitude reliably above roughly 12km — necessary for high-altitude balloon flights. This is done by sending the module a specific configuration command at startup (a UBX-CFG-NAV5 message, in u-blox's binary protocol).
The original firmware sent this command but never actually confirmed the module accepted it — it just printed a success message regardless. On inspection, the command being sent was malformed: it was missing its checksum bytes, meaning the GPS module had no valid way to accept it and was silently ignoring it every time. The board would have flown with the GPS still in default mode without anyone knowing.
The firmware now reports this status as part of every GPS reading — the ground station or any downstream tooling can see whether airborne mode is confirmed active, failed, or unconfirmed, instead of trusting a print statement that never checked anything.
Sending a configuration command successfully is not the same as the receiving device actually applying it. If a setting matters for how your mission behaves, verify it took effect — with an acknowledgment if the device supports one, with a direct read-back if it doesn't — and report the real, confirmed state, not just "we sent the command."
During bench testing, the SD card sometimes failed to mount at boot and sometimes mounted fine, with no consistent pattern. The first explanation — that the board had been physically bumped and the card had worked loose — turned out to be a real, confirmed cause on at least one occasion. But a later, controlled test showed the same on/off pattern happening across power cycles with the board sitting completely untouched, which ruled out physical handling as the explanation for that pattern.
This points at a marginal timing issue rather than a mechanical one: SD cards need their supply voltage and a short settle period before their initialization sequence will reliably succeed, and that margin can vary slightly from one power-up to the next for reasons that have nothing to do with how the card is seated.
A short retry loop at boot — if the first mount attempt fails, wait briefly and try again, up to a few times, before giving up:
SD_MOUNT_RETRIES = 3
for attempt in range(1, SD_MOUNT_RETRIES + 1):
if mount_sd():
break
print(f"SD mount attempt {attempt}/{SD_MOUNT_RETRIES} failed, retrying...")
time.sleep_ms(300)
else:
print("SD mount failed after all retries -- flight log will not record")
This resolved the issue cleanly across repeated testing.
A reliable boot-time mount doesn't guarantee the card stays seated through real flight conditions — vibration during ascent and temperature extremes at altitude can still work a friction-fit card loose even when bench testing looks perfect. Worth considering before flight, roughly in order of how much protection each gives:
An intermittent failure that happens with no physical handling involved is a different kind of problem than one that happens after the board gets bumped. Both are real and worth fixing, but they point in different directions — check which one you're actually looking at before deciding on a fix.
Open issue — not yet fixed This is a structural gap in the current firmware, not a bug that's been resolved. It's included here as a known risk for anyone building on this board today.
Both the SCK-915 and SCK-2400 radio boards bridge commands to this payload board over a simple UART link. When the radio board sends a command to the payload processor and waits for a reply, it currently accepts whatever response arrives next as the answer — it doesn't check that the reply actually corresponds to the command it sent.
Normally this isn't a problem. But the payload board also sends autonomous GPS telemetry (a "beacon") on its own independent timer, completely decoupled from command/response timing. If that beacon happens to transmit at the same moment an unrelated command is waiting for a reply, the radio board can mistake the beacon data for the answer to a completely different command — this was directly observed: a request for onboard temperature came back holding GPS coordinates instead.
Compounding this, the radio board's command-handling loop blocks — it can't process anything else — for up to several seconds while waiting for a reply that may never come. With a beacon interval on the same order as typical command round-trip time, the odds of this kind of collision on any given command turn out to be uncomfortably high, not a rare edge case.
None built into the firmware yet. During development, the autonomous beacon can be temporarily disabled to get reliable command testing done — but the beacon is the actual telemetry downlink in flight, so this is a testing convenience only, not something to rely on for a real mission.
The command protocol between the radio board and the payload processor needs real request/response matching — a sequence number or command echo that lets the radio board confirm a reply actually corresponds to what it asked for, so beacon traffic arriving at an inconvenient moment gets correctly ignored instead of mistaken for an answer. Until this lands, any use case involving frequent on-demand commands running at the same time as the autonomous beacon should be treated as carrying real risk of this kind of mismatch.
From the sensor manufacturer's own soldering guidance (application note AN808), for anyone assembling boards with this part:
A few practices from this bring-up that are worth carrying into future work on this firmware:
Found something that isn't covered here, or have your own hard-won lesson to add? Open an issue or PR against the firmware repo — this document is meant to grow with the project.