RGB PC Light Concept With XIAO RP2040

by Arnov Sharma in Circuits > Microcontrollers

1627 Views, 10 Favorites, 0 Comments

RGB PC Light Concept With XIAO RP2040

04 (53).gif
IMG_3164.JPG
01 (50).gif

Hi everyone, and now for something flashy: a straightforward RGB PC Light idea built with Seeed's XIAO RP2040 MCU and a custom WS2812 LED Matrix.

The objective was to build up a straightforward RGB lighting system for a project of mine (the WoodWork Fusion PC).

The RGB lighting setup will provide internal lighting for the PC, giving it an RGB element that will improve aesthetics

With the help of the FASTLED Library, a well-known addressable LED control library, RP2040 is being used to drive these LEDs, including the WS2812B LEDs, WS2811 LEDs, and many others.

Let's take a look at the hardware used in this project.

Supplies

Following are the materials used in this build-

  • XIAO RP2040 DEV Board
  • WS2812 LED Matrix
  • Jumper wires

XIAO RP2040

xinpin.jpg
IMG_20231008_200944.jpg

For this project, we are using the XIAO RP2040 Dev Board, which is based on the Raspberry Pi RP2040 microcontroller. Here are the key details about the XIAO RP2040 development board:

  • Microcontroller: The XIAO RP2040 is powered by the Raspberry Pi RP2040 microcontroller, which features a dual-core ARM Cortex-M0+ processor running at up to 133 MHz, 264KB of SRAM, and 2MB of onboard flash memory.
  • Compact Size: The XIAO RP2040 is designed to be compact and portable. It's small in size, making it suitable for projects with limited space.
  • GPIO Pins: The board comes with a number of general-purpose input/output (GPIO) pins, allowing users to interface with various sensors, displays, and other electronic components. These pins can be programmed for digital input/output, analog input, PWM, I2C, SPI, and UART communication.
  • USB Connectivity: The XIAO RP2040 features a micro USB port for power and data communication. It can be programmed and powered through this USB connection.
  • Power Supply: The board can be powered via the USB port or an external power source. It has a wide input voltage range, typically from 3.5V to 5.5V.
  • Onboard Components: The XIAO RP2040 board may include onboard components such as LEDs, buttons, and a reset button, which can be used for basic input/output and debugging purposes.
  • Programming: The board can be programmed using various programming languages and development environments, including MicroPython, CircuitPython, C/C++, and more. It is compatible with the Raspberry Pi Pico SDK, providing a rich set of libraries and tools for development.
  • Community Support: Being based on the RP2040 microcontroller, the XIAO RP2040 benefits from the large and active Raspberry Pi community. There are plenty of resources, tutorials, and community forums available for support and collaboration.

WS2812 LED Matrix

09-90-Cn0FRTocgYgif.gif

Here's the matrix that we are using, and its a 16x8 configuration matrix that is laid out in an OXPLOW layout. OXPLOW is a matrix type in which LEDs go one way in one row and then backward in the next row, and so on. This layout is also called Boustrophedon.

There's also another layout, which is the serpentine layout, and LEDs in this layout are laid out in a continuous chain like a snake, thus the name serpentine.

This Matrix is controlled via the FAST LED Library but can be operated with a bunch of existing libraries like ADAFRUIT's Neopixel Library, SmartMatrix Library, etc.

This matrix is custom-built and was prepared a year ago. You can check out the project's page for more in-depth details.

https://www.instructables.com/Custom-16x8-Ws2812-Matrix-Project/

The WS2812B LED is being used in this matrix, which is an intelligent control LED light source. The control circuit and RGB chips are integrated into a package of 5050 components. Internally, it includes an intelligent digital port data latch and signal reshaping amplification drive circuit

The data transfer protocol uses a single NZR communication mode. After the pixel power-on reset, the DIN port receives data from the controller; the first pixel collects initial 24 bit data and then sends it to the internal data latch; and the other data, which is reshaping by the internal signal reshaping amplification circuit, is sent to the next cascade pixel through the DO port.

Its operating voltage is between +3.5 and +5.3 volts DC.

Checkout its datasheet for more info- https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf

Seeed Fusion Service

01-101-ZARzjDuaMwgif.gif
02-102-AANhUC6tNTgif.gif

For this project, we are using two Seeed Services, which are the XIAO RP2040 DEV Board itself and the RGB Matrix, which was made using the Seeed Fusion PCB Service.

The order for the matrix was placed for a white solder mask with black silkscreen, and PCBs arrived in less than a week, which was super fast.

The quality was super good considering the rate, which was also pretty low.

Seeed Fusion offers one-stop prototyping for PCB manufacture and PCB assembly, and as a result, they produce superior-quality PCBs and fast-turnkey PCBA within 7 working days.

Seeed Studio Fusion PCB Assembly Service takes care of the entire fabrication process, from PCB manufacturing, parts sourcing, assembly, and testing services, so you can be sure that they are getting a quality product.

After gauging market interest and verifying a working prototype, Seeed Propagate Service can help you bring the product to market with professional guidance and a strong network of connections.

