Skip to content

Commit

Permalink
use const generics for ws2812 bitbang driver
Browse files Browse the repository at this point in the history
  • Loading branch information
Univa committed Apr 3, 2024
1 parent 80d4bea commit f02e391
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 24 deletions.
20 changes: 18 additions & 2 deletions rumcake-macros/src/drivers/ws2812.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,33 @@ pub fn get_led_from_matrix_coordinates(input: MatrixLike<OptionalItem<Literal>>)

pub mod bitbang {
use proc_macro2::{Ident, TokenStream};
use proc_macro_error::abort;
use quote::quote;
use syn::LitInt;

crate::parse_as_custom_fields! {
pub struct WS2812BitbangArgsBuilder for WS2812BitbangArgs {
pin: Ident,
fudge: Option<LitInt>
}
}

pub fn setup_ws2812_bitbang(WS2812BitbangArgs { pin }: WS2812BitbangArgs) -> TokenStream {
pub fn setup_ws2812_bitbang(
WS2812BitbangArgs { pin, fudge }: WS2812BitbangArgs,
) -> TokenStream {
let fudge = if let Some(lit) = fudge {
lit.base10_parse::<u8>().unwrap_or_else(|_| {
abort!(
lit,
"The provided fudge value could not be parsed as a u8 value."
)
})
} else {
60
};

quote! {
::rumcake::drivers::ws2812_bitbang::setup_driver(::rumcake::hw::platform::output_pin!(#pin))
::rumcake::drivers::ws2812_bitbang::setup_driver::<{ ::rumcake::hw::platform::SYSCLK }, #fudge>(::rumcake::hw::platform::output_pin!(#pin))
}
}
}
55 changes: 33 additions & 22 deletions rumcake/src/drivers/ws2812_bitbang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ pub use rumcake_macros::{
pub mod driver {
use core::arch::arm::__nop as nop;

use crate::hw::platform::SYSCLK;
use embassy_time::Duration;
use embedded_hal::digital::v2::OutputPin;
use smart_leds::RGB8;

Expand All @@ -49,17 +47,19 @@ pub mod driver {
}
}

const NOP_FUDGE: f64 = 0.6;

const TICK_CONV_FACTOR: f64 = (SYSCLK as u64 / gcd(SYSCLK as u64, 1_000_000_000)) as f64
/ (1_000_000_000 / gcd(SYSCLK as u64, 1_000_000_000)) as f64;

pub struct Ws2812<P: OutputPin> {
/// WS2812 driver. Const parameter C represents the clock speed of your chip, and F represents
/// a fudge value. These const parameters determine together determine how many `nop`
/// instructions are generated to simulate delay.
pub struct Ws2812<const C: u32, const F: u8, P: OutputPin> {
pin: P,
}

impl<P: OutputPin> Ws2812<P> {
pub fn new(mut pin: P) -> Ws2812<P> {
impl<const C: u32, const F: u8, P: OutputPin> Ws2812<C, F, P> {
const NOP_FUDGE: f64 = 0.01 * F as f64;
const TICK_CONV_FACTOR: f64 = (C as u64 / gcd(C as u64, 1_000_000_000)) as f64
/ (1_000_000_000 / gcd(C as u64, 1_000_000_000)) as f64;

pub fn new(mut pin: P) -> Ws2812<C, F, P> {
pin.set_low().ok();
Self { pin }
}
Expand All @@ -69,26 +69,26 @@ pub mod driver {
for _ in 0..8 {
if data & 0x80 == 0x80 {
self.pin.set_high().ok();
for _ in 0..(T1H as f64 * TICK_CONV_FACTOR * NOP_FUDGE) as i32 {
for _ in 0..(T1H as f64 * Self::TICK_CONV_FACTOR * Self::NOP_FUDGE) as i32 {
unsafe {
nop();
}
}
self.pin.set_low().ok();
for _ in 0..(T1L as f64 * TICK_CONV_FACTOR * NOP_FUDGE) as i32 {
for _ in 0..(T1L as f64 * Self::TICK_CONV_FACTOR * Self::NOP_FUDGE) as i32 {
unsafe {
nop();
}
}
} else {
self.pin.set_high().ok();
for _ in 0..(T0H as f64 * TICK_CONV_FACTOR * NOP_FUDGE) as i32 {
for _ in 0..(T0H as f64 * Self::TICK_CONV_FACTOR * Self::NOP_FUDGE) as i32 {
unsafe {
nop();
}
}
self.pin.set_low().ok();
for _ in 0..(T0L as f64 * TICK_CONV_FACTOR * NOP_FUDGE) as i32 {
for _ in 0..(T0L as f64 * Self::TICK_CONV_FACTOR * Self::NOP_FUDGE) as i32 {
unsafe {
nop();
}
Expand All @@ -106,14 +106,19 @@ pub mod driver {
}

// Reset time
// Technically this isn't needed as long as the user sets a reasonable FPS value, but we'll keep it anyways.
embassy_time::block_for(Duration::from_micros(RES));
for _ in 0..(RES as f64 * Self::TICK_CONV_FACTOR * Self::NOP_FUDGE) as i32 {
unsafe {
nop();
}
}
}
}
}

/// Create an instance of the WS2812 bitbang driver with the provided output pin.
pub fn setup_driver(output_pin: impl OutputPin) -> Ws2812<impl OutputPin> {
pub fn setup_driver<const C: u32, const F: u8>(
output_pin: impl OutputPin,
) -> Ws2812<C, F, impl OutputPin> {
Ws2812::new(output_pin)
}

Expand All @@ -133,8 +138,8 @@ pub trait WS2812BitbangBacklightMatrixDriver {
}

#[cfg(feature = "underglow")]
impl<P: OutputPin, K: crate::lighting::underglow::UnderglowDevice>
crate::lighting::underglow::UnderglowDriver<K> for Ws2812<P>
impl<const C: u32, const F: u8, P: OutputPin, K: crate::lighting::underglow::UnderglowDevice>
crate::lighting::underglow::UnderglowDriver<K> for Ws2812<C, F, P>
where
[(); K::NUM_LEDS]:,
{
Expand Down Expand Up @@ -166,10 +171,12 @@ where

#[cfg(feature = "simple-backlight")]
impl<
const C: u32,
const F: u8,
P: OutputPin,
K: WS2812BitbangSimpleBacklightDriver
+ crate::lighting::simple_backlight::SimpleBacklightDevice,
> crate::lighting::simple_backlight::SimpleBacklightDriver<K> for Ws2812<P>
> crate::lighting::simple_backlight::SimpleBacklightDriver<K> for Ws2812<C, F, P>
where
[(); K::NUM_LEDS]:,
{
Expand Down Expand Up @@ -200,10 +207,12 @@ where

#[cfg(feature = "simple-backlight-matrix")]
impl<
const C: u32,
const F: u8,
P: OutputPin,
K: WS2812BitbangBacklightMatrixDriver
+ crate::lighting::simple_backlight_matrix::SimpleBacklightMatrixDevice,
> crate::lighting::simple_backlight_matrix::SimpleBacklightMatrixDriver<K> for Ws2812<P>
> crate::lighting::simple_backlight_matrix::SimpleBacklightMatrixDriver<K> for Ws2812<C, F, P>
where
[(); K::LIGHTING_ROWS * K::LIGHTING_COLS]:,
{
Expand Down Expand Up @@ -251,10 +260,12 @@ where

#[cfg(feature = "rgb-backlight-matrix")]
impl<
const C: u32,
const F: u8,
P: OutputPin,
K: WS2812BitbangBacklightMatrixDriver
+ crate::lighting::rgb_backlight_matrix::RGBBacklightMatrixDevice,
> crate::lighting::rgb_backlight_matrix::RGBBacklightMatrixDriver<K> for Ws2812<P>
> crate::lighting::rgb_backlight_matrix::RGBBacklightMatrixDriver<K> for Ws2812<C, F, P>
where
[(); K::LIGHTING_ROWS * K::LIGHTING_COLS]:,
{
Expand Down

0 comments on commit f02e391

Please sign in to comment.