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::{
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

View file

@ -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};

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 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);

View file

@ -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<hal::interrupt::typelevel::EXTI7_0> 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)]

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 {
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.