Generate 24-bit color from RGB LED with Raspberry Pi

Chakrit Yau
6 min readDec 3, 2022

--

Controlling RGB LED with a Raspberry Pi is quite a simple task. However, when searching for RGB LED tutorials, most top results are rather too simplistic — only combining red, green, and blue at their maximum output. This limits the number of colors you can generate with your RGB LED.

But there is a better way at controlling RGB LED — using PWM. PWM allows you to fine-control the output of each individual color. So, you can generate any color from 24-bit RGB color space.

In this tutorial, I assume the usage of RPi.GPIO library or similar.

What is PWM?

PWM stands for Pulse Width Modulation. In normal mode, you can set GPIO pin to HIGH (100%) or LOW (0%). With PWM, you can send out any power output from 0% to 100%. This is accomplished through modulation of signal voltage. For example, if you ask for 50% power output (or, formally known as, 50% duty cycle), PWM will send out a signal which comprises of half 100% signal and half 0% signal. The average will therefore come out at 50%.

Illustration showing how PWM works. Source: https://en.wikipedia.org/wiki/Pulse-width_modulation

PWM with Raspberry Pi

Raspberry Pi (or any other similar boards) has built-in PWM support through GPIO pins. You simply have to instantiate the pin as PWM output.

For example, if you want to make Pin 23 PWM. You simple have to instantiate it as:

GPIO.setup(23, GPIO.OUT)
pwm_pin = GPIO.PWM(23, 10) # Pin number, Freq

The first line is the same as a basic output setting. The second line converts a basic output to PWM output.

Notice that PWM takes two arguments — pin number and frequency.

Frequency is how often PWM should modulate the signal in hertz (Hz). For example, I supply a value of 10 for Frequency. So, PWM will chop signal in one time interval into 10 blocks. Then, I can select output from 1/10, 2/10, …, 9/10, to 10/10.

Since Frequency dictates the granularity of output control, it is important to set it to at least high enough for your desired modulation.

After instantiation, we start PWM output by:

pwm_pin.start(0)

Then, we can control the output by calling ChangeDutyCycle method.

pwm_pin.ChangeDutyCycle(0)
pwm_pin.ChangeDutyCycle(0.5)
pwm_pin.ChangeDutyCycle(1)

The first line will send out LOW signal. The second line will send out 50% HIGH and 50% LOW. Lastly, the third line simply outputs HIGH.

Once, you are done. Tell your GPIO to stop.

pwm_pin.stop()

More information can be found on raspberry-gpio-python wiki

Connecting RGB LED

Now, it’s time to hook an RGB LED up. An RGB LED has 4 wires — 3 for RGB and 1 common cathode/anode. It is important to know if your LED is a common cathode or a common anode type, since wiring and coding will be slightly different.

A common cathode LED is an LED that share a single negative terminal with all 3 colors. On the other hand, a common anode LED shares a single positive terminal.

Common Cathode LED and Common Anode LED. Source: https://www.circuitstoday.com/interface-common-anode-and-common-cathode-rgb-leds-with-arduino

The above picture shows the difference. You can find the picture and more information on:

I am going to use a common Cathode RGB LED for my project.

Wiring is quite simple. I am going to connect each RGB connector to a GPIO pin and a resistor. I use 1000 Ohm resistors for green and blue, and an 800 Ohm resistor for red. You can adjust resistance to suit your need. Less resistance (less Ohm) will allow more current to flow and consequently make LED brighter.

The common Cathode terminal is connected to a ground pin.

I am using an Orange Pi Zero 2 board, since Raspberry Pi is in a shortage as of writing. However, it should be a straightforward job to convert schematic and code to a Raspberry Pi or other boards.

Wiring Schematic

If you are using a different board, then you would need to refer to your pin layout diagram to locate suitable GPIO pins and associated pin numbers. For Orange Pi Zero, you can find information below.

Orange Pi Zero Pin Layout Diagram. Source: oshlab.com

https://linux-sunxi.org/Xunlong_Orange_Pi_Zero_Plus_2

Python Code

I am going to control the RGB LED with Python and OPi. OPi is a GPIO library for Orange Pi, based on RPi.GPIO. So, you should be able to simply replace the import statement with RPi.

from OPi import GPIO
import time
import numpy as np

# Set board to Orange Pi Zero 2
GPIO.setboard(GPIO.H616)
GPIO.setmode(GPIO.BOARD)

RED_PIN = 23
GREEN_PIN = 21
BLUE_PIN = 19

GPIO.setup(RED_PIN, GPIO.OUT)
GPIO.setup(GREEN_PIN, GPIO.OUT)
GPIO.setup(BLUE_PIN, GPIO.OUT)

# Set GPIO to PWM mode with frequency of 256Hz
# Frequency can be any number above 0
# I chose 256 because we are going to use 8-bit per channel
red = GPIO.PWM(RED_PIN, 256)
green = GPIO.PWM(GREEN_PIN, 256)
blue = GPIO.PWM(BLUE_PIN, 256)

red.start(0)
green.start(0)
blue.start(0)

for _ in range(10):
# Random 3 integers
target = np.random.randint(0, high=255, size=3)

# Modulate duty cycle from 0-100
# We convert from 8-bit (0-255) to 0-100
red.ChangeDutyCycle(target[0] * 100 / 256)
green.ChangeDutyCycle(target[1] * 100 / 256)
blue.ChangeDutyCycle(target[2] * 100 / 256)
time.sleep(5)

# stop PWM
red.stop()
green.stop()
blue.stop()

GPIO.cleanup()

After setting up the board, I declare pin 23/21/19 as PWM outputs. Frequency is chosen as 256, as this is the number of steps in an 8-bit channel.

Then, we random 3 integers, each one from 0 to 255. After that, we feed each integer to each terminal by converting RGB value to corresponding duty cycles. Since there are 256 colors in a channel, I divide the random integer with 256 first to compress it to 0–1 range. Then, the result is multiplied by 100 to convert it to 0–100 range required by duty cycle specification. Notice that duty cycle does not need to be an integer.

If you are using a common anode LED, you will need to invert the duty cycle — e.g. 100 — target[0] * 100 / 256

When we run this code, RGB LED will randomly show 10 colors. Each color will stay on for 5 seconds. Finally, we clean up and exit.

A random color chosen by the code above

I hope this tutorial will be helpful to your endeavor with Raspberry Pi/Orange Pi!

--

--

Chakrit Yau

Chief Technical Officer and Researcher at DeeperTrade | Former Data Scientist at KBTG