diff --git a/esp-hal-smartled/src/lib.rs b/esp-hal-smartled/src/lib.rs index a40cb8d9650..75d47b0a9cf 100644 --- a/esp-hal-smartled/src/lib.rs +++ b/esp-hal-smartled/src/lib.rs @@ -30,7 +30,10 @@ use esp_hal::{ clock::Clocks, gpio::OutputPin, peripheral::Peripheral, - rmt::{Error as RmtError, PulseCode, TxChannel, TxChannelConfig, TxChannelCreator}, + rmt::{ + asynch::TxChannelAsync, Error as RmtError, PulseCode, TxChannel, TxChannelConfig, + TxChannelCreator, TxChannelCreatorAsync, + }, }; use smart_leds_trait::{SmartLedsWrite, RGB8}; @@ -274,3 +277,80 @@ where } } } + +/// Adapter taking an RMT channel and a specific pin and providing RGB LED +/// interaction functionality using the `smart-leds` crate +pub struct SmartLedsAdapterAsync +where + TX: TxChannelAsync, +{ + channel: Option, + pulses: (u32, u32), +} + +impl<'d, TX> SmartLedsAdapterAsync +where + TX: TxChannelAsync, +{ + /// Create a new adapter object that drives the pin using the RMT channel. + pub fn new( + channel: C, + pin: impl Peripheral

+ 'd, + clocks: &Clocks, + ) -> SmartLedsAdapterAsync + where + O: OutputPin + 'd, + C: TxChannelCreatorAsync<'d, TX, O>, + { + let config = TxChannelConfig { + clk_divider: 1, + idle_output_level: false, + carrier_modulation: false, + idle_output: true, + + ..TxChannelConfig::default() + }; + + let channel = channel.configure(pin, config).unwrap(); + + // Assume the RMT peripheral is set up to use the APB clock + let src_clock = clocks.apb_clock.to_MHz(); + + Self { + channel: Some(channel), + pulses: ( + u32::from(PulseCode { + level1: true, + length1: ((SK68XX_T0H_NS * src_clock) / 1000) as u16, + level2: false, + length2: ((SK68XX_T0L_NS * src_clock) / 1000) as u16, + }), + u32::from(PulseCode { + level1: true, + length1: ((SK68XX_T1H_NS * src_clock) / 1000) as u16, + level2: false, + length2: ((SK68XX_T1L_NS * src_clock) / 1000) as u16, + }), + ), + } + } + + /// Convert all RGB8 items of the iterator to the RMT format and + /// add them to internal buffer, then start a singular RMT operation + /// based on that buffer. + pub async fn write(&mut self, iterator: T) -> Result<(), LedAdapterError> + where + T: IntoIterator, + I: Into, + { + let channel = self.channel.as_mut().unwrap(); + let mut itr = PulseGenerator::new( + ByteGenerator::new(iterator.into_iter().map(|v| v.into())), + self.pulses, + ); + match channel.transmit(&mut itr).await { + Ok(()) => Ok(()), + Err(e) => Err(LedAdapterError::TransmissionError(e)), + } + } +} diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 1ceeb01f282..12a58f5c8f4 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -1,3 +1,5 @@ +#![feature(associated_type_bounds)] + //! # Remote Control Peripheral (RMT) //! //! ## Overview @@ -286,10 +288,7 @@ impl<'d> Rmt<'d, crate::Async> { _clocks: &Clocks, ) -> Result { Self::new_internal( - peripheral, - frequency, - _clocks, - Some(asynch::async_interrupt_handler), + peripheral, frequency, _clocks, None, //Some(asynch::async_interrupt_handler), ) } } @@ -481,7 +480,7 @@ where } >::reset_threshold_set(); - // re-fill RX RAM + // re-fill TX RAM let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) as *mut u32; @@ -1014,11 +1013,11 @@ pub trait TxChannel: private::TxChannelInternal { D: IntoIterator, R: Iterator, { - let mut data = data.into_iter(); + let mut data = data.into_iter().fuse(); Self::send_raw(&mut data, false, 0); SingleShotTxTransaction { channel: self, - data: data.fuse(), + data, ram_index: 0, } } @@ -1142,41 +1141,90 @@ pub mod asynch { const INIT: AtomicWaker = AtomicWaker::new(); static WAKER: [AtomicWaker; NUM_CHANNELS] = [INIT; NUM_CHANNELS]; - pub(crate) struct RmtTxFuture + pub(crate) struct RmtTxFuture + Copy> where - T: TxChannelAsync, + C: TxChannelAsync, + D: Iterator, { - _phantom: PhantomData, + _phantom: PhantomData, + data: Fuse, + ram_index: usize, } - impl RmtTxFuture + impl RmtTxFuture where - T: TxChannelAsync, + C: TxChannelAsync, + T: Into + Copy, + D: Iterator, { - pub fn new(_instance: &T) -> Self { + pub fn new(_instance: &C, data: Fuse) -> Self { Self { _phantom: PhantomData, + data, + ram_index: 0, } } } - impl core::future::Future for RmtTxFuture + impl core::future::Future for RmtTxFuture where - T: TxChannelAsync, + C: TxChannelAsync, + T: Into + Copy, + D: Iterator, { - type Output = (); + type Output = Result<(), Error>; - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKER[T::CHANNEL as usize].register(ctx.waker()); + fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + //WAKER[C::CHANNEL as usize].register(ctx.waker()); - if T::is_error() || T::is_done() { - Poll::Ready(()) - } else { - Poll::Pending + if C::is_error() { + return Poll::Ready(Err(Error::TransmissionError)); + } + + if C::is_done() { + return Poll::Ready(Ok(())); + } + + // never gets set :| + if !C::is_threshold_set() { + return Poll::Pending; + } + C::reset_threshold_set(); + + // re-fill TX RAM + let ptr = (constants::RMT_RAM_START + + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) + as *mut u32; + + loop { + let Some(v) = self.data.next() else { + break; + }; + unsafe { + ptr.add(self.ram_index).write_volatile(v.into()); + } + self.ram_index += 1; + if self.ram_index == constants::RMT_CHANNEL_RAM_SIZE { + self.ram_index = 0; + break; + } + if self.ram_index == (constants::RMT_CHANNEL_RAM_SIZE / 2) { + break; + } } + if C::is_threshold_set() { + return Poll::Ready(Err(Error::Underflow)); + } + Poll::Pending } } - + impl Unpin for RmtTxFuture + where + C: TxChannelAsync, + T: Into + Copy, + D: Iterator, + { + } /// TX channel in async mode pub trait TxChannelAsync: private::TxChannelInternal { /// Start transmitting the given pulse code sequence. @@ -1187,19 +1235,14 @@ pub mod asynch { Self: Sized, D: IntoIterator, { - Self::clear_interrupts(); - Self::listen_interrupt(super::private::Event::End); - Self::listen_interrupt(super::private::Event::Error); - let mut data = data.into_iter(); + // Self::clear_interrupts(); + // Self::listen_interrupt(super::private::Event::End); + // Self::listen_interrupt(super::private::Event::Error); + // Self::listen_interrupt(super::private::Event::Threshold); + let mut data = data.into_iter().fuse(); Self::send_raw(&mut data, false, 0); - RmtTxFuture::new(self).await; - - if Self::is_error() { - Err(Error::TransmissionError) - } else { - Ok(()) - } + RmtTxFuture::new(self, data).await } }