,------.,--. ,--. ,--. ,------. ,--. ,--. ,--.
| .---'| | ,---. ,---.,-' '-.,--.--. ,---. ,--,--, `--' ,---. ,---. | .--. ',--.--. ,---. ,-| |,--.,--. ,---.,-' '-.`--' ,---. ,--,--,
| `--, | || .-. :| .--''-. .-'| .--'| .-. || \,--.| .--'( .-' | '--' || .--'| .-. |' .-. || || || .--''-. .-',--.| .-. || \
| `---.| |\ --.\ `--. | | | | ' '-' '| || || |\ `--..-' `) | | --' | | ' '-' '\ `-' |' '' '\ `--. | | | |' '-' '| || |
`------'`--' `----' `---' `--' `--' `---' `--''--'`--' `---'`----' `--' `--' `---' `---' `----' `---' `--' `--' `---' `--''--'
This week, we explored PCB fabrication using the Modela milling machine to understand the practical design limits of our in-house process. We characterized design rules such as trace width, spacing, and drill tolerances, and applied them to produce a functional PCB design ready for submission to a board house.
Using this mill file as a base, we found that 0.015 inches is the minimum trace width the Modela can process with a 1/64" end mill bit. Narrower traces either peel off the page or, in the case of a 'milled out' gap, are at the limit of being correctly registered in the CAM software. After testing and validating the PCB, we submitted the design to a board house for professional fabrication. This summary highlights the interaction between digital design, physical constraints, and precision manufacturing. Additional reflections, images, and step-by-step details will be provided on our shared web page.
Gert showing us how to use the modela mill
Tolerance test
As a complete newbie to PCB design, PCB stuffing, coding, what have you, I wanted to start really simple. Using last week's design of an RGB LED light that switches colors depending on what switches you throw on. One would be Red, one Blue and one Green. This would affect a LED somewhere else on the board. Simple right?
Schematic and Fabrication of my PCB
Tracing file for all the connections of my RGB board
OK so group project happened, I was excited to start milling my own board! Earlier in the week I went to two walkthroughs of the Modela SRM-20. But when I show up, 1 of the 2 PCB mills is already down. That's ok, I'll just wait in the queue. No biggie. I left myself plenty of time to design, build, program and debug this week. Immediately I see people experiencing errors with the Modela SRM-20. I would say 9/10 problems are with the interface between the PC and machine. There are two commands to punch into terminal in the JS folder. No indication of which one is the correct one on the Architecture Shops Website. Trial by fire, sure. There was a diagram that was kind of helpful.
I found that you need to constantly close the firefox explorer, the terminal and shut off the Modela cutter. Then you need to do the following:
node deviceserver.js ::ffff:127.0.0.1 1234
Why is it so finicky? if a mouse farts in the nearby room it might disturb the machine. It's high strung, you're high strung, everyone is taking way too long to get the only machine working. I am usually excellent at this, but last night I spent 2 hours trying to get a simple board milled. Read on.
The first board went relatively ok. When I went to cut the outline 1/32 path, unfortunately it pulled off the spoil board. I used plenty of tape and I applied tons of pressure but maybe the spoil board was over-spoiled.
Next board was good. When I went to cut out the board with the 1/32 end mill, the toolpath was offset inwards. Looking over the PNG, I realized that the issue was in the gerber to png application. You need to select 'Fill Edge Cut'. OK new board.
whoops, board went ok, but then the pin holes were cut way too wide, no idea why. Also there should not be pin holes. I just put those on a different layer. New board.
The traces are really narrow. I assume that the 1/64 end mill that I was using was damaged. It's ok. I'll just run another one. At this point, who cares!
I see the curse has not yet been lifted. No idea why but the board lifted again. Once again, plenty of tape. Maybe the heavens have it out for me.
This board was finally ok! time to 'stuff' it.
First I had to closely inspect the pathways to make sure that there were no bridges caused by frayed edges or metal splinters connecting paths that were not supposed to connect
Next up, I needed to make sure I had the correct inventory of parts. Above is showing a backing paper with the relevant parts labeled.
In order to select the correct resistors, I had a little bit of issue. I needed to look up the RGB LED that I was feeding to make sure I did not overwhelm the power requirements while not over-resisting where the light would not even be visible
According to the data sheet for the LED - the CLV1A-FKB: PLCC4 3 in 1 SMD LED - I needed to identify the forward voltage of the red, green and blue diodes.
To safely use the CLV1A-FKB RGB LED with the Seeed XIAO RP2040, I needed to calculate the correct series resistor for each color. The LED datasheet specifies the forward voltage for each diode (Red: 2.0 V typical, Green: 3.2 V typical, Blue: 3.2 V typical) and a forward current of 20 mA.
The XIAO RP2040 GPIO pins operate at 3.3 V and are limited to around 15 mA per pin for safe operation. Because of this lower voltage and current limit, I could not drive the LED at the full 20 mA typical current without risking damage to the board.
Using the Ohm’s Law LED resistor calculator, I applied the formula:
R = (Vsupply − VF) ÷ IF
Where Vsupply is the GPIO voltage (3.3 V), VF is the forward voltage of the LED, and IF is the desired current (I chose 10 mA to stay safe). This gave the following recommended resistances:
Because the green and blue channels barely exceed the GPIO voltage, driving them directly from the XIAO is not ideal. For safe and bright operation, the LED should be powered by 5 V through a transistor or MOSFET, using the XIAO only to control the switches. This ensures all colors illuminate properly without exceeding the microcontroller's current limits.
I found the digital magnification to be a complete asset to soldering my board together. A few things came up. I found the resistors as a bridge to work really well! And using a 0 ohm resistor was a great strategy to jumping over another line and looks pretty cool as well. The LED was hellish to solder, unfortunately. I think that I was completely underestimating what size it would be and it was really challenging to get a solder connection to all its four pins!
Final board. Now its time to trying some code out.
What should have been a straightforward coding exercise turned into a deep dive into the unpredictable world of debugging. The process taught me that sometimes, the problem isn't the code but the hardware's ghost in the machine.
Above left is before, and above right is after
Still nothing was lighting up. I decided to double check over the CLV1A-FKB: PLCC4 3 in 1 SMD LED Data sheet to make sure that the Anode and Cathode plugs were correct. The footprint from the fab library is completely misleading. You can clearly see the anode in a different spot. It's not just an issue of notation on the LED component but is an issue with its footprint and geometry as well. I had to rotate the entire component and override the footprint in kicad in order to make an entirely new board as the LED has a rectangular ratio and not a square pin layout. I double checked with Griffin's github website where he had the correct orientation. I'm not sure why my library component from Fab was so incorrect, but it did cost me some time and my sanity.
I tried to fix the problem initially through some janky solution to see if I could get a LED light working correctly. Ultimately I decided it was somehow quicker to just redo everything from exporting gerber files to milling to stuffing.
Rotating the LED seemed to work! Unfortunately now, two issues still persist. One is that the colors of the LED do not change, the second is that then pins do not seem to change the readout of high or low. The debugging continues!
Code for Simple ON/OFF with Three Switches. The slide switches (D0, D1, D2) are controlling the corresponding Red, Green, and Blue LEDs (D10, D8, D9).
// --- PIN ASSIGNMENTS ---
const int RED_PIN = 10;
const int GREEN_PIN = 8;
const int BLUE_PIN = 9;
const int SW_RED = 0; // Red Switch Input (D0)
const int SW_GREEN = 1; // Green Switch Input (D1)
const int SW_BLUE = 2; // Blue Switch Input (D2)
void setup() {
// Set LED pins as outputs
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
// Set Switch pins as inputs with internal PULLUP resistors
// HIGH (1) = Switch Open, LOW (0) = Switch Slid to GND
pinMode(SW_RED, INPUT_PULLUP);
pinMode(SW_GREEN, INPUT_PULLUP);
pinMode(SW_BLUE, INPUT_PULLUP);
// Initialize all LEDs to OFF state (Common Anode: HIGH = OFF)
digitalWrite(RED_PIN, HIGH);
digitalWrite(GREEN_PIN, HIGH);
digitalWrite(BLUE_PIN, HIGH);
}
void loop() {
// Read the state of the switches
bool redPressed = (digitalRead(SW_RED) == LOW);
bool greenPressed = (digitalRead(SW_GREEN) == LOW);
bool bluePressed = (digitalRead(SW_BLUE) == LOW);
// Control Logic (If switch is slid/LOW, set LED LOW/ON)
digitalWrite(RED_PIN, redPressed ? LOW : HIGH);
digitalWrite(GREEN_PIN, greenPressed ? LOW : HIGH);
digitalWrite(BLUE_PIN, bluePressed ? LOW : HIGH);
delay(10);
}
My initial Ohm's Law calculations were for a safe operating current, but they were too high for the Green and Blue LEDs to turn on at all with a 3.3V power source. I learned that for a Common Anode setup, high-value resistors can prevent current flow if the voltage drop across the LED is too high. My fix was to use a 100 ohm resistor for Red and a 25 ohm resistor for Green and Blue. I was told by other people that these values of resistors are not used, so I said I'd try to keep with 100 anyway, as a 0 ohm resistor would damage my board.
Even with the correct resistors, the LEDs stayed permanently on and the switches were unresponsive. Using the Serial Monitor, I confirmed that the microcontroller's input pins were stuck at a permanent LOW state, which is typically caused by a short circuit to Ground. The same issue was preventing the LEDs from turning off, as the short was holding their control pins at 0V.
// --- PIN ASSIGNMENTS (Switch Inputs Only) ---
const int SW_RED = 0;
const int SW_GREEN = 1;
const int SW_BLUE = 2;
void setup() {
pinMode(SW_RED, INPUT_PULLUP);
pinMode(SW_GREEN, INPUT_PULLUP);
pinMode(SW_BLUE, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("--- Switch Diagnosis Mode ---");
Serial.println("Expected: 1 when open, 0 when slid.");
}
void loop() {
int redState = digitalRead(SW_RED);
int greenState = digitalRead(SW_GREEN);
int blueState = digitalRead(SW_BLUE);
Serial.print("Red: "); Serial.print(redState);
Serial.print(" | Green: "); Serial.print(greenState);
Serial.print(" | Blue: "); Serial.println(blueState);
delay(10);
}
Just when I gave up, I sent my work to Anthony who immediately noticed my error. The pins in the Xiao RP2040 are read differently in code. I updated my code following his advice to include 'D' before the digital pins. I feel silly how simple a mistake that was!
// --- PIN ASSIGNMENTS ---
const int RED_PIN = D10;
const int GREEN_PIN = D8;
const int BLUE_PIN = D9;
const int SW_RED = D0; // Red Switch Input (D0)
const int SW_GREEN = D1; // Green Switch Input (D1)
const int SW_BLUE = D2; // Blue Switch Input (D2)
void setup() {
// Set LED pins as outputs
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
// Set Switch pins as inputs with internal PULLUP resistors
// HIGH (1) = Switch Open, LOW (0) = Switch Slid to GND
pinMode(SW_RED, INPUT_PULLUP);
pinMode(SW_GREEN, INPUT_PULLUP);
pinMode(SW_BLUE, INPUT_PULLUP);
// Initialize all LEDs to OFF state (Common Anode: HIGH = OFF)
digitalWrite(RED_PIN, HIGH);
digitalWrite(GREEN_PIN, HIGH);
digitalWrite(BLUE_PIN, HIGH);
}
void loop() {
// Read the state of the switches
bool redPressed = (digitalRead(SW_RED) == LOW);
bool greenPressed = (digitalRead(SW_GREEN) == LOW);
bool bluePressed = (digitalRead(SW_BLUE) == LOW);
// Control Logic (If switch is slid/LOW, set LED LOW/ON)
digitalWrite(RED_PIN, redPressed ? LOW : HIGH);
digitalWrite(GREEN_PIN, greenPressed ? LOW : HIGH);
digitalWrite(BLUE_PIN, bluePressed ? LOW : HIGH);
delay(10);
}
| Red | Green | Blue | Resulting Color |
|---|---|---|---|
| 0 | 0 | 0 | Off / Black |
| 1 | 0 | 0 | Red |
| 0 | 1 | 0 | Green |
| 0 | 0 | 1 | Blue |
| 1 | 1 | 0 | Yellow |
| 1 | 0 | 1 | Magenta / Pink |
| 0 | 1 | 1 | Cyan / Aqua |
| 1 | 1 | 1 | White |
I wanted to see the Serial Monitor output so I could see what’s happening in real time, as in which switches are pressed and which LEDs are on.
// --- PIN ASSIGNMENTS ---
const int RED_PIN = D10;
const int GREEN_PIN = D8;
const int BLUE_PIN = D9;
const int SW_RED = D0; // Red Switch Input (D0)
const int SW_GREEN = D1; // Green Switch Input (D1)
const int SW_BLUE = D2; // Blue Switch Input (D2)
void setup() {
// Initialize Serial communication
Serial.begin(9600);
while (!Serial) {
; // Wait for Serial to initialize (optional on some boards)
}
Serial.println("System initialized. Waiting for switch input...");
// Set LED pins as outputs
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
// Set Switch pins as inputs with internal PULLUP resistors
pinMode(SW_RED, INPUT_PULLUP);
pinMode(SW_GREEN, INPUT_PULLUP);
pinMode(SW_BLUE, INPUT_PULLUP);
// Initialize all LEDs to OFF (Common Anode: HIGH = OFF)
digitalWrite(RED_PIN, HIGH);
digitalWrite(GREEN_PIN, HIGH);
digitalWrite(BLUE_PIN, HIGH);
}
void loop() {
// Read the state of the switches
bool redPressed = (digitalRead(SW_RED) == LOW);
bool greenPressed = (digitalRead(SW_GREEN) == LOW);
bool bluePressed = (digitalRead(SW_BLUE) == LOW);
// Control LEDs (LOW = ON for Common Anode)
digitalWrite(RED_PIN, redPressed ? LOW : HIGH);
digitalWrite(GREEN_PIN, greenPressed ? LOW : HIGH);
digitalWrite(BLUE_PIN, bluePressed ? LOW : HIGH);
// Send serial output
Serial.print("Red: ");
Serial.print(redPressed ? "ON" : "OFF");
Serial.print(" | Green: ");
Serial.print(greenPressed ? "ON" : "OFF");
Serial.print(" | Blue: ");
Serial.println(bluePressed ? "ON" : "OFF");
delay(200); // Small delay to make serial output readable
}
My original idea was to create an RGB light where R, G and B would be mapped to capacitance sensing. I was inspired by Quentin's board . I have run out of time, but I will aim to mill this shortly after class to see if it works.
It's a slight adjustment of my current switch configuration.
I had to overlay a few shapes in photoshop to break some of my design rules
Despite the horrors, I now have a working RGB switch board, and I feel much more confident handling SMD components, calculating resistor values, and debugging hardware-software interactions.