From 5660da0c7cd7fcb91766e45b31e2a0e2e2c75e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Wed, 21 Jun 2023 12:10:49 +0200 Subject: [PATCH] feat: add strip support using fmt --- src/main.rs | 24 +++++++++++++ src/strip.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/strip.rs diff --git a/src/main.rs b/src/main.rs index e69c19f..486b14a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,14 @@ #![no_std] #![no_main] +mod strip; use embedded_hal::serial::{Read, Write}; use esp_backtrace as _; use hal::{clock::ClockControl, pulse_control::{ClockSource}, peripherals::Peripherals, prelude::*, timer::{TimerGroup, Timer, Timer0}, Rtc, IO, Delay, interrupt, PulseControl, Uart}; use hal::uart::config::{Config, DataBits, Parity, StopBits}; use nb::Error::{WouldBlock, Other}; +use smart_leds::{RGB8, SmartLedsWrite}; +use crate::strip::StripTiming; const LEDS_COUNT: usize = 72; const COMMAND_BUFFER: usize = 200; @@ -34,6 +37,27 @@ fn main() -> ! { wdt0.disable(); wdt1.disable(); + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + + let mut delay = Delay::new(&clocks); + + let pulse = PulseControl::new( + peripherals.RMT, + &mut system.peripheral_clock_control, + ).unwrap(); + + let mut strip = strip::Strip::<_, { LEDS_COUNT * 24 + 1 }>::new( + pulse.channel0, + io.pins.gpio25, + StripTiming::new( + 800u32.nanos(), + 450u32.nanos(), + 400u32.nanos(), + 850u32.nanos(), + ), + ); + + let mut rgb_data: [RGB8; 72] = [RGB8 { r: 0, g: 0, b: 0 }; 72]; loop { } diff --git a/src/strip.rs b/src/strip.rs new file mode 100644 index 0000000..0c35ad2 --- /dev/null +++ b/src/strip.rs @@ -0,0 +1,97 @@ +use core::slice::IterMut; +use hal::gpio::{OutputPin}; +use hal::peripheral::Peripheral; +use hal::pulse_control::{OutputChannel, ConfiguredChannel, PulseCode, RepeatMode, TransmissionError, ClockSource}; +use smart_leds::{RGB8, SmartLedsWrite}; +use fugit::{Duration, NanosDuration}; + +pub struct Strip { + channel: CHANNEL, + timing: StripTiming +} + +pub struct StripTiming { + one_high_duration: Duration::, + one_low_duration: Duration::, + zero_high_duration: Duration::, + zero_low_duration: Duration::, +} + +impl StripTiming { + pub fn new(one_high_duration: Duration::, + one_low_duration: Duration::, + zero_high_duration: Duration::, + zero_low_duration: Duration::) -> Self { + StripTiming { + one_high_duration, + one_low_duration, + zero_high_duration, + zero_low_duration, + } + } +} + +impl<'d, CHANNEL, const COUNT: usize> Strip + where CHANNEL: ConfiguredChannel +{ + pub fn new(mut channel: UnconfiguredChannel, pin: impl Peripheral + 'd, timing: StripTiming) -> Self + where UnconfiguredChannel: OutputChannel = CHANNEL> + { + channel + .set_channel_divider(4) // 1 tick = 50 ns = 0.05 us + .set_carrier_modulation(false) + .set_idle_output(true) + .set_idle_output_level(false) + .set_clock_source(ClockSource::APB); + + let channel = channel.assign_pin(pin); + + Strip:: { + channel, + timing + } + } + + fn byte_to_pulse_code(&self, byte: u8, data: &mut IterMut) -> () { + for i in 0..8u8 { + let bit = if (byte & (1 << (7 - i))) > 0 { true } else { false }; + *data.next().unwrap() = self.bit_to_pulse_code(bit); + } + } + + fn bit_to_pulse_code(&self, bit: bool) -> u32 { + let length1 = if bit { self.timing.one_high_duration } else { self.timing.zero_high_duration }; + let length2 = if bit { self.timing.one_low_duration } else { self.timing.zero_low_duration }; + + let length1 = NanosDuration::::from_ticks(length1.ticks() / 50); + let length2 = NanosDuration::::from_ticks(length2.ticks() / 50); + + PulseCode { + level1: true, + length1, + level2: false, + length2, + }.into() + } +} + +impl SmartLedsWrite for Strip + where CHANNEL: ConfiguredChannel +{ + type Error = TransmissionError; + type Color = RGB8; + + fn write(&mut self, iterator: T) -> Result<(), Self::Error> where T: Iterator, I: Into { + let mut buffer: [u32; COUNT] = [0; COUNT]; + let mut iter_mut = buffer.iter_mut(); + for item in iterator { + let rgb = item.into(); + self.byte_to_pulse_code(rgb.g, &mut iter_mut); + self.byte_to_pulse_code(rgb.r, &mut iter_mut); + self.byte_to_pulse_code(rgb.b, &mut iter_mut); + } + *iter_mut.next().unwrap() = 0; + + self.channel.send_pulse_sequence_raw(RepeatMode::SingleShot, &buffer) + } +} \ No newline at end of file -- 2.48.1