raspberrypi_utils_sys/
ws2812.rs1use crate::*;
2
3const WS2812_WRAP_TARGET: u32 = 0;
4const WS2812_WRAP: u32 = 3;
5
6const WS2812_T1: u32 = 3;
7const WS2812_T2: u32 = 4;
8const WS2812_T3: u32 = 3;
9const FREQ: u32 = 800_000;
10
11pub struct Ws2812 {
12 pio: *mut pio_instance,
13 sm: u32,
14 gpio_pin: u32,
15 offset: u32,
16}
17
18impl Ws2812 {
19 pub fn new(gpio: u32) -> Result<Self, String> {
20 unsafe {
21 let pio0: PIO = pio_open_helper(0); stdio_init_all();
24
25 let pio = pio0;
28
29 let sm = pio_claim_unused_sm(pio, true);
30
31 if sm < 0 {
32 return Err("No unused state machine available".to_string());
33 }
34
35 let pio_program_instructions: [u16; 4] = [
36 0x6221, 0x1223, 0x1300, 0xa342, ];
43 let ws2812_program = pio_program {
44 instructions: pio_program_instructions.as_ptr(),
45 length: 4,
46 origin: -1,
47 pio_version: 0,
48 };
49
50 let offset = pio_add_program(pio, &ws2812_program);
51
52 println!("WS2812, using GPIO {:?}", gpio);
53 println!("Loaded program at {:?}, using sm {:?}", offset, sm);
54
55 Ok(Self {
56 pio,
57 sm: sm as u32,
58 gpio_pin: gpio,
59 offset,
60 })
61 }
62 }
63
64 fn program_get_default_config(&self) -> pio_sm_config {
65 unsafe {
66 let mut c = pio_get_default_sm_config();
67 sm_config_set_wrap(
68 &mut c,
69 self.offset + WS2812_WRAP_TARGET,
70 self.offset + WS2812_WRAP,
71 );
72 sm_config_set_sideset(&mut c, 1, false, false);
73
74 c
75 }
76 }
77
78 pub fn program_init(&self, frequency: Option<u32>, is_rgbw: bool) {
79 let frequency = frequency.unwrap_or(FREQ);
80
81 unsafe {
82 pio_gpio_init(self.pio, self.gpio_pin);
83 pio_sm_set_consecutive_pindirs(self.pio, self.sm, self.gpio_pin, 1, true);
84 let mut c: pio_sm_config = self.program_get_default_config();
85 sm_config_set_sideset_pins(&mut c, self.gpio_pin);
86 sm_config_set_out_shift(&mut c, false, true, if is_rgbw { 32 } else { 24 });
87 sm_config_set_fifo_join(&mut c, pio_fifo_join_PIO_FIFO_JOIN_TX);
88 let cycles_per_bit = WS2812_T1 + WS2812_T2 + WS2812_T3;
89 let div = clock_get_hz(clock_index_clk_sys) as f32 / (frequency * cycles_per_bit) as f32;
90 sm_config_set_clkdiv(&mut c, div);
91 pio_sm_init(self.pio, self.sm, self.offset, &mut c);
92 pio_sm_set_enabled(self.pio, self.sm, true);
93 }
94 }
95
96 pub fn put_pixel(&self, pixel_grb: u32) {
97 unsafe {
98 pio_sm_put_blocking(self.pio, self.sm, pixel_grb << 8);
99 }
100 }
101}
102
103pub const fn urgb_u32(r: u8, g: u8, b: u8) -> u32 {
104 ((r as u32) << 8) | ((g as u32) << 16) | (b as u32)
105}