From c8c42c01940f759c2e97e5718d87daf8fbdc424e Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Wed, 5 Nov 2025 11:42:27 -0700 Subject: [PATCH] add coin button handling and move coin dac inside app --- ch32v-insert-coin/src/app.rs | 23 +++++-- ch32v-insert-coin/src/insert_coin/mod.rs | 2 +- .../src/insert_coin/services/dac.rs | 7 +- ch32v-insert-coin/src/main.rs | 64 +++++++++++++++---- ch32v-insert-coin/src/system.rs | 42 ++---------- 5 files changed, 81 insertions(+), 57 deletions(-) diff --git a/ch32v-insert-coin/src/app.rs b/ch32v-insert-coin/src/app.rs index 91f5b0c..e1c9bf8 100644 --- a/ch32v-insert-coin/src/app.rs +++ b/ch32v-insert-coin/src/app.rs @@ -96,7 +96,7 @@ pub mod sequencer { } use crate::insert_coin::{ - LedService, Service, SimplePwmCore, TickService, TickServiceData, TickTimerService, + DacService, LedService, Service, SimplePwmCore, TickService, TickServiceData, TickTimerService, }; use crate::synthesizer::SynthesizerService; @@ -193,11 +193,13 @@ pub struct Services { pub led1: LedService, pub led2: LedService, pub synth0: SynthesizerService, + pub sample_player: DacService<'static>, } impl Services { pub fn tick(&mut self) { self.synth0.tick(); + self.sample_player.tick(); } } @@ -352,9 +354,17 @@ impl App { if self.services.synth0.need_service() { let out = self.services.synth0.service() / self.settings.volume.as_volume_divisor(); + // self.interfaces + // .pwm_core + // .write_amplitude(ch32_hal::timer::Channel::Ch4, out); + } + + if self.services.sample_player.need_service() { + self.services.sample_player.service(); + let out = self.services.sample_player.get_amplitude(); self.interfaces .pwm_core - .write_amplitude(ch32_hal::timer::Channel::Ch4, out); + .write_amplitude(ch32_hal::timer::Channel::Ch4, out as u8); } } } @@ -374,8 +384,10 @@ impl App { pub fn main_button(&mut self) { // TODO } - pub fn coin_detect(&mut self) { - // TODO + pub fn coin_detect(&self) { + #[cfg(feature = "enable_print")] + println!("coin detect"); + self.services.sample_player.play_sample(); } } @@ -390,8 +402,6 @@ impl App { // INTERFACE: // 1. short press handling // 2. long press handling -// 3. volume press handling -// 4. brightness press handling // // SYSTEM: // 1. deep sleep @@ -401,3 +411,4 @@ impl App { // STRETCH TODO LIST // 1. clean up edge detector // 2. better handling for pwm scaling (brightness / volume) +// 3. better interrupt handling structs diff --git a/ch32v-insert-coin/src/insert_coin/mod.rs b/ch32v-insert-coin/src/insert_coin/mod.rs index 461dc22..766dcca 100644 --- a/ch32v-insert-coin/src/insert_coin/mod.rs +++ b/ch32v-insert-coin/src/insert_coin/mod.rs @@ -1,7 +1,7 @@ mod insert_coin; mod services; -pub use services::{LedService, Service, TickTimerService}; +pub use services::{DacService, LedService, Service, TickTimerService}; pub use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore}; pub use services::{TickService, TickServiceData}; diff --git a/ch32v-insert-coin/src/insert_coin/services/dac.rs b/ch32v-insert-coin/src/insert_coin/services/dac.rs index 4cdaec0..1d18994 100644 --- a/ch32v-insert-coin/src/insert_coin/services/dac.rs +++ b/ch32v-insert-coin/src/insert_coin/services/dac.rs @@ -1,5 +1,4 @@ -use crate::insert_coin::services::{TickServiceData, TickService}; - +use crate::insert_coin::services::{TickService, TickServiceData}; use adpcm_pwm_dac::dac::DpcmDecoder; use ch32_hal::timer::Channel; @@ -21,6 +20,10 @@ impl<'a> DacService<'a> { } } + pub fn play_sample(&self) { + self.dpcm_decoder.borrow_mut().seek_to_sample(0); + } + pub fn load_data(&self, data: &'a [u8]) { self.dpcm_decoder.borrow_mut().load_data(data); self.dpcm_decoder.borrow_mut().seek_to_sample(0); diff --git a/ch32v-insert-coin/src/main.rs b/ch32v-insert-coin/src/main.rs index 288203b..d8c1cc3 100644 --- a/ch32v-insert-coin/src/main.rs +++ b/ch32v-insert-coin/src/main.rs @@ -22,7 +22,7 @@ use app::{ }; use ch32_hal::{adc::AdcChannel, interrupt::typelevel::Handler, timer::low_level::OutputPolarity}; -use insert_coin::{CoreConfig, InsertCoin, LedService, SimplePwmCore}; +use insert_coin::{CoreConfig, DacService, InsertCoin, LedService, SimplePwmCore}; use ch32_hal as hal; use hal::bind_interrupts; @@ -56,8 +56,8 @@ impl Flag { #[derive(Debug)] struct InputFlags { - sense_coin_flag: bool, - main_btn_flag: bool, + sense_coin_flag: Flag, + main_btn_flag: Flag, volume_btn_flag: bool, light_ctrl_btn_flag: bool, systick_flag: Flag, @@ -66,8 +66,8 @@ struct InputFlags { impl Default for InputFlags { fn default() -> Self { Self { - sense_coin_flag: false, - main_btn_flag: false, + sense_coin_flag: Flag { value: false }, + main_btn_flag: Flag { value: false }, volume_btn_flag: false, light_ctrl_btn_flag: false, systick_flag: Flag { value: false }, @@ -76,8 +76,8 @@ impl Default for InputFlags { } static mut INPUT_FLAGS: InputFlags = InputFlags { - sense_coin_flag: false, - main_btn_flag: false, + sense_coin_flag: Flag { value: false }, + main_btn_flag: Flag { value: false }, volume_btn_flag: false, light_ctrl_btn_flag: false, systick_flag: Flag { value: false }, @@ -90,8 +90,15 @@ impl Handler for Test { println!("on_interrupt()"); critical_section::with(|_| unsafe { let flags = system::clear_interrupt(2, 6); - INPUT_FLAGS.sense_coin_flag = flags.sense_coin_flag; - INPUT_FLAGS.main_btn_flag = flags.main_btn_flag; + if flags[0] { + // safe because single-threaded + #[allow(static_mut_refs)] + INPUT_FLAGS.sense_coin_flag.set(); + } + if flags[1] { + #[allow(static_mut_refs)] + INPUT_FLAGS.main_btn_flag.set(); + } }); } } @@ -184,10 +191,11 @@ fn app_main(mut p: hal::Peripherals) -> ! { pwm.set_polarity(led0_ch, OutputPolarity::ActiveLow); pwm.set_polarity(led1_ch, OutputPolarity::ActiveLow); - let sample_rate_hz = 4000; + // let sample_rate_hz = 4000; // let sample_rate_hz = 16000; - let dac_tick_per_service = 5; - let tick_rate_hz = sample_rate_hz * dac_tick_per_service; + // let dac_tick_per_service = 5; + // let tick_rate_hz = sample_rate_hz * dac_tick_per_service; + let tick_rate_hz = 50000; let core_config = CoreConfig::new(tick_rate_hz); @@ -265,11 +273,22 @@ fn app_main(mut p: hal::Peripherals) -> ! { // let square_wt = SimpleWavetable::new(&SQUARE_WAVETABLE); // let square = SimpleWavetableSynthesizer::new(square_wt, tick_rate_hz); + // DAC servicer setup + let dac_sample_rate_hz = 16000; + let dac_tick_per_service = tick_rate_hz / dac_sample_rate_hz; + let dac_service_data = TickServiceData::new(dac_tick_per_service); + + let coin_sound = include_bytes!("../audio/coin2.raw"); + + let sample_player = DacService::new(ch32_hal::timer::Channel::Ch4, dac_service_data); + sample_player.load_data(coin_sound); + let app_services = Services { led0: LedService::new(led0_ch), led1: LedService::new(led1_ch), led2: LedService::new(led2_ch), synth0: SynthesizerService::new(tick_rate_hz), + sample_player, }; let app_sequences = Sequences { @@ -368,6 +387,27 @@ fn app_main(mut p: hal::Peripherals) -> ! { light_ctrl_btn_input.reset(); } + // coin_detect interrupt + + unsafe { + #[allow(static_mut_refs)] + if INPUT_FLAGS.sense_coin_flag.active() { + #[allow(static_mut_refs)] + INPUT_FLAGS.sense_coin_flag.clear(); + + #[cfg(feature = "enable_print")] + println!("coin flag active"); + sense_coin_input.begin(); + } + sense_coin_input.service(); + if sense_coin_input.ready() { + #[cfg(feature = "enable_print")] + println!("debounced coin_input value: {}", sense_coin_input.value()); + sense_coin_input.reset(); + app.coin_detect(); + } + } + // systick tick if unsafe { #[allow(static_mut_refs)] diff --git a/ch32v-insert-coin/src/system.rs b/ch32v-insert-coin/src/system.rs index 0ee18a6..484d513 100644 --- a/ch32v-insert-coin/src/system.rs +++ b/ch32v-insert-coin/src/system.rs @@ -20,8 +20,8 @@ pub unsafe fn init_gpio_irq(pin: u8, port: u8, rising: bool, falling: bool) { }); } -pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> crate::InputFlags { - let mut input_flags = crate::InputFlags::default(); +pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> [bool; 2] { + let mut output = [false, false]; let exti = &hal::pac::EXTI; @@ -35,53 +35,23 @@ pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> crate::InputFlags { // We don't handle or change any EXTI lines above 24. let bits = bits.0 & 0x00FFFFFF; + #[cfg(feature = "enable_print")] println!("bits: {bits:08x}"); // coin_flag if (bits & (0x1 << coin_pin)) != 0x0 { #[cfg(feature = "enable_print")] println!("coin irq!"); - input_flags.sense_coin_flag = true; + output[0] = true; } // button_flag if (bits & (0x1 << button_pin)) != 0x0 { #[cfg(feature = "enable_print")] println!("main_btn irq!"); - input_flags.main_btn_flag = true; - // CHECK PC6 - // unsafe { - // let mut val = 0; - // let reg: u32 = 0x40011008; - // val = (reg as *mut u32).read_volatile(); - // if ((val >> 0x6) & 0x1) == 0x0 { - // input_flags.volume_btn_flag = true; - // #[cfg(feature = "enable_print")] - // println!("volume irq!"); - // println!("CBANK: {val:08x}"); - // } - // } - // // CHECK PD6 - // unsafe { - // let mut val = 0; - // let reg: u32 = 0x40011408; - // val = (reg as *mut u32).read_volatile(); - // // if ((val >> 0x6) & 0x1) == 0x0 { - // input_flags.main_btn_flag = true; - // #[cfg(feature = "enable_print")] - // println!("main_btn irq!"); - // println!("DBANK: {val:08x}"); - // // } - // } + output[1] = true; } - // light_ctrl_btn_flag - // if (bits & (0x1 << light_ctrl_btn_pin)) != 0x0 { - // #[cfg(feature = "enable_print")] - // println!("light ctrl btn irq!"); - // input_flags.light_ctrl_btn_flag = true; - // } - // Clear pending - Clears the EXTI's line pending bits. exti.intfr().write(|w| w.0 = bits); @@ -94,7 +64,7 @@ pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> crate::InputFlags { exti.intenr().modify(|w| w.set_mr(coin_pin, true)); // enable interrupt exti.intenr().modify(|w| w.set_mr(button_pin, true)); // enable interrupt - input_flags + output } /// enter standby (SLEEPDEEP) mode, with WFE enabled.