IO6: Buses and drivers: I2C, SPI, UART and reading a datasheet
Writing and testing a driver
🎯You'll be able to
Write a small driver that hides the bus details, retries glitches, gives up in time, reports clear errors, and can be tested without hardware.
🏠The everyday picture
A good receptionist handles callers: they redial a dropped line once or twice, take a message if nobody answers, and never leave a caller on hold for ever.
📘What it really is
-
One class per chip:
LV20Driver(i2c)withcheck(),read(board)andstandby(). The rest of the firmware doesn't touch registers. -
Retries: retry a failed transaction a few times (the kit uses 3), because buses glitch. Then raise a clear
SensorError. - Timeouts: wait for the ready bit with a limit (100 ms in the kit), sleeping briefly between checks.
- Read in one go: read related bytes in one transaction (DIST_L, DIST_H, TEMP), so they come from the same measurement.
- Clear errors: say what failed and where: address, register, value. Don't turn bus errors into silent zeros.
- Testable: pass the bus in, so tests can give a simulated one with faults (NACKs, a stuck sensor, the wrong chip).
- Leave it tidy: put the chip in standby when done, even after an error if you can.
📝A worked example
Input: the starter's read(), which writes CTRL and reads straight away, big-endian, unsigned.
Steps:
- Write CTRL = 0x01, sleep 30 ms, then poll STATUS every 5 ms until ready or 100 ms have passed.
- Read 3 bytes from 0x28; distance = raw[0] | raw[1] << 8; temperature = (raw[2] − 256 if raw[2] > 127 else raw[2]) / 2.
- Wrap each transaction in a 3-try retry that raises
SensorError.
Expected output: Project 1's tests 1 to 3 passing.
🌍Where it's used
- Open-source driver libraries for MicroPython, Arduino and Zephyr.
- Product firmware, where each part has a driver.
- Hardware bring-up, when a new board is first powered on.
📝Case scenario
A driver returned 0 whenever the bus failed. The dashboard showed an empty tank every time a cable was loose, and people rushed to check. Raising an error and reporting "sensor fault" instead of 0 ended the false alarms.
🖱️Try it
Write the three test cases you'd want for any I2C driver, beyond "it reads correctly". Success: a wrong chip, a bus that fails a few times then works, and a chip that never becomes ready.
⚠️Common mistakes
- Silent zeros on errors. Sign: false readings. Fix: raise a clear error.
- Infinite waits. Sign: hangs. Fix: timeouts.
- Reading related bytes separately. Sign: values from two different measurements. Fix: one transaction.
🛠️For your project
Project 1's tests 1 to 4 check your driver: chip check, timing and conversion, retries and standby.
✅Quick check
Why should a driver raise an error instead of returning 0 when the bus fails?
Show the answer
A 0 looks like a real reading and causes false alarms.
Why read DIST_L, DIST_H and TEMP in one transaction?
Show the answer
So all three come from the same measurement.
