FastLED 3.10.9
Loading...
Searching...
No Matches
bus.h
Go to the documentation of this file.
1#pragma once
2
5
7#include "fl/stl/noexcept.h"
9#include "fl/stl/stdint.h"
10#include "platforms/is_platform.h"
11
12// Platform CMSIS/Arduino headers may define peripheral pointer macros that
13// collide with Bus enumerators and qualified names such as Bus::SPI.
14#pragma push_macro("UART")
15#pragma push_macro("SPI")
16#pragma push_macro("I2S")
17#undef UART
18#undef SPI
19#undef I2S
20
21namespace fl {
22
23struct ClocklessChipset;
24struct SpiChipsetConfig;
25
38
39template<typename Chipset> struct DefaultBus;
40
41#if defined(FL_IS_STUB) || defined(FL_IS_WASM)
42
43template<> struct DefaultBus<ClocklessChipset> {
44 static constexpr Bus value = Bus::BIT_BANG;
45};
46
47template<> struct DefaultBus<SpiChipsetConfig> {
48 static constexpr Bus value = Bus::BIT_BANG;
49};
50
51#elif defined(FL_IS_ESP32)
52
53#if defined(FL_IS_ESP_32P4) || defined(FL_IS_ESP_32C6) || \
54 defined(FL_IS_ESP_32H2) || defined(FL_IS_ESP_32C5)
55template<> struct DefaultBus<ClocklessChipset> {
56 static constexpr Bus value = Bus::FLEX_IO;
57};
58#else
59template<> struct DefaultBus<ClocklessChipset> {
60 static constexpr Bus value = Bus::RMT;
61};
62#endif
63
64#if defined(FL_IS_ESP_32S3) || defined(FL_IS_ESP_32DEV) || \
65 defined(FL_IS_ESP_32P4) || defined(FL_IS_ESP_32C6) || \
66 defined(FL_IS_ESP_32H2) || defined(FL_IS_ESP_32C5)
67template<> struct DefaultBus<SpiChipsetConfig> {
68 static constexpr Bus value = Bus::FLEX_IO;
69};
70#else
71template<> struct DefaultBus<SpiChipsetConfig> {
72 static constexpr Bus value = Bus::BIT_BANG;
73};
74#endif
75
76#elif defined(FL_IS_TEENSY_4X)
77
78template<> struct DefaultBus<ClocklessChipset> {
79 static constexpr Bus value = Bus::FLEX_IO;
80};
81
82template<> struct DefaultBus<SpiChipsetConfig> {
83 static constexpr Bus value = Bus::FLEX_IO;
84};
85
86#elif defined(FL_IS_ARM_LPC)
87
88// LPC845 defaults clockless AUTO to the USART DMA engine. Other LPC8xx /
89// LPC11Uxx / LPC15xx targets keep the shared cycle-counted C++ driver
90// (FASTLED_M0_USE_C_IMPLEMENTATION in led_sysdefs_arm_lpc.h), which is
91// what Bus::BIT_BANG names.
92template<> struct DefaultBus<ClocklessChipset> {
93#if defined(FL_IS_ARM_LPC_845) && FASTLED_LPC_UART_DMA
94 static constexpr Bus value = Bus::UART;
95#else
96 static constexpr Bus value = Bus::BIT_BANG;
97#endif
98};
99
100// LPC845 / LPC804 have a hardware SPI driver (spi_arm_lpc.h, UM11029).
101// LPC11xx / LPC15xx do not yet ship one (#2845 Stage 4) — they fall
102// through to the unspecialized DefaultBus, which is intentional: a
103// link error there is the right signal that no SPI driver is wired.
104#if defined(FL_IS_ARM_LPC_845) || defined(FL_IS_ARM_LPC_804)
105template<> struct DefaultBus<SpiChipsetConfig> {
106 static constexpr Bus value = Bus::SPI;
107};
108#endif
109
110#elif defined(FL_IS_RP2040) || defined(FL_IS_RP2350)
111
112template<> struct DefaultBus<SpiChipsetConfig> {
113 static constexpr Bus value = Bus::SPI;
114};
115
116#elif defined(FL_IS_ESP8266)
117
118// ESP8266 has no peripheral engine wired through the channel API yet, so both
119// chipset families resolve to the shared GPIO bit-bang driver
120// (`src/platforms/shared/bitbang/bus_traits.h`). A native engine (I2S, see
121// #4943) can replace the clockless default later. This is a template selection,
122// not a code-enabling define: naming `Bus::AUTO` is what keeps the driver's
123// translation unit, and the selection is fully type-checked either way.
124template<> struct DefaultBus<ClocklessChipset> {
125 static constexpr Bus value = Bus::BIT_BANG;
126};
127
128template<> struct DefaultBus<SpiChipsetConfig> {
129 static constexpr Bus value = Bus::BIT_BANG;
130};
131
132#endif
133
134template<Bus B> struct BusInstanceCount {
135 static constexpr fl::u8 value = 1;
136};
137
138#if defined(FL_IS_TEENSY_4X)
139template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 2; };
140template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 4; };
141template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 1; };
142#elif defined(FL_IS_ESP_32S3)
143template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 2; };
144template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 2; };
145template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 3; };
146#elif defined(FL_IS_ESP_32C6)
147template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 2; };
148template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 1; };
149template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 2; };
150#elif defined(FL_IS_ESP_32DEV)
151// Classic ESP32 (FastLED#3576 Phase 1): FLEX_IO instance 0 = I2S1
152// primary clockless bank, instance 1 = I2S0 second bank ("I2S0",
153// contended with the clocked-SPI driver via the port-claim registry).
154template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 2; };
155template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 2; };
156template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 2; };
157#elif defined(FL_IS_ARM_LPC_845)
158template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 1; };
159#elif defined(FL_IS_RP2350)
160template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 3; };
161template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 2; };
162template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 2; };
163#elif defined(FL_IS_RP2040)
164template<> struct BusInstanceCount<Bus::FLEX_IO> { static constexpr fl::u8 value = 2; };
165template<> struct BusInstanceCount<Bus::SPI> { static constexpr fl::u8 value = 2; };
166template<> struct BusInstanceCount<Bus::UART> { static constexpr fl::u8 value = 2; };
167#endif
168
169inline const char* busName(Bus b, fl::u8 which = 0) FL_NO_EXCEPT {
170 (void)which;
171 switch (b) {
172 case Bus::AUTO: return "AUTO";
173 case Bus::BIT_BANG: return "BIT_BANG";
174 case Bus::UART: return "UART";
175 case Bus::SPI: return "SPI";
176 case Bus::DUAL_SPI: return "DUAL_SPI";
177 case Bus::QUAD_SPI: return "QUAD_SPI";
178 case Bus::OCTAL_SPI: return "OCTAL_SPI";
179 case Bus::RMT: return "RMT";
180 case Bus::FLEX_IO: return "FLEX_IO";
181 }
182 return "";
183}
184
186inline const char* busDriverName(Bus b, fl::u8 which = 0, bool spi = false) FL_NO_EXCEPT {
187 switch (b) {
188 case Bus::FLEX_IO:
189#if defined(FL_IS_TEENSY_4X)
190 (void)spi;
191 return which == 0 ? "OBJECT_FLED" : "FLEX_IO";
192#elif defined(FL_IS_ESP8266)
193 // ESP8266 has no parallel-I/O bank; `Bus::FLEX_IO` names its native
194 // I2S output engine (#4943), matching ESP32's I2S naming.
195 (void)which;
196 (void)spi;
197 return "I2S";
198#elif defined(FL_IS_RP2040) || defined(FL_IS_RP2350)
199 (void)spi;
200 if (which == 0) return "PIO0";
201 if (which == 1) return "PIO1";
202 #if defined(FL_IS_RP2350)
203 if (which == 2) return "PIO2";
204 #endif
205 return "FLEX_IO_UNAVAILABLE";
206#elif defined(FL_IS_ESP32)
207#if FASTLED_HAS_PARLIO
208 (void)which;
209 (void)spi;
210 return "PARLIO";
211#elif FASTLED_HAS_LCD_SPI || FASTLED_HAS_LCD_CAM_CLOCKLESS
212 (void)which;
213 return spi ? "LCD_SPI" : "LCD_CLOCKLESS";
214#elif FASTLED_HAS_I2S_SPI || FASTLED_HAS_I2S_LED
215 (void)which;
216 return spi ? "I2S_SPI" : "I2S";
217#else
218 (void)which;
219 (void)spi;
220 return "FLEX_IO";
221#endif
222#else
223 (void)which;
224 (void)spi;
225 return "FLEX_IO";
226#endif
227 case Bus::AUTO:
228 case Bus::BIT_BANG:
229 case Bus::DUAL_SPI:
230 case Bus::QUAD_SPI:
231 case Bus::OCTAL_SPI:
232 case Bus::RMT:
233 (void)spi;
234 return busName(b, which);
235 case Bus::SPI:
236#if defined(FL_IS_RP2040) || defined(FL_IS_RP2350)
237 (void)spi;
238 return which == 0 ? "SPI0" : "SPI1";
239#else
240 (void)spi;
241 return busName(b, which);
242#endif
243 case Bus::UART:
244 (void)spi;
245#if defined(FL_IS_RP2040) || defined(FL_IS_RP2350)
246 return which == 0 ? "UART0" : "UART1";
247#elif defined(FL_IS_TEENSY_4X)
248 (void)which;
249 return "LPUART";
250#else
251 (void)which;
252 return "UART";
253#endif
254 }
255 return "";
256}
257
259 "Bus changed: update busName() and busDriverName()");
260
261} // namespace fl
262
263#pragma pop_macro("I2S")
264#pragma pop_macro("SPI")
265#pragma pop_macro("UART")
Zero-filled feature macros for portable bus selection.
unsigned char u8
Definition s16x16x4.h:132
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
const char * busName(Bus b, fl::u8 which=0) FL_NO_EXCEPT
Definition bus.h:169
const char * busDriverName(Bus b, fl::u8 which=0, bool spi=false) FL_NO_EXCEPT
Concrete ChannelManager driver name for a portable bus.
Definition bus.h:186
Bus
Portable public bus selector.
Definition bus.h:27
@ FLEX_IO
Definition bus.h:36
@ DUAL_SPI
Definition bus.h:32
@ QUAD_SPI
Definition bus.h:33
@ SPI
Definition bus.h:31
@ OCTAL_SPI
Definition bus.h:34
@ BIT_BANG
Definition bus.h:29
@ RMT
Definition bus.h:35
@ UART
Definition bus.h:30
@ AUTO
Definition bus.h:28
Base definition for an LED controller.
#define FL_STATIC_ASSERT(...)
Portable compile-time assertion wrapper.
static constexpr fl::u8 value
Definition bus.h:135
Clockless chipset configuration (single data pin)
Definition config.h:33
SPI chipset configuration (data + clock pins)
Definition config.h:103