

Rpi camera led
Interposer for the Raspberry Pi camera flex cable: passes the 15-way CSI bus straight through and adds I2C-controlled camera GPIO, PWM illumination LEDs and an ambient light sensor, driven by a CH32V003.
- Size
- 25 × 23.9 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 24
- Nets
- 22
- Pads
- 94
- Tracks, vias
- 37, 0
- Pours
- 2
- Routed
- Yes
- KiCad
- KiCad 9.0 (file 20241229)
- Created
- 3 Sep 2026
- Updated
- 5 Sep 2026
Overview
Rpi camera led is an open-source printed circuit board by mithro, from the mithro/rpi-camera-led repository on GitHub, published under the Apache-2.0 licence. It is a 2-layer board of 25 × 23.9 mm with 24 parts on 22 nets, routed with 37 tracks and 0 vias.
It is built around the CH32V003A4M6 and AO3400A. Its parts include 9 resistors, 4 connectors, 2 capacitors, 2 diodes and 2 transistors. It belongs with the RISC-V boards of this library.
Main components
2README
README.mdRPi Camera LED
An interposer for the Raspberry Pi camera flex cable (15 pin, 1.0 mm pitch FPC). It sits in the middle of the cable, passes all fifteen camera signals straight through, and adds a CH32V003A4M6 that gives the Pi I2C-controlled camera GPIO, PWM illumination LEDs and an ambient light reading.
Hardware
KiCad schematic · PDF · board
Board: 15-way FFC camera interposer
| 3D render, top | 3D render, bottom | Layout (copper, silk, outline) |
|---|---|---|
![]() | ![]() |
25.0 × 23.9 mm, two layers, everything on the front. J1 (left) faces the Raspberry Pi and J2 (right) faces the camera; they sit 180° apart so the two cable segments leave opposite edges and the board drops into an existing cable run in line. The MCU is the SOIC-16 in the middle, the two white illumination LEDs and the phototransistor are along the top edge.
The outline is the Camera Module 2 board: 25.000 × 23.862 mm with 2.0 mm corner
radii, and the same four Ø2.2 mm mounting holes, so the interposer takes the
camera's screws. Those come straight off the official mechanical drawing
(RP-008149-DS,
RPI-CAM-V2_1): "4x 2.2mm diameter holes", 2 mm in from each end of the 25 mm
axis — a 21.0 mm pitch — and 12.5 mm apart on the other. check_pcb.py now
verifies pitch and drill, because these went missing once already without
anyone noticing.
The layout is in progress. Eleven of the twenty footprints — C1, C2, J3, J4, Q1, R1–R4, R8 and R9 — are still parked outside the board outline, which is why they float around the board in the renders. The fifteen-way pass-through bus is routed; the rest is not. DRC reports 21 violations and 34 unconnected items.
Four of those violations are the mounting holes, and they are a real conflict rather than noise. All four holes land underneath a connector housing. On the camera the 21.0 mm pitch runs between two edges that carry nothing, and its single FFC connector sits on a third; this board has a connector on both ends of that axis, each housing 5.30 mm deep, so the holes — 2 mm in from each end — sit under them. Nothing on the board is wrong in isolation; the camera's mounting pattern and two edge-mounted connectors simply cannot both fit on a 25 mm span. Resolving it means giving something up: a longer board, connectors on the 25 mm edges instead, or mounting holes that no longer match the camera.
How the cables run
| With cables fitted | Isometric |
|---|---|
![]() | ![]() |
Both cables enter from the outside edges and run away from the board in opposite directions, so the interposer drops into an existing cable run in line. That follows from where the cable entry is on this connector: the manufacturer's Section A‑A shows the solder tail stepping down and out at one end while the cable channel opens at the other, and the top view labels Terminal at one end and Latch at the other with the 5.30 mm housing between them. It is also the only way a slide lock can work — you pull the slider, insert the cable and push it back, all at the same end. So the cable entry is at the latch end, away from the pads, and with each connector's housing flush against its board edge that entry points outward.
The two cable stubs are drawn different ways up, and that is the point. J1 is bottom contact, so its cable presents bared copper downwards and shows you the blue backing; J2 is top contact, so its cable is the other way up and shows you the conductors. That flip is the whole reason for pairing an F part with an E part, and it is what lets both segments be ordinary Raspberry Pi camera cables — the same flip you can see in a real cable, blue stiffener on one face at one end, bared conductors on the other face at the other.
The stubs are illustrative and are not part of the board: they exist only in a throwaway copy that the render script builds and deletes. Their 16.00 × 0.30 mm section is the drawing's recommended FFC dimension. The bared conductors and the backing are drawn a little longer than the 4 mm insertion depth so that a few millimetres of each stay visible outside the connector — otherwise the orientation they exist to show would be buried inside it.
Regenerate the images with uv run hardware/tools/render_board.py, and the
connector models with uv run hardware/tools/gen_connector_model.py. The
render script refills the copper zones first, via the pcbnew Python module
inside the KiCad snap, because kicad-cli has no zone-fill command and a
stale pour renders as authoritatively as a fresh one — when this was first
wired up the stored B.Cu pour was less than half its true area, and refilling
it dropped DRC from 116 violations to 17.
Connectors, and which cables fit
J1 and J2 are not the same part, and that is deliberate:
| part | contacts | mates with | |
|---|---|---|---|
| J1 → Raspberry Pi | JUSHUO AFA07-S15FCA-00 (LCSC C262721) | bottom — cable copper faces the board | a standard Pi camera cable |
| J2 → camera | JUSHUO AFA07-S15ECA-00 (LCSC C262742) | top — cable copper faces away | a standard Pi camera cable |
The reason is cable parity. A Raspberry Pi camera cable is an opposite-side FFC — "type 2", contacts on one face at one end and the other face at the other — because the Pi's CSI socket is top-contact and the camera module's is bottom-contact. Cutting one continuous cable anywhere yields one same-side half and one opposite-side half, so an interposer whose two connectors want the copper on the same face forces one odd, hard-to-buy cable. One that wants it on opposite faces absorbs the asymmetry, and both segments become ordinary Raspberry Pi camera cables. Bottom-contact at J1 plus top-contact at J2 is that pairing.
The two variants share one land pattern — verified against both JUSHUO drawings
— so nothing on the board moves between them. Since only the contact side
differs, and it is invisible on an assembled board, the distinction is called
out in each symbol's value, in the MPN, and as a BOTTOM CONTACT / TOP CONTACT marker on the fab layer.
Both footprints and their 3D models live in this repository, in
hardware/rpi-camera-led.pretty and hardware/rpi-camera-led.3dshapes. KiCad's
stock footprint references a STEP file for the JUSHUO AFA07 series that does not
exist — not in the KiCad distribution and not in kicad-packages3D upstream,
which ships no JUSHUO models at all. Third-party libraries have one, but under
terms that forbid redistribution, so hardware/tools/gen_connector_model.py
builds it from the manufacturer's published drawing instead: a 22.00 × 6.95 ×
2.50 mm envelope matching the drawing's DIM D, the F.Fab outline and the side
view's height, with the housing and latch coloured as the drawing's notes
specify. Both STEP and WRL are generated, the latter in the 0.1-inch units
KiCad expects.
The pass-through bus is wired J1 pin k ↔ J2 pin 16−k. That looks reversed
but is exactly right: the two connectors are 180° apart, so J1 pad k
physically faces J2 pad 16−k, and joining the pads that face each other is
both the straight route and the electrically transparent one — the board
behaves as a splice in the middle of one continuous cable.
check_pcb.py measures that facing alignment as a number, because losing it to
a stray drag puts a dogleg in all fifteen nets and is invisible by eye.
Verifying
uv run hardware/tools/check_schematic.py # ERC + netlist vs design intent
uv run hardware/tools/check_pcb.py # connector alignment + DRC paritycheck_schematic.py currently fails: its expected-netlist table still
describes the older pin-for-pin bus, and four issues from the last eeschema
session are open — U1 pin 13 is unconnected, SWIO and CAM_IO1 have been merged
onto one net, I2C is landed on pins that cannot carry it on this package (the
CH32V003 SOP-16 reaches the peripheral only on pins 1 and 2, since both AFIO
remaps need PD0 or PC5 and the package bonds out neither), and four no-connect
flags dangle.
The schematic is maintained by hand in eeschema — connections between adjacent
parts are drawn as wires rather than left implicit in matching global labels.
hardware/tools/gen_schematic.py is the generator that bootstrapped it, but
running it overwrites the schematic and would discard that manual wiring.
Firmware
CH32V003 firmware: a fail-safe I2C bootloader plus an
application exposing camera GPIO control, RPi-side GPIO readback, GPIO
pass-through, LED brightness (hardware PWM) and an ambient light reading over
a Linux-friendly SMBus register map at address 0x42. Builds with
riscv64-unknown-elf-gcc and ch32v003fun
(git submodule update --init, then make in firmware/bootloader and
firmware/app).
The firmware still targets the older pin map and needs updating to match the current schematic.
Research
Part availability research comparing JLCPCB's PCBA parts library and NextPCB's Rev0 service (which sources components from HQ Online's 600k+ in-stock inventory):
- I2C controllable RGB LEDs
- I2C GPIO expanders with LED driving capability
- Cheap (< $0.50) MCUs with I2C and no external parts required
- RPi camera compatible FPC connectors (1.0 mm pitch, 15 pin)
License
Apache 2.0 — see LICENSE.
Parts
24| Qty | Value | Footprint | References |
|---|---|---|---|
| 4 | MountingHole_2.2mm_M2 | MountingHole_2.2mm_M2 | H1, H2, H3, H4 |
| 2 | 0 | Resistor_SMD:R_0402_1005Metric | R6, R7 |
| 2 | 10R | Resistor_SMD:R_0603_1608Metric | R3, R4 |
| 2 | 4.7k | Resistor_SMD:R_0402_1005Metric | R1, R2 |
| 2 | White LED | LED_SMD:LED_0805_2012Metric | D1, D2 |
| 1 | 100R | Resistor_SMD:R_0402_1005Metric | R5 |
| 1 | 100nF | Capacitor_SMD:C_0402_1005Metric | C1 |
| 1 | 10k | Resistor_SMD:R_0402_1005Metric | R8 |
| 1 | 1uF | Capacitor_SMD:C_0402_1005Metric | C2 |
| 1 | 47k | Resistor_SMD:R_0402_1005Metric | R9 |
| 1 | AO3400A | Package_TO_SOT_SMD:SOT-23 | Q1 |
| 1 | CH32V003A4M6 | Package_SO:SOIC-16_3.9x9.9mm_P1.27mm | U1 |
| 1 | FFC 15P 1.0mm bottom contact (to Raspberry Pi) | rpi-camera-led:JUSHUO_AFA07-S15FCA-00_1x15-1MP_P1.0mm_Horizontal | J1 |
| 1 | FFC 15P 1.0mm top contact (to camera) | rpi-camera-led:JUSHUO_AFA07-S15ECA-00_1x15-1MP_P1.0mm_Horizontal | J2 |
| 1 | Phototransistor | LED_SMD:LED_0805_2012Metric | Q2 |
| 1 | Qwiic (JST SH 1.0mm) | Connector_JST:JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal | J3 |
| 1 | SWD program header 2.54mm | Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical | J4 |
Questions
How big is the Rpi camera led PCB?
It measures 25 × 23.9 mm and has 2 copper layers, 1.6 mm thick.
What parts does the Rpi camera led use?
24 parts, built around the CH32V003A4M6 and AO3400A. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
Where can I download the Rpi camera led KiCad files?
From the mithro/rpi-camera-led repository on GitHub, at the commit this page was made from: the board is hardware/rpi-camera-led.kicad_pcb and its schematic hardware/rpi-camera-led.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the Rpi camera led design in my own project?
Its repository publishes it under the Apache-2.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).
Similar boards
- 2 layers34.5 × 24 mm

- 2 layers43.9 × 54.1 mm

- 2 layers213.7 × 144.8 mm

UV Curing Box
koko69420/UV-Curing-Box
UV PCB resin curing box controller using WCH CH32V003 RISC-V MCU, 4x4 keypad, TM1637 display, and KiCad PCB
151 parts - 2 layers45 × 49.8 mm

CCCCPPPS MkI
BogdanTheGeek/CCCCPPPS
Cheap Crappy Constant Current Portable Programmable Power Supply
26 parts12MIT - 4 layers

SUNNY C1-HEAD
RSXLX/sunny-the-growing-sunflower-lamp
SUNNY — The Growing Sunflower Lamp | A personal lamp with customizable exteriors, traceable fabrication, and a local creative workspace.
55 parts - 2 layers48 × 36.5 mm

Osillyscope etchable
tvlad1234/osillyscope
Low cost, low part count CH32V003-based oscilloscope
31 parts30MIT - 2 layers24.1 × 21.6 mm

Ch32v003a4m6-breakout
mverdon/ch32v003a4m6-breakout
Breakout board for prototyping with the CH32V003 MCU
4 partsCERN-OHL-P-2.0 - 2 layers19 × 36.8 mm




