The Founders and the Broadcom Legacy
If you are searching for who created the raspberry pi, the direct answer is a team of six Cambridge University researchers and industry veterans: Eben Upton, Rob Mullins, Jack Lang, Alan Mycroft, David Braben, and Pete Lomas. They formed the Raspberry Pi Foundation in 2009, officially launching the first $35 board in February 2012. Their goal was not to build a commercial empire, but to reverse a decline in applicants with foundational hardware and software skills applying to university computer science programs.
From an engineering perspective, the founders made a critical decision that defined the platform's DNA: partnering with Broadcom. While other educational boards relied on simple microcontrollers, Upton and Lomos leveraged Broadcom's mobile application processors (specifically the BCM2835) to deliver high-definition video and a full Linux stack at a rock-bottom price point. This decision locked the Raspberry Pi into Broadcom's proprietary VideoCore GPU and memory-mapped I/O (MMIO) architecture for over a decade.
However, if you are building embedded projects today, the architecture the founders originally championed has fundamentally changed. To understand how to debug modern Pi hardware, we have to look at how the silicon has evolved.
Silicon Evolution: From BCM2835 to the RP1 Southbridge
The most significant architectural shift in the platform's history occurred with the introduction of the Raspberry Pi 5. The founders' original vision relied entirely on Broadcom System-on-Chips (SoCs) where the CPU, GPU, and I/O controllers shared the same silicon die. The Pi 5 broke this mold by introducing the RP1, a custom-designed I/O southbridge chip built in-house by the Raspberry Pi team.
| Board Variant | Primary SoC / Southbridge | I/O Architecture | Linux GPIO Chip Enumeration | Max SPI/I2C Hardware Buses |
|---|---|---|---|---|
| Pi 1 Model B (2012) | Broadcom BCM2835 | Direct MMIO (ARM11) | /dev/gpiochip0 |
1x SPI, 1x I2C |
| Pi 3B+ (2018) | Broadcom BCM2837B0 | Direct MMIO (Cortex-A53) | /dev/gpiochip0 |
2x SPI, 1x I2C |
| Pi 4 Model B (2019) | Broadcom BCM2711 | Direct MMIO (Cortex-A72) | /dev/gpiochip0 |
6x SPI, 6x I2C (muxed) |
| Pi 5 (2023/2024) | BCM2712 + RP1 | PCIe-linked Southbridge | /dev/gpiochip4 |
4x SPI, 3x I2C (native RP1) |
Understanding this table is the difference between a project that boots and one that throws kernel panics. Notice the shift in the Linux GPIO chip enumeration. This single detail is the root cause of 90% of GPIO failures when developers port legacy code to modern hardware.
Project Build: RP1 GPIO Interrupt Debugger
To test the latency and pinmuxing of the modern RP1 architecture, we will build a hardware-in-the-loop interrupt debugger. This tool monitors a physical button press via a hardware interrupt and mirrors the state to an output pin, which you can verify with a logic analyzer or oscilloscope.
Parts List & Exact Variants
- Target Board: Raspberry Pi 5 (8GB) Rev 1.0 running Raspberry Pi OS (64-bit, Bookworm or later)
- Logic Analyzer: Saleae Logic Pro 8 (or any 24MHz 8-channel clone) for verifying interrupt latency
- Switch: Omron B3F-1000 tactile switch (rated for 10M cycles)
- Resistor: 10kΩ 1/4W carbon film (for external pull-up, though RP1 internal pull-ups are also configured in code)
- Wiring: 24 AWG silicone jumper wires
Pin Mapping Table
| Function | BCM GPIO Number | Physical Pin (40-Pin Header) | RP1 Pad Configuration |
|---|---|---|---|
| Interrupt Input | GPIO 17 | Pin 11 | Pull-up enabled, Schmitt trigger on |
| Mirror Output | GPIO 27 | Pin 13 | Push-pull, 8mA drive strength |
| Ground | GND | Pin 9 | N/A |
Compilable Python Code (Target: Pi 5)
The legacy RPi.GPIO library is deprecated and does not support the Pi 5's RP1 southbridge. For modern embedded Python development, we use lgpio, the official C-based GPIO library maintained by the Foundation. Install it via sudo apt install python3-lgpio.
import lgpio
import time
import sys
import signal
# TARGET BOARD: Raspberry Pi 5 (8GB)
# The RP1 southbridge enumerates as gpiochip4 on the Pi 5.
# (If porting to Pi 4, change this to 0).
CHIP_NUM = 4
IN_PIN = 17
OUT_PIN = 27
# Global handle for cleanup
h = None
def interrupt_callback(chip, gpio, level, flags):
"""Triggered on both rising and falling edges."""
print(f"[INT] GPIO {gpio} changed to Level {level}")
# Mirror the input state to the output pin
lgpio.gpio_write(chip, OUT_PIN, level)
def graceful_exit(sig, frame):
"""Clean up GPIO states on Ctrl+C."""
print("\nShutting down and releasing GPIO lines...")
if h is not None:
lgpio.gpio_write(h, OUT_PIN, 0)
lgpio.gpiochip_close(h)
sys.exit(0)
signal.signal(signal.SIGINT, graceful_exit)
def main():
global h
try:
# Open the specific gpiochip for the Pi 5 RP1
h = lgpio.gpiochip_open(CHIP_NUM)
except lgpio.error as e:
print(f"FATAL: Failed to open gpiochip{CHIP_NUM}. Error: {e}")
sys.exit(1)
except PermissionError as e:
print(f"FATAL: {e}. Ensure your user is in the 'gpio' group.")
sys.exit(1)
try:
# Claim the input line with a pull-up resistor and noise filtering
lgpio.gpio_claim_input(h, IN_PIN, lgpio.SET_PULL_UP)
# Claim the output line
lgpio.gpio_claim_output(h, OUT_PIN, 0)
# Attach the interrupt callback (BOTH_EDGES)
cb = lgpio.gpio_callback(h, IN_PIN, interrupt_callback)
print(f"Debugger active. Monitoring GPIO {IN_PIN} on gpiochip{CHIP_NUM}.")
print("Press Ctrl+C to exit.")
# Keep the main thread alive
while True:
time.sleep(1)
except Exception as e:
print(f"Runtime Error: {e}")
finally:
lgpio.gpiochip_close(h)
if __name__ == "__main__":
main()
Debugging: When the GPIO Fails to Trigger
When migrating embedded projects to the Pi 5, developers inevitably hit a wall. If your script crashes or fails to register button presses, do not assume the hardware is defective. Follow this decision path.
Exact Error: PermissionError: [Errno 13] Permission denied: '/dev/gpiochip4'
The Cause: Modern Raspberry Pi OS uses udev rules to manage hardware permissions. By default, the root user owns the GPIO character devices. If you are running your script as a standard user (e.g., pi), the kernel will block access to the RP1 southbridge.
The Fix: Add your user to the gpio and dialout groups, then reboot to apply the udev rules.
sudo usermod -aG gpio,dialout $USER
Exact Error: lgpio.error: 'gpiochip_open' failed
The Cause: You are trying to open gpiochip0 on a Pi 5, or gpiochip4 on a Pi 4. As shown in Table 1, the RP1 southbridge shifts the enumeration index.
- Verify the Chip Offset: Run
ls /dev/gpiochip*in the terminal. On a Pi 5, you will see/dev/gpiochip4(the RP1) and/dev/gpiochip0(the main BCM2712 power management pins). You must target chip 4 for header pins. - Check for Pinmux Conflicts: If GPIO 17 isn't triggering, ensure it hasn't been claimed by a Device Tree overlay. Run
sudo raspi-configand verify that Serial Port and I2C interfaces are disabled if you are using their default pins. - Measure the Physical Pull-Up: The RP1's internal pull-ups are roughly 50kΩ. In high-noise environments (like near switching power supplies), this is too weak. Use a multimeter to verify your external 10kΩ resistor is pulling the line to a solid 3.3V.
For deeper architectural documentation on the RP1's register maps and interrupt routing, refer to the official Raspberry Pi RP1 Peripherals Datasheet. Understanding the silicon is just as important as knowing who created the Raspberry Pi and why they designed it this way.
Extending and Simplifying the Build
Not every project requires hardware interrupts, and sometimes the 27 available GPIO lines on the RP1 header aren't enough. Here is how to adapt this debugger to your specific constraints.
How to Extend: Bypassing the RP1 Pin Limit
If you need to monitor 16+ interrupt sources, do not try to wire them all to the Pi's native header. The RP1's interrupt routing can become saturated, leading to microsecond-level latency jitter.
The Solution: Add an MCP23017 I2C Port Expander. Wire the MCP23017's INTA pin to Pi GPIO 17. The MCP23017 will handle the hardware debouncing and edge-detection for 16 external pins, and only trigger the Pi's RP1 interrupt when a specific register changes. You can read the state via I2C inside the Python callback. This offloads the polling overhead from the main BCM2712 CPU to the dedicated I/O expander.
How to Simplify: Dropping Interrupts for Polling
If you are building a simple UI button or a slow-moving limit switch, hardware interrupts introduce unnecessary complexity regarding thread safety and debounce logic.
The Solution: Strip out the lgpio.gpio_callback function entirely. Replace the while True: time.sleep(1) loop with a polling loop:
state = lgpio.gpio_read(h, IN_PIN)
Run this inside a loop with a time.sleep(0.02) delay (50Hz polling). This acts as a natural software debounce filter, ignoring any contact bounce shorter than 20ms, and eliminates the need for complex callback error handling. It uses marginally more CPU, but on a Cortex-A76, a 50Hz polling loop consumes less than 0.01% of a single core.
By understanding the hardware lineage—from the founders' original BCM2835 vision to today's PCIe-linked RP1 southbridge—you can write embedded code that is resilient, performant, and aligned with the actual silicon on your workbench.






