Goodbye, Arduino.

Hello, Pearl.

Project Motivation

After a couple of years working with Arduino-based projects and AVR microcontrollers, I wanted a deeper understanding of the development boards I relied on. I also wanted to move beyond the Arduino IDE and start familiarizing myself with more professional programmers and IDE’s.

Most importantly: I wanted to make my projects more “mine”. Usually, when a project is ready to leave my desk for any kind of field testing or deployment, I was soldering headers to a PCB and attaching an entire dev board to the prototype. I wanted a controller that I knew inside-out, which could embed directly into the PCB designs of future projects.

Dev. Boards used in previous projects.

PCB Design

When it came to designing Pearl, I knew the real challenge and learning would come from the programming side. CubeIDE was brand new to me, and I wanted to focus on that. So, for the PCB design I decided to stick with what I already knew: EasyEDA.

While I’m comfortable with through-hole soldering and have done it plenty of times, I don’t have a reflow oven. This made EasyEDA’s integration with JLCPCB’s surface-mount assembly service the perfect fit, especially since Pearl was one of my first projects where I embraced surface-mount components. I had already ordered over 20 custom PCBs through JLCPCB for past projects—most were through-hole designs that I soldered myself, but a few had some surface-mount assembly done for me. For Pearl, I leaned into that convenience, letting me focus on refining the rest of the project.

Zoomed-in view of CPU in schematic.

Microcontroller

I knew I wanted something scalable, so I could apply what I learned across multiple projects. The STM32L412KBT6, an STM32 microcontroller with an ARM Cortex-M4 core, was the perfect choice for its scalability and adaptability. STM32 microcontrollers have a consistent architecture, making it easy to transfer knowledge from one series to another. This flexibility is great for future projects, whether they involve low-power designs or high-performance computing.

I also wanted a microcontroller with versatile features to learn how to work with different peripherals using a new IDE. The STM32L412KBT6 includes UART for serial communication, PWM for motor and LED control, I2C and SPI for connecting sensors and external devices, ADC for analog input, and GPIO for general-purpose signaling. These features give me plenty of opportunities to dive into hardware-level programming and deepen my understanding of embedded systems.

The STM32L412KBT6 mounted on Pearl v1.0.

User Interface

Normally, with Arduino, I rely on debugging messages via UART. With Pearl, I didn’t want to depend on setting up serial communication before getting a feel for the basics. I knew programming would be complicated, so I designed the hardware to make it easy to verify code and functionality with simple input and visual feedback. This led to some straightforward design decisions.

I added a power indicator LED connected directly to VIN to quickly confirm that the board was receiving power. I also included an LED on pin 15, allowing me to test code immediately without needing external components or debugging code. To simplify prototyping, I added a pushbutton on pin 31 for basic input tests and a reset button tied to RST for quick reboots during development. These small features saved time and let me focus on writing and testing code more effectively.

Power

Since I was the only one using this board, I felt comfortable regulating the voltage down to 3.3V with an LDO that has a relatively narrow input range of 1.9V–5.5V. Most of my planned tests were powered by USB at my desk, with the rest using either my adjustable desktop power supply or a custom external voltage regulator.

To protect my PC, I added a diode between the USB and VIN to prevent any backflow of current that could cause damage. I also allocated five GND pins, creating a larger ground network to avoid running out of connections during prototyping—something I had frequently encountered in earlier projects.

I left two VIN pins connected, to either receive power from an outside source, or pass USB power directly on to peripherals. I also included two regulated 3.3v outputs able to safely supply a total of 1.5 amps.

Power pins (VIN, GND, and 3.3v).

Pearl At Work

Currently, I’m using Pearl as the platform for a custom aerial drone stabilizing system. The setup includes a connection via ST-LINK for programming, a USB-TTL serial converter for debugging messages and commands, a BNO055 inertial measurement unit (IMU) for orientation data, and four LEDs representing the drone’s motors.

The IMU feeds data into a PID controller, which adjusts the duty cycles of the PWM signals sent to each LED. By observing the intensity of the LEDs, I can simulate and verify the functionality of the stabilizing system. Each LED represents a brushless motor’s ESC, so this setup allows me to test and refine the control system without connecting actual motors. It’s an efficient way to focus on understanding and fine-tuning the control aspects before moving to hardware with propellers.

Putting all of that together, it demonstrates Pearl’s UART, I2C, and PWM/Timer functionality.

Learning from Mistakes

Designing Pearl and implementing it in various projects has come with a slew of valuable lessons. Many of which have already been factored into the new design of Pearl v1.1.

Clockwork

Now that the system clock wasn’t being handled for me, I found that I had a lot to learn: High-speed versus low-speed. Internal versus external. Prescalers, muxes, and timers—I wasn’t used to thinking about any of these things prior to working on Pearl. This is why you can see a HSE crystal oscillator connected to the CPU’s LSE pins. Once I started programming Pearl, I learned that for my purposes, the CPU’s internal clock was more than sufficient. Pearl v1.1 may not even include an external clock. If it does, I’ll connect it to the right pins.

Brighter is Not Better

Perhaps out of pure vanity, I wanted the two onboard LED indicators to glow brilliantly. So, I only used 100-ohm current-limiting resistors, and I got way more than I bargained for. The LEDs are downright blinding. Whenever I work with the board, I have to angle it away or tape over it to protect my eyes. In the next iteration, I’ll be increasing the resistor values.

Traces and Pours

Outside mentorship pointed out that I overlooked adding a proper ground plane or pour in the initial design. Although the board functions, this omission could have caused noise issues in more complex setups. Additionally, I learned that USB communication relies on differential signaling, and my traces for those lines should have been routed closely together to avoid potential signal integrity problems. Pearl v1.1 will address both of these issues.

The Post-Arduino Learning Curve

It’s steep. Learning STM32 CubeIDE and CubeProgrammer has taken a great deal of patience, and I’ve only scratched the surface. The level of control and potential for optimization is exciting, but it comes at the cost of major delays as I muddle my way through registers, configurations, and bits. These lessons won’t have any direct impact on the next iteration of Pearl, because being forced to learn new programming techniques is a feature, not a bug.