esp-hal-smartled: Calculate cycles from clocks (#1154)

This commit is contained in:
W Etheredge 2024-02-12 09:36:30 -06:00 committed by GitHub
parent 8903b1ea8b
commit c92d69cb09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 34 additions and 47 deletions

View File

@ -27,41 +27,19 @@
use core::{fmt::Debug, slice::IterMut}; use core::{fmt::Debug, slice::IterMut};
use esp_hal::{ use esp_hal::{
clock::Clocks,
gpio::OutputPin, gpio::OutputPin,
peripheral::Peripheral, peripheral::Peripheral,
rmt::{Error as RmtError, PulseCode, TxChannel, TxChannelConfig, TxChannelCreator}, rmt::{Error as RmtError, PulseCode, TxChannel, TxChannelConfig, TxChannelCreator},
}; };
use smart_leds_trait::{SmartLedsWrite, RGB8}; use smart_leds_trait::{SmartLedsWrite, RGB8};
// Specifies what clock frequency we're using for the RMT peripheral (if
// properly configured)
//
// TODO: Factor in clock configuration, this needs to be revisited once #24 and
// #44 have been addressed.
#[cfg(feature = "esp32")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32c3")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32c6")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32h2")]
const SOURCE_CLK_FREQ: u32 = 16_000_000;
#[cfg(feature = "esp32s2")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
#[cfg(feature = "esp32s3")]
const SOURCE_CLK_FREQ: u32 = 40_000_000;
const SK68XX_CODE_PERIOD: u32 = 1200; const SK68XX_CODE_PERIOD: u32 = 1200;
const SK68XX_T0H_NS: u32 = 320; const SK68XX_T0H_NS: u32 = 320;
const SK68XX_T0L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T0H_NS; const SK68XX_T0L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T0H_NS;
const SK68XX_T1H_NS: u32 = 640; const SK68XX_T1H_NS: u32 = 640;
const SK68XX_T1L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T1H_NS; const SK68XX_T1L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T1H_NS;
const SK68XX_T0H_CYCLES: u16 = ((SK68XX_T0H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T0L_CYCLES: u16 = ((SK68XX_T0L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T1H_CYCLES: u16 = ((SK68XX_T1H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T1L_CYCLES: u16 = ((SK68XX_T1L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
/// All types of errors that can happen during the conversion and transmission /// All types of errors that can happen during the conversion and transmission
/// of LED commands /// of LED commands
#[derive(Debug)] #[derive(Debug)]
@ -99,6 +77,7 @@ where
{ {
channel: Option<TX>, channel: Option<TX>,
rmt_buffer: [u32; BUFFER_SIZE], rmt_buffer: [u32; BUFFER_SIZE],
pulses: (u32, u32),
} }
impl<'d, TX, const BUFFER_SIZE: usize> SmartLedsAdapter<TX, BUFFER_SIZE> impl<'d, TX, const BUFFER_SIZE: usize> SmartLedsAdapter<TX, BUFFER_SIZE>
@ -110,6 +89,7 @@ where
channel: C, channel: C,
pin: impl Peripheral<P = O> + 'd, pin: impl Peripheral<P = O> + 'd,
rmt_buffer: [u32; BUFFER_SIZE], rmt_buffer: [u32; BUFFER_SIZE],
clocks: &Clocks,
) -> SmartLedsAdapter<TX, BUFFER_SIZE> ) -> SmartLedsAdapter<TX, BUFFER_SIZE>
where where
O: OutputPin + 'd, O: OutputPin + 'd,
@ -126,19 +106,37 @@ where
let channel = channel.configure(pin, config).unwrap(); 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 { Self {
channel: Some(channel), channel: Some(channel),
rmt_buffer, rmt_buffer,
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,
}),
),
} }
} }
fn convert_rgb_to_pulse( fn convert_rgb_to_pulse(
value: RGB8, value: RGB8,
mut_iter: &mut IterMut<u32>, mut_iter: &mut IterMut<u32>,
pulses: (u32, u32),
) -> Result<(), LedAdapterError> { ) -> Result<(), LedAdapterError> {
Self::convert_rgb_channel_to_pulses(value.g, mut_iter)?; Self::convert_rgb_channel_to_pulses(value.g, mut_iter, pulses)?;
Self::convert_rgb_channel_to_pulses(value.r, mut_iter)?; Self::convert_rgb_channel_to_pulses(value.r, mut_iter, pulses)?;
Self::convert_rgb_channel_to_pulses(value.b, mut_iter)?; Self::convert_rgb_channel_to_pulses(value.b, mut_iter, pulses)?;
Ok(()) Ok(())
} }
@ -146,24 +144,13 @@ where
fn convert_rgb_channel_to_pulses( fn convert_rgb_channel_to_pulses(
channel_value: u8, channel_value: u8,
mut_iter: &mut IterMut<u32>, mut_iter: &mut IterMut<u32>,
pulses: (u32, u32),
) -> Result<(), LedAdapterError> { ) -> Result<(), LedAdapterError> {
for position in [128, 64, 32, 16, 8, 4, 2, 1] { for position in [128, 64, 32, 16, 8, 4, 2, 1] {
*mut_iter.next().ok_or(LedAdapterError::BufferSizeExceeded)? = *mut_iter.next().ok_or(LedAdapterError::BufferSizeExceeded)? =
match channel_value & position { match channel_value & position {
0 => PulseCode { 0 => pulses.0,
level1: true, _ => pulses.1,
length1: SK68XX_T0H_CYCLES,
level2: false,
length2: SK68XX_T0L_CYCLES,
}
.into(),
_ => PulseCode {
level1: true,
length1: SK68XX_T1H_CYCLES,
level2: false,
length2: SK68XX_T1L_CYCLES,
}
.into(),
} }
} }
@ -193,7 +180,7 @@ where
// This will result in an `BufferSizeExceeded` error in case // This will result in an `BufferSizeExceeded` error in case
// the iterator provides more elements than the buffer can take. // the iterator provides more elements than the buffer can take.
for item in iterator { for item in iterator {
Self::convert_rgb_to_pulse(item.into(), &mut seq_iter)?; Self::convert_rgb_to_pulse(item.into(), &mut seq_iter, self.pulses)?;
} }
// Finally, add an end element. // Finally, add an end element.

View File

@ -40,7 +40,7 @@ fn main() -> ! {
// LEDs here to initialize the internal LED pulse buffer to the correct // LEDs here to initialize the internal LED pulse buffer to the correct
// size! // size!
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio33, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio33, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.

View File

@ -35,7 +35,7 @@ fn main() -> ! {
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio2, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio2, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.

View File

@ -34,7 +34,7 @@ fn main() -> ! {
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio8, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio8, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.

View File

@ -34,7 +34,7 @@ fn main() -> ! {
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio8, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio8, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.

View File

@ -35,7 +35,7 @@ fn main() -> ! {
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio18, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio18, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.

View File

@ -35,7 +35,7 @@ fn main() -> ! {
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations
let rmt_buffer = smartLedBuffer!(1); let rmt_buffer = smartLedBuffer!(1);
let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio48, rmt_buffer); let mut led = SmartLedsAdapter::new(rmt.channel0, io.pins.gpio48, rmt_buffer, &clocks);
// Initialize the Delay peripheral, and use it to toggle the LED state in a // Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop. // loop.