FastLED 3.9.15
Loading...
Searching...
No Matches
ezWS2812.h
Go to the documentation of this file.
1/*
2 * ezWS2812.h - Simple WS2812 (NeoPixel) driver for Silicon Labs MGM240/MG24
3 *
4 * Based on Silicon Labs ezWS2812 library by Tamas Jozsi
5 * Copyright (c) 2024 Silicon Laboratories Inc.
6 *
7 * Integrated into FastLED by FastLED Contributors
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28#pragma once
29
30#ifndef ezWS2812_h
31#define ezWS2812_h
32
33#include <Arduino.h> // ok include - SPI driver hardware abstraction
34#include <SPI.h>
35
36namespace fl {
37namespace third_party {
38
56class ezWS2812 {
57private:
60 SPIClass* spi_;
61 // 8 SPI bits encode 1 WS2812 bit -> 8 * 1.25us = 10us at 0.125us per bit
62 // To hit ~1.25us per WS2812 bit, SPI should be ~6.4MHz (1/6.4MHz = 0.15625us)
63 static constexpr uint32_t kSpiClockHz = 6400000;
64 static constexpr uint16_t kResetTimeUs = 80;
65 static constexpr uint8_t kResetByte = 0x00;
66 static constexpr uint8_t kResetBytes = 32;
67
70 inline uint8_t one() const {
71 return 0xF8; // 11111000 - ~0.78us high at 6.4MHz
72 }
73
76 inline uint8_t zero() const {
77 return 0xC0; // 11000000 - ~0.31us high at 6.4MHz
78 }
79
81 void color_to_spi(uint8_t color, uint8_t* buffer) const {
82 for (int i = 7; i >= 0; i--) {
83 buffer[7-i] = (color & (1 << i)) ? one() : zero();
84 }
85 }
86
87public:
91 ezWS2812(uint16_t num_leds, SPIClass& spi = SPI)
92 : num_leds_(num_leds), brightness_(100), spi_(&spi) {}
93
95 void begin() {
96 spi_->begin();
97 spi_->beginTransaction(SPISettings(kSpiClockHz, MSBFIRST, SPI_MODE0));
98 }
99
101 void end() {
102 spi_->endTransaction();
103 }
104
107 brightness_ = (brightness > 100) ? 100 : brightness;
108 }
109
115 void set_pixel(uint8_t red, uint8_t green, uint8_t blue, uint16_t count = 1) {
116 uint8_t spi_buffer[24]; // 3 colors × 8 bits = 24 SPI bytes per pixel
117
118 // Apply brightness
119 red = (red * brightness_) / 100;
120 green = (green * brightness_) / 100;
121 blue = (blue * brightness_) / 100;
122
123 // Convert to SPI bit patterns (GRB order for WS2812)
124 color_to_spi(green, &spi_buffer[0]); // Green first
125 color_to_spi(red, &spi_buffer[8]); // Red second
126 color_to_spi(blue, &spi_buffer[16]); // Blue third
127
128 // Send pixel data
129 for (uint16_t i = 0; i < count && i < num_leds_; i++) {
130 for (int j = 0; j < 24; j++) {
131 spi_->transfer(spi_buffer[j]);
132 }
133 }
134 }
135
140 void set_all(uint8_t red, uint8_t green, uint8_t blue) {
141 set_pixel(red, green, blue, num_leds_);
142 }
143
147 // Force MOSI low long enough to guarantee WS2812 reset/latch.
148 // Sending zero bytes ensures low even if the last data bit was high.
149 for (uint8_t i = 0; i < kResetBytes; i++) {
150 spi_->transfer(kResetByte);
151 }
153 }
154};
155
174private:
181
183 void send_bit(bool bit_value) const {
184 if (F_CPU >= 78000000) {
185 // Timing for 78MHz CPU
186 if (bit_value) {
187 // Send '1' bit: ~0.8µs high, ~0.45µs low
189 __asm__ volatile(
190 "nop; nop; nop; nop; nop; nop; nop; nop;"
191 "nop; nop; nop; nop; nop; nop; nop; nop;"
192 "nop; nop; nop; nop; nop; nop; nop; nop;"
193 "nop; nop; nop; nop; nop; nop; nop; nop;"
194 "nop; nop; nop; nop; nop; nop; nop; nop;"
195 "nop; nop; nop; nop; nop; nop; nop; nop;"
196 "nop; nop; nop; nop; nop; nop; nop; nop;"
197 "nop; nop; nop; nop; nop; nop; nop; nop;"
198 );
200 __asm__ volatile(
201 "nop; nop; nop; nop; nop; nop; nop; nop;"
202 "nop; nop; nop; nop; nop; nop; nop; nop;"
203 "nop; nop; nop; nop; nop; nop; nop; nop;"
204 "nop; nop; nop; nop; nop; nop;"
205 );
206 } else {
207 // Send '0' bit: ~0.4µs high, ~0.85µs low
209 __asm__ volatile(
210 "nop; nop; nop; nop; nop; nop; nop; nop;"
211 "nop; nop; nop; nop; nop; nop; nop; nop;"
212 "nop; nop; nop; nop; nop; nop; nop; nop;"
213 "nop; nop; nop; nop; nop; nop;"
214 );
216 __asm__ volatile(
217 "nop; nop; nop; nop; nop; nop; nop; nop;"
218 "nop; nop; nop; nop; nop; nop; nop; nop;"
219 "nop; nop; nop; nop; nop; nop; nop; nop;"
220 "nop; nop; nop; nop; nop; nop; nop; nop;"
221 "nop; nop; nop; nop; nop; nop; nop; nop;"
222 "nop; nop; nop; nop; nop; nop; nop; nop;"
223 "nop; nop; nop; nop; nop; nop; nop; nop;"
224 );
225 }
226 } else {
227 // Timing for 39MHz CPU (default)
228 if (bit_value) {
229 // Send '1' bit: ~0.8µs high, ~0.45µs low
231 __asm__ volatile(
232 "nop; nop; nop; nop; nop; nop; nop; nop;"
233 "nop; nop; nop; nop; nop; nop; nop; nop;"
234 "nop; nop; nop; nop; nop; nop; nop; nop;"
235 "nop; nop; nop; nop; nop; nop; nop; nop;"
236 );
238 __asm__ volatile(
239 "nop; nop; nop; nop; nop; nop; nop; nop;"
240 "nop; nop; nop; nop; nop; nop; nop;"
241 );
242 } else {
243 // Send '0' bit: ~0.4µs high, ~0.85µs low
245 __asm__ volatile(
246 "nop; nop; nop; nop; nop; nop; nop; nop;"
247 "nop; nop; nop; nop; nop; nop; nop;"
248 );
250 __asm__ volatile(
251 "nop; nop; nop; nop; nop; nop; nop; nop;"
252 "nop; nop; nop; nop; nop; nop; nop; nop;"
253 "nop; nop; nop; nop; nop; nop; nop; nop;"
254 "nop; nop; nop; nop; nop; nop; nop; nop;"
255 );
256 }
257 }
258 }
259
261 void send_byte(uint8_t byte_value) const {
262 for (int i = 7; i >= 0; i--) {
263 send_bit((byte_value >> i) & 0x01);
264 }
265 }
266
267public:
272 : num_leds_(num_leds), pin_(pin), brightness_(100) {}
273
275 void begin() {
276 pinMode(pin_, OUTPUT);
277 digitalWrite(pin_, LOW);
278
279 // Cache port addresses for faster access
280 // Note: This is platform-specific and needs proper implementation
281 // for Silicon Labs MGM240/MG24
282 pin_mask_ = digitalPinToBitMask(pin_);
283 uint8_t port = digitalPinToPort(pin_);
284 port_set_ = portOutputRegister(port);
285 port_clear_ = port_set_ + 1; // Typically clear register is next
286 }
287
289 void end() {
290 digitalWrite(pin_, LOW);
291 }
292
295 brightness_ = (brightness > 100) ? 100 : brightness;
296 }
297
299 void set_pixel(uint8_t red, uint8_t green, uint8_t blue, uint16_t count = 1) {
300 // Apply brightness
301 red = (red * brightness_) / 100;
302 green = (green * brightness_) / 100;
303 blue = (blue * brightness_) / 100;
304
305 noInterrupts();
306 for (uint16_t i = 0; i < count && i < num_leds_; i++) {
307 // Send in GRB order for WS2812
308 send_byte(green);
309 send_byte(red);
310 send_byte(blue);
311 }
312 interrupts();
313 }
314
316 void set_all(uint8_t red, uint8_t green, uint8_t blue) {
317 set_pixel(red, green, blue, num_leds_);
318 }
319
322 // WS2812 reset time (>50µs low)
324 }
325};
326
327} // namespace third_party
328} // namespace fl
329
330#endif // ezWS2812_h
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
void set_brightness(uint8_t brightness)
Set brightness (0-100%)
Definition ezWS2812.h:106
uint8_t one() const
Convert color bit to SPI signal for '1' bit.
Definition ezWS2812.h:70
void end()
End SPI communication.
Definition ezWS2812.h:101
void end_transfer()
Complete LED data transfer Sends reset signal to latch data into LEDs.
Definition ezWS2812.h:146
static constexpr uint32_t kSpiClockHz
Definition ezWS2812.h:63
uint8_t zero() const
Convert color bit to SPI signal for '0' bit.
Definition ezWS2812.h:76
void begin()
Initialize SPI communication.
Definition ezWS2812.h:95
ezWS2812(uint16_t num_leds, SPIClass &spi=SPI)
Constructor.
Definition ezWS2812.h:91
static constexpr uint8_t kResetBytes
Definition ezWS2812.h:66
void set_all(uint8_t red, uint8_t green, uint8_t blue)
Set all LEDs to the same color.
Definition ezWS2812.h:140
void color_to_spi(uint8_t color, uint8_t *buffer) const
Convert color byte to SPI bit pattern.
Definition ezWS2812.h:81
static constexpr uint8_t kResetByte
Definition ezWS2812.h:65
void set_pixel(uint8_t red, uint8_t green, uint8_t blue, uint16_t count=1)
Set color for specific number of LEDs.
Definition ezWS2812.h:115
static constexpr uint16_t kResetTimeUs
Definition ezWS2812.h:64
ezWS2812gpio(uint16_t num_leds, uint8_t pin)
Constructor.
Definition ezWS2812.h:271
volatile uint32_t * port_set_
Definition ezWS2812.h:179
volatile uint32_t * port_clear_
Definition ezWS2812.h:180
void set_brightness(uint8_t brightness)
Set brightness (0-100%)
Definition ezWS2812.h:294
void send_bit(bool bit_value) const
Send a single bit using precise timing.
Definition ezWS2812.h:183
void end_transfer()
Complete LED data transfer.
Definition ezWS2812.h:321
void end()
End communication.
Definition ezWS2812.h:289
void begin()
Initialize GPIO pin.
Definition ezWS2812.h:275
void set_all(uint8_t red, uint8_t green, uint8_t blue)
Set all LEDs to the same color.
Definition ezWS2812.h:316
void send_byte(uint8_t byte_value) const
Send a byte (8 bits) with MSB first.
Definition ezWS2812.h:261
void set_pixel(uint8_t red, uint8_t green, uint8_t blue, uint16_t count=1)
Set color for specific number of LEDs.
Definition ezWS2812.h:299
fl::u32 uint32_t
Definition coder.h:219
fl::u16 uint16_t
Definition coder.h:214
unsigned char uint8_t
Definition coder.h:209
@ SPI
Generic SPI clockless driver.
Definition bus.h:64
void pinMode(int pin, PinMode mode)
Set pin mode (input, output, pull-up, pull-down)
Definition pin.cpp.hpp:378
void digitalWrite(int pin, PinValue val)
Write digital value to pin.
Definition pin.cpp.hpp:51
void delayMicroseconds(u32 us)
Delay for a given number of microseconds.
Base definition for an LED controller.
Definition crgb.hpp:179