Documentation

CJMCU-64 8x8 WS2812 RGB LED Matrix Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual
Documentation / CJMCU-64 8x8 WS2812 RGB LED Matrix Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual

CJMCU-64 8x8 WS2812 RGB LED Matrix Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual

shillehtekws2812-8x8-led-matrix-arduino-esp32-raspberry-pi

Overview

The CJMCU-64 is an 8×8 matrix of WS2812B addressable RGB LEDs — 64 pixels on one rigid PCB, each with its own tiny controller chip baked into the LED package. One data wire from your microcontroller sets the color and brightness of every pixel individually, so the same three connections that run a single NeoPixel run this whole panel: 5 V, GND, and DIN.

Because the pixels are chainable, the panel has both an input corner (DIN) and an output corner (DOUT). Feed DOUT into the DIN of a second panel and your code simply sees a 128-pixel strip; tile four and you have a 16×16 screen. The catch with 64 RGB LEDs is power: at full white and full brightness the panel can draw close to 3.8 A, far beyond what a microcontroller’s 5 V pin supplies — plan the supply first and the animations second.

This manual covers the pinout, wiring for Arduino, ESP32, Raspberry Pi, and Pico (including the level-shifting question for 3.3 V boards), starter code with an x/y coordinate helper for each platform, and the practical answers on current budgets, chaining, and layout mapping.

At a Glance

Pixels
64 × WS2812B (8×8)
Interface
Single-wire data (DIN)
Chainable
DOUT → next panel’s DIN
Supply
5 V
Max Current
~3.8 A at full white
Color Order
GRB, 800 kHz protocol

Specifications

Parameter Value
LEDs 64 × WS2812B (5050 package), 8×8 grid
Supply voltage 5 V DC (4 – 5.3 V works)
Data signal 800 kHz single-wire, 5 V logic (3.3 V usually works)
Current draw ~60 mA per pixel full white → ~3.8 A panel max
Idle draw ~1 mA per pixel (~64 mA dark)
Color depth 24-bit (8 bits per channel), GRB order
Connections DIN · +5V · GND in; DOUT · +5V · GND out
Chaining Unlimited electrically — limited by power & RAM
Refresh ~400 Hz possible for 64 pixels
Size Approx. 65 × 65 mm

Pinout Diagram

Two pad groups on opposite corners: the input trio (GND, +5V, DIN) where your controller and supply connect, and the output trio (DOUT, +5V, GND) for chaining to the next panel. Power pads on both ends are joined by the board’s power planes, which is also where you inject extra power on longer chains.

CJMCU-64 8x8 WS2812B RGB LED matrix pinout diagram showing DIN, 5V and GND input pads and DOUT chaining pads

Wiring Guide

Arduino Uno Wiring

Matrix Pin Connection Notes
+5V External 5 V supply (≥4 A for full brightness) Not the Uno’s 5V pin for bright animations
GND Supply GND + Arduino GND Grounds must be common
DIN D6 through a 330–470 Ω resistor Resistor protects the first pixel
Do the current math first. 64 pixels × 60 mA is ~3.8 A at full white. USB ports and the Uno’s regulator cannot supply that. Use a dedicated 5 V supply, add a 1000 µF capacitor across +5V/GND at the panel, and cap brightness in software while testing.

ESP32 Wiring

Matrix Pin Connection Notes
+5V External 5 V supply Or VIN when powered from a strong USB source, dim only
GND Supply GND + ESP32 GND Common ground
DIN GPIO 16 via 330 Ω 3.3 V data — see note
3.3 V data on a 5 V pixel. WS2812B wants a data high of ~0.7 × VDD = 3.5 V, so 3.3 V is technically marginal — yet short wires almost always work. If you see flicker or the first pixel glitching, add a 74AHCT125 level shifter or drop the panel supply to ~4.7 V with a diode.

Raspberry Pi Wiring

Matrix Pin Connection Notes
+5V External 5 V supply Pi’s 5 V pin only for dim testing
GND Supply GND + Pi GND (Pin 6) Common ground
DIN GPIO 18 (Pin 12) via 330 Ω PWM pin required by the driver
Library specifics. The rpi_ws281x driver uses the Pi’s PWM hardware on GPIO 18, needs sudo, and conflicts with on-board audio — add dtparam=audio=off in /boot/config.txt if colors glitch. A level shifter on DIN makes the Pi’s 3.3 V signal solid.

Raspberry Pi Pico Wiring

Matrix Pin Connection Notes
+5V VBUS (Pin 40) or external 5 V VBUS = USB 5 V; dim animations only
GND GND (Pin 38) + supply GND Common ground
DIN GP0 (Pin 1) via 330 Ω MicroPython neopixel driver uses PIO
Start at brightness 0.1. Every example below caps brightness. A dim 8×8 already looks great, stays cool, and keeps you inside a USB power budget while you develop — raise it only when the real supply is connected.

Code Examples

Arduino — NeoPixel with X/Y Mapping

matrix_xy.ino
// Library Manager: install "Adafruit NeoPixel"
#include <Adafruit_NeoPixel.h>

#define PIN 6
#define W 8
#define H 8
Adafruit_NeoPixel px(W * H, PIN, NEO_GRB + NEO_KHZ800);

// Set SERPENTINE true if every other row runs backwards on your panel
const bool SERPENTINE = false;

