Your readings look plausible. Do they belong to the same update?

Your sensor prototype has reached the useful stage: it displays readings, saves a log and responds to a button. Occasionally, though, the saved row and the screen disagree. Before replacing the sensor, check whether the software assembled that row from one complete update, or picked up part of it just as the next update arrived.

This matters when a team moves from a single-value demonstration to a device people will use to compare results. A reading may need to travel with its timestamp, channel or measurement number. Each field can look reasonable on its own while the combination describes something the device never recorded.

The practical question is simple: which values must stay together? Decide that before adding filters, extra decimal places or a faster display. Those changes cannot repair a record assembled from mismatched updates.

How a believable record goes wrong

Imagine that a measurement handler stores two fields: a sequence number and a value. The main program reads the sequence number first. Before it reads the value, the handler runs and replaces both fields. The main program resumes and takes the new value. Nothing has to crash for the result to be wrong.

Timeline: the reader takes sequence 41, the handler then replaces the record with sequence 42 and value 180, and the reader resumes and takes value 180, assembling 41 with 180
Two valid updates, 41/120 and 42/180, produce one mixed record, 41/180, that was never measured; the values are illustrative.

This is one form of race condition: the result depends on when two pieces of work overlap. It is different from a noisy sensor. Averaging mismatched records may make a graph smoother while hiding the software problem. It is also different from a stale reading: an older, complete record can be internally consistent, while a newly displayed record may not be.

A classic MicroPython example has a Pyboard timer appending generated values to an array while the main program processes the array and resets its count. The pairing of the data and the count is the useful lesson. That example uses pyb calls, so it is not a drop-in Pico program, and it is not a sensor measurement.

Hand over a record before formatting it

Start by describing the smallest complete record your product needs. For a single sensor, that might be a value, an acquisition timestamp and a sequence number. For multiple sensors, document whether the values were acquired together or at separate times. Protecting software access does not make separately sampled sensors physically simultaneous.

Then give the writer and reader an explicit handoff. The writer prepares data; the reader takes a consistent snapshot into storage the writer will not change while it is in use. Only after that handoff should the reader format text, update the display or save a file. The exact mechanism depends on which execution contexts can access the data.

Shared record of value, time and ID, then a short protected handoff that takes a complete copy, then a private snapshot used for formatting, display and logging
Keep the protected handoff short and do the slow work on the private snapshot afterwards.

The MicroPython interrupt-handler guidance describes short critical sections that stop an interrupt from changing shared data during access. It also warns that delaying interrupts can disrupt timely servicing of devices. Teaching examples sometimes print inside the protected region; in a product, keep slow output outside it and use a short, bounded copy or ownership transfer instead. "Protected" here means a mechanism verified for the actual writer and reader, not an instruction to disable every interrupt.

Check what can still change the data

Identify the writer precisely. Is it a hardware interrupt handler, a scheduled Python callback, a second processor core or a peripheral transferring data directly into memory? These are different situations, and a protection method chosen for one should not be assumed to stop the others.

An official MicroPython discussion opened September 3, 2023 shows the confusion. The author asked whether events were preserved while interrupts were disabled. A maintainer's September 13 explanation separated the hardware event, the low-level handler and the later Python callback, and explained why repeated events are not necessarily preserved as separate occurrences.

For the product, two promises need separate checks: that a record stays consistent, and that required events are not lost. A live display may only need the newest complete sample. A logger meant to retain every measurement needs sufficient buffering, an overflow policy and evidence that the writer cannot silently outrun the reader. Increasing a buffer without measuring the workload only postpones that question.

Make the failure visible before testing real measurements

Use a deliberately recognizable test pattern in software. For example, have the producer emit records whose second field is always ten times their sequence number. The consumer can then flag any pair that breaks that relationship. This is a proposed diagnostic, not a claim that a particular board has passed it.

Run the pattern while the display redraws, logging runs and other intended features are active:

Record the board, firmware version, event rate and enabled features with the result. A clean run supports the tested arrangement and conditions; it does not prove every timing combination is safe. Pair the test with a review of ownership and synchronization, especially if a later change adds a second core, a different callback mechanism or direct memory transfers.

What to ask for before the next user trial

You do not need to become an interrupt specialist to set a useful acceptance requirement. Ask for a clear definition of a complete record, an explanation of who may change it, and a test showing that the display and log use the same complete data. If the product intentionally skips intermediate readings, that should be stated, not mistaken for a fault or hidden as a success.

The result is a more meaningful demonstration: not just a screen that keeps updating, but a data path whose records have a defined meaning. That makes later comparisons, calibration work and user feedback easier to interpret.