Improve ws2812 api

This commit is contained in:
2023-03-16 22:59:59 +01:00
parent 5fa52f7f48
commit 4e83970cc3
2 changed files with 47 additions and 34 deletions

View File

@ -11,7 +11,6 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
extern crate cortex_m_rt; extern crate cortex_m_rt;
//extern crate panic_halt;
mod board; mod board;
mod keyboard; mod keyboard;
@ -22,10 +21,7 @@ mod ws2812;
use board::Board; use board::Board;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::{ use embassy_rp::gpio::{Level, Output, Pin};
gpio::{Level, Output, Pin},
pio::PioPeripheral,
};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use ws2812::Rgb; use ws2812::Rgb;
@ -64,9 +60,8 @@ async fn main(spawner: Spawner) {
//let mut led = Output::new(board.d13, Level::Low); //let mut led = Output::new(board.d13, Level::Low);
let _neopixel_power = Output::new(board.neopixel_power, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High);
let (_, sm, ..) = p.PIO0.split(); let mut neopixel = ws2812::Ws2812::new(p.PIO0, p.DMA_CH0, board.neopixel.degrade());
let mut neopixel = ws2812::Ws2812::new(sm, p.DMA_CH0, board.neopixel.degrade()); let mut neopixels_d5 = ws2812::Ws2812::new(p.PIO1, p.DMA_CH1, board.d5.degrade());
//let mut neopixel = ws2812::Ws2812::new(sm, p.DMA_CH0, board.d5.degrade());
neopixel.write(&[Rgb::new(0xb7, 0x31, 0x2c)]).await; neopixel.write(&[Rgb::new(0xb7, 0x31, 0x2c)]).await;
@ -111,18 +106,32 @@ async fn main(spawner: Spawner) {
//keyboard::test::type_string("Hello there!\n").await; //keyboard::test::type_string("Hello there!\n").await;
//keyboard::test::rollover(['h', 'e', 'l', 'o', 't', 'r', 'a', 'b', 'c', 'd', 'i']).await; //keyboard::test::rollover(['h', 'e', 'l', 'o', 't', 'r', 'a', 'b', 'c', 'd', 'i']).await;
loop { for w in 0usize.. {
//neopixel neopixel.write(&[wheel(w as u8)]).await;
// .write(&[ neopixels_d5
// Rgb::new(0xAA, 0xFF, 0x00), .write(&[
// Rgb::new(0xAA, 0xFF, 0x00), wheel((w + 50) as u8),
// Rgb::new(0xAA, 0xFF, 0x00), wheel((w + 100) as u8),
// Rgb::new(0xAA, 0xFF, 0x00), wheel((w + 150) as u8),
// Rgb::new(0xAA, 0xFF, 0x00), wheel((w + 200) as u8),
// Rgb::new(0xAA, 0xFF, 0x00), ])
// ]) .await;
// .await; Timer::after(Duration::from_millis(10)).await;
//Timer::after(Duration::from_millis(10)).await; //Timer::after(Duration::from_secs(10)).await;
Timer::after(Duration::from_secs(10)).await;
} }
} }
/// Input a value 0 to 255 to get a color value
// The colours are a transition r - g - b - back to r.
fn wheel(mut wheel_pos: u8) -> Rgb {
wheel_pos = 255 - wheel_pos;
if wheel_pos < 85 {
return Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3);
}
if wheel_pos < 170 {
wheel_pos -= 85;
return Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3);
}
wheel_pos -= 170;
Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0)
}

View File

@ -3,27 +3,30 @@ use core::mem::transmute;
use embassy_rp::dma::{self, AnyChannel}; use embassy_rp::dma::{self, AnyChannel};
use embassy_rp::pio::{ use embassy_rp::pio::{
FifoJoin, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, FifoJoin, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection,
SmInstanceBase,
}; };
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use embassy_rp::{gpio, PeripheralRef}; use embassy_rp::{gpio, PeripheralRef};
pub struct Ws2812<P: PioInstance, S: SmInstance> { pub struct Ws2812<P: PioInstance> {
sm: PioStateMachineInstance<P, S>, sm: PioStateMachineInstance<P, SmInstanceBase<0>>,
dma: PeripheralRef<'static, AnyChannel>, dma: PeripheralRef<'static, AnyChannel>,
} }
/// An Rgb value that can be safely transmuted to u32 for use with Ws2812. /// An Rgb value that can be safely transmuted to u32 for use with Ws2812.
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Rgb(u32); pub struct Rgb(u32);
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { impl<P: PioInstance> Ws2812<P> {
pub fn new( pub fn new<PP: PioPeripheral<Pio = P>>(
mut sm: PioStateMachineInstance<P, S>, pio: PP,
dma: impl dma::Channel, dma: impl dma::Channel,
pin: gpio::AnyPin, pin: gpio::AnyPin,
) -> Self { ) -> Self {
let (_, mut sm, ..) = pio.split();
// prepare the PIO program // prepare the PIO program
let side_set = pio::SideSet::new(false, 1, false); let side_set = pio::SideSet::new(false, 1, false);
let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
@ -94,28 +97,29 @@ impl<P: PioInstance, S: SmInstance> Ws2812<P, S> {
} }
pub async fn write(&mut self, colors: &[Rgb]) { pub async fn write(&mut self, colors: &[Rgb]) {
let colors = rgbs_to_u32s(colors); let colors = Rgb::slice_as_u32s(colors);
self.sm.dma_push(self.dma.reborrow(), colors).await; self.sm.dma_push(self.dma.reborrow(), colors).await;
} }
} }
#[inline(always)]
fn rgbs_to_u32s(rgbs: &[Rgb]) -> &[u32] {
// SAFETY: Rgb contains only a u32, and is #[repr(transparent)]
unsafe { transmute(rgbs) }
}
impl Rgb { impl Rgb {
#[inline(always)] #[inline(always)]
pub const fn new(r: u8, g: u8, b: u8) -> Self { pub const fn new(r: u8, g: u8, b: u8) -> Self {
Self(u32::from_be_bytes([g, r, b, 0])) Self(u32::from_be_bytes([g, r, b, 0]))
} }
/// Get the red, green, and blue components of this Rgb.
#[inline(always)] #[inline(always)]
pub const fn components(&self) -> (u8, u8, u8) { pub const fn components(&self) -> (u8, u8, u8) {
let [g, r, b, _] = self.0.to_be_bytes(); let [g, r, b, _] = self.0.to_be_bytes();
(r, g, b) (r, g, b)
} }
#[inline(always)]
pub fn slice_as_u32s(rgbs: &[Rgb]) -> &[u32] {
// SAFETY: Rgb contains only a u32, and is #[repr(transparent)]
unsafe { transmute(rgbs) }
}
} }
impl Debug for Rgb { impl Debug for Rgb {