int xy(int x, int y) {
  if (SERPENTINE && (y % 2 == 1)) return y * W + (W - 1 - x);
  return y * W + x;
}

void setup() {
  px.begin();
  px.setBrightness(30);   // ~12% - keep low on USB power
}

void loop() {
  // moving diagonal rainbow
  for (int t = 0; t < 256; t += 4) {
    for (int y = 0; y < H; y++)
      for (int x = 0; x < W; x++)
        px.setPixelColor(xy(x, y),
          px.ColorHSV((t + (x + y) * 16) * 256));
    px.show();
    delay(30);
  }
}

ESP32 — Same Sketch, Faster Board

esp32_matrix.ino
#include <Adafruit_NeoPixel.h>

#define PIN 16
Adafruit_NeoPixel px(64, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  px.begin();
  px.setBrightness(40);
}

void loop() {
  // breathing single color
  for (int b = 0; b <= 255; b += 5) { fillAll(0, b / 2, b); delay(15); }
  for (int b = 255; b >= 0; b -= 5) { fillAll(0, b / 2, b); delay(15); }
}

void fillAll(uint8_t r, uint8_t g, uint8_t b) {
  for (int i = 0; i < 64; i++) px.setPixelColor(i, r, g, b);
  px.show();
}

Raspberry Pi — Python (rpi_ws281x)

matrix_demo.py
import time
from rpi_ws281x import PixelStrip, Color

# sudo pip3 install rpi_ws281x   |   run with: sudo python3 matrix_demo.py

strip = PixelStrip(64, 18, brightness=40)  # 64 px, GPIO 18
strip.begin()

def xy(x, y, serpentine=False):
    if serpentine and y % 2 == 1:
        return y * 8 + (7 - x)
    return y * 8 + x

while True:
    # column sweep
    for x in range(8):
        for y in range(8):
            strip.setPixelColor(xy(x, y), Color(0, 80, 160))
        strip.show()
        time.sleep(0.08)
    for i in range(64):
        strip.setPixelColor(i, Color(0, 0, 0))
    strip.show()
    time.sleep(0.3)

Raspberry Pi Pico — MicroPython

pico_matrix.py
from machine import Pin
from neopixel import NeoPixel
import time

np = NeoPixel(Pin(0), 64)
BRIGHT = 0.1   # 10%

def xy(x, y, serpentine=False):
    if serpentine and y % 2 == 1:
        return y * 8 + (7 - x)
    return y * 8 + x

def put(x, y, r, g, b):
    np[xy(x, y)] = (int(r * BRIGHT), int(g * BRIGHT), int(b * BRIGHT))

while True:
    # expanding square
    for ring in range(4):
        lo, hi = 3 - ring, 4 + ring
        for x in range(lo, hi + 1):
            put(x, lo, 255, 60, 0)
            put(x, hi, 255, 60, 0)
        for y in range(lo, hi + 1):
            put(lo, y, 255, 60, 0)
            put(hi, y, 255, 60, 0)
        np.write()
        time.sleep(0.15)
    time.sleep(0.3)
    np.fill((0, 0, 0))
    np.write()

Frequently Asked Questions

Can I power it from USB while developing?
Yes, if you cap brightness. At the 10–15% brightness used in the examples the whole panel stays under ~500 mA even fully lit. The rule of thumb: full white current ≈ 3.8 A × (brightness fraction). For anything bright or for chained panels, switch to a dedicated 5 V supply.
How do I know if my panel is row-by-row or serpentine?
Light pixels 0–15 one at a time and watch row two: if it fills left-to-right the layout is progressive (leave SERPENTINE false); if it fills right-to-left, set the flag true. The xy() helper in every example handles either with one boolean.
How many panels can I chain?
Data-wise, dozens — each pixel regenerates the signal. The real limits are power (inject 5 V and GND every 1–2 panels rather than daisy-chaining all current through the first pads) and controller RAM/refresh: 4 panels = 256 pixels = 768 bytes of frame data and a ~7.7 ms update, still fine on any board here.
Do I really need the resistor and capacitor?
They are cheap insurance. The 330–470 Ω series resistor on DIN damps reflections that can destroy the first pixel’s data input, and the 1000 µF capacitor across the supply absorbs the inrush spike when power connects. Panels run without them — until the day one doesn’t.
Why are my colors wrong (red and green swapped)?
WS2812B pixels expect data in GRB order, and every library has a setting for it (NEO_GRB in Adafruit_NeoPixel, the default in MicroPython’s neopixel). If you write raw tuples and see swapped channels, reorder to (G, R, B) or set the library’s color order flag.
Can I run it as a scrolling text display?
Yes — use a matrix-aware layer: Adafruit_NeoMatrix on Arduino/ESP32 gives you the full GFX text API on top of the panel (tell it your layout flags), and on the Pi/Pico you can render text into a small framebuffer and copy it through the xy() mapper. One 8×8 shows one character at a time; chain panels for readable scrolling.
The first pixel flickers or the panel glitches randomly. What now?
Classic 3.3 V-data symptoms. Shorten the DIN wire, make sure grounds are common at one point, and if it persists add a 74AHCT125/74HCT245 level shifter — it converts the 3.3 V signal to a clean 5 V and the glitches vanish. Long supply runs also benefit from injecting power at the panel rather than through breadboard rails.

Related Tutorials