esp icon indicating copy to clipboard operation
esp copied to clipboard

LEDS interface I2S setup/async mode

Open SpComb opened this issue 2 months ago • 2 comments

Fixes https://github.com/qmsk/esp/issues/86

New leds -> interface_setup = true mode to replace the leds_tx() -> i2s_out_setup() with a one-time i2s_out_setup(). This only works with one leds per interface, and does not work if sharing interfaces between multiple leds instances. This is currently only supported for I2S interfaces, and has no effect for other interfaces.

This allows a new async mode of operation where leds_interface_i2s_tx() now calls i2s_out_write_*() -> i2s_out_start() instead of i2s_out_flush(), which fills the I2S DMA buffer and starts the DMA/TX as previously, but does not wait for it to complete. The next loop -> tx can then start filling up the DMA buffer as DMA descriptors are freed up by the EOF interrupt, and waits for the previous TX to complete before starting the new TX using the recycled DMA buffer/descriptors.

This significantly increases the efficiency of the LEDS I2S interface, and it can now reach framerates close to the theoretical maximum (800kbps / (24-bits-per-pixel × pixel-count)).

SpComb avatar Oct 28 '25 18:10 SpComb

54.6 FPS with TEST_MODE_CHASE and 600 serial LEDs - that's 98.3% of the theoretical maxium (800000 / 24 / 600 = 55.55555555555556).

> leds stats reset
	      spi : open              0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	      spi : tx                0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util

	     uart : open              0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     uart : tx                0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util

	     i2s0 : open              0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     i2s0 : write            76 count @        1.390s =   54.7/s avg,        1.391s total,   18.3ms avg, 100.0% util
	     i2s0 : start          2476 count @       48.338s =   51.2/s avg,        0.192s total,    0.1ms avg,   0.4% util
	     i2s0 : flush             0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util

	     i2s1 : open              0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     i2s1 : write             0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     i2s1 : start             0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     i2s1 : flush             0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util

	 sequence : read              0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	 sequence : skip              0 count @        0.000s =    nan/s avg
leds2:
	     task : loop             78 count @        1.428s =   54.6/s avg,        1.445s total,   18.5ms avg, 101.2% util
	     task : test             79 count @        1.446s =   54.6/s avg,        0.002s total,    0.0ms avg,   0.1% util
	     task : artnet            0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     task : sequence          0 count @        0.000s =    0.0/s avg,        0.000s total,    0.0ms avg,   0.0% util
	     task : update           80 count @        1.465s =   54.6/s avg,        1.480s total,   18.5ms avg, 101.0% util

	   artnet : timeout           0 count @        0.000s =    nan/s avg
	   artnet : sync              0 count @        0.000s =    nan/s avg
	     sync : none              0 count @        0.000s =    nan/s avg
	     sync : timeout           0 count @        0.000s =    nan/s avg
	     sync : missed            0 count @        0.000s =    nan/s avg
	     sync : full              0 count @        0.000s =    nan/s avg
	   update : timeout           0 count @        0.000s =    nan/s avg

SpComb avatar Oct 28 '25 18:10 SpComb

config save -> flash writes have a nasty tendency to block i2s_out_dma_flush(), the EOF / TOTAL_EOF interrupts are somehow getting lost...?

> config save
I (132396) config_save: /config/boot.ini.new
I (132796) config_save: state save
> E (137566) i2s_out_dma_flush: timeout -> bits=00000001
E (137566) i2s_out_wait: i2s_out_dma_flush
E (137566) leds_interface_i2s_tx: i2s_out_start
E (137576) update_leds: leds_tx
W (137576) leds_main: leds1: update_leds
W (137576) user_alert: ERROR_LEDS
W (137576) reset_leds: Reset LEDS interface
E (142576) i2s_out_dma_flush: timeout -> bits=00000001
E (142576) i2s_out_wait: i2s_out_dma_flush
E (142576) leds_interface_i2s_close: i2s_out_close
W (142586) reset_leds: leds_interface_close

This is still recoverable per reset_leds(), with a 2×timeout pause in LED updates.

SpComb avatar Oct 28 '25 20:10 SpComb