aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranton smeenk <[email protected]>2023-04-18 20:56:57 +0200
committerDario Nieuwenhuis <[email protected]>2023-04-18 20:59:25 +0200
commit3260f6b2aff824a5f7f2a81283b234bdb1bd3e24 (patch)
treed23428ff0278b4a38bf856cde83c11f872876dd5
parent2080d8bb6de58eb2da2ca5df2437ac8cc6577661 (diff)
stm32/spi: add new_txonly_nosck constructor, for neopixels, with an example in the stm32g0 directory.
-rw-r--r--embassy-stm32/src/spi/mod.rs17
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs101
2 files changed, 118 insertions, 0 deletions
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 9ce0cebfe..492d0649a 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -177,6 +177,23 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
177 ) 177 )
178 } 178 }
179 179
180 pub fn new_txonly_nosck(
181 peri: impl Peripheral<P = T> + 'd,
182 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
183 txdma: impl Peripheral<P = Tx> + 'd,
184 rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
185 freq: Hertz,
186 config: Config,
187 ) -> Self {
188 into_ref!(mosi);
189 unsafe {
190 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
191 mosi.set_speed(crate::gpio::Speed::Medium);
192 }
193
194 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
195 }
196
180 /// Useful for on chip peripherals like SUBGHZ which are hardwired. 197 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
181 /// The bus can optionally be exposed externally with `Spi::new()` still. 198 /// The bus can optionally be exposed externally with `Spi::new()` still.
182 #[allow(dead_code)] 199 #[allow(dead_code)]
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
new file mode 100644
index 000000000..81fdd15cb
--- /dev/null
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -0,0 +1,101 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::word::U5;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14const NR_PIXELS: usize = 15;
15const BITS_PER_PIXEL: usize = 24; // 24 for rgb, 32 for rgbw
16const TOTAL_BITS: usize = NR_PIXELS * BITS_PER_PIXEL;
17
18struct RGB {
19 r: u8,
20 g: u8,
21 b: u8,
22}
23impl Default for RGB {
24 fn default() -> RGB {
25 RGB { r: 0, g: 0, b: 0 }
26 }
27}
28pub struct Ws2812 {
29 // Note that the U5 type controls the selection of 5 bits to output
30 bitbuffer: [U5; TOTAL_BITS],
31}
32
33impl Ws2812 {
34 pub fn new() -> Ws2812 {
35 Ws2812 {
36 bitbuffer: [U5(0); TOTAL_BITS],
37 }
38 }
39 fn len(&self) -> usize {
40 return NR_PIXELS;
41 }
42 fn set(&mut self, idx: usize, rgb: RGB) {
43 self.render_color(idx, 0, rgb.g);
44 self.render_color(idx, 8, rgb.r);
45 self.render_color(idx, 16, rgb.b);
46 }
47 // transform one color byte into an array of 8 byte. Each byte in the array does represent 1 neopixel bit pattern
48 fn render_color(&mut self, pixel_idx: usize, offset: usize, color: u8) {
49 let mut bits = color as usize;
50 let mut idx = pixel_idx * BITS_PER_PIXEL + offset;
51
52 // render one bit in one spi byte. High time first, then the low time
53 // clock should be 4 Mhz, 5 bits, each bit is 0.25 us.
54 // a one bit is send as a pulse of 0.75 high -- 0.50 low
55 // a zero bit is send as a pulse of 0.50 high -- 0.75 low
56 // clock frequency for the neopixel is exact 800 khz
57 // note that the mosi output should have a resistor to ground of 10k,
58 // to assure that between the bursts the line is low
59 for _i in 0..8 {
60 if idx >= TOTAL_BITS {
61 return;
62 }
63 let pattern = match bits & 0x80 {
64 0x80 => 0b0000_1110,
65 _ => 0b000_1100,
66 };
67 bits = bits << 1;
68 self.bitbuffer[idx] = U5(pattern);
69 idx += 1;
70 }
71 }
72}
73
74#[embassy_executor::main]
75async fn main(_spawner: Spawner) {
76 let p = embassy_stm32::init(Default::default());
77 info!("Start test using spi as neopixel driver");
78
79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, Hertz(4_000_000), Config::default());
80
81 let mut neopixels = Ws2812::new();
82
83 loop {
84 let mut cnt: usize = 0;
85 for _i in 0..10 {
86 for idx in 0..neopixels.len() {
87 let color = match (cnt + idx) % 3 {
88 0 => RGB { r: 0x21, g: 0, b: 0 },
89 1 => RGB { r: 0, g: 0x31, b: 0 },
90 _ => RGB { r: 0, g: 0, b: 0x41 },
91 };
92 neopixels.set(idx, color);
93 }
94 cnt += 1;
95 // start sending the neopixel bit patters over spi to the neopixel string
96 spi.write(&neopixels.bitbuffer).await.ok();
97 Timer::after(Duration::from_millis(500)).await;
98 }
99 Timer::after(Duration::from_millis(1000)).await;
100 }
101}