Wiring Diagram

03_QGE04vEbY7.jpg
IMG_20231008_200922.jpg

The wiring layout for this configuration is very straightforward: the VCC of the matrix is connected to the XIAO's 5V port, the GND of the matrix is connected to the matrix's GND, and the Din of the matrix is connected to the XIAO DEV Board's D0.

Eventually, we will power this RGB LED setup with a 5V supply from the PC's motherboard.

CODE

#include <FastLED.h>

#define LED_PIN D0

#define COLOR_ORDER GRB
#define CHIPSET WS2811

#define BRIGHTNESS 128

// Helper functions for an two-dimensional XY matrix of pixels.
// Simple 2-D demo code is included as well.
//
// XY(x,y) takes x and y coordinates and returns an LED index number,
// for use like this: leds[ XY(x,y) ] == CRGB::Red;
// No error checking is performed on the ranges of x and y.
//
// XYsafe(x,y) takes x and y coordinates and returns an LED index number,
// for use like this: leds[ XYsafe(x,y) ] == CRGB::Red;
// Error checking IS performed on the ranges of x and y, and an
// index of "-1" is returned. Special instructions below
// explain how to use this without having to do your own error
// checking every time you use this function.
// This is a slightly more advanced technique, and
// it REQUIRES SPECIAL ADDITIONAL setup, described below.


// Params for width and height
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;

// Param for different pixel layouts
const bool kMatrixSerpentineLayout = true;
const bool kMatrixVertical = false;

// Set 'kMatrixSerpentineLayout' to false if your pixels are
// laid out all running the same way, like this:
//
// 0 > 1 > 2 > 3 > 4
// |
// .----<----<----<----'
// |
// 5 > 6 > 7 > 8 > 9
// |
// .----<----<----<----'
// |
// 10 > 11 > 12 > 13 > 14
// |
// .----<----<----<----'
// |
// 15 > 16 > 17 > 18 > 19
//
// Set 'kMatrixSerpentineLayout' to true if your pixels are
// laid out back-and-forth, like this:
//
// 0 > 1 > 2 > 3 > 4
// |
// |
// 9 < 8 < 7 < 6 < 5
// |
// |
// 10 > 11 > 12 > 13 > 14
// |
// |
// 19 < 18 < 17 < 16 < 15
//
// Bonus vocabulary word: anything that goes one way
// in one row, and then backwards in the next row, and so on
// is call "boustrophedon", meaning "as the ox plows."


// This function will return the right 'led index number' for
// a given set of X and Y coordinates on your matrix.
// IT DOES NOT CHECK THE COORDINATE BOUNDARIES.
// That's up to you. Don't pass it bogus values.
//
// Use the "XY" function like this:
//
// for( uint8_t x = 0; x < kMatrixWidth; x++) {
// for( uint8_t y = 0; y < kMatrixHeight; y++) {
//
// // Here's the x, y to 'led index' in action:
// leds[ XY( x, y) ] = CHSV( random8(), 255, 255);
//
// }
// }
//
//
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;

if( kMatrixSerpentineLayout == false) {
if (kMatrixVertical == false) {
i = (y * kMatrixWidth) + x;
} else {
i = kMatrixHeight * (kMatrixWidth - (x+1))+y;
}
}

if( kMatrixSerpentineLayout == true) {
if (kMatrixVertical == false) {
if( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
} else { // vertical positioning
if ( x & 0x01) {
i = kMatrixHeight * (kMatrixWidth - (x+1))+y;
} else {
i = kMatrixHeight * (kMatrixWidth - x) - (y+1);
}
}
}

return i;
}


// Once you've gotten the basics working (AND NOT UNTIL THEN!)
// here's a helpful technique that can be tricky to set up, but
// then helps you avoid the needs for sprinkling array-bound-checking
// throughout your code.
//
// It requires a careful attention to get it set up correctly, but
// can potentially make your code smaller and faster.
//
// Suppose you have an 8 x 5 matrix of 40 LEDs. Normally, you'd
// delcare your leds array like this:
// CRGB leds[40];
// But instead of that, declare an LED buffer with one extra pixel in
// it, "leds_plus_safety_pixel". Then declare "leds" as a pointer to
// that array, but starting with the 2nd element (id=1) of that array:
// CRGB leds_with_safety_pixel[41];
// CRGB* const leds( leds_plus_safety_pixel + 1);
// Then you use the "leds" array as you normally would.
// Now "leds[0..N]" are aliases for "leds_plus_safety_pixel[1..(N+1)]",
// AND leds[-1] is now a legitimate and safe alias for leds_plus_safety_pixel[0].
// leds_plus_safety_pixel[0] aka leds[-1] is now your "safety pixel".
//
// Now instead of using the XY function above, use the one below, "XYsafe".
//
// If the X and Y values are 'in bounds', this function will return an index
// into the visible led array, same as "XY" does.
// HOWEVER -- and this is the trick -- if the X or Y values
// are out of bounds, this function will return an index of -1.
// And since leds[-1] is actually just an alias for leds_plus_safety_pixel[0],
// it's a totally safe and legal place to access. And since the 'safety pixel'
// falls 'outside' the visible part of the LED array, anything you write
// there is hidden from view automatically.
// Thus, this line of code is totally safe, regardless of the actual size of
// your matrix:
// leds[ XYsafe( random8(), random8() ) ] = CHSV( random8(), 255, 255);
//
// The only catch here is that while this makes it safe to read from and
// write to 'any pixel', there's really only ONE 'safety pixel'. No matter
// what out-of-bounds coordinates you write to, you'll really be writing to
// that one safety pixel. And if you try to READ from the safety pixel,
// you'll read whatever was written there last, reglardless of what coordinates
// were supplied.

