Skip to the content
PCBKitNew board
4 layers164.9 × 102 mmCarrier, the printed circuit board in 3D

One board that turns the Pi 4 + 7" screen into a complete car radio replacement. It bolts onto the Pi like a HAT, plugs into the truck's radio harness, and does everything the factory radio did plus what the Pi needs:

Size
164.9 × 102 mm
Copper layers
4
Thickness
1.6 mm
Parts
171
Nets
117
Pads
583
Tracks, vias
1,630, 319
Pours
31
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
20 Jul 2026
Updated
29 Oct 2026

Overview

Carrier is an open-source printed circuit board by AJXD2, from the AJXD2/carplay-project repository on GitHub. It is a 4-layer board of 164.9 × 102 mm with 171 parts on 117 nets, routed with 1,630 tracks and 319 vias.

It is built around the ADS1115IDGSR, LM61460AFSQRJRRQ1 and PCM1808QPWRQ1, with the TAS6424EQDKQRQ1, CAT24C32WI-GT3 and DS3231SN#T&R among its other parts. Its parts include 75 capacitors, 46 resistors, 10 diodes, 9 inductors and 8 ICs.

Main components

12

README

hardware/carrier/README.md

Carrier board (2007 4Runner head unit)

One board that turns the Pi 4 + 7" screen into a complete car radio replacement. It bolts onto the Pi like a HAT, plugs into the truck's radio harness, and does everything the factory radio did plus what the Pi needs:

  • survives car power (reverse battery, load dump, cranking) and switches itself fully off with the key (a few µA left on the battery)
  • powers the Pi, the screen and the fans (5 V, 6 A)
  • drives the four stock speakers from the Pi's digital audio (no USB DAC, no ground-loop hum)
  • reads the steering-wheel buttons (learn mode, any wheel)
  • senses key, headlights (night mode) and reverse
  • keeps the clock running with the power off
  • runs two fans, and tells the Pi what it is at boot (HAT ID EEPROM)

Software for it lives in launcher/board/.

Status

StageState
SchematicDone. ERC 0 errors / 0 warnings.
Parts list (BOM)Done. 148 fitted parts, every one with an LCSC number, stock checked at JLCPCB.
PlacementDone for the nominal Pi position. DRC: no overlaps or clearance errors.
RoutingDone. 0 unrouted, 0 DRC errors, schematic parity 0.
Silkscreen tidyDone (10 cosmetic silkscreen warnings left).
Pi position on the screenMeasured on the real screen and confirmed with a printed fit test (see Mechanical).
SoftwareInstalled and running in the truck (launcher/board/install.sh, carrierd); 21 tests on simulated hardware.
Simulation + assembly checkDone 2026-09-29: SPICE on every analog block, pinouts and land patterns against datasheets, placement file against JLC's footprints (VERIFICATION.md).
HousingDesigned (tools/housing.py): PETG shell + fan lid, clearance-checked against the board, Pi and screen, and checked that each part can go in. First shell printed as a dash and screen fit test; its lid screw blocks stopped the board going in, now moved. Shell and lid to be reprinted.
OrderingRev A built (2 boards). Board 2 in the truck since 2026-10-28; board 1 has dead audio clocks (X1 or U8 joint, to rework). Bring-up log and in-truck results: BRINGUP.md.

How it works, block by block

The schematic (carrier.kicad_sch, one A2 sheet, PDF in out/carrier.pdf) is split into boxed sections. The same section names tag every part (hidden Section field) so the board layout can find each block.

