$ oracova task "implement and test the gyro driver"
plan MPU6000 gyro/accel · SPI1 · DUT STM32F411, real silicon
world mpu6000 model v1.2 , validated against real silicon
synth → bench FPGA ................ ok · 4 m 12 s
bench DUT board seated
netlist parse DUT board PCBA: SPI1 → PA5 SCK · PA6 MISO · PA7 MOSI · PA4 nCS
map DUT pins → base connector → FPGA balls ............ 4 nets routed
bench internal logic analyzer armed on SPI1
wiretest gpio loopback, no protocol: fabric drives each net, reads each pin back over SWD
PA5 ✓ PA6 ✓ PA7 ✓ PA4 ✓ 4/4 nets toggle · 0 shorts · 0 opens
bench wiring is ground truth : every failure after this line is firmware
iter 1 write driver: spi init · read WHO_AM_I @ 12.5 MHz · t+7 min
build ok flash ok test running
who_am_i .................................. FAIL read 0x9C then 0xE3, expected 0x68
internal logic analyzer · spi1 · iter 1
nCS SCLK MISO 12.5 MHz on a 1 MHz register bus Config read clocked at 12.5 MHz. This part caps register reads at 1 MHz; 20 MHz is for sensor data only.
la register reads cap at 1 MHz on this part; data reads may run to 20 MHz
fix config clock → ÷128 = 0.78 MHz, under the cap · sensor burst 12.5 MHz → rebuild
iter 2 flash ok · test running · t+21 min
who_am_i .................................. PASS 0x68
gyro_x .................................... FAIL reads 0x0000, always
internal logic analyzer · spi1 · iter 2
MOSI 0 0 1 1 1 0 1 1 bit 7 addr byte = 0x3B 0 0 1 1 1 0 1 1
MOSI · addr byte = 0x3B · bit 7 first
bit 7 = 0 → that's a write, not a read. The 0x80 read flag is missing.
la addr 0x3B sent without the 0x80 read bit
fix set the 0x80 read flag in the burst path → rebuild
iter 3 flash ok · test running · t+34 min
gyro_x .................................... data flows
rate check: world spins the table 90 °/s, ground truth · driver reports 11.3
fix driver set FS_SEL=3 (±2000 °/s) but scaled with the ±250 default: 131 → 16.4
iter 4 flash ok · full suite · t+43 min
who_am_i .................................. PASS
self test ................................. PASS
rate step 90 °/s .......................... PASS
burst read @ 8 kHz sustained .............. PASS
iter 5 improve: burst reads over DMA , get the CPU out of the read path · t+49 min
flash ok · test running
burst read @ 8 kHz ........................ FAIL transfer never starts
regs NDTR frozen: driver armed DMA1, but SPI1 requests only route to DMA2
fix retarget SPI1 DMA → DMA2 streams 0/3 · CR2 TXDMAEN|RXDMAEN → rebuild
iter 6 flash ok · test running · t+58 min
burst read @ 8 kHz ........................ FAIL stream armed, zero requests
regs stream 0 CHSEL=0. SPI1_RX is channel 3 on this stream
fix CHSEL → 3 on both streams → rebuild
iter 7 flash ok · test running · t+65 min
gyro_x .................................... data flows, shifted by one byte
la 14 bytes clocked per frame, 15 needed (addr + 14 data): NDTR missed the address byte
fix NDTR = 15: count the address byte, discard rx[0] → rebuild
iter 8 flash ok · full suite · t+70 min
who_am_i .................................. PASS
self test ................................. PASS
rate step 90 °/s .......................... PASS
burst read @ 8 kHz over DMA ............... PASS
cpu cycles moving gyro bytes .............. 0
result gyro driver implemented · DMA-accelerated · tested · 8 iterations · 1 h 12 min unattended
checker deterministic, fixed thresholds. The agent never grades its own work