stm32/spi: add new_txonly_nosck constructor, for neopixels, with an example in the stm32g0 directory.
This commit is contained in:
		
				
					committed by
					
						
						Dario Nieuwenhuis
					
				
			
			
				
	
			
			
			
						parent
						
							2080d8bb6d
						
					
				
				
					commit
					3260f6b2af
				
			@@ -177,6 +177,23 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn new_txonly_nosck(
 | 
				
			||||||
 | 
					        peri: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
 | 
					        mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
 | 
				
			||||||
 | 
					        txdma: impl Peripheral<P = Tx> + 'd,
 | 
				
			||||||
 | 
					        rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
 | 
				
			||||||
 | 
					        freq: Hertz,
 | 
				
			||||||
 | 
					        config: Config,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        into_ref!(mosi);
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
 | 
				
			||||||
 | 
					            mosi.set_speed(crate::gpio::Speed::Medium);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Useful for on chip peripherals like SUBGHZ which are hardwired.
 | 
					    /// Useful for on chip peripherals like SUBGHZ which are hardwired.
 | 
				
			||||||
    /// The bus can optionally be exposed externally with `Spi::new()` still.
 | 
					    /// The bus can optionally be exposed externally with `Spi::new()` still.
 | 
				
			||||||
    #[allow(dead_code)]
 | 
					    #[allow(dead_code)]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										101
									
								
								examples/stm32g0/src/bin/spi_neopixel.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								examples/stm32g0/src/bin/spi_neopixel.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
 | 
					use embassy_stm32::dma::word::U5;
 | 
				
			||||||
 | 
					use embassy_stm32::dma::NoDma;
 | 
				
			||||||
 | 
					use embassy_stm32::spi::{Config, Spi};
 | 
				
			||||||
 | 
					use embassy_stm32::time::Hertz;
 | 
				
			||||||
 | 
					use embassy_time::{Duration, Timer};
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const NR_PIXELS: usize = 15;
 | 
				
			||||||
 | 
					const BITS_PER_PIXEL: usize = 24; // 24 for rgb, 32 for rgbw
 | 
				
			||||||
 | 
					const TOTAL_BITS: usize = NR_PIXELS * BITS_PER_PIXEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct RGB {
 | 
				
			||||||
 | 
					    r: u8,
 | 
				
			||||||
 | 
					    g: u8,
 | 
				
			||||||
 | 
					    b: u8,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Default for RGB {
 | 
				
			||||||
 | 
					    fn default() -> RGB {
 | 
				
			||||||
 | 
					        RGB { r: 0, g: 0, b: 0 }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					pub struct Ws2812 {
 | 
				
			||||||
 | 
					    // Note that the U5 type controls the selection of 5 bits to output
 | 
				
			||||||
 | 
					    bitbuffer: [U5; TOTAL_BITS],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Ws2812 {
 | 
				
			||||||
 | 
					    pub fn new() -> Ws2812 {
 | 
				
			||||||
 | 
					        Ws2812 {
 | 
				
			||||||
 | 
					            bitbuffer: [U5(0); TOTAL_BITS],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn len(&self) -> usize {
 | 
				
			||||||
 | 
					        return NR_PIXELS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn set(&mut self, idx: usize, rgb: RGB) {
 | 
				
			||||||
 | 
					        self.render_color(idx, 0, rgb.g);
 | 
				
			||||||
 | 
					        self.render_color(idx, 8, rgb.r);
 | 
				
			||||||
 | 
					        self.render_color(idx, 16, rgb.b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // transform one color byte into an array of 8 byte. Each byte in the array does represent 1 neopixel bit pattern
 | 
				
			||||||
 | 
					    fn render_color(&mut self, pixel_idx: usize, offset: usize, color: u8) {
 | 
				
			||||||
 | 
					        let mut bits = color as usize;
 | 
				
			||||||
 | 
					        let mut idx = pixel_idx * BITS_PER_PIXEL + offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // render one bit in one spi byte. High time first, then the low time
 | 
				
			||||||
 | 
					        // clock should be 4 Mhz, 5 bits, each bit is 0.25 us.
 | 
				
			||||||
 | 
					        // a one bit is send as a pulse of 0.75 high -- 0.50 low
 | 
				
			||||||
 | 
					        // a zero bit is send as a pulse of 0.50 high -- 0.75 low
 | 
				
			||||||
 | 
					        // clock frequency for the neopixel is exact 800 khz
 | 
				
			||||||
 | 
					        // note that the mosi output should have a resistor to ground of 10k,
 | 
				
			||||||
 | 
					        // to assure that between the bursts the line is low
 | 
				
			||||||
 | 
					        for _i in 0..8 {
 | 
				
			||||||
 | 
					            if idx >= TOTAL_BITS {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let pattern = match bits & 0x80 {
 | 
				
			||||||
 | 
					                0x80 => 0b0000_1110,
 | 
				
			||||||
 | 
					                _ => 0b000_1100,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            bits = bits << 1;
 | 
				
			||||||
 | 
					            self.bitbuffer[idx] = U5(pattern);
 | 
				
			||||||
 | 
					            idx += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::main]
 | 
				
			||||||
 | 
					async fn main(_spawner: Spawner) {
 | 
				
			||||||
 | 
					    let p = embassy_stm32::init(Default::default());
 | 
				
			||||||
 | 
					    info!("Start test using spi as neopixel driver");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, Hertz(4_000_000), Config::default());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut neopixels = Ws2812::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let mut cnt: usize = 0;
 | 
				
			||||||
 | 
					        for _i in 0..10 {
 | 
				
			||||||
 | 
					            for idx in 0..neopixels.len() {
 | 
				
			||||||
 | 
					                let color = match (cnt + idx) % 3 {
 | 
				
			||||||
 | 
					                    0 => RGB { r: 0x21, g: 0, b: 0 },
 | 
				
			||||||
 | 
					                    1 => RGB { r: 0, g: 0x31, b: 0 },
 | 
				
			||||||
 | 
					                    _ => RGB { r: 0, g: 0, b: 0x41 },
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                neopixels.set(idx, color);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cnt += 1;
 | 
				
			||||||
 | 
					            // start sending the neopixel bit patters over spi to the neopixel string
 | 
				
			||||||
 | 
					            spi.write(&neopixels.bitbuffer).await.ok();
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(500)).await;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_millis(1000)).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user