SectionPartsWhat it does
HarnessJ1, Molex Micro-Fit 3.0 2x10 verticalTruck wiring in; plug faces the firewall
Input protectionLM74800-Q1 + 2x BUK7Y4R8-60E + SMBJ33CAReverse-battery block, cuts off above 34.3 V (32.6-36.0 V worst case; load dump), slow soft start (~2.5 V/ms). Its enable (SYS_EN) is the board's master switch
5 V buckLM61460-Q1, 4.7 µH5 V / 6 A at 400 kHz for Pi, screen (through GPIO pins 2/4 and the display's pogo pins), fans. Turns on at 6.0 V, off at 4.3 V, so it rides through cranking
3.3 VTLV75533Amp logic, ADC, RTC, EEPROM, clocks
Power hold + sensingdiodes, RC, 3x MMBT3904SYS_EN = key OR the Pi's hold line. Key/lights/reverse become active-low 3.3 V inputs
AmplifierTAS6424E-Q14 x BTL, about 25 W/ch into 4 Ω at 14.4 V, 2.1 MHz switching, I2C controlled (0x6A)
Output filters8x 3.3 µH + 1 µF + 1 nFReconstruction filter per speaker leg (TI reference values)
Audio clocks12.288 MHz oscillator + PCM1808-Q1The board is the audio clock master (see decisions)
Mic input3.5 mm jack J4 (PJ-320D) into the PCM1808Electret car mic for calls and Siri: bias from 3.3 V, ESD and RF filtering at the jack, the PCM1808's ADC sends it to the Pi on GPIO20. Mic on the tip; ring and sleeve grounded
Status LEDs3 red 0603 (D8-D10), tagged 12V / 5V / PIWhich power stage is alive: protected 12 V, the 5 V rail, and the Pi holding the board on
Steering wheel + battery ADCADS1115 (0x48)Two ladder inputs (1k pull-ups, ESD, RC filter), battery voltage on AIN2
RTC + ID EEPROMDS3231SN + CR2032 (0x68), CAT24C32 (0x50)Clock through power-off; HAT ID per the Raspberry Pi HAT design guide
PiJ2, 2x20 socket on the undersideMates with the Pi's header
Fans2x 4-pin headers, 2N7002 eachPWM from the Pi, inverted by the FET; tach readback
Debug + mountingUART header (not fitted), H1-H6Pi holes isolated per HAT spec; H5/H6 are grounded M3 holes beside the amp (heatsink strap or ground wire)

Design decisions and why

  • Class-D amp fed digitally (I2S). The old setup went through a USB sound card; digital audio straight to the amp removes that and the ground-loop path. The TAS6424E-Q1 is automotive (AEC-Q100), survives 40 V load dump, and was the only in-stock 4-channel part with digital input at JLCPCB.
  • The board is the audio clock master. The Pi's PCM block carries only two channels, and the TAS6424 needs a real master clock (128-512 x the sample rate) outside TDM mode. So a 12.288 MHz oscillator drives the amp's MCLK directly and a PCM1808-Q1 in master mode (MD1 = MD0 = high, strapped, no software) divides it to the bit clock (64 fs) and frame clock (48 kHz). All three come from one crystal and cannot drift apart. The Pi runs its I2S port as a clock consumer. Consequences: audio is fixed at 48 kHz (PulseAudio resamples), and the rear speakers play the same stereo as the front (SDIN1 and SDIN2 share the data); the fader and balance use the amp's per-channel volume. The CS2100 clock chip originally planned was dropped: JLC only stocks the -10 to 70 °C grade.
  • One master switch. The LM74800's enable turns the whole board off. SYS_EN is the OR of the key (with a 4.7-10 s RC grace period so a crank before the Pi boots does not cut power, even when the key goes straight to START) and the Pi's own hold line (GPIO26). The Pi decides when to power off: key off for 8 s, then it shuts down cleanly, drops the hold line, and the board switches off 3-5 s later (3 uA standby after 7-12 s). A hung Pi is reset by its watchdog, which also drops the hold line. Times are from tools/sim.py over part tolerances.
  • Steering wheel by learn mode. Toyota wheels are resistor ladders on two wires. Instead of hard-coding resistor values, the software asks for each button once and remembers what it reads. It refuses two buttons it cannot tell apart.
  • Harness as one latching plug. Every truck wire ends in one Micro-Fit plug (like a PC's ATX connector) that clicks into the board. 8.5 A per contact; 12 V and ground use several pins each.
  • Heatsink copied from TI's evaluation board. The amp's thermal pad is on top of the chip. TI's EVM uses a custom 20 x 41.4 mm finned heatsink screwed down with M3 screws and Arctic Silver paste; ours is the same footprint with fins sized for CNC machining (tools/heatsink.py). Its feet sit on grounded pads, which grounds the heatsink as TI requires. Rev A skips the CNC part on cost and uses a stock 20 x 20 x 10 mm heatsink instead; see "Amp heatsink" under the shopping list for what that needs.
  • Part choices for car conditions. Every IC is rated to at least 85 °C. Caps upstream of the 35 V cutoff are 100 V (the TVS can clamp to 53 V), the rest of the 12 V side is 50 V X7R. Speaker-filter 1 nF caps are C0G. Boot caps are 0603 (fit the amp's 0.635 mm pin pitch; datasheet asks for X7R ≥ 16 V, these are 50 V).
  • Fans fail safe. The PWM FET's gate pull-down leaves the fans at full speed whenever the Pi is not driving them.

Full calculations (divider values, time constants, cut-off voltages) are written as notes on the schematic next to each circuit.

Mechanical

Display: Hosyond 7" DSI, 164.9 x 102.0 mm, 12.25 mm thick per the manufacturer's drawing (datasheets/hosyond/). The board uses the same outline. Its own four mounting holes sit 5 mm in from each corner (154.89 x 91.92 mm apart), each with a 4 mm threaded M2.5 pillar: the housing screws onto those before the Pi and board go on (the board sits 12.6 mm above the pillar tops, clear of the screw heads).

Where the Pi sits on the screen. First estimated from Hosyond's product photo (the Pi's 58 x 49 mm hole pattern set the scale), then measured on the real screen on 2026-09-24 with a printed fit plate and calipers, Pi board edge to screen edge:

Pi edgeTo the screen edge
Ports side (USB/Ethernet)36.65 mm
Display ribbon side43.40 mm
GPIO side15.35 mm
USB-C / HDMI side31.45 mm

The sums (165.05 x 102.80, all values rounded down) match the 165 x 103 screen. Left/right differed from the photo estimate by 1.35 mm, up/down by under 0.2 mm. The plate's screw holes, header window and port notch all lined up.

Viewed from the back, from the display's top-left cornermm
Upper Pi holesx 60.15 and 118.15, y 35.1
Lower Pi holesx 60.15 and 118.15, y 84.1
Pi outlinex 36.65 to 121.65, y 31.6 to 87.6
Orientationrotated 180°: GPIO header at the bottom, USB/Ethernet toward the right of the screen as seen from the front

The manufacturer's drawing then confirmed the Pi holes at 60.36 / 118.36 mm from the screen's left edge and 35.19 / 84.19 mm from its top (within 0.2 mm of the measurements), and set the final outline.

How the correction is applied: the board is referenced to the Pi, so the Pi, every part, the notch and the cable slot stay where they are and only the outer outline moves (OUTLINE_SHIFT in tools/place.py). All copper was routed at least 3 mm from the outer edges for exactly this; with the final outline the edge margin is 2.5 mm.

Board shape. The Pi is mid-screen, so its USB/Ethernet block (13.5 mm tall Ethernet jack, board sits 11 mm above the Pi) is ~30 mm in from the display's edge. The board has a notch from the port block to the left edge (back view): the jacks clear it and cables can reach them. A slot next to the Pi's DSI connector clears the display ribbon (HAT spec position).

Stack-up (from the screen's glass, toward the firewall):

Layerz (mm)Source
Display module0 to 8.25Hosyond drawing
Its rear parts and pillars (corner and Pi)8.25 to 12.25Hosyond drawing (12.25 total); check with calipers
Pi 4 board12.25 to 13.85Pi spec
Header base + socket13.85 to 26.852.5 + 8.5 mm, HAT standard (11 mm M2.5 standoffs), plus a 1 mm nylon spacer on the Pi (the stack was loose without it) and a 1 mm nylon washer under the carrier ("Pi standoffs" below); the header pins go 4 mm into the socket instead of 6
Carrier board26.85 to 28.451.6 mm
Tallest parts on itto ~41470 µF cap 12.5 mm, harness plug + mated housing
Amp heatsinkto 41.020 x 20 x 10 mm stock heatsink on the 2.33 mm chip + tape
Fans (in the housing lid)44 to 54Noctua NF-A4x10, 3 mm above the heatsink
Housing lid54 to 56.4tools/housing.py

Board stack 165 x 103 x ~41 mm; in its housing 176.7 x 106.2 x 56.4 mm, sized to slide through the Metra 95-8210 dash kit's double DIN opening. The heatsink, the 470 µF cap and the harness plug all end at about the same height. (The CNC heatsink in mech/ is cut to the same 10 mm height, so it fits without moving the lid.)

Fit test before ordering: tools/fit_plate.py writes mech/fit_plate.stl, a 1.6 mm plate with the board's exact outline, notch, cable slot, Pi and heatsink holes and a window for the Pi header. Print it text side up, mount it on the Pi with the 11 mm standoffs, and check the edges against the screen and the holes against the standoffs.

Housing. tools/housing.py builds a two-part PETG housing from the same numbers as the board (place.py, part positions read from carrier.kicad_pcb) and checks it against the board, Pi, heatsink and screen where they sit, and along the way in: the screen from the front, the Pi and the board straight in from the open back, and a screwdriver down onto each pillar screw. It also checks the shell and lid against the Metra 95-8210 trim panel's opening (about 177.8 x 108.0 mm, ruler-measured; KIT_OPENING) with 0.5 mm to spare on each side (exit 1 on any clash, blocked path or misfit):

  • Shell (mech/housing_shell.stl): walls 0.5 mm outside the screen outline, with a skirt down flush with the glass front: 2.4 mm at the sides, 1.6 mm top and bottom (the screen is 102.0 mm tall against the kit's ~108 mm opening). The right wall (driver side, seen from the back) is 6.0 mm thicker, taking the kit opening's spare width. Corner tabs sit on the screen's four pillars (2.9 mm holes, M2.5 x 6 screws). A ledge under the board's top edge either side of J1 (x 90 to 145, stopping 1 mm short of J1's pins) takes the push when the harness goes in: open item 5. Vent slots below the board (Pi level) and above it, an opening in the left wall for the USB cables (CarPlay dongle), and a hole in the right wall for the mic plug (12 mm counterbore through the thick wall). Four M3 heat-set inserts hold the lid, all outside the board's path in (it has only 0.5 mm to the walls): two go straight down into the top of the thick right wall (y 20 and 82), two sit in 7 x 7 x 8 mm blocks on the left wall inside the Pi's port notch (y 35 and 84), where the board has no edge. All four are kept off the corners so a screwdriver reaches the pillar screws. The kit's own side brackets hold the housing in the dash: three more M3 heat-set inserts, pressed in from outside at the old bracket pads' positions (y 25 and 77, 34 mm from the glass). Two go into the thick right wall; on the left only the lower one, in a block inside the port notch (the upper one would sit in the board's way in). The mic plug's hole may sit behind the kit's right bracket: cut the bracket if so.
  • Lid (mech/housing_lid.stl): both fans hang under it, blowing in. Fan 1 sits over the amp heatsink (the airflow the stock heatsink needs); fan 2 sits over the Pi's port notch, so its air goes down past the jacks, under the board across the Pi, and out of the low vents. Grilles over both, an opening the harness plug passes through (and its latch can be pressed through), and two ribs either side of J1 that stop 0.2 mm above the board so pulling the plug can't lift it. A lip locates it inside the shell.
  • Fit ring (mech/housing_fit_ring.stl): the bottom 17 mm of the shell, about a fifth of the plastic. Print it first and check the skirt fit and the four pillar screws.

Exhaust (slots + USB opening) is 2.0x the open area of the two fan grilles.

Print in PETG, 0.16 mm layers, 6 walls (every wall comes out solid), 30% gyroid, textured PEI: the shell on its front rim (screen side down, 5 mm outer brim), the lid on its outer face. The lid needs no supports. The shell needs them only under the four corner tabs: each is a 10 mm corner overhang held by two walls, and its underside is the face that sits on the pillar. Paint support enforcers on those four undersides (tree); auto supports miss some of them. With an AMS, use PLA for the support interface and accept Bambu Studio's suggested settings (0 mm top Z distance, interlaced rectilinear): PLA does not bond to PETG, so the tab undersides come out flat. PETG-only supports need 0.2 mm top Z distance instead. The STEP files are in the assembly frame, for importing into other CAD.

Onshape: the same parts are rebuilt feature by feature in the private document "CarPlay Head Unit Housing" (https://cad.onshape.com/documents/92519b2e7fb9667b3fe711ef), with a fan part, a reference part studio (screen, pillars, Pi, HAT standoffs, board with its notch and slot, heatsink, J1) and a "Head unit assembly" fastening it all together. It is behind housing.py now: no thick right wall, no mic counterbore, and the old lid screw blocks. Those features sit at fixed coordinates and are not linked to each other, so housing.py stays the master: change sizes there, check them with its clearance check, then redo the affected features in Onshape.

Hardware: 4x M2.5 x 6 (shell to pillars), 4x M3 x 5.7 heat-set inserts + 4x M3 x 8 countersunk (lid), 3x M3 x 5.7 heat-set inserts + M3 screws (kit brackets), the screws in the Noctua box through the lid into the fans (or M3 x 16 + nuts).

Assembly: press the four lid inserts in from the back (about 240 °C for PETG), screw the shell to the screen, fit the Pi, then drop the board straight in from the back onto its standoffs (its top edge rests on the ledge), plug the fans into the board, and close the lid. Gap check on the bench: the board should sit on the ledge with no rocking and the ribs just touching it.

PETG starts to soften around 75 to 80 °C. If it sags in a summer dash, reprint the same files in ASA.

3D model: tools/assembly.py builds display + Pi 4 + board + stock heatsink + housing + fans (mech/assembly.step, mech/assembly.stl; generated, not committed). Review images: out/3d/*.png via tools/render3d.py; housing_cut_j1.png and housing_cut_fan1.png are sections through the J1 clamp and through fan 1 and the heatsink.

Wiring the truck

The truck has three plugs behind the radio: a 10-pin (power, front speakers, illumination) and a 6-pin (rear speakers), both yellowish, plus a white 20-pin that carries the steering-wheel wires. The Klintotour Toyota adapter mates with all three; nothing on the truck gets cut. Cut the 16-pin Android plug off the adapter's far end and crimp its wires into the Micro-Fit plug (diagram: tools/harness_diagram.py, writes out/harness.png).

The adapter's 16-pin end uses the usual Android colour code: the EIA power and speaker colours, brown and brown/white for the wheel, and a loose pink lead tagged BACK for reverse. Wire positions inside that 16-pin shell vary between makers, so go by colour. On the Toyota side the wheel is 20-pin #7 (SW1: seek, volume), #8 (SW2: mode, phone, voice) and #6 (its ground, which the adapter joins to black). Only non-JBL trucks: the adapter does not work with the JBL amplifier.

To build the plug: solder each wire to a pre-crimped Micro-Fit lead, heat-shrink it, and push the pin into its numbered hole until it clicks. Pin n sits directly above pin n+10. Use both +12 V pins and at least two grounds: loud music peaks at 10 to 12 A, more than one Micro-Fit contact is rated for. The speaker order (FR, FL, RR, RL) is not a typo: it matches the amp's output order on the board, so the four speaker tracks run straight to the plug without crossing.

PinSignalAdapter wire
1, 11+12 V constantYellow
2, 12, 19GroundBlack
7Key / accessoryRed
17Headlights on (illumination)Orange
10Reverse (+12 V in reverse)Pink, tagged BACK; splice to the reverse-light feed
8Steering wheel 1 (seek, volume)Brown (KEY1)
18Steering wheel 2 (mode)Brown/white (KEY2)
9Steering wheel groundLeave empty (the adapter grounds the wheel through black)
3 / 13Front right + / −Gray / gray-black
4 / 14Front left + / −White / white-black
5 / 15Rear right + / −Purple / purple-black
6 / 16Rear left + / −Green / green-black
20Not used

Blue (antenna / amp turn-on) and anything else on the 16-pin are not used: cap them. Before the first plug-in, check with a meter that +12 V (1, 11) has no continuity to ground (2, 12, 19), and confirm KEY1 / KEY2: adapter in the truck, key off, ohms from brown and from brown/white to black; the reading changes as the wheel buttons are pressed. Earlier measurements on the purple SWC wire: seek+ ~0 Ω, seek− 331 Ω, vol+ 100 Ω, vol− "3.111" (unit unclear). Learn mode makes the exact values irrelevant.

Pi GPIO map

Header pinBCMNetUse
2, 45V+5VBoard powers the Pi (and the screen through its pogo pins)
1, 173V3(unused)The board makes its own 3.3 V
3, 5GPIO2/3I2C_SDA/SCLAmp 0x6A, ADC 0x48, RTC 0x68 (Pi has 1.8k pull-ups)
27, 28ID_SD/SCID_SDA/SCLHAT EEPROM 0x50 (3.9k pull-ups on the board)
12GPIO18I2S_BCLKBit clock, input (board is master)
35GPIO19I2S_FSYNCFrame clock, input
40GPIO21I2S_DOUTAudio data to the amp
32, 33GPIO12/13FAN1/2_PWMHardware PWM, 25 kHz, inverted
36, 7GPIO16/4FAN1/2_TACHTach, 2 pulses/rev
11GPIO17~ACC_ONKey on (active low)
13GPIO27~LIGHTS_ONHeadlights (active low, may be PWM-dimmed)
38GPIO20I2S_DINMic audio from the PCM1808, input
26GPIO7~REVERSEReverse gear (active low)
37GPIO26PI_HOLDKeeps the board powered while high
15, 16GPIO22/23~AMP_STBY/~AMP_MUTEAmp control
18, 22GPIO24/25~AMP_FAULT/~AMP_WARNAmp status (open drain)
31GPIO6~ADC_ALERTADC ready (unused by software for now)
29GPIO5~RTC_INTRTC alarm
8, 10GPIO14/15UART_TX/RXDebug header (not fitted)

Shopping list (besides the board)

From DigiKey (genuine Molex; Amazon does not carry the 20-way housing):

QtyPartLink
2Micro-Fit 3.0 2x10 plug housing, Molex 43025-2000DigiKey
25Micro-Fit pre-crimped lead, socket + 300 mm 18 AWG, Molex 2147611124DigiKey
opt.Micro-Fit extraction tool, Molex 11-03-0043 (the Amazon "11-03-0044" tools are Mini-Fit Jr, wrong size)DigiKey

From Amazon:

QtyPartLink
1Klintotour Toyota adapter (for the white steering-wheel plug)B0FBRNCNPD
1CR2032B07G7KRQQ5
1M2.5 standoffs, 11 mm body + 6 mm threadB07KM27KC6
2Noctua NF-A4x10 5V PWM (each includes an extension cable)B07DXS86G7
1Posi-Tap 18-24 AWGB01HSBYX3I
118 AWG wire (reverse run), stranded pure copper (not CCA: copper-clad aluminium); splice solid core to a stranded tail before any pin or Posi-TapB07D74RGVM
1Heat-shrink assortmentB01MFA3OFA
120 x 20 x 10 mm aluminium heatsinks with thermal tape (one goes on the amp)
1 packM2.5 nylon washers (see "Pi standoffs" below)
1Car microphone, 3.5 mm plug, plain 2-wire electret (head-unit type, not USB or a TRRS headset)
opt.4-pin PWM fan extensionsB0CNLDNZB2

Amp heatsink (rev A). The CNC heatsink in mech/ (copied from TI's EVM) was dropped on cost. Rev A uses one stock 20 x 20 x 10 mm heatsink centred on U7. Parts in that area are at most 1.8 mm tall against the 2.33 mm chip, so it sits flat. Anything up to 41 x 20 mm fits (long side along the chip); past 20 mm the other way it hits the speaker inductors. Three conditions:

  • A fan must blow across it. In still air with tape, loud music would reach the amp's 160 °C shutdown; with airflow it stays around 100-120 °C, and the software cuts 6 dB on the amp's warning.
  • Hold it mechanically. Tape alone can let go in a hot dash and leave a loose aluminium block on the board. Use thermal epoxy instead, or a metal strap across the fins on long M3 screws through H5/H6 (they sit just outside a 20 mm heatsink).
  • Ground it. TI requires the heatsink on GND and the tape insulates. A short wire from a fin to H5 or H6 (GND pads; screw + ring terminal), or the metal strap, does it.

Pi standoffs. Signal tracks pass under the metal at two Pi holes: at H1, I2S_FSYNC (top) and ~AMP_MUTE / I2C_SDA (bottom); at H4, +3V3 (top). The Pi's holes are grounded, so a standoff or screw head that wears through the mask would short them. Put a nylon washer on both faces of the board at all four holes (1 mm, the same on every hole so the board sits level; the housing assumes 1 mm under the board). Fix in rev B: keep copper 3 mm from the Pi hole centres.

Order options: 4 layers, 1 oz inner copper (the default is 0.5 oz; the +12V_PROT and +5V planes on In2 carry up to ~12 A peak at full volume); ENIG suits the 0.5 mm WSON/VQFN parts better than HASL. J2 is on the underside, so the assembler may ask to confirm assembly on both sides. In JLC's placement preview, check the parts whose footprints JLC draws differently from KiCad (tools/jlc_cpl.py already corrects the placement file for them): BT1 with its + contact on the square pad, J1's latch and the fan headers' ramps on the side the silkscreen shows, pin-1 dots on Q1-Q7 and U2-U7, and Q1/Q2 and L1 sitting centred on their pads (JLC's LFPAK56 pads differ from ours; JLC has no footprint for L1 to check against).

Files

PathWhat
carrier.kicad_sch / .kicad_pcb / .kicad_proKiCad 10 project (generated, see below)
lib/carrier.kicad_sym, lib/carrier.pretty/Custom symbols and footprints
lib/ref/EasyEDA/JLC reference symbols and footprints used to check pinouts
datasheets/Every datasheet used, plus the HAT mechanical drawing and TI's EVM guide
mech/heatsink.step, .stlCNC heatsink (not used on rev A; stock heatsink instead)
mech/housing_*.stl, .stepPrinted housing: shell, lid, fit ring
tools/Generators and checks (below)
out/Renders, PDF, BOM, reports (generated, not committed)

Regenerating everything

The schematic and board are produced by scripts, not edited by hand, so every value and position is reviewable in one place. KiCad runs as a Flatpak; kicad-cli is a wrapper in ~/.local/bin. The Python virtualenv .venv holds easyeda2kicad, cadquery and matplotlib.

bash
cd hardware/carrier
python3 tools/make_symbols.py            # lib/carrier.kicad_sym
python3 tools/gen_sch.py                 # carrier.kicad_sch (part numbers included)
python3 tools/render.py                  # out/sch/full.png, plus crops: render.py name x1 y1 x2 y2
kicad-cli sch erc -o out/erc.rpt carrier.kicad_sch
kicad-cli sch export pdf -o out/carrier.pdf carrier.kicad_sch
kicad-cli sch export bom --fields 'Value,Reference,Footprint,LCSC,MPN,Manufacturer,${QUANTITY},${DNP}' \
  --labels 'Comment,Designator,Footprint,LCSC,MPN,Manufacturer,Qty,DNP' \
  --group-by 'Value,Footprint,LCSC,${DNP}' --exclude-dnp -o out/bom_jlcpcb.csv carrier.kicad_sch

tools/build_board.sh                     # placement, planes, hand routes, Freerouting, finish, DRC (~20 min)
tools/build_board.sh noauto              # stop before the autorouter
flatpak run --command=python3 org.kicad.KiCad tools/dump_pcb.py   # then:
.venv/bin/python tools/view_pcb.py NAME [x0 y0 x1 y1] [--nets TEXT] [--labels]   # out/pcb/NAME.png
.venv/bin/python tools/fit_plate.py      # mech/fit_plate.stl

.venv/bin/python tools/heatsink.py       # mech/heatsink.step/.stl
kicad-cli pcb export step --subst-models --force -o mech/carrier_board.step carrier.kicad_pcb
.venv/bin/python tools/housing.py        # mech/housing_*.stl/.step + clearance check
.venv/bin/python tools/assembly.py       # mech/assembly.step/.stl
.venv/bin/python tools/render3d.py       # out/3d/*.png

tools/jlc_export.sh                      # fab/: Gerbers + drill zip, BOM, CPL
flatpak run --command=python3 org.kicad.KiCad tools/check_cpl.py --dump   # then:
.venv/bin/python tools/check_cpl.py      # CPL vs JLC's footprints, exit 1 on a mismatch
.venv/bin/python tools/sim.py            # SPICE testbenches, out/sim/*.png, exit 1 on a failed check

What each script owns:

  • make_symbols.py: custom symbols (TAS6424, LM61460, LM74800, DS3231, PCM1808, harness, Pi header). Pin numbers and names were checked against datasheets / EasyEDA each time a symbol was rearranged.
  • gen_sch.py + schlib.py: the schematic. Each section is a function placed at an anchor; PARTS maps (value, footprint) to MPN / manufacturer / LCSC. Part UUIDs are derived from references, so reruns are byte-identical and the board stays linked to the schematic.
  • gen_pcb.py + place.py: board outline, 4-layer stackup, JLC design rules, net classes and placement. place.py holds the Pi position, the notch/slot geometry and every block's layout, with parts found by Section field and nets.
  • route.py: everything that carries current or needs care, locked so the autorouter works around it. In1 is solid GND; In2 is split into +12V_PROT (protection, amp, buck input) and +5V (buck output, Pi, LDO, clocks, fans). Top-layer pours for the battery path, VMID, buck VIN/PGND/SW and output, amp PVDD and the Pi's 5 V pins. Hand-routed amp outputs (P legs on top, M legs dropped to the bottom under the coils) and speaker lanes (1 mm, nested so none cross). Every GND pad gets its own via to In1, and +5V/+12V pads over their In2 region likewise. The LM74800's 0.5 mm pins and a few tight nets are routed by maze.py (a small grid router). Nothing copper within 3 mm of the outer edge.
  • autoroute.py exports to Freerouting (with keepouts guarding the pours) and imports the result; finish.py maze-routes anything left open.
  • jlc_export.sh + jlc_cpl.py: order files. jlc_cpl.py moves each part to JLC's footprint origin and adds the rotation JLC's footprint needs (JLC_ROT, JLC_ORIGIN); check_cpl.py re-derives both from JLC's footprints and checks fab/carrier_cpl.csv.
  • sim.py + ngspice_run.py: SPICE testbenches for the analog blocks, run in KiCad's bundled ngspice. Values are copied from gen_sch.py (constants at the top of sim.py); change both together.
  • heatsink.py, housing.py, assembly.py, render3d.py: mechanical. HEATSINK=stock|double|cnc picks the amp heatsink the assembly and the housing check use. heatsink_thermal.py: rough junction temperatures for each heatsink option, swept over the unmeasured fan airflow. assembly.py owns the stack heights; housing.py takes them from it. Re-export mech/carrier_board.step after any board change, before housing.py (its clearance check uses it).

Verification so far

  • ERC: 0 errors, 0 warnings.
  • Netlist check: every Pi GPIO lands on its intended net; amp pins, speaker filters and clock nets checked net by net.
  • Board: 0 schematic-parity issues; no courtyard overlaps or clearance errors; parts clear of the Pi socket's solder pins by 3 mm; only parts under 2.2 mm under the heatsink.
  • BOM: 148 fitted parts, all LCSC numbers present and in stock when chosen (2026-09-22/24).
  • Pi socket orientation: pin 1 over the Pi's pin 1, checked by pad position (a mirrored socket would put 5 V on the wrong pins).
  • Software: 18 tests on simulated hardware, including the GPIO request struct compared byte for byte with <linux/gpio.h>.
  • SPICE (tools/sim.py, 37 checks over tolerance corners): power hold, key/lights/reverse inputs, soft start, OV cutoff, buck UVLO and setpoint, speaker filters, steering-wheel and battery ADC, mic bias, fan PWM.
  • Pinouts of every IC and the land patterns of the LM74800 and LM61460 checked against their datasheets; TAS6424 wiring against TI's fig 10-2.
  • Placement file: every part's rotation and centre checked against JLC's own footprint (tools/check_cpl.py): 0 mismatches.

Open items

  1. Fit check: done 2026-09-24, the corrected outline (mech/fit_frame.stl) fits the screen, screw holes, header and port notch exactly.
  2. Display thickness and pillar height now come from Hosyond's drawing (8.25 + 4.0 mm). The housing's corner tabs, J1 ledge and lid ribs depend on them: check glass-to-pillar-top (12.25 mm) with calipers, and print the fit ring before the full housing.
  3. Tidy silkscreen; add the harness pin table next to J1: done.
  4. Final review: done 2026-10-07 (VERIFICATION.md, third pass). Order the board + assembly; stock heatsink instead of CNC.
  5. Enclosure: support the board under J1: done 2026-10-12, the housing's ledge under J1 and the lid ribs above it (tools/housing.py). Not printed yet.
  6. On first power-up: confirm the react-carplay window class used for steering-wheel keys, run learn mode, check amp start-up and fault handling on real hardware, and check the mic capture path (the overlay puts two dummy codecs on one I2S link; set mic gain in software).

Parts

171
QtyValueFootprintReferences
18100nFCapacitor_SMD:C_0603_1608MetricC6, C7, C10, C11, C13, C14, C15, C18, C19, C22, C26, C29, C31, C33, C67, C69 +2
171uFCapacitor_SMD:C_0603_1608MetricC20, C21, C27, C28, C37, C38, C39, C40, C43, C44, C45, C46, C47, C48, C49, C50 +1
1410kResistor_SMD:R_0603_1608MetricR6, R8, R10, R11, R15, R19, R20, R22, R23, R25, R26, R34, R36, R44
91nFCapacitor_SMD:C_0603_1608MetricC52, C54, C56, C58, C60, C62, C64, C66, C75
91uFCapacitor_SMD:C_0805_2012MetricC35, C51, C53, C55, C57, C59, C61, C63, C65
81kResistor_SMD:R_0603_1608MetricR5, R7, R12, R16, R33, R43, R45, R46
83.3uHInductor_SMD:L_Chilisin_BMRx00060630L2, L3, L4, L5, L6, L7, L8, L9
5100kResistor_SMD:R_0603_1608MetricR17, R27, R31, R35, R37
510uFCapacitor_SMD:C_1206_3216MetricC16, C17, C30, C32, C34
410uFCapacitor_SMD:C_0805_2012MetricC68, C70, C72, C73
433RResistor_SMD:R_0603_1608MetricR38, R39, R40, R41
4PiMountingHole:MountingHole_2.7mm_M2.5H1, H2, H3, H4
3100nFCapacitor_SMD:C_0805_2012MetricC1, C2, C4
347kResistor_SMD:R_0603_1608MetricR18, R21, R24
347uFCapacitor_SMD:C_1210_3225MetricC12, C24, C25
3H15VND3BDiode_SMD:D_SOD-323D2, D3, D7
3MMBT3904Package_TO_SOT_SMD:SOT-23Q3, Q4, Q5
3REDLED_SMD:LED_0603_1608MetricD8, D9, D10
20RResistor_SMD:R_0603_1608MetricR9, R30
21N4148WDiode_SMD:D_SOD-123D4, D5
22.2uFCapacitor_SMD:C_0805_2012MetricC41, C42
22N7002Package_TO_SOT_SMD:SOT-23Q6, Q7
23.9kResistor_SMD:R_0603_1608MetricR13, R14
2BUK7Y4R8-60EPackage_TO_SOT_SMD:LFPAK56Q1, Q2
2HeatsinkMountingHole:MountingHole_3.2mm_M3_Pad_ViaH5, H6
1100RResistor_SMD:R_0603_1608MetricR1
110nFCapacitor_SMD:C_0603_1608MetricC8
112.288MHzOscillator:Oscillator_SMD_Abracon_ASE-4Pin_3.2x2.5mmX1
12.2kResistor_SMD:R_0603_1608MetricR42
1220nFCapacitor_SMD:C_0603_1608MetricC5
122nFCapacitor_SMD:C_0805_2012MetricC3
122pFCapacitor_SMD:C_0603_1608MetricC23
124.9kResistor_SMD:R_0603_1608MetricR32
126.7kResistor_SMD:R_0603_1608MetricR28
13.74kResistor_SMD:R_0603_1608MetricR4
133.2kResistor_SMD:R_0603_1608MetricR29
14.7uHInductor_SMD:L_APV_APH0840L1
1470uFCapacitor_SMD:CP_Elec_10x12.5C36
15.11kResistor_SMD:R_0603_1608MetricR3
195.3kResistor_SMD:R_0603_1608MetricR2
1ADS1115IDGSPackage_SO:TSSOP-10_3x3mm_P0.5mmU2
1BZT52C15Diode_SMD:D_SOD-123D6
1CAT24C32Package_SO:SOIC-8_3.9x4.9mm_P1.27mmU4
1CR2032Battery:BatteryHolder_MYOUNG_BS-07-A1BJ001_CR2032BT1
1DS3231SNPackage_SO:SOIC-16W_7.5x10.3mm_P1.27mmU3
1EEPROM_WPJumper:SolderJumper-2_P1.3mm_Open_RoundedPad1.0x1.5mmJP1
1FAN1Connector:FanPinHeader_1x04_P2.54mm_VerticalM1
1FAN2Connector:FanPinHeader_1x04_P2.54mm_VerticalM2
1Harness_4RunnerConnector_Molex:Molex_Micro-Fit_3.0_43045-2012_2x10_P3.00mm_VerticalJ1
1LM61460-Q1carrier:TI_RJR0014A_VQFN-HR-14_3.5x4mmU5
1LM74800-Q1Package_SON:WSON-12-1EP_3x3mm_P0.5mm_EP1.5x2.5mmU1
1MICConnector_Audio:Jack_3.5mm_PJ320D_HorizontalJ4
1PCM1808-Q1Package_SO:TSSOP-14_4.4x5mm_P0.65mmU8
1Pi 4 GPIOConnector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_VerticalJ2
1SMBJ33CADiode_SMD:D_SMBD1
1TAS6424E-Q1Package_SO:SSOP-56_7.5x18.5mm_P0.635mmU7
1TLV75533PDBVPackage_TO_SOT_SMD:SOT-23-5U6
1UARTConnector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ3
1WPTestPoint:TestPoint_Pad_D1.5mmTP1

Questions

How big is the Carrier PCB?

It measures 164.9 × 102 mm and has 4 copper layers, 1.6 mm thick.

What parts does the Carrier use?

171 parts, built around the ADS1115IDGSR, LM61460AFSQRJRRQ1, PCM1808QPWRQ1 and TAS6424EQDKQRQ1. 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 Carrier KiCad files?

From the AJXD2/carplay-project repository on GitHub, at the commit this page was made from: the board is hardware/carrier/carrier.kicad_pcb and its schematic hardware/carrier/carrier.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Carrier design in my own project?

Its repository states no licence, so its author keeps all rights: ask AJXD2 before reusing the design.

Similar boards

  • 4 layers170 × 101 mmFreeDSP G, the printed circuit board in 3D

    FreeDSP G

    freeDSP/FreeDSP-G

    ADAU1467 DSP Board for Electric Guitar Players

    377 parts7CC0-1.0
  • 4 layers65 × 56 mm2026 WRO Hat, the printed circuit board in 3D

    2026 WRO Hat

    Spaceflakes/2026-FE-The-Rdacted

    49 parts1
  • 2 layers145 × 60.3 mmMkulima hardware, the printed circuit board in 3D

    Mkulima hardware

    Kazenzi/The-robotic-farmer

    Click the Youtube Thumbnail below for a youtube demo video:

    147 parts1MIT
  • 4 layers52.9 × 79.6 mmPCB Pere V1, the printed circuit board in 3D

    PCB Pere V1

    CaptainDJMax/2627_Projet3AMSC_Index_Stellaire

    Ceci est notre projet sur l'index stellaire

    93 partsMIT
  • 2 layers170 × 120 mmMotor pid, the printed circuit board in 3D

    Motor pid

    gallicchio/motor-pid

    The motor-position feedback loop of Learning the Art of Electronics (Hayes & Horowitz), Lab 10L, as a 170 x 120 mm printed circuit board whose silkscreen is the schematic.

    110 parts
  • 4 layers191.5 × 121.8 mmFoxhunt1, the printed circuit board in 3D

    Foxhunt1

    gx1400/kicad_foxhunt_batterytest

    Custom amateur radio fox hunt (hidden transmitter) controller, aimed at being a flexible, dynamic platform for a wide range of fox-hunt formats — not just a fixed single-mode beacon.

    260 parts
  • 4 layers41.2 × 49.9 mmEdu V2.2, the printed circuit board in 3D

    Edu V2.2

    LivioScherrer/MinTurtle

    75 parts
  • 4 layers150 × 40 mmLinklite v2, the printed circuit board in 3D

    Linklite v2

    WeasalCrafter/linklite-v2

    Programming and KiCad files for LinkLite v2: a modular lighting system with wireless control and syncing.

    116 partsMIT