Electronics design
weekly schedule.
| Time block | Wed | Thu | Fri | Sat | Sun | Mon | Tue | Wed |
|---|---|---|---|---|---|---|---|---|
| Global class | 3 h | |||||||
| Local class | 1,5 h | 1.5 h | ||||||
| Research | 2 h | 2 h | 1 h | |||||
| Design | 3 h | 2 h | ||||||
| Fabrication | ||||||||
| Documentation | 2 h | 1h | 1 h | 4 h | ||||
| Review |
background.
Electronics has been part of my training since university. During my engineering degree I worked extensively with circuit simulation — I ran my first electrical circuit simulations in PSpice, which gave me a solid foundation for understanding component behaviour before building anything physical. That said, the transition from schematic simulation to PCB design and physical fabrication is a different discipline, and this week was my first structured exposure to the full pipeline.
On the measurement side, the multimeter is a tool I use daily in my professional work as an automation and robotics engineer. Continuity checks, voltage verification, and basic component testing are routine tasks on industrial control systems, so that part of this week felt immediately familiar.
overview
This week is about electronics design — taking a circuit idea all the way from schematic to a fabrication-ready PCB using an EDA tool. Coming from an automation and robotics background, I deal with PLCs and pre-built boards every day, but I have never actually designed my own PCB from scratch. So this is genuinely new territory for me.
I used KiCad 9 (the CERN-backed open-source EDA tool) to design a simple development board around the Seeed XIAO RP2040 — the same microcontroller I have been working with since Week 04. The board has a socket for the XIAO, an LED with a current-limiting resistor, a tactile button with a pull-down resistor, and open header pins for future expansion. Simple on paper, but the real learning is in the process itself: understanding ERC errors, figuring out trace routing by hand, exporting SVGs correctly, and navigating the frankly unintuitive mods Project interface to generate toolpaths for the Roland MDX-20.
learning objectives.
- Understand the full PCB design workflow: schematic → layout → fabrication files
- Learn to use KiCad 9 (schematic editor, PCB editor, ERC, DRC)
- Use the Fab Lab component libraries for KiCad
- Understand what ERC and DRC check and why they matter
- Generate fabrication-ready SVG files for PCB milling
- Prepare toolpaths with mods Project for the Roland MDX-20
- Use test equipment to observe microcontroller operation (group assignment)
- Simulate a circuit
assignments.
- Group assignment: Use the test equipment in the lab to observe the operation of an embedded microcontroller circuit (multimeter, oscilloscope, logic analyzer minimum)
- Individual assignment — Simulate a circuit
- Individual assignment — Design an embedded microcontroller system using parts from the Fab inventory, check design rules for fabrication
- Extra credit: try another design workflow
- Extra credit: design a case
group assignment — Test equipment.
For the group assignment, we need to demonstrate the use of test equipment on a microcontroller circuit board. I am documenting the instruments I will be working with. The actual testing will happen once the board is fabricated in Week 08 (Electronics Production).
Multimeter — Fluke 179 True RMS.
This is my personal multimeter. I bought it years ago and it has been my daily instrument in the field — verifying motors, checking power distribution panels, debugging industrial control systems. It is the kind of tool you learn to trust.
| Feature | Specification |
|---|---|
| DC voltage | 0.1 mV – 1000 V |
| AC voltage | 0.1 mV – 1000 V (True RMS) |
| DC/AC current | 0.01 mA – 10 A |
| Resistance | 0.1 Ω – 50 MΩ |
| Capacitance | 1 nF – 9999 μF |
| Temperature | -40 °C – 400 °C |
| Safety rating | CAT III 1000 V, CAT IV 600 V |
I want to highlight the CAT III/IV rating specifically. In automation and robotics consulting, I frequently need to verify voltages on motors, power distribution lines, and control cabinets running at 380 V and 400 V AC. Having probes rated for those voltages is a safety requirement, not a luxury.
Testing and measurements with multimeter.
I recorded a demonstration of the different measurements and tests I performed on my XIAO RP2040 board using a digital multimeter. The video shows:
- Voltage measurements across the integrated LED (parallel mode).
- Continuity tests on PCB traces and solder joints.
- Diode check mode to verify LED polarity and functionality.
- Attempts to measure current consumption and the limitations encountered with integrated components.
Multimeter testing: voltage measurements, continuity checks, and diode verification on XIAO RP2040 board
This hands-on testing helped me understand the practical challenges of characterizing integrated modules versus discrete components.
Oscilloscope — DSO Shell (DIY kit).
An oscilloscope displays electrical signals as waveforms: voltage on the vertical axis, time on the horizontal. Unlike a multimeter, which gives you a single static reading, an oscilloscope shows how a signal behaves over time — its shape, frequency, amplitude, and duty cycle. That makes it the right tool for anything involving PWM, communication protocols, or any signal that changes faster than a display can follow.
The DSO Shell at Fab Lab León is a pocket unit assembled from a DIY soldering kit. It runs on a 9 V battery and has limited bandwidth compared to a bench instrument, but it is fully adequate for inspecting microcontroller-level signals.
What do we expect to see?
PWM (Pulse Width Modulation) does not actually vary the voltage on a pin — it varies the proportion of time the pin spends at its high logic level within each cycle. At 1 kHz, the pin switches on and off 1000 times per second. The RP2040 operates at 3.3 V logic, so the pin alternates between 0 V and 3.3 V at that rate. The LED cannot respond fast enough to each individual pulse, so it perceives the average — which is why it appears to fade smoothly even though the pin is always either fully on or fully off.
On the oscilloscope screen we therefore expect to see a rectangular wave — clean vertical edges, a flat top at ~3.3 V, a flat bottom at 0 V — and the width of the high pulse changing continuously as the duty cycle ramps up and down. The carrier frequency should read close to 1000 Hz, and the Vpp should be close to 3.3 V.
Verifying the setup in Thonny.
Before connecting the oscilloscope, I went through a few steps to confirm the signal was actually present on the target pin.
Step 1 — Confirm the interpreter. In Thonny, Tools → Options → Interpreter must be set to MicroPython (RP2040) on the correct COM port. The status bar at the bottom of the window confirms this.
Step 2 — Check available pins. With no datasheet for the Qpad immediately at hand, I queried the board directly from the Thonny shell:
from machine import Pin
print(dir(Pin.board)) # lists all GPIO names exposed by the firmware
This returned all GPIO names available on the firmware, confirming GP26 (D0) was present and unassigned.
Step 3 — Verify PWM on the target pin. Before running the full fading loop, I sent a static 50 % duty cycle to GP26 to confirm the pin was functional:
from machine import Pin, PWM
p = PWM(Pin(26)) # assign PWM peripheral to GP26 (physical pad D0)
p.freq(1000) # set carrier frequency to 1 kHz
p.duty_u16(32768) # 32768 out of 65535 = 50 % duty cycle
print("OK") # confirm execution reached this line
The shell returned OK and the LED lit at half brightness — confirming the pin was outputting PWM correctly.
Step 4 — Run the fading script. Once the static test passed, I loaded the full script:
from machine import Pin, PWM
from time import sleep
led = PWM(Pin(26)) # assign PWM to GP26 — D0 header pin, accessible with a probe
led.freq(1000) # 1 kHz carrier: 1000 on/off cycles per second
while True:
# ramp duty cycle up from 0 % to 100 %
for duty in range(0, 65536, 512): # 65535 = full on in MicroPython's u16 scale
led.duty_u16(duty) # update duty cycle
sleep(0.01) # wait 10 ms before next step
# ramp duty cycle back down from 100 % to 0 %
for duty in range(65536, 0, -512):
led.duty_u16(duty)
sleep(0.01)
The LED faded smoothly and continuously. With the signal confirmed active on D0, the oscilloscope probes could be connected with confidence.
Measurement.
The board used is the Qpad — a didactic game pad built around the XIAO RP2040, developed at CBA MIT. The black probe goes to a GND pad on the board; the red probe to the D0 header pin on the XIAO.
The DSO Shell was configured at 1 V/div vertically and 0.2 ms/div horizontally.
| Parameter | Measured | Expected |
|---|---|---|
| Frequency | 1.112 kHz | 1.000 kHz |
| Period | 0.898 ms | 1.000 ms |
| Vpp | 3.40 V | 3.30 V |
| Duty cycle | 83.6 % | 0–100 % (sweeping) |
| Vrms | 1.21 V | — |
Is this coherent with what we expected?
Yes, completely. The waveform is a clean rectangular wave — confirming the pin switches fully between its two logic states with no intermediate levels, exactly as PWM requires.
The frequency reads 1.112 kHz against the 1000 Hz set in code. The discrepancy comes from the overhead of the MicroPython interpreter executing the sleep() calls and the loop itself, which adds a few microseconds per cycle. This is normal and expected when generating PWM this way in MicroPython.
The Vpp of 3.40 V against the nominal 3.3 V of the RP2040 is within the DSO Shell’s calibration tolerance — a 3 % deviation is entirely acceptable for this instrument.
The duty cycle of 83.6 % simply reflects the exact moment in the fading sweep at which the oscilloscope triggered. Had the screenshot been taken a moment earlier or later it would show a different value — which is precisely the point: the duty cycle is what the code is changing continuously, and the oscilloscope captures it at one instant.
All observations are consistent with the code, with the expected behaviour of PWM, and with the visual result seen on the LED.
DSO Shell measuring the PWM output on pin D0 of the Qpad (XIAO RP2040). The waveform shifts as the duty cycle changes during the fading cycle.
Logic analyzer — 24 MHz 8-channel.
A logic analyzer captures digital signals over time and displays them as timing diagrams. Unlike an oscilloscope, which measures voltage as a continuous analogue value, a logic analyzer only resolves high and low states — but it does so with high timing precision and can decode communication protocols (I2C, SPI, UART) automatically. For a PWM signal, the key advantage over the oscilloscope is the ability to capture several seconds of data and see how the duty cycle evolves across the entire recording.
The unit at Fab Lab León is a generic 8-channel USB device compatible with the Saleae Logic 2 software (version 2.4.42). It connects to the computer via USB and requires no external power.
Setup in Logic 2
Configuration used:
- Sample rate: 12 MS/s (closest available to the recommended 10 MS/s)
- Capture mode: Timer — 3 seconds
- Analyzers: none — PWM is not a serial protocol, so no decoder is needed
- Channel: D0 only (CH0 on the logic analyzer)
- Glitch filter: enabled
Connections are identical to the oscilloscope: CH0 cable to D0, GND cable to a GND pad on the Qpad.
Capture results
Logic 2 capturing the PWM output on pin D0 of the Qpad (XIAO RP2040). The full 3-second timeline shows the duty cycle sweeping continuously as the fading script runs.
Oscilloscope vs logic analyzer — same signal, two perspectives
Both instruments measured the same PWM signal on pin D0. The results are consistent and complementary:
| Parameter | DSO Shell (oscilloscope) | Logic 2 (logic analyzer) |
|---|---|---|
| Frequency | 1.112 kHz | 1.000 kHz |
| Period | 0.898 ms | 0.999 ms |
| Duty cycle | 83.6 % | 75 % |
| Vpp | 3.40 V | — (digital only) |
| Timeline view | Single frame | Full 3 s sweep |
The duty cycle and frequency differ between the two readings because each instrument captured a different moment in the fading sweep — the duty cycle is continuously changing, so any two snapshots will show different values. Both are correct for their respective instants.
The oscilloscope provides the voltage dimension — confirming the signal swings between 0 V and 3.3 V as expected. The logic analyzer provides the time dimension — the overview capture makes it immediately visible that the pulse width is sweeping across the full recording, something the oscilloscope cannot show in a single frame.
Neither instrument alone tells the complete story. Together they give a full characterisation of the signal.
Individual assignment — PCB design with KiCad
Setting up KiCad 9 and the Fab libraries
First step: install KiCad 9 and import the Fab Lab component libraries. These libraries contain symbols and footprints for the components available in the Fab inventory, which ensures whatever I design can actually be built with what we have in stock. The installation process follows the Fab Academy KiCad tutorial.
One important detail: when searching for components in the schematic editor, I had to make sure I was looking inside the Fab library folders specifically, not the default KiCad libraries. The Fab footprints match the actual parts we have.
Schematic design — first iteration
My board follows the minimum requirements for this week: a XIAO RP2040 on a socket, one LED, one tactile button, and open pins for future use. The circuit is straightforward:
- M1:
Module_XIAO_Generic_SocketSMD— the XIAO socket from the Fab library - D1:
LED_1206— a 1206-package LED connected to pin D0 - R1: 1 kΩ resistor — current limiting for the LED (calculated for ~2 mA at 3.3 V with a ~1.8 V forward drop)
- SW1:
Switch_Tactile_Omron— a tactile push button connected to pin D1 - R2: 470 Ω resistor — pull-down for the button
A couple of things I got wrong on this first pass that Claude pointed out during our design session:
Resistor naming. I initially named the 1 kΩ resistor R1K, which is not standard EDA practice. The convention is to use a sequential reference designator (R1, R2, R3…) and put the value separately. KiCad’s annotation tool later caught this and renamed it to R1K1, which is still ugly. I ended up fixing it to just R1 with a value of 1K.
Unused pins need no-connect flags. Pins D2 through D10 are intentionally unused in this design, but KiCad does not know that. Without explicit no-connect flags (the X symbol), the ERC will flag every single one as an unconnected pin warning. In KiCad 9, you place them via Place → No Connect Flag or the shortcut Q.
Running the ERC — and learning from the errors
The Electrical Rules Check is where things got interesting. I ran it and got a wall of violations.
The 4 warnings were about global labels (D0, D1, A0, A1) not being connected elsewhere in the schematic — single-sheet design, used once. Not a real problem.
The 3 errors were more puzzling: “Input Power pin not driven by any Output Power pins” on the XIAO’s 3V3 (pin 12), 5V (pin 14), and GND (pin 13). What does this even mean?
Claude’s explanation: The XIAO symbol in the Fab library defines 3V3, 5V, and GND as Power Input pins. KiCad expects every Power Input pin to be driven by a corresponding Power Output pin somewhere in the schematic. But since the XIAO generates these voltages internally from USB, there is no explicit Power Output pin in my schematic feeding those nets. The ERC sees undriven power rails and flags them as errors.
The fix: add a PWR_FLAG symbol to each of these nets. PWR_FLAG tells the ERC that the net is indeed powered. It is annotation-only — it does not add any physical component to the board.
This was a genuine “aha” moment. The circuit works perfectly fine without the flags, but understanding why the ERC complains — and resolving it properly instead of just ignoring the errors — felt like the right approach.
Final schematic
The final schematic includes all the fixes: PWR_FLAG on the three power nets, no-connect flags on all unused XIAO pins, and properly named components. The ERC passes clean.
PCB layout — manual routing.
Moving from schematic to PCB layout, the first thing I did was set up the track widths in Board Setup → Design Rules → Pre-defined Sizes: 0.4 mm (standard for Fab Academy boards milled with a 1/64” endmill) and 0.8 mm as a wider option. In practice, I routed everything at 0.4 mm.
I routed every trace manually — no autorouter. The principle is straightforward: keep traces as short and direct as possible. Less resistance, cleaner signal paths, and easier to mill. With only a handful of components, the routing was manageable, though I had to think carefully about physical placement to avoid crossings on a single-layer board.
Design Rules Check (DRC).
Once the layout was complete, I ran the DRC with “Test for parity between PCB and schematic” enabled. This checks not only physical design rules (minimum clearances, track widths) but also verifies that the PCB matches the schematic — no missing connections, no extra traces.
Clean. Zero violations, zero unconnected items, zero schematic parity errors.
Exporting SVGs for fabrication.
For milling on the Roland MDX-20, we need SVG files — one for copper traces (F.Cu layer) and one for the board outline (Edge.Cuts layer). I went to File → Plot and configured the export:
I opened the exported SVGs in Illustrator to verify they looked correct before feeding them into mods:
Verifying toolpaths with mods.
mods Project is a web-based tool for generating machine toolpaths. It is… not the most intuitive interface I have ever used. The entire thing is a visual node-based pipeline where you connect processing modules with cables. Powerful in concept, overwhelming in practice when you first open it.
Before going further, I wanted to verify the toolpath visually — roughly like a slicer preview in 3D printing. I loaded the PNG exported from the Gerber file (converted using gerber2png.fablelab.kerala.in) into mods and the result was completely wrong.
My instructors and I spent time troubleshooting — different export settings, different mods configurations. Nothing resolved it. The breakthrough came during a session with Nuria (one of the local instructors): she shared a PNG that had previewed correctly on her laptop, I loaded it on mine, and it was still broken. At that point I noticed the mods interface had changed slightly — it looked like the tool had been updated. On a hunch, I tried Firefox instead of Brave.
Brave is built on Chromium — the same open-source engine that powers Chrome — yet Chrome rendered mods correctly while Brave did not. The most likely explanation involves Brave’s aggressive privacy features, which by default can intercept or modify WebAssembly execution and canvas-based rendering. mods relies heavily on both for its toolpath computation. Maybe disabling Brave Shields for the mods domain could likely resolve it, but I have not confirmed this. For now, Firefox or Chrome are the verified browsers for running mods at Fab Lab León.
The milling parameters are configured in the “set PCB defaults” module:
| Profile | Tool diameter | Cut depth | Max depth | Offsets | Speed |
|---|---|---|---|---|---|
| Mill traces (1/64”) | 0.40 mm | 0.10 mm | 0.10 mm | 4 | 4 mm/s |
| Mill outline (1/32”) | 0.79 mm | 0.61 mm | 1.83 mm | 1 | 4 mm/s |
| Mill traces (10 mil) | 0.25 mm | 0.10 mm | 0.10 mm | 4 | 2 mm/s |
The mill raster 2D module is where you hit Calculate to generate the toolpath:
The save file problem.
After hitting Calculate, nothing happened when I tried to save the .rml file. Looking at the output section more carefully, I realized the save file module was disconnected — the on/off switch routing the toolpath output to “save file” was off (grey), while the switch going to WebUSB (direct machine connection) was active.
The fix: click the lower on/off toggle to activate the save file route, then re-run Calculate. The .rml downloaded immediately. But it took me a while to figure this out — the visual feedback in mods is subtle and the documentation is sparse. Estimated machining time shown by mods: approximately 1 hour 25 minutes.
The actual milling will happen in Week 08 — Electronics Production.
Workflow diagram.
After going through this entire process, I want to leave a clear reference for my future self. This is the complete flow from idea to fabrication-ready files:
flowchart TD
A["Install KiCad 9 + Fab Libraries"] --> B["Schematic Editor"]
B --> B1["Place components from Fab library"]
B1 --> B2["Wire connections"]
B2 --> B3["Add PWR_FLAG to power nets"]
B3 --> B4["Add no-connect flags to unused pins"]
B4 --> B5["Run Annotate"]
B5 --> C["Run ERC"]
C -->|Errors| B
C -->|Clean| D["PCB Editor"]
D --> D1["Set track widths — Board Setup\n0.4 mm for 1/64 inch endmill"]
D1 --> D2["Place and arrange components"]
D2 --> D3["Route traces manually"]
D3 --> D4["Draw board outline — Edge.Cuts"]
D4 --> E["Run DRC with schematic parity"]
E -->|Errors| D
E -->|Clean| F["Export SVG — File → Plot"]
F --> F1["F.Cu layer → traces"]
F --> F2["Edge.Cuts → outline"]
F1 --> G["mods Project"]
F2 --> G
G --> G1["Load SVG into\nRoland Monofab PCB pipeline"]
G1 --> G2["Select tool profile\n1/64 in traces · 1/32 in outline"]
G2 --> G3["Calculate toolpath"]
G3 --> G4["Activate save file switch"]
G4 --> H["Download .rml file"]
H --> I["Mill on Roland MDX-20\nWeek 08"]
style A fill:#0FD9B0,stroke:#0a8a6e,color:#000
style I fill:#0FD9B0,stroke:#0a8a6e,color:#000
Simulation
Pending — I plan to simulate the LED + button circuit in Wokwi before fabrication.
Reflection
This was my first time designing a PCB from scratch, and honestly, the hardest part was not the circuit itself — it was navigating the tools. KiCad is powerful but has a steep learning curve, especially around library management and understanding what the ERC is actually telling you. The PWR_FLAG issue is a perfect example: the error message is technically correct but completely opaque if you do not already know how KiCad models power pins internally.
mods Project was the other surprise. The node-based pipeline is flexible, but the UI gives very little feedback about what is connected and what is not. The save file switch being off by default cost me a good chunk of time just staring at the screen wondering why nothing was downloading. And then the browser compatibility issue added another layer of frustration — spending time debugging a toolpath rendering problem that turned out to be a Brave vs. Firefox issue is not where you expect to lose an afternoon.
On the positive side, routing traces by hand on a simple board was satisfying. There is something appealing about finding the cleanest path for each connection, keeping things short and direct. I can see how this becomes a real puzzle on more complex boards.
The connection to my final project is clear: eventually I will need to design the control PCB for my standing desk — managing four synchronized motors with PID control, reading encoder feedback, driving a TFT display, and handling user input. This week’s board is trivial compared to that, but the workflow is the same. Just more components, more nets, and tighter constraints.
Design files
{/* TODO: add .rml files once milling is confirmed */}