#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
CRGB* const leds( leds_plus_safety_pixel + 1);

uint16_t XYsafe( uint8_t x, uint8_t y)
{
if( x >= kMatrixWidth) return -1;
if( y >= kMatrixHeight) return -1;
return XY(x,y);
}


// Demo that USES "XY" follows code below

void loop()
{
uint32_t ms = millis();
int32_t yHueDelta32 = ((int32_t)cos16( ms * (27/1) ) * (350 / kMatrixWidth));
int32_t xHueDelta32 = ((int32_t)cos16( ms * (39/1) ) * (310 / kMatrixHeight));
DrawOneFrame( ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768);
if( ms < 5000 ) {
FastLED.setBrightness( scale8( BRIGHTNESS, (ms * 256) / 5000));
} else {
FastLED.setBrightness(BRIGHTNESS);
}
FastLED.show();
}

void DrawOneFrame( uint8_t startHue8, int8_t yHueDelta8, int8_t xHueDelta8)
{
uint8_t lineStartHue = startHue8;
for( uint8_t y = 0; y < kMatrixHeight; y++) {
lineStartHue += yHueDelta8;
uint8_t pixelHue = lineStartHue;
for( uint8_t x = 0; x < kMatrixWidth; x++) {
pixelHue += xHueDelta8;
leds[ XY(x, y)] = CHSV( pixelHue, 255, 255);
}
}
}


void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
FastLED.setBrightness( BRIGHTNESS );
}

Here's the code for controlling LED matrices using the FastLED library in Arduino. It sets up a two-dimensional matrix of LEDs and provides functions to address individual LEDs in the matrix.

Let's break down the key components of the code:

Libraries and Definitions

#include <FastLED.h>
#define LED_PIN D0
#define COLOR_ORDER GRB
#define CHIPSET WS2811
#define BRIGHTNESS 128

The code includes the FastLED library and defines some constants like LED pin, color order, chipset type, and brightness.

Matrix Configuration

const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;
const bool kMatrixSerpentineLayout = true;
const bool kMatrixVertical = false;

These constants define the width, height, and layout of the LED matrix. The matrix can be serpentine (back-and-forth) or not, and it can be oriented vertically or horizontally.

Helper Functions

uint16_t XY( uint8_t x, uint8_t y) { ... }
uint16_t XYsafe( uint8_t x, uint8_t y) { ... }

These functions calculate the index of an LED in the matrix based on its x and y coordinates. XYsafe performs error checking and returns -1 for out-of-bounds coordinates.

Main Functions

void loop() { ... }
void DrawOneFrame( uint8_t startHue8, int8_t yHueDelta8, int8_t xHueDelta8) { ... }
void setup() { ... }
  • loop() function continuously updates the LED colors in the matrix.
  • DrawOneFrame() function sets the colors for all LEDs in the matrix based on a starting hue and hue deltas for both x and y coordinates.
  • setup() function initializes the FastLED library, sets up the LED array, and defines the LED brightness.

LED Array Setup

#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
CRGB* const leds( leds_plus_safety_pixel + 1);

Defines an array of CRGB objects representing the LEDs. An additional "safety pixel" is added for error handling. The leds pointer points to the second element of this array, allowing negative indices for out-of-bounds access to the safety pixel.


Additional Notes

  • The code generates dynamic patterns on the LED matrix by varying hues based on time.
  • The matrix layout is flexible, allowing different physical arrangements of LEDs.
  • It includes safety checks to prevent out-of-bounds access to the LED array.

This code provides a robust framework for creating animations on a 16x16 LED matrix. You can modify the DrawOneFrame() function to create different visual effects. The safety checks ensure that you can manipulate pixels without worrying about array bounds, simplifying the code and making it more reliable.

RESULT

02 (54).gif
03 (53).gif

Here is the result of this small build: a functioning RGB light that is being powered by an XIAO RP2040 DEV Board. This setup is now prepared to be put inside the PC, but first we must create a similar custom board that will be mounted on top of the Woodworks Fusion PC.

This setup was created as a proof of concept, and because it functions successfully, we can go on to this project's next phase.

Leave a comment if you need any help regarding this project, This is it for today folks.

Thanks to Seeed Studio for supporting this project. You guys can check them out if you need great PCB and stencil service for less cost and great quality.

And I'll be back with a new project pretty soon!