← Personal Projects / Portfolio

LocalGadgetGarage project journal

STM32 RGB Lamp

Can a lamp be fashionable? I am sure millions of people will say "Yes, Of Course!". Well, this lamp definitely isn't. The cool thing is that it can be. I'm going to be introducing what I consider a pretty neat project. Similar to my previous project, the LED Tow Hitch, this lamp takes advantage of magnets to allow a user to swap designs based on their personality, mood, season, or anything else they can think of. Furthermore, we are able to integrate powerful RGB LEDs and a microcontroller, allowing for some pretty fun effects.

01

Introduction

Can a lamp be fashionable? An interior designer would say so. This lamp definitely isn't. The cool thing is that it can be. I'm going to be introducing what I consider a pretty neat product. Similar to my previous project, the LED Tow Hitch, this lamp takes advantage of magnets to allow a user to swap designs based on their personality, mood, season, etc. Even better, because this is a lamp meant to accessorize your desk or a shelf, we are able to integrate powerful RGB LEDs and a microcontroller, allowing for some pretty fun effects.

Project image
STM32-Based RGB Lamp
STM32-Based RGB Lamp
STM32-Based RGB Lamp
02

Project Overview

This project consists of 3 main components:

  • LED PCB: We will need to create a compact board that can fit within the lamp housing.
  • Firmware: We will need to create firmware that will run on the microcontroller for the LED effects;
  • 3D Printed, Modular, Enclosure: We will need a stylish enclosure that can protect the PCB and easily swap designs;
03

Watts Up? [Input Power]

Before starting a project, I like to picture how I want the product to be powered. A battery? USB? For this lamp, I envisioned myself plugging into an outlet near my desk. With this in mind, I have had great experiences using AC/DC wall plugs. They are cheap, plentiful on Amazon, and they are sold in a wide variety of voltage and amperage ratings.

STM32-Based RGB Lamp
04

Glowing with the Flow [RGB LEDs]

RGB LEDs are very common electronics. Manufacturers like JLCPCB have thousands to choose from. However, because I planned on having JLCPCB do the assembly for me, I was limited in the components I could pick. One non-negotiable was that I wanted an LED with a built-in IC. This, at a minimum, means I wouldn’t have to worry about managing current like I had to with the tow hitch cover. I also didn't need any high-current or ultra-brigh LEDs because those typically require more heat management consideration. This narrowed down my choices significantly, and I settled on the SK6812 series LED.

STM32-Based RGB Lamp
05

Microcontroller

For the microcontroller, I was already set on the ST-family, mainly because I am very familiar with their microcontrollers and tools. I settled on ST's STM32G0F6, ST's 'Budget Line'. The G0 has basic peripherals like I2C, SPI, UART, Hardware Timers, and a speedy enough 64Mhz clock. This was more than enough for my application and future applications.

Writing this now, in hind site, the F6 in particular DOES run out of pins really quick. This makes a great application-specific MCU, but if you are looking for upgradability, I would get a higher pin package. Additionally, the low RAM and Flash size (32K/8K) will have you making sure every variable and line of code in your firmware needs to be there.

STM32-Based RGB Lamp
06

System Design

Given these components, we can map a high-level overview of our system.

STM32-Based RGB Lamp
07

Pin Selection

With our system’s design in mind, we can identify and map all the pins we will use before getting into any programming. In STM32Cube we can set our SWDIO, SWCLK, and Timer (PWM) pins. We can also add an additional pin, configured for an interrupt, so that we can use a button to change effects.

STM32-Based RGB Lamp
08

The Schematic

STM32-Based RGB Lamp

Some key points of the schematic:

  • Following the LED's datasheet, each individual LED needs a decoupling capacitor.
  • Header pins are included for ST-Link (Firmware Flashing). So, we need to expose those pins for SWDIO, SWCLK, RESET, etc.
  • We use a switching regulator and then an LDO. The switching regulator (Buck) is better for stepping down those larger voltage differences and efficiently handling those larger currents (3A). Once converted to 5V, a simple LDO can save us space, complexity, and cost.These are much cheaper than a buck and should be able to easily handle the current/power requirements of the STM32G0.
  • Don't forget, we need the level shifter! The LED's minimum logic voltage is (0.7 * Vdd). This means the minimum voltage the LED’s can support ‘talking to’ is 3.5V. However, out STM32 outputs a 3.3V signal. So, we use a level shifter to reliably let our MCU communicate with the 5V LEDs.
  • We also leave exposed pads to have flexability with the button that will change LED effects.
09

The PCB

STM32-Based RGB Lamp
10

LED Driving (PWM)

The SK6812 line of LEDs requires a specific digital waveform at its logic input. This signal is how we communicate the color and brightness information for each LED. We can use one of our MCU's timers in PWM mode to generate this waveform, but first we need to understand the specific timing the LEDs require.

