add coin button handling and move coin dac inside app

This commit is contained in:
sigil-03 2025-11-05 11:42:27 -07:00
parent 930d10218f
commit c8c42c0194
5 changed files with 81 additions and 57 deletions

View file

@ -96,7 +96,7 @@ pub mod sequencer {
} }
use crate::insert_coin::{ use crate::insert_coin::{
LedService, Service, SimplePwmCore, TickService, TickServiceData, TickTimerService, DacService, LedService, Service, SimplePwmCore, TickService, TickServiceData, TickTimerService,
}; };
use crate::synthesizer::SynthesizerService; use crate::synthesizer::SynthesizerService;
@ -193,11 +193,13 @@ pub struct Services {
pub led1: LedService, pub led1: LedService,
pub led2: LedService, pub led2: LedService,
pub synth0: SynthesizerService, pub synth0: SynthesizerService,
pub sample_player: DacService<'static>,
} }
impl Services { impl Services {
pub fn tick(&mut self) { pub fn tick(&mut self) {
self.synth0.tick(); self.synth0.tick();
self.sample_player.tick();
} }
} }
@ -352,9 +354,17 @@ impl App {
if self.services.synth0.need_service() { if self.services.synth0.need_service() {
let out = self.services.synth0.service() / self.settings.volume.as_volume_divisor(); 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 self.interfaces
.pwm_core .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) { pub fn main_button(&mut self) {
// TODO // TODO
} }
pub fn coin_detect(&mut self) { pub fn coin_detect(&self) {
// TODO #[cfg(feature = "enable_print")]
println!("coin detect");
self.services.sample_player.play_sample();
} }
} }
@ -390,8 +402,6 @@ impl App {
// INTERFACE: // INTERFACE:
// 1. short press handling // 1. short press handling
// 2. long press handling // 2. long press handling
// 3. volume press handling
// 4. brightness press handling
// //
// SYSTEM: // SYSTEM:
// 1. deep sleep // 1. deep sleep
@ -401,3 +411,4 @@ impl App {
// STRETCH TODO LIST // STRETCH TODO LIST
// 1. clean up edge detector // 1. clean up edge detector
// 2. better handling for pwm scaling (brightness / volume) // 2. better handling for pwm scaling (brightness / volume)
// 3. better interrupt handling structs

View file

@ -1,7 +1,7 @@
mod insert_coin; mod insert_coin;
mod services; mod services;
pub use services::{LedService, Service, TickTimerService}; pub use services::{DacService, LedService, Service, TickTimerService};
pub use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore}; pub use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore};
pub use services::{TickService, TickServiceData}; pub use services::{TickService, TickServiceData};

View file

