Who Invented Raspberry Pi? The Cambridge Origins
The Raspberry Pi was invented by a team of computer scientists and engineers at the University of Cambridge, primarily led by Eben Upton, alongside Rob Mullins, Jack Lang, Alan Mycroft, David Braben, and Pete Lomos. The concept began taking shape around 2006 when Upton, then an admissions director at Cambridge, noticed a steep decline in the programming skills of computer science applicants. Students were arriving with experience in high-level web design, but lacked the low-level hardware hacking and systems programming knowledge that previous generations gained from tinkering with machines like the BBC Micro or Amiga.
To solve this, the team set out to build a bare-bones, highly accessible computer that cost no more than $25. Pete Lomos led the hardware design, eventually settling on a Broadcom system-on-chip (SoC) because Upton was working as an ASIC architect at Broadcom at the time. Jack Lang, a successful entrepreneur and Cambridge alumni, provided crucial early seed funding. The Raspberry Pi Foundation was officially registered as a charity in 2009, and the first Raspberry Pi Model B shipped in February 2012. For a deeper look at the foundation's charitable mandate, you can review the historical timeline of the Raspberry Pi and its educational impact.
Today, the original $35 mandate has evolved into a massive ecosystem. While the flagship models now push desktop-replacement performance, the foundational ethos of cheap, accessible GPIO hardware lives on in the Pi Zero and Pico lines. To honor that original hardware-hacking spirit, we are going to build, wire, and debug a modern embedded sensor node.
The 2026 Pi Selection Decision Tree
Before wiring any sensors, you must select the right board. The Pi ecosystem has fractured into distinct use cases. Use this decision matrix to pick your hardware, terminating in our default recommendation for embedded IoT projects.
| Use Case | Power Budget | Recommended Board (2026) | Approx. Price |
|---|---|---|---|
| Desktop / Edge AI / Computer Vision | 15W - 25W | Raspberry Pi 5 (8GB) | $80 |
| Headless IoT / Remote Sensor Node | < 2W (Idle) | Raspberry Pi Zero 2 W | $15 |
| Bare-metal RTOS / Ultra-low power | < 1W | Raspberry Pi Pico W | $6 |
Project Build: I2C BME280 Environmental Logger
We will build a headless environmental logger using the Pi Zero 2 W and a Bosch BME280 sensor. This project targets the exact hardware constraints Eben Upton's original team envisioned: low cost, standard protocols, and real-world physical computing.
Difficulty & Time Rating
- Difficulty: 2/5 (Intermediate - requires basic Linux CLI and I2C concepts)
- Time to Complete: 45 minutes
Parts List
- Microcontroller: Raspberry Pi Zero 2 W (with pre-soldered GPIO header)
- Sensor: Adafruit BME280 I2C/SPI Breakout (Product ID: 2652)
- Wiring: 4-pin female-to-female Dupont jumper wires (22 AWG silicone)
- Storage: 16GB SanDisk High Endurance MicroSD card (for continuous logging)
- Power: 5V 2.5A USB-C power supply or a 3.7V LiPo with a Pi Sugar UPS HAT
Pin Mapping Table
The BME280 uses the I2C bus. On the Raspberry Pi, the primary hardware I2C bus (I2C1) is mapped to specific GPIO pins. Do not use software I2C unless absolutely necessary, as it causes CPU spikes and timing errors.
| Pi Zero 2 W Pin (Physical) | GPIO / Function | BME280 Breakout Pin | Wire Color |
|---|---|---|---|
| Pin 1 | 3.3V Power | VIN (or 3Vo) | Red |
| Pin 6 | Ground | GND | Black |
| Pin 3 | GPIO 2 (SDA1) | SDA | Yellow |
| Pin 5 | GPIO 3 (SCL1) | SCL | Blue |
Hardware Note: The Adafruit 2652 breakout includes onboard 10kΩ pull-up resistors on the SDA and SCL lines. If you use a cheaper, bare-bones BME280 module from an online marketplace, you may need to add external 4.7kΩ pull-up resistors between the SDA/SCL lines and 3.3V to prevent signal degradation.
Python Code with Hardware Error Handling
This code targets the Raspberry Pi Zero 2 W running Raspberry Pi OS (Bookworm or later). We use the Adafruit Blinka/CircuitPython libraries, which provide robust hardware abstraction and explicit error handling for I2C bus lockups.
First, install the dependencies via your terminal:
sudo apt update
sudo apt install python3-pip python3-venv
python3 -m venv env
source env/bin/activate
pip3 install adafruit-blinka adafruit-circuitpython-bme280
Create a file named logger.py and paste the following complete, compilable code:
import time
import board
import busio
import adafruit_bme280
import csv
from datetime import datetime
# --- PIN DEFINITIONS & BUS INITIALIZATION ---
# Explicitly define the hardware I2C pins for the Pi Zero 2 W
SCL_PIN = board.SCL # Physical Pin 5 (GPIO 3)
SDA_PIN = board.SDA # Physical Pin 3 (GPIO 2)
# Initialize the I2C bus with a conservative 100kHz frequency
# to prevent timing issues on longer wire runs.
i2c = busio.I2C(SCL_PIN, SDA_PIN, frequency=100000)
def init_sensor():
"""Initialize BME280 with hardware error handling."""
try:
# Default I2C address for Adafruit BME280 is 0x77
sensor = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x77)
# Set oversampling to reduce noise
sensor.oversampling_temperature = 2
sensor.oversampling_pressure = 2
sensor.oversampling_humidity = 2
return sensor
except ValueError as e:
print(f"[FATAL] I2C Bus Lock or Init Error: {e}")
print("Check if I2C is enabled in raspi-config.")
raise SystemExit(1)
except Exception as e:
print(f"[FATAL] Unexpected hardware fault: {e}")
raise SystemExit(1)
def log_data(sensor):
"""Read sensor and append to CSV."""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
temp_c = sensor.temperature
humidity = sensor.relative_humidity
pressure_hpa = sensor.pressure
print(f"{timestamp} | {temp_c:.1f}C | {humidity:.1f}% | {pressure_hpa:.1f}hPa")
with open("environment_log.csv", "a", newline="") as file:
writer = csv.writer(file)
writer.writerow([timestamp, temp_c, humidity, pressure_hpa])
if __name__ == "__main__":
bme_sensor = init_sensor()
print("Starting environmental logger. Press Ctrl+C to stop.")
try:
while True:
try:
log_data(bme_sensor)
except OSError as e:
# Catches transient I2C bus errors without crashing the loop
print(f"[WARN] Transient I2C read error: {e}. Retrying in 10s.")
time.sleep(60) # Log every 60 seconds
except KeyboardInterrupt:
print("\nLogger stopped by user.")
Debugging: 'Remote I/O Error' and Boot Failures
When working with I2C on the Pi, the most notorious failure mode is the OSError: [Errno 121] Remote I/O error. At the silicon level, this means the Pi (master) sent a clock pulse and an address, but the BME280 (slave) never pulled the SDA line low to send an ACKnowledge (ACK) bit. The Linux kernel interprets this missing ACK as a remote I/O failure.
The First Three Things to Check When It Fails
- Verify I2C is enabled at the OS level: Run
sudo raspi-config, navigate to Interface Options > I2C, and enable it. Alternatively, check/boot/firmware/config.txt(or/boot/config.txton older OS versions) and ensure the linedtparam=i2c_arm=onis present and uncommented. Reboot after changing. - Scan the bus for the device address: Run
sudo i2cdetect -y 1. You should see77in the grid. If the grid is entirely empty, your wiring is wrong or the sensor is dead. If you see76instead of77, your specific breakout board has the address pad bridged; update the Python code toaddress=0x76. - Test physical continuity: Power down the Pi. Use a multimeter in continuity mode to probe from the Pi's physical Pin 3 to the BME280 SDA pad, and Pin 5 to the SCL pad. Dupont wires frequently have internal crimp failures that look perfect from the outside.
If
i2cdetect shows an address, but your Python script still throws [Errno 121], you likely have a power brownout. The Pi Zero 2 W can experience micro-second voltage dips on the 3.3V rail when the WiFi radio transmits, causing the BME280 to reset and drop off the bus mid-transaction. Power the Pi with a high-quality 5V/2.5A supply, or add a 100µF electrolytic capacitor across the 3.3V and GND pins on the GPIO header to smooth the rail.
Ranked Causes for Errno 121
- Cause 1 (60%): Loose Dupont wire or cold solder joint on the SDA/SCL header.
- Cause 2 (25%): I2C interface disabled in
config.txtorraspi-config. - Cause 3 (10%): Incorrect I2C address hardcoded in Python (using 0x77 when the board is strapped to 0x76).
- Cause 4 (5%): Missing pull-up resistors on cheap clone sensors, causing signal rise times to fail the I2C spec at 400kHz. (Fixed by dropping bus frequency to 100kHz in the code above).
Extending and Simplifying the Build
Depending on your deployment environment, you may need to alter the hardware footprint of this project.
How to Simplify (Drop the OS Overhead)
If you do not need a full Linux environment, local TLS encryption, or complex networking, drop the Raspberry Pi Zero 2 W and switch to the Raspberry Pi Pico W. The Pico W runs MicroPython on a bare-metal RTOS. It boots in milliseconds, draws microamps in deep sleep, and eliminates the SD card corruption risks associated with sudden power loss on Linux-based Pis. You will need to rewrite the code using the machine.I2C MicroPython module, but the physical wiring remains identical.
How to Extend (Off-Grid LoRaWAN Integration)
To push this from a local desk logger to a remote agricultural or industrial monitor, add a Dragino LoRa/GPS HAT or wire an RFM95W LoRa transceiver to the Pi Zero 2 W's SPI bus (GPIO 10/MOSI, 9/MISO, 11/SCK, plus a CE0 chip select pin). By integrating the sx127x Python library, you can transmit the BME280 CSV payloads over LoRaWAN to a The Things Network (TTN) gateway up to 15km away, completely bypassing the need for local WiFi infrastructure. Ensure you upgrade your power system to a 12V lead-acid or LiFePO4 battery paired with a solar charge controller, as the LoRa transmit spikes can draw up to 120mA momentarily.
For official pinout diagrams and advanced peripheral configurations, always cross-reference the Raspberry Pi hardware configuration documentation before committing to a custom PCB layout.