Before getting into the SK6812 timing, it is helpful to understand a few of the STM32 peripherals and registers we will be using: the timer, ARR, CCR, and DMA.

At its simplest, a hardware timer is just a counter. The MCU provides the timer with a clock, and the timer increments its internal counter every clock cycle. For example, if our timer is running at 16 MHz, the counter increments 16 million times per second. More in depth, the Auto-Reload Register, or ARR, tells the timer when to reset this counter and start again. If ARR is set to 18, for example, the timer counts:

0, 1, 2, 3 ... 17, 18

After reaching 18, it rolls back to 0 and repeats.

Because we started at 0, this gives us 19 total timer counts. By controlling ARR, we are therefore controlling the period, or frequency, of our PWM signal.

The Capture/Compare Register, or CCR, controls where within that period the PWM output changes state. In the PWM mode we are using, we can think of CCR as determining how long the output stays HIGH. For example, imagine that our timer counts from 0 to 18. If CCR is set relatively low, the output will only remain HIGH for a small portion of that period. If CCR is set higher, it will remain HIGH for a larger portion of the period.

Therefore, ARR and CCR control two different things:

ARR = How long is the entire PWM period?

CCR = How long within that period does the signal remain HIGH?

This gives us control over both the frequency and duty cycle of our PWM waveform.

The last piece is DMA, or Direct Memory Access. Normally, if we wanted to continuously change CCR, our CPU would have to repeatedly write a new value into the CCR register. For the SK6812, this would have to happen for every single bit we transmit. DMA gives peripherals such as our timer the ability to transfer data to or from memory without requiring the CPU to manually perform every transfer. In our case, we can create an array in memory containing all of the CCR values we want to send:

6, 12, 12, 6, ...

DMA can then automatically transfer each value from this array into the timer's CCR register at the appropriate time. This is particularly useful because the timer handles the precise PWM timing, DMA handles feeding it the next value, and the CPU is free to do something else.

With that background, we can now determine what ARR and CCR values we actually need for the SK6812.

According to the datasheet, the symbol period is approximately 1.2 µs. This is the amount of time we have to transmit a single bit, regardless of whether that bit is a 0 or a 1.

We can convert this period into a frequency using:

f = 1 / T and f = 1 / 1.2 µs ≈ 833 kHz

Therefore, we want our timer to generate a new PWM period at approximately 833 kHz. Our timer clock is running at 16 MHz. This means the timer counter increments once every 62.5 ns:

1 / 16 MHz = 62.5 ns

We can then determine how many timer counts fit inside one 1.2 µs SK6812 symbol:

16 MHz / 833 kHz ≈ 19 counts

Since the timer counts from 0 through ARR, the total number of counts is ARR + 1. Therefore, we can set our ARR to approximately:

ARR = 19 - 1 = 18

This means the timer will count from 0 to 18 before starting the next PWM period. That entire period represents one bit being sent to the SK6812.

Next, we need to determine our CCR value. While ARR determines the total length of the PWM period, CCR determines how long the signal stays HIGH during that period.

In a normal PWM application, we could use this to set an arbitrary duty cycle. For example, setting CCR to approximately half of the timer period would produce a roughly 50% duty cycle.

However, we are not actually using PWM to directly control the brightness of the LED. Instead, we are taking advantage of the PWM hardware to generate the specific HIGH and LOW timings required by the SK6812 communication protocol.

The SK6812 differentiates a 0 from a 1 based on how long the signal remains HIGH during each symbol. A 0 has a relatively short HIGH time, while a 1 has a longer HIGH time. The total symbol period remains approximately the same.

For our timer configuration, we can represent these two values using approximately:

Bit 0: CCR = 6

Bit 1: CCR = 12

This is where DMA becomes particularly useful. Instead of having the CPU manually update CCR every 1.2 µs, we can create a buffer containing all of our 6s and 12s. DMA then feeds these values into the timer's CCR register one after another.

For example:

LED Data: 0 1 1 0

CCR Buffer: 6 12 12 6

The process might look something like this:

Memory → DMA → CCR → Timer → SK6812

11

Future Improvements

The 3D printed design is very solid (adapted from our LED Tow Hitch), but there are a few improvements that can be made on the PCB side:

  • Clean up the firmware! Currently, these LED effects can use up my very limited Flash memory, so I'd like to make optimizations in the future to make it more lean
  • Focus more on modular design. The intent with this board was to make an LED lamp AND to allow my PCB to be flexible enough to use on other projects. I'd like to continue working on supporting more voltages, currents, etc.
12

Conclusion

After all is said and done, we get a cool, sleek, RGB lamp with swappable covers!

STM32-Based RGB Lamp
STM32-Based RGB Lamp