I80Peripheral
Source:
I80Peripheral.h
I80Peripheral¶
src/light/drivers/I80Peripheral.h:24Inherits:
LedPeripheral
Output driver: parallel 8-or-16-lane WS2812B over the ESP-IDF esp_lcd i80 bus, the scale path on all three i80-capable ESP32 families.
RMT gives a chip 4-8 channels; this gives 8-16 lanes for the wall time of one. The shared body lives in ParallelLedDriver and the wire format in [ParallelSlots.h].
Prior art: Adafruit's LCD_CAM discovery, hpwit's I2SClockless lineage, FastLED's S3 driver. Architecture studied and never copied, on IDF's esp_lcd rather than the raw registers.
Public Attributes¶
int8_t clockPin = > 0 ? -1 : 10
: The i80 bus's write strobe; the pixel clock the peripheral mandates. See the driver page.
int8_t dcPin = > 0 ? 33 : 11
: The i80 bus's data/command select; unused by WS2812 but mandated by the peripheral.
Public Methods¶
virtual inline uint8_t lanesAvailable() const override
: The number of i80 lanes this chip provides (0 = no i80 bus on this chip); the orchestrator's.
virtual inline bool powerOfTwoBus() const override
: Whether the bus width must round to a power of two. On i80 it must.
virtual inline size_t dmaBudgetBytes() const override
: The largest frame whole-frame DMA can carry, 0 meaning no bound.
virtual inline bool loopbackFullWidth() const override
: Whether the loopback needs the full operational bus width. On i80 it does.
virtual inline LedHwBlock hwBlock() const override
: The peripheral block this backend claims, for the sibling guard.
virtual inline bool busContentionCleared() const override
: Whether the shared peripheral instance this bus needs is free right now.
virtual inline const char * initFailMsg() const override
: What the status says when the bus will not come up.
virtual inline uint16_t clockPinForBus() const override
: The GPIO spare lanes park on, overriding the interface default.
virtual inline void addBusControls(ControlList & controls) override
: Bind the sacrificial WR (clockPin) and DC pins the i80 peripheral mandates.
virtual inline bool busControlTriggersBuild(const char * name) const override
: Whether changing name needs the bus rebuilt: clockPin and dcPin do.
virtual inline const char * validateBusFatal() const override
: Why the bus pins are fatally wrong, or null when they are usable.
virtual inline const char * validateBusPins(const uint16_t * lanes, uint8_t n) const override
: Which data lane collides with WR or DC, as a warning, or null when the set is clear.
virtual inline bool supportsPinExpander() const override
: Whether a 74HCT595 pin expander can ride this bus.
virtual inline bool busInit(size_t frameBytes, bool wantSecondBuffer) override
: Create the i80 bus and its DMA buffers for frameBytes on the current lanes.
virtual inline uint8_t * busBuffer(uint8_t i) override
: DMA buffer i (0 or 1) the orchestrator encodes into.
virtual inline size_t busCapacity() const override
: The per-buffer byte capacity (fixed at bus creation; both buffers equal).
virtual inline bool busTransmit(uint8_t i, size_t bytes) override
: Start the autonomous transfer of the first bytes of DMA buffer i, returning whether it began.
virtual inline bool busWait(uint8_t i, uint32_t ms) override
: Block up to ms for buffer i's in-flight transfer to complete.
virtual inline uint32_t busLastTransmitUs() const override
: The most recent DMA transfer's wire time (µs): the WS2812 output floor.
virtual inline void busDeinit() override
: Tear down the i80 bus and its DMA buffer.
virtual inline platform::RmtLoopbackResult busLoopback(const uint8_t * frame, size_t frameBytes, size_t dataBytes, uint8_t rowBits) override
: Run the loopback self-test on a full-width private bus.
virtual inline void recordBusPins() override
: Store WR and DC alongside the data pins, so editing either rebuilds the bus.
virtual inline bool extraBusPinsCurrent() const override
: Whether the live bus's WR and DC pins still match the controls, so a rebuild can be skipped.
More info¶
One API, two peripherals. ESP-IDF exposes one public i80 API and routes it to whatever the silicon has: LCD_CAM on the S3, P4 and S31, and the I2S peripheral on the classic, its only route past 8 lanes. They are mutually exclusive per chip, so lanesAvailable() reads whichever lane count is non-zero. Named for the bus, since two peripherals serve it.
The 3-slot-per-bit wire contract. Each WS2812 bit becomes three bus slots at 2.67 MHz, a 375 ns slot: every active lane HIGH, the data bits, then all LOW. A 1 is HIGH 750 ns and a 0 375 ns, approximating RMT's 700/350 rather than the lineage's ~416 ns. That stays under the 380 ns T0H max newer WS2812B revisions spec.
Both silicon paths do whole-frame chained DMA. So the classic I2S path is WiFi-underrun-immune by construction, and needs none of the ISR-refilled ring the lineage requires.