; ; ws2812.pio ; ; WS2812B waveform generator. One PIO state machine clocks the 1.25us bit ; cell directly, which is what PIO is for - unlike the Circle build, which ; has to fake the waveform by streaming 8 SPI bytes per data bit. ; ; Timing per bit (T1+T2+T3 = 10 cycles = 1.25us, so the SM runs at 8MHz): ; '0' = 0.4us high, 0.85us low ; '1' = 0.8us high, 0.45us low ; .program ws2812 .side_set 1 .define public T1 3 .define public T2 3 .define public T3 4 .wrap_target bitloop: out x, 1 side 0 [T3 - 1] jmp !x do_zero side 1 [T1 - 1] do_one: jmp bitloop side 1 [T2 - 1] do_zero: nop side 0 [T2 - 1] .wrap % c-sdk { #include "hardware/clocks.h" static inline void ws2812_program_init (PIO pio, uint sm, uint offset, uint pin, float freq) { pio_gpio_init (pio, pin); pio_sm_set_consecutive_pindirs (pio, sm, pin, 1, true); pio_sm_config c = ws2812_program_get_default_config (offset); sm_config_set_sideset_pins (&c, pin); // 24 bits per LED, shifted out MSB first, auto-pulled a byte-triple at a time. sm_config_set_out_shift (&c, false, true, 24); sm_config_set_fifo_join (&c, PIO_FIFO_JOIN_TX); int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3; float div = clock_get_hz (clk_sys) / (freq * cycles_per_bit); sm_config_set_clkdiv (&c, div); pio_sm_init (pio, sm, offset, &c); pio_sm_set_enabled (pio, sm, true); } %}