Writing Project Atlas
By Andrew HigginsFull-Stack Engineer & Team Lead at Moat
The Schematic Is Not the Board
A four-layer STM32 control board for a Formula SAE car: the stackup, three different ways to switch a rail, and a debug feature that killed the 12 V supply.
Project Atlas is a four-layer control board built to replace the ageing electronics on BYU Racing's electric car. I led the electronics group, four of us, none of whom had designed a PCB before. In practice two of us did most of the work, and the board layout was entirely mine along with most of the schematic. This is what is on the board and what went wrong with it.
Stackup and the split plane
Four layers: ground pours on the top, bottom, and first inner layer, with the second inner layer carrying power. That last layer is not a plane so much as three planes sharing a sheet of copper, split into separate zones for 12 V, 5 V and 3.3 V.
Splitting one layer three ways is the compromise you make when you want a solid ground reference on both outer layers and cannot afford six layers. Ground stays continuous under every signal, which is what actually matters for return paths, and the three supplies get poured copper instead of traces. The cost is that the power layer now has boundaries in it, and anything passing through the board passes through whichever zone happens to be overhead. Hold that thought.
Power in
Twelve volts arrives through a 4 A fuse and a 100 uF bulk capacitor. An MPM3610 synchronous buck brings that to 5 V, and an ST1L05 linear regulator takes 5 V to 3.3 V. Using an LDO for the second stage is deliberate: the drop is small, the 3.3 V load is a microcontroller and some logic rather than anything hungry, and a linear part downstream of a switcher keeps switching noise off the analog supply. The STM32's VDDA gets a further ferrite bead and its own capacitors.
Three ways to switch a rail
The board exposes six switched outputs to the car, two per voltage, and they are not the same circuit three times. They are three different circuits, because the requirement is different at each voltage.
The 12 V channels are proper high-side switches. A GPIO drives a 2N7002 through a 1 k series resistor; the small NMOS pulls down the gate of an IRF9Z24S P-channel MOSFET that sits between the 12 V rail and the output, with a 10 k pull-up holding that gate at 12 V when the NMOS is off and a 100 k pull-down on the logic side so the channel is off during reset. You need the NMOS because the STM32 cannot pull a PMOS gate to 12 V, and you need the PMOS because switching the high side leaves the load's ground intact.
The 5 V channels are open drain. A 2N7002 with a 500 ohm pull-up to 5 V and a 1 nF capacitor on the output. This switch sinks rather than sources, which is the right shape for signalling to something that pulls itself up, and it is a great deal cheaper than another high-side stage.
The 3.3 V channels are the microcontroller's own pins. No switch at all.
Three answers to what sounds like one question. Worth saying plainly, because the earlier description of this board on my own site said all six were PMOS high-side switches, which was true of exactly two of them.
Sense comes back the other way: four ADC inputs, two on the 5 V outputs and two on the 3.3 V outputs, so firmware can read what the channel is actually doing rather than what it commanded.
CAN
Three independent buses, each on a TJA1051T-3. The car needs more than one, and the FDCAN peripherals on the STM32G474 provide three, so there are three transceivers rather than a shared bus with arbitration headaches.
The T-3 suffix is the point. It is the variant with a separate VIO pin: the transceiver runs VCC at 5 V for the bus side, which is where CAN's common mode range wants to be, while VIO ties to 3.3 V so the TXD and RXD pins match the microcontroller directly. No level shifters, no resistor dividers, no 5 V logic reaching a 3.3 V pin. One part number choice removes an entire class of interface bug.
We arrived at that part by argument. A teammate found a functionally equivalent TI transceiver and asked whether it would work; I asked him to explain why it would work instead, and the reasoning is how we ended up on the NXP part. A grad student had also told us early on to put one status LED per CAN line rather than one for the board. Those are on the delivered hardware, silkscreened LEDCAN1 through LEDCAN3, alongside indicators on the 3.3 V and 5 V rails.
USB-C, and the bridge that never worked
The USB port is a 16-pin Type-C receptacle with 5.1 k CC resistors, presenting the board as a device. Protection is layered: a PACDN042Y3R array and a TPD2EUSB30 on the data lines, plus a Schottky isolating the incoming USB power from the board's own 5 V rail so plugging in a laptop while the car is powered does not connect two supplies.
Behind that is a CP2102N bridging USB to one of the STM32's UARTs. The reasoning was that the G474 has native USB but using it means the bootloader, the pin assignment and the enumeration all become things you have to get right on your first board, whereas a bridge presents a serial port to any laptop and stays out of the way.
It did not work. The port enumerates on a computer, which was enough to tell us the connector, the protection and the bridge were alive, but we never got code onto the board through it. Programming happened over the six-pin ST-Link header instead. Diagnosing the USB path properly was still on the list when the year ended.
The fault
The board came back in mid March. Indicators lit, 5 V came up, 3.3 V came up, and 12 V was dead into a short.
We went looking for it the wrong way. A teammate took one of the spare bare boards and started cutting traces on the 12 V plane to bisect it. That works on a net made of tracks. Twelve volts on this board is a poured zone, and every pad sitting in that copper is already tied to everything else in it, so there is nothing to bisect. We spent two weeks with a technique that matched a different topology, and our conclusion drifted toward blaming a bad via at the fab, which is what you conclude once you have stopped suspecting yourself.
It was a test point.
The board carries single-pin test points for 12 V, 5 V, 3.3 V and three for ground. Every one is a plated through-hole, and every through-hole pad on this board keeps copper on all four layers. A through-hole pad is not a feature of the layer you placed it on. It is a column of copper through the entire stackup, and what it passes through on the way is whatever the split plane happens to be doing at those coordinates. Two of the ground test points sit inside the 12 V region of that power layer.
On the schematic none of this is visible. A ground test point is a pin on the ground net; the 12 V test point is a pin on the 12 V net; they are on different sheets and nothing connects them. The relationship only exists in the layout, in the third dimension, at coordinates the schematic does not have. That is the whole lesson and it is why this piece is called what it is. A schematic is a claim about connectivity. The board is a physical object, and it can be wrong in ways the claim cannot express.
I cut the test point away. The rail came back.
Where it ended
The programming path still did not work after that, and I never found out why. The school year ended, my time with the team ended, and the board is now being worked on by people who came after me.
So this is not a success story with a bow on it. The rails work, the indicators work, the CAN transceivers are populated and correct, and programming happens over a debug probe rather than the interface I designed for it. Someone else gets to find out what is wrong with the USB path.
What I would do differently is smaller than it sounds. Not fewer test points, more thought about what a test point physically is. On a board with a split power plane, every through-hole is a decision about all four layers at once, and a debug feature that crosses a plane it has no business crossing is not a debug feature. It is a fault waiting for a power-up.