

Bazauto block detection
Two-channel active-high DCC block detector board (KiCad) for the Westgate Hollow layout
- Size
- 48 × 38 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 37
- Nets
- 17
- Pads
- 83
- Tracks, vias
- 117, 38
- Pours
- 2
- Routed
- Yes
- KiCad
- KiCad 10.0 (file 20260206)
- Created
- 14 Sep 2026
- Updated
- 14 Sep 2026
Overview
Bazauto block detection is an open-source printed circuit board by bazauto, from the bazauto/block-detection repository on GitHub, published under the CERN-OHL-P-2.0 licence. It is a 2-layer board of 48 × 38 mm with 37 parts on 17 nets, routed with 117 tracks and 38 vias.
It is built around the TLV9002IDGKR-MS, 1N4148W and BAT54S. Its parts include 11 resistors, 5 capacitors, 4 diodes, 3 connectors and 2 ICs.
Main components
3TLV9002IDGKR-MS
VSSOP-8-2.75V~-900mV、900mV~2.75V -40℃~+85℃ 1.8V~5.5V 1.8uV/℃ 1MHz 1V/us 1mV 1pA 2 28uA 45mA 5pA 65nV/√Hz@1kHz 80dB Rail-to-Rail Input, Rail-to-Rail Output VSSOP-8 Operational Amplifier ROHSMSKSEMIOperational Amplifier1N4148W
SOD-123150mA 1A 1V@50mA 1uA@75V 400mW 4ns 75V Independent SOD-123 Switching Diodes ROHSSTMicroelectronicsSwitching DiodesBAT54S
SOT-231 Pair Series Connection 1V@100mA 200mA 2uA@25V 30V 600mA SOT-23 Schottky Diodes ROHSMDDSchottky Diodes
README
README.md2-Channel DCC Block Detector (Active High)
CT-based occupancy detection for the Westgate Hollow layout. Two independent channels, each turning the current in an external current transformer into a push-pull logic level: HIGH (3.3 V) = block occupied, LOW (0 V) = clear.
Single +3.3 V rail, fed in through the output header. Board is 48 × 38 mm, 2 layers, four M2 mounting holes.
Why build this
So that a broken cable or connection under the layout doesn't register as a clear block.
The off-the-shelf detectors used so far are active low: they pull their output to
0 V when a block is occupied, and leave it open when clear. The feedback node's
inputs are pulled up, so a broken wire floats high, and that reads exactly like a
clear block, the permissive state (bazauto/layout-feedback#9).
This board is active high: occupied drives 3.3 V, clear drives 0 V. A broken wire into a pulled-up input now floats to the occupied side.
Status
Revision 1.0: 10 boards ordered from PCBWay, awaiting delivery. Nothing has been measured on hardware yet.
Files
| File | What it is |
|---|---|
bazauto-block-detection.kicad_sch | Schematic (KiCad 10 format) |
bazauto-block-detection.kicad_pcb | 2-layer PCB, fully routed |
bazauto-block-detection.kicad_sym | Project symbols: TLV9002IDGKR, TLV3212IDGKR |
sym-lib-table | Project symbol library table. There is no project footprint table: every footprint comes from the stock KiCad libraries and is stored in the board file |
bom.csv | Bill of materials, grouped |
fab/rev-1.0/ | Revision 1.0 as sent to fab: Gerbers, drill files, Gerber job file, position file, the zipped Gerber set, and SOURCE.txt fingerprinting the board they came from. See Fabrication revisions |
BOM_PCBWay_bazauto-block-detection.xlsx | Not in the repo. bom.csv poured into PCBWay's template, ready to upload. Generate it locally; see Regenerating |
scripts/ | Generators and checkers — see Regenerating |
Everything else (resistors, caps, diodes, connectors, trimmers) comes from the stock KiCad 10 libraries, so the project opens on any standard install.
Circuit
Each channel is the same chain:
CT ─ terminal block ─ burden ─ ESD clamp ─ 1k ─ precision peak detector ─ comparator ─ OUT
J1 / J2 R1,R2,R3 D1 / D2 R4/R5 U1 + D3/D4 + C3/C4 + R8/R9 U2 J3
+ JP1Burden. The CT secondary is loaded across the input terminals. Channel 1 is switchable, channel 2 is fixed:
| Channel | JP1 | Burden | Use |
|---|---|---|---|
| 1 | open | 1.1 kΩ | Programming track (service-mode ACK pulse) |
| 1 | fitted | 1.1 k ∥ 110 R = 100.0 Ω | Standard track |
| 2 | — | 100 Ω fixed | Standard track only |
The parallel combination is exact: 1100 × 110 / 1210 = 100.0 Ω.
Clamp. D1/D2 (BAT54S, series pair) clamp the input to roughly −0.3 V / +3.6 V. R4/R5 (1 k) then limit the current into the op-amp's input structure on the negative half-cycle — the CT output is bipolar and a single-supply op-amp input sits at the very edge of its absolute maximum without them.
Peak detector. The op-amp drives D3/D4 with the diode inside the feedback loop, so the forward drop is divided out by the loop gain — no 0.6 V loss on a signal this small. R6/R7 (100 Ω) sit between the op-amp output and the diode: they are inside the loop too, and stop the RRIO output from ringing into the 10 µF hold capacitor. C3/C4 hold the envelope, R8/R9 bleed it away.
Comparator. The envelope goes to +IN, the trimmer wiper to −IN, and the push-pull output drives the header directly. R10/R11 (10 M) add positive feedback so the output does not chatter as the envelope crosses the threshold.
Setting up
Time constants and tuning, all measurable on the board:
- Release time. R8/R9 × C3/C4 = 100 kΩ × 10 µF ≈ 1 s to decay. That doubles as debounce for dirty wheels. For a faster release drop the bleed resistor — 10 k gives ≈ 100 ms.
- Hysteresis. V_hyst ≈ 3.3 V × R_bleed / R_hyst = 3.3 × 100 k / 10 M ≈ 33 mV. Lower R10/R11 for more.
- Threshold. With the block clear, turn RVn until OUTn just goes low, then back off about 10 %.
Test points, all on the top side:
| TP | Net | Use |
|---|---|---|
| TP1 / TP3 | VREF1 / VREF2 | Trimmer wiper — the threshold you have dialled in |
| TP2 / TP4 | ENV1 / ENV2 | Peak-detector output — the rectified envelope |
| TP5 | GND | Scope ground |
⚠ Known concerns with revision 1.0
1. The signal chain has no gain, and that makes the threshold hard to set.
This is the one thing worth changing. The detector is a unity-gain rectifier, so the comparator threshold has to be set in the millivolt region. With a 1:100 CT and a 100 Ω burden, 10 mA of track current gives about 10 mV at the envelope node. The trimmer spans the full 0–3.3 V across 10 kΩ, so 10 mV is 0.3 % of its travel — a fraction of one turn on a 12-turn trimmer — and it is the same order as the comparator's own input offset voltage. Setting it repeatably will be unpleasant, and it will drift.
The cheap fix is one resistor: put ~330 kΩ in series between +3V3 and the top of each trimmer (RV1 pin 1, RV2 pin 1). The wiper then covers roughly 0–100 mV instead of 0–3.3 V, giving about 30× the resolution and swamping nothing else. The alternative is to give the op-amp stage gain instead of running it at unity.
Revision 1.0, as ordered, does not include this change (there is no 330 kΩ
part in bom.csv). Sizing it properly needs the CT's actual turns ratio. It
affects two nets and about 4 mm of track.
2. Verify the TLV3212IDGKR pinout against the datasheet. The comparator symbol uses the industry-standard 8-pin dual layout — 1=OUTA, 2=INA−, 3=INA+, 4=GND, 5=INB+, 6=INB−, 7=OUTB, 8=V+ — which is what TLV3202IDGKR uses in the same DGK package. I could not confirm TLV3212's pin assignment from a datasheet in this session. TLV3202IDGKR is a verified drop-in if you would rather not check. Same for TLV9002IDGKR, though that one follows the universal dual-op-amp pinout and is not in doubt.
3. AGND is the plane, not a separate net. The spec asked for the filter returns to go to AGND and for a solid, unbroken ground plane. Those pull in opposite directions — a genuine second net needs a split, and a split is exactly what section 6 forbids. I used one continuous GND pour and kept the analog returns physically local instead: C3/C4 and R8/R9 ground through their own vias straight into the plane, a few millimetres from the op-amp's own ground via.
Layout
- B.Cu is a ground pour. F.Cu carries the signals plus a second GND pour in the gaps. 30 ground vias tie the two together: 16 taking SMD ground pads straight down to the plane, 14 stitching the pours across the board.
- +3V3 runs as a perimeter ring (top edge, right edge, bottom edge) with a spine threaded through the gap between the two pad rows of U1 and U2, so it never crosses a channel's signal path.
- The two channels are mirrored top and bottom about the board centreline, with the shared dual op-amp and comparator between them. Both ICs are rotated so channel A faces the top band and channel B the bottom.
- 0.1 µF decoupling (C1, C2) sits against each IC's V+ pin; C5 is the 10 µF bulk.
Where the ground plane is interrupted. Four short bottom-layer hops let crossing nets pass each other, 8.60 mm of track in total on a 1824 mm² board:
| Net | From → to | Length |
|---|---|---|
| +3V3 | (20.20, 22.00) → (20.20, 24.00) | 2.00 mm |
| /OUT1 | (42.20, 18.30) → (43.80, 18.30) | 1.60 mm |
| /OUT2 | (31.90, 22.60) → (33.45, 22.60) | 1.55 mm |
| OA2 out | (21.50, 22.75) → (21.50, 26.20) | 3.45 mm |
scripts/check_plane.py audits this and reports which analog nets pass over a
void. Current result: the CT input rails, both op-amp inputs, ENV1 and VREF1
have completely unbroken copper beneath them. Four crossings remain, all in
channel 2's middle band — ENV2 twice, VREF2 once, channel 2's op-amp output
once — and in each the trace crosses a void under 1 mm wide. Those nets carry a
rectified DC envelope and a DC threshold reference, where a sub-millimetre
detour in the return path at DCC frequencies is not a real effect. If you want them gone, the honest fix is a 4-layer stack-up, not
more clever 2-layer routing.
One placement change from your version: C1 moved 0.65 mm right (to x = 23.45) so that channel 2's feedback trace and op-amp output each get their own corridor past it. Everything else is where you left it.
Regenerating
Run with KiCad's bundled Python, from the project directory:
K="C:/Program Files/KiCad/10.0"
python scripts/gen_schematic.py # schematic + project symbol lib
python scripts/verify_netlist.py # netlist vs. design intent
"$K/bin/python.exe" scripts/route_pcb.py # routing + pours (placement is preserved)
"$K/bin/python.exe" scripts/check_board.py # placement + board-vs-schematic nets
"$K/bin/python.exe" scripts/check_plane.py # ground-plane auditroute_pcb.py loads the existing board, so hand-adjusted placement and
silkscreen survive; it only rebuilds tracks, vias and zones.
| Script | Does |
|---|---|
gen_schematic.py | Builds the schematic from real KiCad library symbols; wires are computed from actual pin coordinates |
kicadlib.py | S-expression reader/writer and symbol-library helpers |
probe_transform.py | Derives KiCad's symbol placement transform empirically from its own demo files |
verify_netlist.py | Compares the extracted netlist against the intended one, net by net |
route_pcb.py | Routing, ground pours, silkscreen legends |
check_board.py | Courtyard overlaps, off-board parts, board nets vs. schematic |
check_plane.py | Bottom-layer voids and which analog nets cross them |
make_pcbway_bom.py | Fills PCBWay's BOM template; fails if it has drifted from bom.csv. Needs PCBWay's sample BOM template saved locally as Sample_BOM_PCBWay.xlsx. It's PCBWay's file, so it isn't committed, and neither is the output. |
check_fab_outputs.py | Checks the newest fab/rev-X.Y/ against the board it was generated from; --record writes that revision's SOURCE.txt. Plain Python, needs kicad-cli on PATH or KICAD_CLI set |
Fabrication revisions
Each set of files sent to a board house lives in its own fab/rev-X.Y/ folder
and is never regenerated in place, so the repo always holds exactly what a
revision was. Each revision is also tagged in git (rev-1.0).
fab/rev-X.Y/SOURCE.txt records the SHA-256 of the board file (line endings
normalised) that its outputs came from. CI runs scripts/check_fab_outputs.py:
- Board unchanged since the newest revision: it regenerates the outputs and fails if the committed ones differ. That catches Gerbers left stale after a board edit, and a zip that disagrees with the loose files. Gerbers are compared by the geometry they draw, because KiCad doesn't write primitives in a stable order.
- Board changed: work on the next revision is under way. It reports a notice and passes.
To cut a new revision, for example 1.1:
- Plot Gerbers, drill files (Excellon, PTH and NPTH separate) and the position
file (CSV, mm, both sides) into
fab/rev-1.1/, and zip the Gerbers, the Gerber job file and the drill files asbazauto-block-detection.zipthere. python scripts/check_fab_outputs.py --record rev-1.1python scripts/check_fab_outputs.py, which must report all outputs matching.- Land it through a PR, then tag the merge commit
rev-1.1.
Verification
Everything below was run against the files in this directory:
kicad-cli sch erc 0 errors, 0 warnings
verify_netlist.py all 17 nets match design intent, no unconnected pins
kicad-cli pcb drc 0 violations, 0 unconnected items
check_board.py 37 footprints, 0 problems (no overlaps, nets match schematic)
check_plane.py 8.60 mm bottom-layer track; 4 analog crossings (see above)CI re-runs the two kicad-cli checks and check_fab_outputs.py on every pull
request (see .github/workflows/ci.yml). DRC there runs with --schematic-parity at error
severity. At warning severity the parity check reports 80 cosmetic mismatches:
footprints saved without their library prefix, and field text such as a
Datasheet of '' against ~. None is a net or connection mismatch.
Gerbers and drill files for revision 1.0 are in fab/rev-1.0/, and regenerating
them from the current board reproduces them exactly. Nothing has been measured on
hardware yet. The threshold-resolution concern above is analysis, not a bench
result.
Licence
Copyright © 2026 Paul Barrett.
| Material | Licence |
|---|---|
The hardware design: schematic, board, project symbol library, BOM, Gerbers and drill files, and the enclosure model (enclosure/, except check_fit.py) | CERN-OHL-P-2.0 |
Software: everything in scripts/, and enclosure/check_fit.py | MIT |
Source location: https://github.com/bazauto/block-detection
Third-party material, notably the KiCad library symbols the project symbols are derived from, is listed in THIRD-PARTY-NOTICES.md.
Parts
37| Qty | Value | Footprint | References |
|---|---|---|---|
| 4 | M2 | MountingHole_2.2mm_M2 | H1, H2, H3, H4 |
| 3 | 10uF | C_0805_2012Metric | C3, C4, C5 |
| 2 | 100R | R_0805_2012Metric | R6, R7 |
| 2 | 100k | R_0805_2012Metric | R8, R9 |
| 2 | 100nF | C_0805_2012Metric | C1, C2 |
| 2 | 10M | R_0805_2012Metric | R10, R11 |
| 2 | 10k | Potentiometer_Bourns_3269W_Vertical | RV1, RV2 |
| 2 | 1N4148W | D_SOD-123 | D3, D4 |
| 2 | 1k | R_0805_2012Metric | R4, R5 |
| 2 | BAT54S | SOT-23 | D1, D2 |
| 1 | 1.1k | R_1206_3216Metric | R1 |
| 1 | 100R | R_1206_3216Metric | R3 |
| 1 | 110R | R_1206_3216Metric | R2 |
| 1 | CT1 | TerminalBlock_Phoenix_PT-1,5-2-3.5-H_1x02_P3.50mm_Horizontal | J1 |
| 1 | CT2 | TerminalBlock_Phoenix_PT-1,5-2-3.5-H_1x02_P3.50mm_Horizontal | J2 |
| 1 | ENV1 | TestPoint_Pad_D1.5mm | TP2 |
| 1 | ENV2 | TestPoint_Pad_D1.5mm | TP4 |
| 1 | GND | TestPoint_Pad_D1.5mm | TP5 |
| 1 | MODE | PinHeader_1x02_P2.54mm_Vertical | JP1 |
| 1 | OUT | PinHeader_1x04_P2.54mm_Vertical | J3 |
| 1 | TLV3212IDGKR | MSOP-8_3x3mm_P0.65mm | U2 |
| 1 | TLV9002IDGKR | MSOP-8_3x3mm_P0.65mm | U1 |
| 1 | VREF1 | TestPoint_Pad_D1.5mm | TP1 |
| 1 | VREF2 | TestPoint_Pad_D1.5mm | TP3 |
Similar boards
- 4 layers137 × 79.5 mm

- 4 layers106 × 63.5 mm

- 2 layers115.2 × 78.6 mm

- 2 layers200 × 120 mm

- 2 layers100 × 102 mm

- 4 layers99.9 × 99.9 mm

- 2 layers262.2 × 100 mm

- 2 layers100.6 × 131 mm

Habitat V5
machadoleonardo94/HabitatControl-hardware
Hardware files for HabitatControl, designed on DipTrace
161 parts1
Questions
How big is the Bazauto block detection PCB?
It measures 48 × 38 mm and has 2 copper layers, 1.6 mm thick.
What parts does the Bazauto block detection use?
37 parts, built around the TLV9002IDGKR-MS, 1N4148W and BAT54S. 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 Bazauto block detection KiCad files?
From the bazauto/block-detection repository on GitHub, at the commit this page was made from: the board is bazauto-block-detection.kicad_pcb and its schematic bazauto-block-detection.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the Bazauto block detection design in my own project?
Its repository publishes it under the CERN-OHL-P-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).