diff options
Diffstat (limited to 'embassy-rp/src/pio_programs/ws2812.rs')
| -rw-r--r-- | embassy-rp/src/pio_programs/ws2812.rs | 93 |
1 files changed, 78 insertions, 15 deletions
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index e6851b1a6..3c16367e6 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs | |||
| @@ -1,21 +1,67 @@ | |||
| 1 | //! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | 1 | //! [ws2812](https://www.sparkfun.com/categories/tags/ws2812) |
| 2 | 2 | ||
| 3 | use embassy_time::Timer; | 3 | use embassy_time::Timer; |
| 4 | use fixed::types::U24F8; | 4 | use fixed::types::U24F8; |
| 5 | use smart_leds::{RGB8, RGBW}; | 5 | use smart_leds::{RGB8, RGBW}; |
| 6 | 6 | ||
| 7 | use crate::Peri; | ||
| 8 | use crate::clocks::clk_sys_freq; | 7 | use crate::clocks::clk_sys_freq; |
| 9 | use crate::dma::{AnyChannel, Channel}; | 8 | use crate::dma::{AnyChannel, Channel}; |
| 10 | use crate::pio::{ | 9 | use crate::pio::{ |
| 11 | Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, | 10 | Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, |
| 12 | }; | 11 | }; |
| 12 | use crate::Peri; | ||
| 13 | 13 | ||
| 14 | const T1: u8 = 2; // start bit | 14 | const T1: u8 = 2; // start bit |
| 15 | const T2: u8 = 5; // data bit | 15 | const T2: u8 = 5; // data bit |
| 16 | const T3: u8 = 3; // stop bit | 16 | const T3: u8 = 3; // stop bit |
| 17 | const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; | 17 | const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; |
| 18 | 18 | ||
| 19 | /// This trait defines the contract for color ordering | ||
| 20 | pub trait ColorOrder { | ||
| 21 | type ColorType; | ||
| 22 | |||
| 23 | // Pack the type specific struct into a u32 word in the correct order | ||
| 24 | fn pack(color: Self::ColorType) -> u32; | ||
| 25 | } | ||
| 26 | |||
| 27 | /// Color orders for WS2812B, type RGB8 | ||
| 28 | /// Green, Red, Blue order is the common default for WS2812B | ||
| 29 | pub struct Grb; | ||
| 30 | impl ColorOrder for Grb { | ||
| 31 | type ColorType = RGB8; | ||
| 32 | fn pack(color: Self::ColorType) -> u32 { | ||
| 33 | (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8) | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Red, Green, Blue is used by some WS2812B implementations | ||
| 38 | pub struct Rgb; | ||
| 39 | impl ColorOrder for Rgb { | ||
| 40 | type ColorType = RGB8; | ||
| 41 | fn pack(color: Self::ColorType) -> u32 { | ||
| 42 | (u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8) | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | /// Color orders RGBW strips | ||
| 47 | /// Green, Red, Blue, White order is the common default for RGBW strips | ||
| 48 | pub struct Grbw; | ||
| 49 | impl ColorOrder for Grbw { | ||
| 50 | type ColorType = RGBW<u8>; | ||
| 51 | fn pack(color: Self::ColorType) -> u32 { | ||
| 52 | (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0) | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Red, Green, Blue, White order | ||
| 57 | pub struct Rgbw; | ||
| 58 | impl ColorOrder for Rgbw { | ||
| 59 | type ColorType = RGBW<u8>; | ||
| 60 | fn pack(color: Self::ColorType) -> u32 { | ||
| 61 | (u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0) | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 19 | /// This struct represents a ws2812 program loaded into pio instruction memory. | 65 | /// This struct represents a ws2812 program loaded into pio instruction memory. |
| 20 | pub struct PioWs2812Program<'a, PIO: Instance> { | 66 | pub struct PioWs2812Program<'a, PIO: Instance> { |
| 21 | prg: LoadedProgram<'a, PIO>, | 67 | prg: LoadedProgram<'a, PIO>, |
| @@ -52,12 +98,19 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { | |||
| 52 | 98 | ||
| 53 | /// Pio backed RGB ws2812 driver | 99 | /// Pio backed RGB ws2812 driver |
| 54 | /// Const N is the number of ws2812 leds attached to this pin | 100 | /// Const N is the number of ws2812 leds attached to this pin |
| 55 | pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { | 101 | pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER = Grb> |
| 102 | where | ||
| 103 | ORDER: ColorOrder<ColorType = RGB8>, | ||
| 104 | { | ||
| 56 | dma: Peri<'d, AnyChannel>, | 105 | dma: Peri<'d, AnyChannel>, |
| 57 | sm: StateMachine<'d, P, S>, | 106 | sm: StateMachine<'d, P, S>, |
| 107 | _order: core::marker::PhantomData<ORDER>, | ||
| 58 | } | 108 | } |
| 59 | 109 | ||
| 60 | impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | 110 | impl<'d, P: Instance, const S: usize, const N: usize, ORDER = Grb> PioWs2812<'d, P, S, N, ORDER> |
| 111 | where | ||
| 112 | ORDER: ColorOrder<ColorType = RGB8>, | ||
| 113 | { | ||
| 61 | /// Configure a pio state machine to use the loaded ws2812 program. | 114 | /// Configure a pio state machine to use the loaded ws2812 program. |
| 62 | pub fn new( | 115 | pub fn new( |
| 63 | pio: &mut Common<'d, P>, | 116 | pio: &mut Common<'d, P>, |
| @@ -93,7 +146,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 93 | sm.set_config(&cfg); | 146 | sm.set_config(&cfg); |
| 94 | sm.set_enable(true); | 147 | sm.set_enable(true); |
| 95 | 148 | ||
| 96 | Self { dma: dma.into(), sm } | 149 | Self { |
| 150 | dma: dma.into(), | ||
| 151 | sm, | ||
| 152 | _order: core::marker::PhantomData, | ||
| 153 | } | ||
| 97 | } | 154 | } |
| 98 | 155 | ||
| 99 | /// Write a buffer of [smart_leds::RGB8] to the ws2812 string | 156 | /// Write a buffer of [smart_leds::RGB8] to the ws2812 string |
| @@ -101,8 +158,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 101 | // Precompute the word bytes from the colors | 158 | // Precompute the word bytes from the colors |
| 102 | let mut words = [0u32; N]; | 159 | let mut words = [0u32; N]; |
| 103 | for i in 0..N { | 160 | for i in 0..N { |
| 104 | let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); | 161 | words[i] = ORDER::pack(colors[i]); |
| 105 | words[i] = word; | ||
| 106 | } | 162 | } |
| 107 | 163 | ||
| 108 | // DMA transfer | 164 | // DMA transfer |
| @@ -115,12 +171,19 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 115 | /// Pio backed RGBW ws2812 driver | 171 | /// Pio backed RGBW ws2812 driver |
| 116 | /// This version is intended for ws2812 leds with 4 addressable lights | 172 | /// This version is intended for ws2812 leds with 4 addressable lights |
| 117 | /// Const N is the number of ws2812 leds attached to this pin | 173 | /// Const N is the number of ws2812 leds attached to this pin |
| 118 | pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> { | 174 | pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER = Grbw> |
| 175 | where | ||
| 176 | ORDER: ColorOrder<ColorType = RGBW<u8>>, | ||
| 177 | { | ||
| 119 | dma: Peri<'d, AnyChannel>, | 178 | dma: Peri<'d, AnyChannel>, |
| 120 | sm: StateMachine<'d, P, S>, | 179 | sm: StateMachine<'d, P, S>, |
| 180 | _order: core::marker::PhantomData<ORDER>, | ||
| 121 | } | 181 | } |
| 122 | 182 | ||
| 123 | impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> { | 183 | impl<'d, P: Instance, const S: usize, const N: usize, ORDER = Grbw> RgbwPioWs2812<'d, P, S, N, ORDER> |
| 184 | where | ||
| 185 | ORDER: ColorOrder<ColorType = RGBW<u8>>, | ||
| 186 | { | ||
| 124 | /// Configure a pio state machine to use the loaded ws2812 program. | 187 | /// Configure a pio state machine to use the loaded ws2812 program. |
| 125 | pub fn new( | 188 | pub fn new( |
| 126 | pio: &mut Common<'d, P>, | 189 | pio: &mut Common<'d, P>, |
| @@ -156,7 +219,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> | |||
| 156 | sm.set_config(&cfg); | 219 | sm.set_config(&cfg); |
| 157 | sm.set_enable(true); | 220 | sm.set_enable(true); |
| 158 | 221 | ||
| 159 | Self { dma: dma.into(), sm } | 222 | Self { |
| 223 | dma: dma.into(), | ||
| 224 | sm, | ||
| 225 | _order: core::marker::PhantomData, | ||
| 226 | } | ||
| 160 | } | 227 | } |
| 161 | 228 | ||
| 162 | /// Write a buffer of [smart_leds::RGBW] to the ws2812 string | 229 | /// Write a buffer of [smart_leds::RGBW] to the ws2812 string |
| @@ -164,11 +231,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> | |||
| 164 | // Precompute the word bytes from the colors | 231 | // Precompute the word bytes from the colors |
| 165 | let mut words = [0u32; N]; | 232 | let mut words = [0u32; N]; |
| 166 | for i in 0..N { | 233 | for i in 0..N { |
| 167 | let word = (u32::from(colors[i].g) << 24) | 234 | words[i] = ORDER::pack(colors[i]); |
| 168 | | (u32::from(colors[i].r) << 16) | ||
| 169 | | (u32::from(colors[i].b) << 8) | ||
| 170 | | u32::from(colors[i].a.0); | ||
| 171 | words[i] = word; | ||
| 172 | } | 235 | } |
| 173 | 236 | ||
| 174 | // DMA transfer | 237 | // DMA transfer |
