Leading a 20-person controls & firmware team on a Formula SAE electric race car
I lead the group behind the car's electronics: ECU architecture, telemetry, HIL/SIL test infrastructure, and vehicle control logic. My focus this year has been making the firmware testable so we can improve code coverage and catch bugs before they reach the car.
Our hardware-abstraction layer had grown so broad that it worked against us: the old idea was that all code should be platform-agnostic, which pushed IO so far from the application that we couldn't use STM32 timers or interrupts where we needed them. I rescoped it so SIL tests one task at a time, sitting between unit tests and HIL, rather than mocking the whole system at once.
A task takes abstract peripheral interfaces; STM32 and SIL each supply their own implementation.
The old pattern had tasks reach out to global bindings:: peripherals directly, tying
every task to one board and making it impossible to substitute mocks for SIL. I moved the boundary to dependency
injection: a task takes its peripherals and shared resources as arguments, so the same code runs on the STM32 with
real drivers or in a SIL binary with mocks.
// BEFORE — task reaches for global bindings, hard-wired to one board void task_10hz() { float v1 = bindings::suspension_travel1.ReadVoltage(); // global bindings::veh_can.Send(TxSuspensionTravel12{...}); // global } // AFTER — dependencies injected; runs on STM32 or in SIL (racecar #529) void ReadAndSendTemperatures(float update_period_ms, VehBus& veh_can_bus, FanController& fan_controller, etl::array<TempSensor, kSensorCount>& temp_sensors);
I built a Raspberry Pi-based system that turns live CAN traffic into usable telemetry during testing while keeping a complete local record on an SSD.
CAN frames flow through DBC decoding, local storage, InfluxDB, and Grafana.
Dashboard views for live vehicle signals and fault monitoring.
Currently building. Reflashing an ECU used to mean physically reaching a board buried in the chassis and connecting a programmer. I'm building an over-the-air path instead: a Raspberry Pi pushes firmware to any ECU over the CAN bus the car already runs.
A resident bootloader on each ECU receives the image over CAN and reflashes the app in place.
In progress. SIL proves the logic; HIL proves the firmware on real hardware. I'm writing controller sequences that run the ECUs against simulated vehicle IO on our HIL rig, so we validate behaviour before anything touches the car.
Developing firmware for automated testing and designing analog circuitry for optical hardware, Ottawa ON
My work centred on validating hardware faster. I built a menu-driven ATE framework that follows a board from prototype through production: my firmware runs on a Raspberry Pi and drives a test board that plugs into a machine exercising the real production boards.
Fan-RPM test fixture used to validate the dedicated tachometer measurement circuit.
Pi-hosted firmware drives a test board connected to the hardware under test.
Firmware and real-time tooling for a digital instrument, Toronto ON
A faulty hall-effect sensor or a misaligned assembly could pass initial checks and only fail later in QA. I wanted those caught the moment a unit was built, so I wrote a C test sequence that streams live sensor data straight to the assembler.
Live hall-effect sensor readout used on the assembly line.
Personal project, STM32 hardware and firmware
I designed my own adapter end to end, board and firmware, and owned the full bring-up loop
Assembled STM32-based USB-to-CAN adapter board (Altium).
Schematic: USB-C, CAN transceiver with switchable termination, power regulation, and header.
STM32 firmware, Formula Electric vehicle
The LV BMS sits in the car's safety chain: it monitors cell voltages and enforces the constraints that decide whether the vehicle can run. Because it's safety-critical, I built the firmware around defensive, deterministic behaviour rather than clever features.
LV Controller to LV BMS over SPI; LV BMS to LV Battery through an ISOSPI transceiver.