

Ws281x levelConverter
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
274AHC1G04SE
SOT-353-40℃~+125℃ 1 1 1.5V~3.85V 1.9V、2.9V、4.4V 1uA 2V~5.5V 500mV~1.65V 7.5ns@5V,50pF 74AHC 8mA 8mA Noise suppression function Schmitt trigger SOT-353 Inverters ROHSDiodes IncorporatedInvertersUSBLC6-2P6
SOT-666-6-40℃~+125℃ 150nA 17V 2 3.5pF 5.25V 5A@8/20us 6V ESD IEC 61000-4-2 Unidirectional SOT-666-6 ESD and Surge Protection (TVS/ESD) ROHSSTMicroelectronicsESD And Surge Protection (TVS/ESD)
README
README.mdShort 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'.
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| value | 1 | X | 0 | 0 | 1 | X | 0 | 0 |
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:
- 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.
- 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| Qty | Value | Footprint | References |
|---|---|---|---|
| 8 | 100n | Capacitors_SMD:C_0805_HandSoldering | C2, C3, C5, C6, C7, C10, C11, C13 |
| 3 | 10k | Resistors_SMD:R_0805_HandSoldering | R3, R4, R5 |
| 2 | 74AHC1G04 | CustomFootprints:SOT-353 | U1, U2 |
| 2 | SUPPLY_IN | CustomFootprints:SupplySocket | P2, P3 |
| 1 | 100 | Resistors_SMD:R_0805_HandSoldering | R2 |
| 1 | 100n (opt) | Capacitors_SMD:C_0805_HandSoldering | C4 |
| 1 | 1u | Capacitors_SMD:C_0805_HandSoldering | C8 |
| 1 | 1u (opt) | Capacitors_SMD:C_0805_HandSoldering | C9 |
| 1 | 4.7u | Capacitors_SMD:C_0805_HandSoldering | C1 |
| 1 | 47 | Resistors_SMD:R_0805_HandSoldering | R1 |
| 1 | 470 | Resistors_SMD:R_0805_HandSoldering | R6 |
| 1 | 470u | Capacitors_ThroughHole:C_Radial_D7.5_L11.2_P2.5 | C12 |
| 1 | USBLC6-2 | TO_SOT_Packages_SMD:SOT-23-6_Handsoldering | U3 |
| 1 | WS281xDIN | Pin_Headers:Pin_Header_Straight_1x01 | P4 |
| 1 | WS281x_5V | Wire_Pads:SolderWirePad_2x_1-5mmDrill | P5 |
| 1 | WS281x_GND | Wire_Pads:SolderWirePad_2x_1-5mmDrill | P6 |
| 1 | bead | Choke_SMD:Choke_SMD_1206_Handsoldering | L1 |
| 1 | stm32f103 | Pin_Headers:Pin_Header_Straight_1x03 | P1 |
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 mm

- 2 layers

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 mm

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 mm

- 2 layers85 × 40 mm

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 mm

- 4 layers100 × 80 mm

- 4 layers104.5 × 91 mm

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