@ -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 adpcm_pwm_dac::dac::DpcmDecoder;
use ch32_hal::timer::Channel; 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]) { pub fn load_data(&self, data: &'a [u8]) {
self.dpcm_decoder.borrow_mut().load_data(data); self.dpcm_decoder.borrow_mut().load_data(data);
self.dpcm_decoder.borrow_mut().seek_to_sample(0); self.dpcm_decoder.borrow_mut().seek_to_sample(0);

View file

@ -22,7 +22,7 @@ use app::{
}; };
use ch32_hal::{adc::AdcChannel, interrupt::typelevel::Handler, timer::low_level::OutputPolarity}; 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 ch32_hal as hal;
use hal::bind_interrupts; use hal::bind_interrupts;
@ -56,8 +56,8 @@ impl Flag {
#[derive(Debug)] #[derive(Debug)]
struct InputFlags { struct InputFlags {
sense_coin_flag: bool, sense_coin_flag: Flag,
main_btn_flag: bool, main_btn_flag: Flag,
volume_btn_flag: bool, volume_btn_flag: bool,
light_ctrl_btn_flag: bool, light_ctrl_btn_flag: bool,
systick_flag: Flag, systick_flag: Flag,
@ -66,8 +66,8 @@ struct InputFlags {
impl Default for InputFlags { impl Default for InputFlags {
fn default() -> Self { fn default() -> Self {
Self { Self {
sense_coin_flag: false, sense_coin_flag: Flag { value: false },
main_btn_flag: false, main_btn_flag: Flag { value: false },
volume_btn_flag: false, volume_btn_flag: false,
light_ctrl_btn_flag: false, light_ctrl_btn_flag: false,
systick_flag: Flag { value: false }, systick_flag: Flag { value: false },
@ -76,8 +76,8 @@ impl Default for InputFlags {
} }
static mut INPUT_FLAGS: InputFlags = InputFlags { static mut INPUT_FLAGS: InputFlags = InputFlags {
sense_coin_flag: false, sense_coin_flag: Flag { value: false },
main_btn_flag: false, main_btn_flag: Flag { value: false },
volume_btn_flag: false, volume_btn_flag: false,
light_ctrl_btn_flag: false, light_ctrl_btn_flag: false,
systick_flag: Flag { value: false }, systick_flag: Flag { value: false },
@ -90,8 +90,15 @@ impl Handler<hal::interrupt::typelevel::EXTI7_0> for Test {
println!("on_interrupt()"); println!("on_interrupt()");
critical_section::with(|_| unsafe { critical_section::with(|_| unsafe {
let flags = system::clear_interrupt(2, 6); let flags = system::clear_interrupt(2, 6);
INPUT_FLAGS.sense_coin_flag = flags.sense_coin_flag; if flags[0] {
INPUT_FLAGS.main_btn_flag = flags.main_btn_flag; // 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(led0_ch, OutputPolarity::ActiveLow);
pwm.set_polarity(led1_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 sample_rate_hz = 16000;
let dac_tick_per_service = 5; // let dac_tick_per_service = 5;
let tick_rate_hz = sample_rate_hz * dac_tick_per_service; // let tick_rate_hz = sample_rate_hz * dac_tick_per_service;
let tick_rate_hz = 50000;
let core_config = CoreConfig::new(tick_rate_hz); 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_wt = SimpleWavetable::new(&SQUARE_WAVETABLE);
// let square = SimpleWavetableSynthesizer::new(square_wt, tick_rate_hz); // 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 { let app_services = Services {
led0: LedService::new(led0_ch), led0: LedService::new(led0_ch),
led1: LedService::new(led1_ch), led1: LedService::new(led1_ch),
led2: LedService::new(led2_ch), led2: LedService::new(led2_ch),
synth0: SynthesizerService::new(tick_rate_hz), synth0: SynthesizerService::new(tick_rate_hz),
sample_player,
}; };
let app_sequences = Sequences { let app_sequences = Sequences {
@ -368,6 +387,27 @@ fn app_main(mut p: hal::Peripherals) -> ! {
light_ctrl_btn_input.reset(); 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 // systick tick
if unsafe { if unsafe {
#[allow(static_mut_refs)] #[allow(static_mut_refs)]

View file

@ -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 { pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> [bool; 2] {
let mut input_flags = crate::InputFlags::default(); let mut output = [false, false];
let exti = &hal::pac::EXTI; 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. // We don't handle or change any EXTI lines above 24.
let bits = bits.0 & 0x00FFFFFF; let bits = bits.0 & 0x00FFFFFF;
#[cfg(feature = "enable_print")]
println!("bits: {bits:08x}"); println!("bits: {bits:08x}");
// coin_flag // coin_flag
if (bits & (0x1 << coin_pin)) != 0x0 { if (bits & (0x1 << coin_pin)) != 0x0 {
#[cfg(feature = "enable_print")] #[cfg(feature = "enable_print")]
println!("coin irq!"); println!("coin irq!");
input_flags.sense_coin_flag = true; output[0] = true;
} }
// button_flag // button_flag
if (bits & (0x1 << button_pin)) != 0x0 { if (bits & (0x1 << button_pin)) != 0x0 {
#[cfg(feature = "enable_print")] #[cfg(feature = "enable_print")]
println!("main_btn irq!"); println!("main_btn irq!");
input_flags.main_btn_flag = true; output[1] = 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}");
// // }
// }
} }
// 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. // Clear pending - Clears the EXTI's line pending bits.
exti.intfr().write(|w| w.0 = 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(coin_pin, true)); // enable interrupt
exti.intenr().modify(|w| w.set_mr(button_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. /// enter standby (SLEEPDEEP) mode, with WFE enabled.