From dab048d30123b413a720d60fbb818714226cd707 Mon Sep 17 00:00:00 2001 From: Jet Pham Date: Fri, 3 Oct 2025 14:35:03 -0700 Subject: [PATCH] feat: expand into 8 leds --- src/animations/binary.rs | 14 ++-- src/animations/mod.rs | 4 +- src/animations/ping.rs | 13 ++-- src/animations/surge.rs | 4 +- src/animations/tyler.rs | 20 ------ src/animations/wave.rs | 6 +- src/bin/main.rs | 140 +++++++++++++++++++++------------------ 7 files changed, 95 insertions(+), 106 deletions(-) delete mode 100644 src/animations/tyler.rs diff --git a/src/animations/binary.rs b/src/animations/binary.rs index e8e731e..285bd13 100644 --- a/src/animations/binary.rs +++ b/src/animations/binary.rs @@ -1,11 +1,11 @@ -pub fn binary_animation(time_ms: u32) -> [u8; 6] { - let increment_interval_ms = 1000.0 / 64.0; - let count = (time_ms as f32 / increment_interval_ms) as u32 % 64; - - let mut leds = [0u8; 6]; - (0..6).for_each(|i| { +pub fn binary_animation(time_ms: u32) -> [u8; 8] { + let increment_interval_ms = 3000 / 256; + let count = (time_ms / increment_interval_ms) % 256; + + let mut leds = [0u8; 8]; + (0..8).for_each(|i| { if count & (1 << i) != 0 { - leds[5-i] = 100; + leds[7-i] = 100; } }); diff --git a/src/animations/mod.rs b/src/animations/mod.rs index ae1b4b6..37c5b08 100644 --- a/src/animations/mod.rs +++ b/src/animations/mod.rs @@ -1,13 +1,11 @@ -pub type AnimationFunction = fn(u32) -> [u8; 6]; +pub type AnimationFunction = fn(u32) -> [u8; 8]; pub mod wave; pub mod surge; pub mod ping; pub mod binary; -pub mod tyler; pub use wave::wave_animation; pub use surge::surge_animation; pub use ping::ping_animation; pub use binary::binary_animation; -pub use tyler::tyler_animation; diff --git a/src/animations/ping.rs b/src/animations/ping.rs index d7293dd..5f92652 100644 --- a/src/animations/ping.rs +++ b/src/animations/ping.rs @@ -1,17 +1,16 @@ -pub fn ping_animation(time_ms: u32) -> [u8; 6] { +pub fn ping_animation(time_ms: u32) -> [u8; 8] { let cycle_duration_ms = 1000; let cycle_position = (time_ms % cycle_duration_ms) as f32 / cycle_duration_ms as f32; - let mut leds = [0u8; 6]; + let mut leds = [0u8; 8]; - let led_index = if cycle_position < 6.0 / 10.0 { - (cycle_position * 10.0) as usize + let led_index = if cycle_position < 8.0 / 14.0 { + (cycle_position * 14.0) as usize } else { - (10.0 - (cycle_position * 10.0)) as usize + (14.0 - (cycle_position * 14.0)) as usize }; - // Ensure we don't go out of bounds - if led_index < 6 { + if led_index < 8 { leds[led_index] = 100; } diff --git a/src/animations/surge.rs b/src/animations/surge.rs index 9f522d6..ace3dd7 100644 --- a/src/animations/surge.rs +++ b/src/animations/surge.rs @@ -1,10 +1,10 @@ use core::f32::consts::PI; -pub fn surge_animation(time_ms: u32) -> [u8; 6] { +pub fn surge_animation(time_ms: u32) -> [u8; 8] { let cycle_duration_ms = 2000; let angle = (time_ms as f32 / cycle_duration_ms as f32) * 2.0 * PI; let sine_value = libm::sinf(angle); let brightness = (sine_value + 1.0) / 2.0; let duty = (brightness * 100.0) as u8; - [duty; 6] + [duty; 8] } diff --git a/src/animations/tyler.rs b/src/animations/tyler.rs deleted file mode 100644 index 4618062..0000000 --- a/src/animations/tyler.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::f32::consts::PI; -use defmt::info; - -pub fn tyler_animation(time_ms: u32) -> [u8; 6] { - let cycle_duration_ms = 3000; - let angle = (time_ms as f32 / cycle_duration_ms as f32) * 2.0 * PI; - - let mut leds = [0u8; 6]; - leds.iter_mut().enumerate().for_each(|(i, led)| { - let sine_value = (1..i+2).fold(1.0, |acc, i| { - let b = i as f32; - acc * libm::sinf(b * angle + (b * 0.5)) - 0.1 - }); - info!("{:?}", sine_value); - let brightness = sine_value.max(0.0); - *led = (brightness * 100.0) as u8; - }); - - leds -} diff --git a/src/animations/wave.rs b/src/animations/wave.rs index 303950f..89bdd6d 100644 --- a/src/animations/wave.rs +++ b/src/animations/wave.rs @@ -1,12 +1,12 @@ use core::f32::consts::PI; -pub fn wave_animation(time_ms: u32) -> [u8; 6] { +pub fn wave_animation(time_ms: u32) -> [u8; 8] { let cycle_duration_ms = 1000; let angle = (time_ms as f32 / cycle_duration_ms as f32) * 2.0 * PI; - let mut leds = [0u8; 6]; + let mut leds = [0u8; 8]; leds.iter_mut().enumerate().for_each(|(i, led)| { - let phase_offset = (i as f32) * (2.0 * PI) / 6.0; + let phase_offset = (i as f32) * (2.0 * PI) / 8.0; let led_angle = angle + phase_offset; let sine_value = libm::sinf(led_angle); let brightness = (sine_value + 1.0) / 2.0; diff --git a/src/bin/main.rs b/src/bin/main.rs index 2277f45..8a6ea35 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -6,35 +6,54 @@ holding buffers for the duration of a data transfer." )] -use defmt::info; -use esp_hal::clock::CpuClock; -use esp_hal::delay::Delay; -use esp_hal::ledc::{ - channel::{self, config::PinConfig, ChannelIFace}, - timer::{self, config::Duty, LSClockSource, TimerIFace}, - LSGlobalClkSource, Ledc, LowSpeed, +use esp_hal::{ + clock::CpuClock, + gpio::{Level, Output, OutputConfig}, + main, + time::{Duration, Instant}, + timer::timg::TimerGroup, }; -use esp_hal::main; -use esp_hal::time::Rate; -use esp_hal::timer::timg::TimerGroup; use panic_rtt_target as _; extern crate alloc; use firebeetle_2_board_esp32_c6::animations::{ - wave::wave_animation, - surge::surge_animation, - ping::ping_animation, - binary::binary_animation, - tyler::tyler_animation + binary::binary_animation, ping::ping_animation, surge::surge_animation, wave::wave_animation, }; esp_bootloader_esp_idf::esp_app_desc!(); +struct SoftwarePWM { + duty_cycles: [u16; 8], + pwm_period: u16, + current_step: u16, +} +impl SoftwarePWM { + fn new() -> Self { + Self { + duty_cycles: [0; 8], + pwm_period: 2000, + current_step: 0, + } + } + + fn set_duty_cycles(&mut self, duty_cycles: [u8; 8]) { + for (i, &duty) in duty_cycles.iter().enumerate() { + self.duty_cycles[i] = (duty as u16 * 20).min(2000); + } + } + + fn should_be_high(&self, led_index: usize) -> bool { + self.current_step < self.duty_cycles[led_index] + } + + fn update_step(&mut self) { + self.current_step = (self.current_step + 1) % self.pwm_period; + } +} #[main] fn main() -> ! { - rtt_target::rtt_init_defmt!(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); @@ -45,63 +64,56 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let _init = esp_wifi::init(timg0.timer0, esp_hal::rng::Rng::new(peripherals.RNG)).unwrap(); - let mut ledc = Ledc::new(peripherals.LEDC); - ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); - - let mut lstimer0 = ledc.timer::(timer::Number::Timer0); - lstimer0 - .configure(timer::config::Config { - duty: Duty::Duty8Bit, - clock_source: LSClockSource::APBClk, - frequency: Rate::from_hz(1000), - }) - .unwrap(); - - let mut channels = [ - ledc.channel(channel::Number::Channel0, peripherals.GPIO1), - ledc.channel(channel::Number::Channel1, peripherals.GPIO18), - ledc.channel(channel::Number::Channel2, peripherals.GPIO9), - ledc.channel(channel::Number::Channel3, peripherals.GPIO19), - ledc.channel(channel::Number::Channel4, peripherals.GPIO20), - ledc.channel(channel::Number::Channel5, peripherals.GPIO21), + let mut leds = [ + Output::new(peripherals.GPIO1, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO18, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO9, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO19, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO20, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO21, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO22, Level::Low, OutputConfig::default()), + Output::new(peripherals.GPIO23, Level::Low, OutputConfig::default()), ]; - channels.iter_mut().for_each(|channel| { - channel - .configure(channel::config::Config { - timer: &lstimer0, - duty_pct: 0, - pin_config: PinConfig::PushPull, - }) - .unwrap(); - }); - - let delay = Delay::new(); - let animations = [wave_animation, surge_animation, binary_animation, ping_animation, tyler_animation]; + let mut pwm = SoftwarePWM::new(); + let animations = [ + wave_animation, + surge_animation, + binary_animation, + ping_animation, + ]; let mut current_animation_index = 0; - let mut animation_start_time = 0u32; let animation_switch_interval_ms = 3000; - let frame_delay_ms = 10; + + let mut animation_start = Instant::now(); loop { let current_animation = animations[current_animation_index]; - let led_values = current_animation(animation_start_time); - info!("LED values: {:?}", led_values); - - channels.iter_mut() - .zip(led_values.iter()) - .for_each(|(channel, &duty_pct)| { - channel.set_duty(duty_pct).unwrap(); - }); - delay.delay_millis(frame_delay_ms); - animation_start_time += frame_delay_ms; - - if animation_start_time >= animation_switch_interval_ms { - animation_start_time = 0; + let animation_elapsed_ms = animation_start.elapsed().as_millis() as u32; + let led_values = current_animation(animation_elapsed_ms); + + pwm.set_duty_cycles(led_values); + + let pwm_cycles = 100; + for _ in 0..pwm_cycles { + for i in 0..8 { + if pwm.should_be_high(i) { + leds[i].set_high(); + } else { + leds[i].set_low(); + } + } + + pwm.update_step(); + + let delay_start = Instant::now(); + while delay_start.elapsed() < Duration::from_micros(5) {} + } + + if animation_elapsed_ms >= animation_switch_interval_ms { + animation_start = Instant::now(); current_animation_index = (current_animation_index + 1) % animations.len(); - info!("Switching to animation {}", current_animation_index); } } - }