Skip to the content
PCBKitNew board
2 layersWs281x levelConverter, the printed circuit board in 3D

Ws281x levelConverter

slapab/ws281x_driver

Simple driver (based on SPI, DMA, bit banding) for ws281x LEDs - implemented on stm32f103c8t6 written in C++11

Copper layers
2
Thickness
1.6 mm
Parts
29
Nets
14
Pads
68
Tracks, vias
96, 7
Pours
4
Routed
Yes
KiCad
KiCad 4
Created
22 Dec 2016
Updated
10 Mar 2017

Overview

Ws281x levelConverter is an open-source printed circuit board by slapab, from the slapab/ws281x_driver repository on GitHub. It is a 2-layer board with 29 parts on 14 nets, routed with 96 tracks and 7 vias.

It is built around the 74AHC1G04SE and USBLC6-2P6. Its parts include 13 capacitors, 6 resistors, 6 connectors, 3 ICs and 1 inductor. It belongs with the STM32 boards of this library.

Main components

2

README

README.md

Short description

NOTE:

The project's name suggests that it should work on all WS281x types LEDs. That was primary intention, but presented driver has been tested only with WS2812B LEDs.

This repository contains driver for WS2812B LED controller where SPI peripheral is using to handle transmission timing. It is written in C++11 and it is using bit banding and DMA to achieve two things:

  • relative small memory usage for storing, manipulating and transfering colors for each LED in the chain
  • using hardware during transmission as often as possible (unfortunately not in 100%)

As a result, the current version to store RGB colors and to transmit them to LEDs requires memory of size:

  • 2 x LEDs count x 3 bytes Two buffers to store each LED color in the chain of size LEDs Count:
    • multiplying by 2 because during ongoing transmission the driver operates on the second buffer
    • multiplying by 3 to store LEDs colors
  • 2 x 12 bytes

These buffers are being used during transmission and each contain prepared RGB color for one LED at the time. DMA copies these bytes to SPI and end of transfer interrupt is used to convert color for next LED in chain. So, this is not fully hardware transmission, but interrupt handling that prepares next LED data to transmit takes about 6µs while CPU is running with 48 MHz clock.

  • 2 x (12 x 2 x size of pointer) bytes

These tables store bit banding regions that correspond to specific bits for each transmitting buffer's byte.

Detailed description

Driver implementation

  • SPI

Using SPI peripheral to drive WS281x LEDs is a well known solution. The idea is simple, each transmitted byte through SPI interface contains two bits of color, so to transmit one RGB color for one LED, there is need to send 12 'encoded' bytes. Because 4 bits during SPI transmission represents one bit in WS281x interface, care must be taken while configuring clock for SPI peripheral: - transmission frequency of one bit of WS281x interface must be as close as to 800 kHz - but taking into consideration tolerances, acceptable transmission frequencies are in the range from 646 kHz to 1.05 MHz. - for example, using 48 MHz to clock SPI peripheral and using prescaler of value 16, each bit will be transmitted with 3MHz frequency. Because 4 bits sent by SPI are just one bit of WS281x's color, so the average frequency for transmitting one bit of LED color is 750kHz.

  • Bit-banding

Bit banding is well explained here.

Two buffers - each 12 bytes long - are being used to transmit colors to LEDs. In the table below I have marked positions of two bits of color inside one transmitting byte. Transmitting bits 7:4 represents one bit of transmitting color and transmitting bits 3:0 represents next bit of color. If bit marked as 'X' is set to '0' then WS281x controller reads bits 7:4 or 3:0 as color's bit '0', otherwise reads them as '1'.

bit76543210
value1X001X00

Presented implementation prepares the table with pointers to bit band regions for 2nd and 6th bit for each byte inside transmitting buffers. Thanks to that writing under appropriate pointer any value greater than 0 sets corresponding bit to '1', and writing zero sets corresponding bit to '0'. Because writing operation to bit banding region is just like STR instruction, so it is quite fast.

  • DMA

    Current implementation is using two DMA channels:

    1. Prior to send any color, need to convert RGB data into transmitting buffers. Like mentioned at the beginning, one LED color (RGB) is converted and stored inside of 12 bytes inside the transmitting buffer. Just before transmission is being started, the application converts colors of two LEDs and places them into transmitting buffers. Then transmission is started and 12 bytes of first buffer are being sent to the SPI peripheral by the DMA. During each end of transfer interrupt the next transmission (from the second buffer) is being started only if end of transmission flag is not set. Next, still inside interrupt routine, checks if there is any color to send - if is, then RGB value is converted and stored inside of just freed transmitting buffer.
    2. There are two buffers which store colors for LEDs. Driver always uses one of them at the time. When send() was called then the driver does:
      • buffer which was just modified will be used as colors source during transmission - it is just 'renamed' to transmitting buffer and the second buffer (which was in the background) will be 'renamed' to active buffer, and there changes made by called API methods will be applied since now.
      • synchronizing these two buffers to have the same content - this ensures that next call to API that modifies LEDs colors will operate on the same content as was before calling send() method. That operation is done by the second channel of the DMA. As the result, the application can modify LED's colors while transmission of the previous 'snapshot' is in progress.

PC visualization application

