SPI-controlled PWM peripheral
Sixteen independently controllable PWM outputs driven over three pins. Verilog RTL on a Tiny Tapeout tile.
- Constraint
- SPI arrives with no relationship to the chip’s 10 MHz clock. Sampling it directly risks metastability and a corrupted register on silicon that can’t be patched.
- Solution
- Two-flop synchronizers, with SCLK oversampled rather than used as a clock, so the whole design stays in one clock domain.
P—01 · ASIC · Personal project
SPI-controlled PWM peripheral
Sixteen independently controllable PWM outputs driven over three pins. Verilog RTL on a Tiny Tapeout tile.
Constraint
SPI arrives from an external controller with no relationship to the chip’s 10 MHz clock. Sampling SCLK, COPI and nCS directly invites metastability and missed edges — and a corrupted frame writes a real register on silicon that can’t be patched.
Design
- Two-flop synchronizers on every SPI input, each reset to its signal’s idle value so releasing reset can’t manufacture a false edge.
- SCLK is oversampled rather than used as a clock. That keeps the entire design in one clock domain and avoids a 16-bit crossing, at the cost of capping SCLK at roughly a quarter of the system clock.
- A write commits only on nCS rising, with exactly 16 bits counted and the R/W bit set. Every other frame is dropped silently — with no return path to report an error, holding the last known-good configuration beats committing a guess.
- Five registers drive 16 outputs: two enable masks, two PWM-mode masks, and a shared 8-bit duty cycle. Each output is muxed between steady-on and PWM, gated by its enable bit, then registered so all 16 switch on the same edge.
Verification
cocotb testbenches in Python driving full SPI transactions, checking register decode, malformed-frame rejection, and duty-cycle accuracy measured across a complete PWM period rather than sampled at a point. Runs in GitHub Actions on every push.
Target
Tiny Tapeout on the SkyWater Sky130 process. ~3 kHz PWM at 8-bit resolution.
Stack
- Verilog
- SPI
- CDC
- cocotb
- GitHub Actions
- Sky130