~ruther/map-led-strip

5660da0c7cd7fcb91766e45b31e2a0e2e2c75e76 — František Boháček 1 year, 9 months ago 4189ee0
feat: add strip support using fmt
2 files changed, 121 insertions(+), 0 deletions(-)

M src/main.rs
A src/strip.rs
M src/main.rs => src/main.rs +24 -0
@@ 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 {

    }

A src/strip.rs => src/strip.rs +97 -0
@@ 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, const COUNT: usize> {
    channel: CHANNEL,
    timing: StripTiming
}

pub struct StripTiming {
    one_high_duration: Duration::<u32, 1, 1_000_000_000>,
    one_low_duration: Duration::<u32, 1, 1_000_000_000>,
    zero_high_duration: Duration::<u32, 1, 1_000_000_000>,
    zero_low_duration: Duration::<u32, 1, 1_000_000_000>,
}

impl StripTiming {
    pub fn new(one_high_duration: Duration::<u32, 1, 1_000_000_000>,
               one_low_duration: Duration::<u32, 1, 1_000_000_000>,
               zero_high_duration: Duration::<u32, 1, 1_000_000_000>,
               zero_low_duration: Duration::<u32, 1, 1_000_000_000>) -> Self {
        StripTiming {
            one_high_duration,
            one_low_duration,
            zero_high_duration,
            zero_low_duration,
        }
    }
}

impl<'d, CHANNEL, const COUNT: usize> Strip<CHANNEL, COUNT>
    where CHANNEL: ConfiguredChannel
{
    pub fn new<P: OutputPin + 'd, UnconfiguredChannel>(mut channel: UnconfiguredChannel, pin: impl Peripheral<P=P> + 'd, timing: StripTiming) -> Self
        where UnconfiguredChannel: OutputChannel<ConfiguredChannel<'d, P> = 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, COUNT> {
            channel,
            timing
        }
    }

    fn byte_to_pulse_code(&self, byte: u8, data: &mut IterMut<u32>) -> () {
        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::<u32>::from_ticks(length1.ticks() / 50);
        let length2 = NanosDuration::<u32>::from_ticks(length2.ticks() / 50);

        PulseCode {
            level1: true,
            length1,
            level2: false,
            length2,
        }.into()
    }
}

impl<CHANNEL, const COUNT: usize> SmartLedsWrite for Strip<CHANNEL, COUNT>
    where CHANNEL: ConfiguredChannel
{
    type Error = TransmissionError;
    type Color = RGB8;

    fn write<T, I>(&mut self, iterator: T) -> Result<(), Self::Error> where T: Iterator<Item=I>, I: Into<Self::Color> {
        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

Do not follow this link