When I've implemented driver to version when it worked quite stable with a few animations running on 300 LEDs strip, I have put hardware to work continuously as a decoration. I have had to figure out how to test new code with lack of fully working hardware. The idea was to separate driver layer from transmission layer, so the PC application has to just simulate transmission process and LEDs. PC visualization application has been made with Qt5 and C++14 as an QtCreator4 project.

When main thread (GUI) is being started it constructs QWidget with small squares which are being painted horizontally. Each square represents one LED. Next, the new thread is created which uses WS281x driver API to run animations (that thread is equivalent to microcontroller program). The PC's transmission layer is just a simple method that runs in the another thread. Its job is send colors bytes provided by the WS281x driver to the main (GUI) thread and simulates transmission time.

PC visualization application sources are stored in pc_visualization_proj subdirectory.

Voltage converter - simple KiCAD project.

To ensure proper data signal shape (conversion level 3.3V -> 5V) I've designed simple hardware using parts that I already had on the 'shelf'. It uses two CMOS NOT gates connected in series and powered from 5V. Input signal from MCU is connected to the first gate through capacitor placed in series. Project files are stored in KiCAD_ws281x_level_converter subdirectory.

Parts

29
QtyValueFootprintReferences
8100nCapacitors_SMD:C_0805_HandSolderingC2, C3, C5, C6, C7, C10, C11, C13
310kResistors_SMD:R_0805_HandSolderingR3, R4, R5
274AHC1G04CustomFootprints:SOT-353U1, U2
2SUPPLY_INCustomFootprints:SupplySocketP2, P3
1100Resistors_SMD:R_0805_HandSolderingR2
1100n (opt)Capacitors_SMD:C_0805_HandSolderingC4
11uCapacitors_SMD:C_0805_HandSolderingC8
11u (opt)Capacitors_SMD:C_0805_HandSolderingC9
14.7uCapacitors_SMD:C_0805_HandSolderingC1
147Resistors_SMD:R_0805_HandSolderingR1
1470Resistors_SMD:R_0805_HandSolderingR6
1470uCapacitors_ThroughHole:C_Radial_D7.5_L11.2_P2.5C12
1USBLC6-2TO_SOT_Packages_SMD:SOT-23-6_HandsolderingU3
1WS281xDINPin_Headers:Pin_Header_Straight_1x01P4
1WS281x_5VWire_Pads:SolderWirePad_2x_1-5mmDrillP5
1WS281x_GNDWire_Pads:SolderWirePad_2x_1-5mmDrillP6
1beadChoke_SMD:Choke_SMD_1206_HandsolderingL1
1stm32f103Pin_Headers:Pin_Header_Straight_1x03P1

Questions

What parts does the Ws281x levelConverter use?

29 parts, built around the 74AHC1G04SE and USBLC6-2P6. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Ws281x levelConverter KiCad files?

From the slapab/ws281x_driver repository on GitHub, at the commit this page was made from: the board is KiCAD_ws281x_level_converter/ws281x_levelConverter.kicad_pcb. PCBKit opens the board in the browser, with nothing to install.

Can I use the Ws281x levelConverter design in my own project?

Its repository states no licence, so its author keeps all rights: ask slapab before reusing the design.

Similar boards

  • 4 layers52 × 57 mmVna, the printed circuit board in 3D

    Vna

    Ttl/vna

    Homemade 30 MHZ - 6 GHz single receiver VNA design files.

    342 parts195
  • 2 layersDiffuino selector, the printed circuit board in 3D

    Diffuino selector

    elixpo/elixpo_chapter

    Elixpo’s canonical collection for public build-and-release Chapters, bringing open-source software, reproducible research, hardware, and community contributions into one attributable record.

    46 parts85
  • 4 layers132 × 84.5 mmHamodule, the printed circuit board in 3D

    Hamodule

    crgarcia12/electronics-homeassistant-lightscontroll

    A smart lighting controller PCB that integrates seamlessly with ESPHome and Home Assistant while maintaining full compatibility with traditional mechanical switches.

    207 parts28
  • 4 layers100 × 66 mmVNA, the printed circuit board in 3D

    VNA

    joshajohnson/vna

    25MHz to 1.25GHz Vector Network Analyser

    254 parts25GPL-3.0
  • 2 layers85 × 40 mmSnapNodes RP2, the printed circuit board in 3D

    SnapNodes RP2

    shBLOCK/TileGlobeMC

    Project Structure ----- - tileglobe: game logic - datagen/mod: a fabric modding environment for extracting/generating data from vanilla (e.g.

    168 parts21
  • 4 layers144.3 × 143.8 mmCheep boards, the printed circuit board in 3D

    Cheep boards

    esl-epfl/HEEPidermis

    278 parts12
  • 4 layers100 × 80 mmLCSDR, the printed circuit board in 3D

    LCSDR

    licheegh/LCSDR

    197 parts7
  • 4 layers104.5 × 91 mmMbed ce ci shield v2, the printed circuit board in 3D

    Mbed ce ci shield v2

    mbed-ce/mbed-ce-ci-shield-v2

    New version of the Mbed OS CE CI Shield -- a shield containing a logic analyzer and components to test features like I2C, SPI, and PWM.

    176 parts7CERN-OHL-P-2.0