diff --git a/.gitmodules b/.gitmodules index 84792a2..e953eec 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "ch32v-insert-coin/ext/ch32-hal"] path = ch32v-insert-coin/ext/ch32-hal - url = https://github.com/sigil-03/ch32-hal.git + url = git@github.com:sigil-03/ch32-hal.git [submodule "ch32v-insert-coin/ext/qingke"] path = ch32v-insert-coin/ext/qingke - url = https://github.com/ch32-rs/qingke.git + url = git@github.com:ch32-rs/qingke.git [submodule "ch32v-insert-coin/ext/adpcm-pwm-dac"] path = ch32v-insert-coin/ext/adpcm-pwm-dac - url = https://git.glyphs.tech/sigil-03/adpcm-pwm-dac.git + url = ssh://git@git.glyphs.tech:222/sigil-03/adpcm-pwm-dac.git [submodule "ch32v-insert-coin/ext/wavetable-synth"] path = ch32v-insert-coin/ext/wavetable-synth url = https://git.glyphs.tech/sigil-03/wavetable-synth.git diff --git a/ch32v-insert-coin/audio/coin3.raw b/ch32v-insert-coin/audio/coin3.raw deleted file mode 100644 index 8c590d9..0000000 Binary files a/ch32v-insert-coin/audio/coin3.raw and /dev/null differ diff --git a/ch32v-insert-coin/audio/coin4.raw b/ch32v-insert-coin/audio/coin4.raw deleted file mode 100644 index f350cd0..0000000 Binary files a/ch32v-insert-coin/audio/coin4.raw and /dev/null differ diff --git a/ch32v-insert-coin/audio/coin5.raw b/ch32v-insert-coin/audio/coin5.raw deleted file mode 100644 index 922bb2c..0000000 Binary files a/ch32v-insert-coin/audio/coin5.raw and /dev/null differ diff --git a/ch32v-insert-coin/bins.zip b/ch32v-insert-coin/bins.zip new file mode 100644 index 0000000..b77a194 Binary files /dev/null and b/ch32v-insert-coin/bins.zip differ diff --git a/ch32v-insert-coin/bins/README.md b/ch32v-insert-coin/bins/README.md new file mode 100644 index 0000000..c548cd9 --- /dev/null +++ b/ch32v-insert-coin/bins/README.md @@ -0,0 +1,4 @@ +TO FLASH / RUN: + +`wlink -v flash --enable-sdi-print --watch-serial bins/coin_sound_8ksps.bin` + diff --git a/ch32v-insert-coin/bins/coin_sound_16ksps.bin b/ch32v-insert-coin/bins/coin_sound_16ksps.bin new file mode 100755 index 0000000..c003c2a Binary files /dev/null and b/ch32v-insert-coin/bins/coin_sound_16ksps.bin differ diff --git a/ch32v-insert-coin/bins/coin_sound_6ksps.bin b/ch32v-insert-coin/bins/coin_sound_6ksps.bin new file mode 100755 index 0000000..9796caf Binary files /dev/null and b/ch32v-insert-coin/bins/coin_sound_6ksps.bin differ diff --git a/ch32v-insert-coin/bins/coin_sound_8ksps.bin b/ch32v-insert-coin/bins/coin_sound_8ksps.bin new file mode 100755 index 0000000..6cafcc9 Binary files /dev/null and b/ch32v-insert-coin/bins/coin_sound_8ksps.bin differ diff --git a/ch32v-insert-coin/ext/adpcm-pwm-dac b/ch32v-insert-coin/ext/adpcm-pwm-dac index 99ce71e..ba25b7c 160000 --- a/ch32v-insert-coin/ext/adpcm-pwm-dac +++ b/ch32v-insert-coin/ext/adpcm-pwm-dac @@ -1 +1 @@ -Subproject commit 99ce71e8d03e382b51732db7d0771349c51c7f48 +Subproject commit ba25b7c89f4deb52426d97fd35eb13496f183775 diff --git a/ch32v-insert-coin/ext/ch32-hal b/ch32v-insert-coin/ext/ch32-hal index 4f11d68..f413367 160000 --- a/ch32v-insert-coin/ext/ch32-hal +++ b/ch32v-insert-coin/ext/ch32-hal @@ -1 +1 @@ -Subproject commit 4f11d68e62dcb0e7098eecf357168724a8322d80 +Subproject commit f41336744c4e2548c8f6ba9b323ae4aa39959f1d diff --git a/ch32v-insert-coin/ext/wavetable-synth b/ch32v-insert-coin/ext/wavetable-synth index 30033e1..e6ca9c7 160000 --- a/ch32v-insert-coin/ext/wavetable-synth +++ b/ch32v-insert-coin/ext/wavetable-synth @@ -1 +1 @@ -Subproject commit 30033e1438c25aed4ea506cdbd69cc4ceffa0b4e +Subproject commit e6ca9c7ed8b9af193333be793983df5e48cb961a diff --git a/ch32v-insert-coin/src/app.rs b/ch32v-insert-coin/src/app.rs deleted file mode 100644 index a8fdbb8..0000000 --- a/ch32v-insert-coin/src/app.rs +++ /dev/null @@ -1,705 +0,0 @@ -#[derive(Default, Clone, Copy)] -pub enum State { - // system is asleep, waiting for wake from coin insertion - DeepSleep, - // system is in low-power mode, dimmed lights, waiting for interaction - Idle, - // system is active. on entry: play coin sound. on button press: play different sound - #[default] - Active, -} - -pub mod settings { - - #[derive(Debug, Default, Clone, Copy)] - pub enum Level { - Off, - Low, - #[default] - Medium, - High, - Maximum, - } - - impl Level { - pub fn next(&mut self) { - *self = match self { - Self::Off => Self::Low, - Self::Low => Self::Medium, - Self::Medium => Self::High, - Self::High => Self::Maximum, - Self::Maximum => Self::Off, - }; - } - } - - // volume control - impl Level { - pub fn as_volume_divisor(&self) -> u8 { - match self { - Self::Off => u8::MAX, - Self::Low => 4, - Self::Medium => 3, - Self::High => 2, - Self::Maximum => 1, - } - } - - pub fn as_brightness_divisor(&self) -> u8 { - match self { - Self::Off => u8::MAX, - Self::Low => 8, - Self::Medium => 6, - Self::High => 4, - Self::Maximum => 2, - } - } - } - - #[derive(Clone, Copy)] - pub struct Settings { - pub brightness: Level, - pub volume: Level, - pub button_sound_index: usize, - } - - impl Default for Settings { - fn default() -> Self { - Self { - brightness: Level::Medium, - volume: Level::Medium, - button_sound_index: 0, - } - } - } -} - -pub mod sequencer { - pub struct BasicSequence<'a> { - sequence: &'a [u8], - index: usize, - } - impl<'a> BasicSequence<'a> { - pub fn new(sequence: &'a [u8]) -> Self { - Self { sequence, index: 0 } - } - pub fn next(&mut self) { - self.index += 1; - if self.index > self.sequence.len() - 1 { - self.index = 0; - } - } - pub fn get_value(&self) -> u8 { - self.sequence[self.index] - } - } - - pub struct SequenceEntry { - pub frequency_hz: u16, - pub duration_ms: u16, - } - - pub struct DynamicSequence<'a> { - sequence: &'a [SequenceEntry], - index: usize, - - // timer stuff - system_tick_rate_hz: usize, - ticks_remaining: usize, - - // playback stuff - num_loops: usize, - loop_count: usize, - - // misc - enabled: bool, - } - - impl<'a> DynamicSequence<'a> { - pub fn new(sequence: &'a [SequenceEntry], system_tick_rate_hz: usize) -> Self { - Self { - sequence, - index: 0, - system_tick_rate_hz, - ticks_remaining: 0, - num_loops: 1, - loop_count: 0, - enabled: false, - } - } - - pub fn play_sequence(&mut self, sequence: &'a [SequenceEntry], num_loops: usize) { - self.sequence = sequence; - self.num_loops = num_loops; - self.loop_count = 0; - self.enabled = true; - self.index = 0; - self.ticks_remaining = 0; - } - - pub fn enable(&mut self) { - self.enabled = true; - } - - pub fn disable(&mut self) { - self.enabled = false; - } - - pub fn tick(&mut self) { - if self.enabled { - self.ticks_remaining = self.ticks_remaining.saturating_sub(1); - } - } - - pub fn need_service(&self) -> bool { - self.enabled && self.ticks_remaining == 0 - } - - pub fn service(&mut self) -> Option { - let entry = &self.sequence[self.index]; - self.ticks_remaining = self.system_tick_rate_hz * (entry.duration_ms as usize) / 1000; - self.index = self.index.saturating_add(1); - - let out = if self.loop_count > self.num_loops { - None - } else { - Some(entry.frequency_hz) - }; - - if self.index > self.sequence.len() - 1 { - self.index = 0; - self.loop_count = self.loop_count.saturating_add(1); - } - - out - } - } -} - -use crate::insert_coin::{ - DacService, LedService, Service, SimplePwmCore, TickService, TickServiceData, TickTimerService, -}; -use crate::synthesizer::SynthesizerService; - -pub use settings::Settings; - -// #[cfg(feature = "enable_print")] -use ch32_hal::println; - -pub struct TimerConfig { - pub sp_timer_ms: usize, - pub lp_timer_ms: usize, - pub batt_adc_timer_ms: usize, - pub usb_adc_timer_ms: usize, - pub led0_timer_ms: usize, - pub led1_timer_ms: usize, - pub shutdown_timer_s: usize, - // pub led2_timer_ms: usize, -} - -pub struct Timers { - sp_timer: TickTimerService, - lp_timer: TickTimerService, - batt_adc_timer: TickTimerService, - usb_adc_timer: TickTimerService, - led0_timer: TickTimerService, - led1_timer: TickTimerService, - shutdown_timer: TickTimerService, - pps_timer: TickTimerService, - // led2_timer: TickTimerService, -} - -impl Timers { - pub fn new(config: TimerConfig, system_tick_rate_hz: usize) -> Self { - Self { - sp_timer: TickTimerService::new( - TickServiceData::new(config.sp_timer_ms * system_tick_rate_hz / 1000), - false, - ), - lp_timer: TickTimerService::new( - TickServiceData::new(config.lp_timer_ms * system_tick_rate_hz / 1000), - false, - ), - batt_adc_timer: TickTimerService::new( - TickServiceData::new(config.batt_adc_timer_ms * system_tick_rate_hz / 1000), - false, - ), - usb_adc_timer: TickTimerService::new( - TickServiceData::new(config.usb_adc_timer_ms * system_tick_rate_hz / 1000), - false, - ), - led0_timer: TickTimerService::new( - TickServiceData::new(config.led0_timer_ms * system_tick_rate_hz / 1000), - true, - ), - led1_timer: TickTimerService::new( - TickServiceData::new(config.led1_timer_ms * system_tick_rate_hz / 1000), - true, - ), - shutdown_timer: TickTimerService::new( - TickServiceData::new(config.shutdown_timer_s), - false, - ), - pps_timer: TickTimerService::new(TickServiceData::new(system_tick_rate_hz), true), - // led2_timer: TickTimerService::new( - // TickServiceData::new(config.led2_timer_ms * system_tick_rate_hz / 1000), - // true, - // ), - } - } - pub fn tick(&mut self) { - self.sp_timer.tick(); - self.lp_timer.tick(); - self.batt_adc_timer.tick(); - self.usb_adc_timer.tick(); - self.led0_timer.tick(); - self.led1_timer.tick(); - self.pps_timer.tick(); - // self.led2_timer.tick(); - } - pub fn need_service(&self) -> bool { - self.sp_timer.need_service() - | self.lp_timer.need_service() - | self.batt_adc_timer.need_service() - | self.usb_adc_timer.need_service() - | self.led0_timer.need_service() - | self.led1_timer.need_service() - | self.shutdown_timer.need_service() - | self.pps_timer.need_service() - // | self.led2_timer.need_service() - } - pub fn init(&mut self) { - self.led0_timer.reset(); - self.led0_timer.enable(true); - } -} - -// pub struct ServiceConfigs { - -// } -// things that sort of don't touch hardware but also do? -// TODO: make this merged with the interfaces maybe -// but also maybe not, since these are things that require servicing -pub struct Services { - pub led0: LedService, - pub led1: LedService, - // pub led2: LedService, - pub synth0: SynthesizerService, - pub sample_player: DacService<'static>, - pub sequencer: sequencer::DynamicSequence<'static>, -} - -impl Services { - pub fn tick(&mut self) { - self.synth0.tick(); - self.sample_player.tick(); - self.sequencer.tick(); - } -} - -pub struct Config { - pub system_tick_rate_hz: usize, - pub timers: TimerConfig, -} - -pub struct Sequences { - pub led0: sequencer::BasicSequence<'static>, - pub led1: sequencer::BasicSequence<'static>, - // pub led2: sequencer::BasicSequence<'static>, - pub audio: &'static [(&'static [sequencer::SequenceEntry], usize)], -} - -// things that touch hardware -pub struct Interfaces { - pub pwm_core: SimplePwmCore<'static, ch32_hal::peripherals::TIM1>, - pub adc_core: crate::AdcCore, - pub amp: crate::Amplifier, - pub usb: crate::Usb, -} - -pub struct App { - state: State, - pub settings: Settings, - timers: Timers, - services: Services, - sequences: Sequences, - interfaces: Interfaces, -} - -use settings::Level; -impl App { - pub fn new( - config: Config, - services: Services, - sequences: Sequences, - interfaces: Interfaces, - settings: Settings, - ) -> Self { - Self { - state: State::default(), - settings, - timers: Timers::new(config.timers, config.system_tick_rate_hz), - services, - sequences, - interfaces, - } - } - - pub fn init(&mut self) { - // self.timers.init(); - self.interfaces.amp.enable(); - - self.timers.batt_adc_timer.reset(); - self.timers.batt_adc_timer.enable(true); - - self.timers.usb_adc_timer.reset(); - self.timers.usb_adc_timer.enable(true); - - self.timers.led0_timer.reset(); - self.timers.led0_timer.enable(true); - - self.timers.led1_timer.reset(); - self.timers.led1_timer.enable(true); - - self.timers.shutdown_timer.reset(); - self.timers.shutdown_timer.enable(true); - - self.timers.pps_timer.reset(); - self.timers.pps_timer.enable(true); - - // self.timers.led2_timer.reset(); - // self.timers.led2_timer.enable(true); - - // self.services.synth0.set_freq(1); - self.services.synth0.disable(); - self.services.sequencer.disable(); - - crate::riscv::asm::delay(2_500_000); - } - - pub fn set_state(&mut self, state: State) { - self.state = state - } - - pub fn state(&self) -> State { - self.state - } - - pub fn settings(&self) -> Settings { - self.settings - } - - pub fn tick(&mut self) { - self.timers.tick(); - self.services.tick(); - } - - pub fn service(&mut self) { - // timers - if self.timers.sp_timer.need_service() { - self.timers.sp_timer.service(); - #[cfg(feature = "enable_print")] - println!("sp service"); - self.timers.sp_timer.reset(); - self.main_button_short_press(); - } - if self.timers.lp_timer.need_service() { - self.timers.lp_timer.service(); - #[cfg(feature = "enable_print")] - println!("lp service"); - self.timers.lp_timer.reset(); - self.main_button_long_press(); - } - if self.timers.batt_adc_timer.need_service() { - self.timers.batt_adc_timer.service(); - if !self.interfaces.usb.powered() { - let bv = self.interfaces.adc_core.get_battery_voltage(); - let avg = self.interfaces.adc_core.get_average(); - // #[cfg(feature = "enable_print")] - // println!("batt adc service: {bv}, {avg}"); - // println!("none USB"); - if avg < 421 { - self.set_state(State::DeepSleep); - } - } - } - if self.timers.usb_adc_timer.need_service() { - self.timers.usb_adc_timer.service(); - #[cfg(feature = "enable_print")] - println!("usb adc service"); - } - if self.timers.led0_timer.need_service() { - let out = match self.settings.brightness { - Level::Off => 0, - Level::Low => 5, - Level::Medium => 25, - Level::High => 75, - Level::Maximum => { - self.sequences.led0.next(); - self.sequences.led0.get_value() / 6 - } - }; - - self.timers.led0_timer.service(); - self.services.led0.set_amplitude(out); - // #[cfg(feature = "enable_print")] - // println!("led0 sevice {}", self.sequences.led0.get_value()); - } - if self.timers.led1_timer.need_service() { - let out = match self.settings.brightness { - Level::Off => 0, - Level::Low => 5, - Level::Medium => 25, - Level::High => 75, - Level::Maximum => { - self.sequences.led1.next(); - self.sequences.led1.get_value() / 6 - } - }; - self.timers.led1_timer.service(); - self.services.led1.set_amplitude(out); - - // #[cfg(feature = "enable_print")] - // println!("led1 service"); - } - if self.timers.pps_timer.need_service() { - self.timers.pps_timer.service(); - self.timers.shutdown_timer.tick(); - } - if self.timers.shutdown_timer.need_service() { - self.timers.shutdown_timer.service(); - self.timers.shutdown_timer.reset(); - // println!("eepy"); - self.set_state(State::DeepSleep); - } - // if self.timers.led2_timer.need_service() { - // let out = match self.settings.brightness { - // Level::Off => 0, - // Level::Low => 5, - // Level::Medium => 25, - // Level::High => 75, - // Level::Maximum => { - // self.sequences.led2.next(); - // self.sequences.led2.get_value() / 6 - // } - // }; - // self.timers.led2_timer.service(); - // self.services.led2.set_amplitude(out); - - // // #[cfg(feature = "enable_print")] - // // println!("led2 service"); - // } - - // services - if self.services.led0.need_service() { - self.interfaces - .pwm_core - .write_amplitude(self.services.led0.channel, self.services.led0.amplitude); - self.services.led0.service(); - } - if self.services.led1.need_service() { - self.interfaces - .pwm_core - .write_amplitude(self.services.led1.channel, self.services.led1.amplitude); - self.services.led1.service(); - } - // if self.services.led2.need_service() { - // self.interfaces - // .pwm_core - // .write_amplitude(self.services.led2.channel, self.services.led2.amplitude); - // self.services.led2.service(); - // } - - // TODO: disable when you get to the end automatically - // in the sequencer, not here - if self.services.sequencer.need_service() { - if let Some(out) = self.services.sequencer.service() { - if out == 0 { - self.services.synth0.disable(); - } else { - self.services.synth0.enable(); - self.services.synth0.set_freq(out.into()); - } - } else { - self.services.sequencer.disable(); - self.services.synth0.disable(); - } - } - - if self.services.synth0.need_service() { - let out = match self.services.synth0.service() { - Some(value) => value / 6 / self.settings.volume.as_volume_divisor(), - None => 0, - }; - 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() / 2; - self.interfaces - .pwm_core - .write_amplitude(ch32_hal::timer::Channel::Ch4, out as u8); - } - } -} - -// interfaces to the app (for buttons, etc.) -impl App { - pub fn shut_down(&mut self) { - self.interfaces - .pwm_core - .write_amplitude(self.services.led0.channel, 0); - self.interfaces - .pwm_core - .write_amplitude(self.services.led1.channel, 0); - crate::riscv::asm::delay(10_000_000); - - self.interfaces.pwm_core.pwm.borrow().shutdown(); - self.interfaces.adc_core.shutdown(); - - self.interfaces.amp.disable(); - } - pub fn volume_button(&mut self) { - self.settings.volume.next(); - #[cfg(feature = "enable_print")] - println!("new volume: {:?}", self.settings.volume); - self.services - .sequencer - .play_sequence(&crate::sequences::COIN_CHIRP, 0); - self.timers.shutdown_timer.reset(); - self.timers.shutdown_timer.enable(true); - } - pub fn brightness_button(&mut self) { - self.settings.brightness.next(); - #[cfg(feature = "enable_print")] - println!("new brightness: {:?}", self.settings.brightness); - self.timers.shutdown_timer.reset(); - self.timers.shutdown_timer.enable(true); - } - pub fn main_button_press(&mut self) { - // TODO - #[cfg(feature = "enable_print")] - println!("main button press"); - self.timers.sp_timer.reset(); - self.timers.lp_timer.reset(); - self.timers.shutdown_timer.reset(); - self.timers.sp_timer.enable(true); - self.timers.lp_timer.enable(true); - self.timers.shutdown_timer.enable(true); - self.main_button_click(); - } - pub fn main_button_release(&mut self) { - // TODO - // #[cfg(feature = "enable_print")] - // println!("main button release"); - // let timers = ( - // self.timers.sp_timer.is_enabled(), - // self.timers.lp_timer.is_enabled(), - // ); - - self.timers.sp_timer.reset(); - self.timers.lp_timer.reset(); - // match timers { - // // click - // (true, true) => self.main_button_click(), - // // short press - // (false, true) => self.main_button_short_press(), - // // long press - // (false, false) => self.main_button_long_press(), - // // anything else is not possible - // _ => {} - // } - } - pub fn coin_detect(&mut self) { - #[cfg(feature = "enable_print")] - println!("coin detect"); - // self.services.sample_player.play_sample(); - self.services - .sequencer - .play_sequence(&crate::sequences::COIN_CHIRP, 0); - self.timers.shutdown_timer.reset(); - self.timers.shutdown_timer.enable(true); - } -} - -// Events -impl App { - pub fn main_button_click(&mut self) { - // TODO - #[cfg(feature = "enable_print")] - println!("click"); - let data = self.sequences.audio[self.settings.button_sound_index]; - self.services.sequencer.play_sequence(data.0, data.1); - - self.settings.button_sound_index += 1; - if self.settings.button_sound_index > self.sequences.audio.len() - 1 { - self.settings.button_sound_index = 0; - } - - self.services.synth0.enable(); - - // TODO: - // this is a hack to stop the coin thing from playing. - self.services.sample_player.disable(); - } - fn main_button_short_press(&self) { - // TODO - #[cfg(feature = "enable_print")] - println!("short press"); - } - fn main_button_long_press(&mut self) { - // TODO - #[cfg(feature = "enable_print")] - println!("long press"); - self.set_state(State::DeepSleep); - } -} - -// Getters -impl App { - pub fn get_state(&self) -> State { - self.state - } - pub fn get_settings(&self) -> Settings { - self.settings - } - pub fn should_wake(&self) -> bool { - if self.interfaces.usb.powered() { - return true; - } else { - if self.interfaces.adc_core.get_average() >= 421 { - return true; - } - } - return false; - } -} - -// TODO LIST -// BROKEN: -// 1. audio scaling causes crash -// 2. popping on sample playback -// 3. actual app sequence (start at idle?) -// -// AUDIO: -// 3. amp_en control -// -// LED: -// -// INTERFACE: -// 1. short press handling -// 2. long press handling -// -// SYSTEM: -// 1. deep sleep -// 2. battery voltage monitoring -// 3. battery voltage cutoff -// -// STRETCH TODO LIST -// 1. clean up edge detector -// 2. better handling for pwm scaling (brightness / volume) -// 3. better interrupt handling structs -// 4. led DynamicSequence diff --git a/ch32v-insert-coin/src/debounced_gpio.rs b/ch32v-insert-coin/src/debounced_gpio.rs deleted file mode 100644 index 784c3fd..0000000 --- a/ch32v-insert-coin/src/debounced_gpio.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::insert_coin::{TickService, TickServiceData, TickTimerService}; -use ch32_hal::gpio::{AnyPin, Input, Pull}; - -pub struct DebouncedGPIO<'a> { - input: Input<'a>, - // value of the GPIO - value: bool, - // GPIO is ready (debounced) - ready: bool, - // debouncer is active - active: bool, - // debounce timer - timer: TickTimerService, -} - -impl<'a> DebouncedGPIO<'a> { - pub fn new(pin: AnyPin, system_tick_rate_hz: usize, debounce_time_ms: usize) -> Self { - // coin debounce timer (100ms) - Self { - input: Input::new(pin, Pull::None), - value: false, - ready: false, - active: false, - timer: TickTimerService::new( - TickServiceData::new(system_tick_rate_hz * debounce_time_ms / 1000), - false, - ), - } - } - - pub fn ready(&self) -> bool { - self.ready - } - - pub fn active(&self) -> bool { - self.active - } - - pub fn value(&self) -> bool { - self.value - } - - pub fn begin(&mut self) { - self.reset(); - self.timer.enable(true); - self.active = true; - } - - pub fn reset(&mut self) { - self.timer.reset(); - self.ready = false; - self.active = false; - } - - pub fn service(&mut self) { - self.timer.tick(); - if self.timer.need_service() { - self.timer.reset(); - self.value = self.input.is_high(); - self.ready = true; - } - } - pub fn is_high_immediate(&self) -> bool { - self.input.is_high() - } -} diff --git a/ch32v-insert-coin/src/insert_coin/insert_coin.rs b/ch32v-insert-coin/src/insert_coin/insert_coin.rs index 8c0a606..79d6598 100644 --- a/ch32v-insert-coin/src/insert_coin/insert_coin.rs +++ b/ch32v-insert-coin/src/insert_coin/insert_coin.rs @@ -11,7 +11,7 @@ use crate::insert_coin::services::{DacService, LedService, Service, TickService, // static LED1_DCS: [u8; 5] = [0u8, 25u8, 50u8, 75u8, 100u8]; pub struct SimplePwmCore<'d, T: GeneralInstance16bit> { - pub pwm: core::cell::RefCell>, + pwm: core::cell::RefCell>, } impl<'d, T: GeneralInstance16bit> SimplePwmCore<'d, T> { @@ -37,20 +37,11 @@ impl<'d, T: GeneralInstance16bit> SimplePwmCore<'d, T> { self.pwm.borrow_mut().set_duty(ch, dc); } - pub fn disable(&self, ch: Channel) { - self.pwm.borrow_mut().disable(ch); - } + // pub fn disable(&self, ch: Channel) { + // self.pwm.borrow_mut().disable(ch); + // } } -// pub struct SimplePwmHandle { -// core: &'static SimplePwmCore<'_, T: GeneralInstance16Bit>, -// channel: Channel, -// } - -// impl SimplePwmHandle { -// pub fn set_amplitude(&self, amplitude: u8) {} -// } - pub struct CoreConfig { pub tick_rate_hz: usize, } diff --git a/ch32v-insert-coin/src/insert_coin/mod.rs b/ch32v-insert-coin/src/insert_coin/mod.rs index 766dcca..e7c42d8 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::{DacService, LedService, Service, TickTimerService}; +pub use services::TickTimerService; -pub use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore}; pub use services::{TickService, TickServiceData}; +pub use insert_coin::{InsertCoin, CoreConfig, SimplePwmCore}; \ No newline at end of file diff --git a/ch32v-insert-coin/src/insert_coin/services/dac.rs b/ch32v-insert-coin/src/insert_coin/services/dac.rs index 0a3b364..4cdaec0 100644 --- a/ch32v-insert-coin/src/insert_coin/services/dac.rs +++ b/ch32v-insert-coin/src/insert_coin/services/dac.rs @@ -1,4 +1,5 @@ -use crate::insert_coin::services::{TickService, TickServiceData}; +use crate::insert_coin::services::{TickServiceData, TickService}; + use adpcm_pwm_dac::dac::DpcmDecoder; use ch32_hal::timer::Channel; @@ -8,7 +9,6 @@ pub struct DacService<'a> { dpcm_decoder: core::cell::RefCell>, amplitude: core::cell::RefCell, pub channel: Channel, - enabled: bool, } impl<'a> DacService<'a> { @@ -18,19 +18,9 @@ impl<'a> DacService<'a> { dpcm_decoder: core::cell::RefCell::new(DpcmDecoder::new()), amplitude: core::cell::RefCell::new(0), channel, - enabled: false, } } - pub fn play_sample(&mut self) { - self.dpcm_decoder.borrow_mut().seek_to_sample(0); - self.enabled = true; - } - - pub fn disable(&mut self) { - self.enabled = false; - } - 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); @@ -46,23 +36,17 @@ impl<'a> DacService<'a> { impl<'a> TickService for DacService<'a> { fn tick(&self) { - if self.enabled { - let mut tc = self.service_data.borrow_mut(); - tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1); - } + let mut tc = self.service_data.borrow_mut(); + tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1); } fn need_service(&self) -> bool { - self.enabled && self.service_data.borrow().ticks_remaining == 0 + self.service_data.borrow().ticks_remaining == 0 } fn service(&self) { let mut tc = self.service_data.borrow_mut(); tc.ticks_remaining = tc.ticks_per_service; - if (self.dpcm_decoder.borrow().is_done()) { - self.set_amplitude(0); - } else { - self.set_amplitude(self.dpcm_decoder.borrow_mut().output_next()); - } + self.set_amplitude(self.dpcm_decoder.borrow_mut().output_next()); } } diff --git a/ch32v-insert-coin/src/insert_coin/services/led.rs b/ch32v-insert-coin/src/insert_coin/services/led.rs index c1bf890..b7e2056 100644 --- a/ch32v-insert-coin/src/insert_coin/services/led.rs +++ b/ch32v-insert-coin/src/insert_coin/services/led.rs @@ -1,6 +1,6 @@ use ch32_hal::timer::Channel; -use crate::insert_coin::services::Service; +use crate::insert_coin::services::{Service}; pub struct LedService { // need_service: core::cell::RefCell, @@ -25,7 +25,9 @@ impl LedService { } } + impl Service for LedService { + fn need_service(&self) -> bool { self.need_service } @@ -34,3 +36,5 @@ impl Service for LedService { self.need_service = false; } } + + diff --git a/ch32v-insert-coin/src/insert_coin/services/tick_timer.rs b/ch32v-insert-coin/src/insert_coin/services/tick_timer.rs index 863314a..a10ab74 100644 --- a/ch32v-insert-coin/src/insert_coin/services/tick_timer.rs +++ b/ch32v-insert-coin/src/insert_coin/services/tick_timer.rs @@ -1,4 +1,4 @@ -use crate::insert_coin::services::{TickService, TickServiceData}; +use crate::insert_coin::services::{TickServiceData, TickService}; pub struct TickTimerService { service_data: core::cell::RefCell, @@ -15,21 +15,22 @@ impl TickTimerService { } } - pub fn is_enabled(&self) -> bool { - self.enabled - } + // pub fn is_enabled(&self) -> bool { + // self.enabled + // } pub fn reset(&mut self) { let mut sd = self.service_data.borrow_mut(); sd.ticks_remaining = sd.ticks_per_service; self.enabled = false; - } + } pub fn enable(&mut self, enable: bool) { self.enabled = enable; } } + impl TickService for TickTimerService { fn tick(&self) { if self.enabled { @@ -47,3 +48,5 @@ impl TickService for TickTimerService { tc.ticks_remaining = tc.ticks_per_service; } } + + diff --git a/ch32v-insert-coin/src/main.rs b/ch32v-insert-coin/src/main.rs index 694ce75..ed5e986 100644 --- a/ch32v-insert-coin/src/main.rs +++ b/ch32v-insert-coin/src/main.rs @@ -9,29 +9,17 @@ mod insert_coin; // system stuff mod system; -mod debounced_gpio; -use debounced_gpio::DebouncedGPIO; - // synthesizer :3 mod synthesizer; -use synthesizer::SynthesizerService; - -// sequences -mod sequences; -use sequences::SEQUENCE_LIST; - -mod app; -use app::{ - sequencer::BasicSequence, App, Config, Interfaces, Sequences, Services, State, TimerConfig, -}; +use synthesizer::AppSynthesizers; use ch32_hal::{adc::AdcChannel, interrupt::typelevel::Handler, timer::low_level::OutputPolarity}; -use insert_coin::{CoreConfig, DacService, InsertCoin, LedService, SimplePwmCore}; +use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore}; use ch32_hal as hal; use hal::bind_interrupts; use hal::delay::Delay; -use hal::gpio::{AnyPin, Input, Level, Output, OutputOpenDrain, Pin, Pull}; +use hal::gpio::{AnyPin, Input, Pin, Pull}; use hal::time::Hertz; use hal::timer::low_level::CountingMode; use hal::timer::simple_pwm::{PwmPin, SimplePwm}; @@ -40,163 +28,213 @@ use hal::println; use qingke::riscv; -use crate::app::sequencer::{DynamicSequence, SequenceEntry}; - -static LED0_SEQ: [u8; 8] = [0u8, 25u8, 50u8, 75u8, 100u8, 75u8, 50u8, 25u8]; - -pub struct Usb { - usb_pin: Input<'static>, +enum Level { + Off, + Low, + Medium, + High, + Maximum, } -impl Usb { - pub fn new(usb_pin: Input<'static>) -> Self { - Self { usb_pin } - } - pub fn powered(&self) -> bool { - self.usb_pin.is_high() - } - // pub fn enable(&mut self) { - // self.usb_pin.set_as_input(Pull::Up); - // } - // pub fn disable(&mut self) { - // self.usb_pin.set_as_input(Pull::None); - // } -} - -pub struct Amplifier { - amp_en: OutputOpenDrain<'static>, -} - -impl Amplifier { - pub fn new(amp_en: OutputOpenDrain<'static>) -> Self { - let mut amp = Self { amp_en }; - amp.disable(); - amp - } - pub fn enable(&mut self) { - self.amp_en.set_low(); - } - pub fn disable(&mut self) { - self.amp_en.set_high(); - } - pub fn enabled(&self) -> bool { - !self.amp_en.is_set_high() +impl Level { + pub fn next(&mut self) { + *self = match self { + Self::Off => Self::Low, + Self::Low => Self::Medium, + Self::Medium => Self::High, + Self::High => Self::Maximum, + Self::Maximum => Self::Off, + }; } } -use hal::adc::Adc; -use hal::peripherals::{ADC1, PD4}; - -pub struct AdcCore { - adc: Adc<'static, ADC1>, - battery_pin: PD4, - batt_values: [u16; 10], - index: usize, +struct Settings { + brightness: Level, + volume: Level, + button_sound_index: usize, } -impl AdcCore { - pub fn new(mut adc: Adc<'static, ADC1>, pin: PD4) -> Self { - riscv::asm::delay(20_000); - adc.calibrate(); +impl Default for Settings { + fn default() -> Self { Self { - adc, - battery_pin: pin, - batt_values: [1024; 10], - index: 0, + brightness: Level::Medium, + volume: Level::Medium, + button_sound_index: 0, } } - - // TODO make this a float or something - pub fn get_battery_voltage(&mut self) -> u16 { - let val = self - .adc - .convert(&mut self.battery_pin, hal::adc::SampleTime::CYCLES241); - self.batt_values[self.index] = val; - self.index += 1; - if self.index > &self.batt_values.len() - 1 { - self.index = 0; - } - val - } - - pub fn get_average(&self) -> u16 { - let mut sum = 0; - for value in &self.batt_values { - sum += value; - } - sum / self.batt_values.len() as u16 - } - - pub fn shutdown(&mut self) { - self.adc.shutdown() - } } -#[derive(Debug)] -struct Flag { +struct DebouncedGPIO<'a> { + input: Input<'a>, + // value of the GPIO value: bool, + // GPIO is ready (debounced) + ready: bool, + // debouncer is active + active: bool, + // debounce timer + timer: TickTimerService, } -impl Flag { + +impl<'a> DebouncedGPIO<'a> { + pub fn new(pin: AnyPin, system_tick_rate_hz: usize, debounce_time_ms: usize) -> Self { + // coin debounce timer (100ms) + Self { + input: Input::new(pin, Pull::Up), + value: false, + ready: false, + active: false, + timer: TickTimerService::new( + TickServiceData::new(system_tick_rate_hz * debounce_time_ms / 1000), + false, + ), + } + } + + pub fn ready(&self) -> bool { + self.ready + } + pub fn active(&self) -> bool { - unsafe { core::ptr::read_volatile(&raw const self.value as *const bool) } + self.active } - pub fn set(&mut self) { - unsafe { core::ptr::write_volatile(&raw mut self.value as *mut bool, true) } + + pub fn value(&self) -> bool { + self.value } - pub fn clear(&mut self) { - unsafe { core::ptr::write_volatile(&raw mut self.value as *mut bool, false) } + + pub fn begin(&mut self) { + self.reset(); + self.timer.enable(true); + self.active = true; } + + pub fn reset(&mut self) { + self.timer.reset(); + self.ready = false; + self.active = false; + } + + pub fn service(&mut self) { + self.timer.tick(); + if self.timer.need_service() { + self.timer.reset(); + self.value = self.input.is_high(); + self.ready = true; + } + } + pub fn is_high_immediate(&self) -> bool { + self.input.is_high() + } +} + +// DeepSleep --coin button irq--> Active +// Active --2s button--> Idle +// Idle/Active --5s button--> DeepSleep + +pub enum SystemState { + // system is asleep, waiting for wake from coin insertion + DeepSleep, + // system is in low-power mode, dimmed lights, waiting for interaction + Idle, + // system is active. on entry: play coin sound. on button press: play different sound + Active, } #[derive(Debug)] struct InputFlags { - sense_coin_flag: Flag, - main_btn_flag: Flag, + sense_coin_flag: bool, + main_btn_flag: bool, volume_btn_flag: bool, light_ctrl_btn_flag: bool, - systick_flag: Flag, } impl Default for InputFlags { fn default() -> Self { Self { - sense_coin_flag: Flag { value: false }, - main_btn_flag: Flag { value: false }, + sense_coin_flag: false, + main_btn_flag: false, volume_btn_flag: false, light_ctrl_btn_flag: false, - systick_flag: Flag { value: false }, } } } +// impl InputFlags { +// pub fn set_sense_coin_flag(&mut self, val: bool) { +// self.sense_coin_flag = val; +// } +// pub fn set_main_btn_flag(&mut self, val: bool) { +// self.main_btn_flag = val; +// } +// pub fn set_volume_btn_flag(&mut self, val: bool) { +// self.volume_btn_flag = val; +// } +// pub fn set_light_ctrl_btn_flag(&mut self, val: bool) { +// self.light_ctrl_btn_flag = val; +// } +// } + static mut INPUT_FLAGS: InputFlags = InputFlags { - sense_coin_flag: Flag { value: false }, - main_btn_flag: Flag { value: false }, + sense_coin_flag: false, + main_btn_flag: false, volume_btn_flag: false, light_ctrl_btn_flag: false, - systick_flag: Flag { value: false }, }; struct Test {} impl Handler for Test { unsafe fn on_interrupt() { - // #[cfg(feature = "enable_print")] - // println!("on_interrupt()"); + #[cfg(feature = "enable_print")] + println!("on_interrupt()"); critical_section::with(|_| unsafe { let flags = system::clear_interrupt(2, 6); - 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(); - } + INPUT_FLAGS.sense_coin_flag = flags.sense_coin_flag; + INPUT_FLAGS.main_btn_flag = flags.main_btn_flag; }); } } +static mut LED: Option> = None; +static mut SYSTICK_COUNT: u32 = 0; +static mut SYNTHESIZERS: Option> = None; +static mut TOGGLE_COUNT: u32 = 0; +static mut TICK_FLAG: bool = false; +static mut SYNTH_TICK_FLAG: bool = false; +static mut NOTE_TICK_FLAG: bool = false; +static mut FREQ: [usize; 2] = [220, 440]; +static mut INDEX: usize = 0; + +fn flag() -> bool { + unsafe { core::ptr::read_volatile(&raw const TICK_FLAG as *const bool) } +} + +fn clear_flag() { + unsafe { + TICK_FLAG = false; + } +} + +fn synth_flag() -> bool { + unsafe { core::ptr::read_volatile(&raw const SYNTH_TICK_FLAG as *const bool) } +} + +fn clear_synth_flag() { + unsafe { + SYNTH_TICK_FLAG = false; + } +} + +fn note_flag() -> bool { + unsafe { core::ptr::read_volatile(&raw const NOTE_TICK_FLAG as *const bool) } +} + +fn clear_note_flag() { + unsafe { + NOTE_TICK_FLAG = false; + } +} + #[qingke_rt::interrupt(core)] fn SysTick() { let r = &ch32_hal::pac::SYSTICK; @@ -205,9 +243,27 @@ fn SysTick() { r.sr().write(|w| w.set_cntif(false)); unsafe { - // safe because single-threaded - #[allow(static_mut_refs)] - INPUT_FLAGS.systick_flag.set(); + // if let Some(ref mut synthesizers) = SYNTHESIZERS { + // println!("tick"); + // synthesizers.tick(); + // } + SYNTH_TICK_FLAG = true; + + if SYSTICK_COUNT % 5000 == 0 { + NOTE_TICK_FLAG = true; + } + + if SYSTICK_COUNT % 50000 == 0 { + TICK_FLAG = true; + // if let Some(ref mut led) = LED { + // let toggle = TOGGLE_COUNT; + // // println!("TOGGLE {toggle}"); + // TOGGLE_COUNT += 1; + // led.toggle(); + // } + // println!("HERE"); + } + SYSTICK_COUNT = SYSTICK_COUNT.wrapping_add(1); } } @@ -239,50 +295,133 @@ fn systick_init(tick_freq_hz: usize) { w.set_stclk(ch32_hal::pac::systick::vals::Stclk::HCLK_DIV8); // HCLK/8 clock source }); } -fn systick_stop() { - let r = &ch32_hal::pac::SYSTICK; - // Reset SysTick - r.ctlr().write(|w| { - // Start with everything disabled - }); -} bind_interrupts!(struct Irqs { EXTI7_0 => Test; }); // TODO: remove -use app::settings::Settings; use insert_coin::TickTimerService; use insert_coin::{TickService, TickServiceData}; -fn app_main(mut p: hal::Peripherals, app_settings: Settings) -> Settings { - // initialize ADC core first, and exit if battery is too low - let mut adc = hal::adc::Adc::new(p.ADC1, Default::default()); - let mut batt_monitor_pin = p.PD4; - let mut adc_core = AdcCore::new(adc, batt_monitor_pin); +fn debug_main(mut p: hal::Peripherals) -> ! { + // LED0 output setup + use hal::gpio::{Level, Output}; + let mut led = Output::new(p.PC3, Level::High, Default::default()); - let mut usb_detect_pin = p.PD5; - let usb_detect_input = Input::new(usb_detect_pin, Pull::Up); - let usb = Usb::new(usb_detect_input); + // unsafe { + // LED = Some(led); + // } - let bv = adc_core.get_battery_voltage(); + println!("pre"); + riscv::asm::delay(20_000_000); + println!("post2"); - // if we don't have USB power, and the batt ADC reads under 421, don't wake - if !usb.powered() && bv < 421 { - adc_core.shutdown(); - return app_settings; + let tick_rate_hz = 100000; // 50khz + + // DAC output setup + let dac_pin = PwmPin::new_ch4::<0>(p.PC4); + // let dac_ch = hal::timer::Channel::Ch4; + + // PWM timer setup + let mut pwm = SimplePwm::new( + p.TIM1, + None, + None, + None, + Some(dac_pin), + Hertz::khz(500), + CountingMode::default(), + ); + + let pwm_core = SimplePwmCore::new(pwm); + unsafe { + use qingke_rt::CoreInterrupt; + + qingke::pfic::disable_interrupt(CoreInterrupt::SysTick as u8); } + + // === synthesizer setup === + // unsafe { + // let mut synth = AppSynthesizers::new(tick_rate_hz, pwm_core); + // synth.square.set_freq(440); + // SYNTHESIZERS = Some(synth); + // } + let mut synth = AppSynthesizers::new(tick_rate_hz, pwm_core); + synth.square.set_freq(440); + + #[cfg(feature = "enable_print")] + println!("begin loop"); + + systick_init(tick_rate_hz); + + unsafe { + use qingke::interrupt::Priority; + use qingke_rt::CoreInterrupt; + qingke::pfic::set_priority(CoreInterrupt::SysTick as u8, Priority::P15 as u8); + qingke::pfic::enable_interrupt(CoreInterrupt::SysTick as u8); + } + + let mut index = 0; + let freqs = [1567, 1396, 1318, 1174, 1046, 987, 880, 783, 698]; + // let freqs = [100, 200, 300, 400, 500, 600, 700, 800, 900]; + // let freqs = [ + // 1000, 990, 980, 970, 960, 950, 940, 930, 920, 910, 900, 890, 880, 870, 860, 850, 840, 830, + // 820, 810, 800, 790, 780, 770, 760, 750, 740, 730, 720, 710, 700, 690, 680, 670, 660, 650, + // 640, 630, 620, 610, 600, 590, 580, 570, 560, 550, 540, 530, 520, 510, 500, 490, 480, 470, + // 460, 450, 440, 430, 420, 410, 400, 390, 380, 370, 360, 350, 340, 330, 320, 310, 300, 290, + // 280, 270, 260, 250, 240, 230, 220, 210, 200, 190, 180, 170, 160, 150, 140, 130, 120, 110, + // 100, + // ]; + + loop { + if flag() { + clear_flag(); + led.toggle(); + } + if synth_flag() { + clear_synth_flag(); + synth.tick(); + } + if note_flag() { + clear_note_flag(); + synth.square.set_freq(freqs[index]); + // println!("{}", { freqs[index] }); + // println!("{}", freqs[index]); + index += 1; + if index > freqs.len() - 1 { + index = 0; + } + } + // if (unsafe { TICK_FLAG == true }) { + // println!("TICK!"); + // led.toggle(); + // unsafe { + // TICK_FLAG = false; + // } + // } + } +} + +fn app_main(mut p: hal::Peripherals, mut delay: Delay) -> ! { // === output setup === // LED0 output setup let led0_pin = PwmPin::new_ch3::<0>(p.PC3); let led0_ch = hal::timer::Channel::Ch3; + // let mut led0_pin = Output::new(p.PC3, Level::High, Default::default()); + // unsafe { + // LED = Some(led0_pin); + // } // LED1 output setup let led1_pin = PwmPin::new_ch1::<0>(p.PD2); let led1_ch = hal::timer::Channel::Ch1; + // LED2 output setup + let led2_pin = PwmPin::new_ch2::<0>(p.PA1); + let led2_ch = hal::timer::Channel::Ch2; + // DAC output setup let dac_pin = PwmPin::new_ch4::<0>(p.PC4); // let dac_ch = hal::timer::Channel::Ch4; @@ -291,40 +430,44 @@ fn app_main(mut p: hal::Peripherals, app_settings: Settings) -> Settings { let mut pwm = SimplePwm::new( p.TIM1, Some(led1_pin), - // Some(led2_pin), - None, + Some(led2_pin), Some(led0_pin), Some(dac_pin), Hertz::khz(200), CountingMode::default(), ); - pwm.set_polarity(led0_ch, OutputPolarity::ActiveHigh); + pwm.set_polarity(led0_ch, OutputPolarity::ActiveLow); pwm.set_polarity(led1_ch, OutputPolarity::ActiveLow); - let mut pwm_core = SimplePwmCore::new(pwm); - pwm_core.write_amplitude(led0_ch, 0); - pwm_core.write_amplitude(led1_ch, 0); - // pwm.set_polarity(led2_ch, OutputPolarity::ActiveLow); - - let tick_rate_hz = 50000; + 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 core_config = CoreConfig::new(tick_rate_hz); + let pwm_core = SimplePwmCore::new(pwm); + + // === synthesizer setup === + // let synthesizer = AppSynthesizers::new(core_config.tick_rate_hz, pwm_core); + // === input setup === // adc - // let mut adc = hal::adc::Adc::new(p.ADC1, Default::default()); - // let mut batt_monitor_pin = p.PD4; - // let adc_core = AdcCore::new(adc, batt_monitor_pin); + let mut adc = hal::adc::Adc::new(p.ADC1, Default::default()); + let mut batt_monitor_pin = p.PD4; // adc2 // let mut usb_detect_dc = hal::adc::Adc::new(p.ADC1, Default::default()); + let mut usb_detect_pin = p.PD5; // println!("ADC_PIN CHANNEL: {}", adc_pin.channel().channel()); + delay.delay_ms(1000); + let adc_cal = adc.calibrate(); - // #[cfg(feature = "enable_print")] - // println!("ADC calibration value: {}", adc_cal); + #[cfg(feature = "enable_print")] + println!("ADC calibration value: {}", adc_cal); // definitions let sense_coin_pin = p.PC2; @@ -332,22 +475,28 @@ fn app_main(mut p: hal::Peripherals, app_settings: Settings) -> Settings { let volume_btn_pin = p.PC6; let light_ctrl_btn_pin = p.PC7; let amp_en = p.PC5; - // let extra_io_1 = p.PD0; - // let extra_io_2 = p.PD3; - - let mut amp_en_output = OutputOpenDrain::new(amp_en, Level::Low, Default::default()); - let amp = Amplifier::new(amp_en_output); + let extra_io_1 = p.PD0; + let extra_io_2 = p.PD3; // set up interrupts - unsafe { system::init_gpio_irq(sense_coin_pin.pin(), sense_coin_pin.port(), true, false) }; + unsafe { system::init_gpio_irq(sense_coin_pin.pin(), sense_coin_pin.port(), false, true) }; unsafe { system::init_gpio_irq(main_btn_pin.pin(), main_btn_pin.port(), true, true) }; + // unsafe { system::init_gpio_irq(volume_btn_pin.pin(), volume_btn_pin.port(), true, true) }; + // unsafe { + // system::init_gpio_irq( + // light_ctrl_btn_pin.pin(), + // light_ctrl_btn_pin.port(), + // true, + // true, + // ) + // }; // coin debouncer (100ms) let mut sense_coin_input = - DebouncedGPIO::new(sense_coin_pin.degrade(), core_config.tick_rate_hz, 20); + DebouncedGPIO::new(sense_coin_pin.degrade(), core_config.tick_rate_hz, 100); // main button debouncer (100ms) let mut main_btn_input = - DebouncedGPIO::new(main_btn_pin.degrade(), core_config.tick_rate_hz, 20); + DebouncedGPIO::new(main_btn_pin.degrade(), core_config.tick_rate_hz, 100); // button debouncer (100ms) let mut volume_btn_input = DebouncedGPIO::new(volume_btn_pin.degrade(), core_config.tick_rate_hz, 100); @@ -355,94 +504,74 @@ fn app_main(mut p: hal::Peripherals, app_settings: Settings) -> Settings { let mut light_ctrl_btn_input = DebouncedGPIO::new(light_ctrl_btn_pin.degrade(), core_config.tick_rate_hz, 100); - let timer_config = TimerConfig { - sp_timer_ms: 1000, - lp_timer_ms: 3000, - batt_adc_timer_ms: 1000, - usb_adc_timer_ms: 10000, - led0_timer_ms: 100, - led1_timer_ms: 100, - // 4 hours: - // shutdown_timer_s: 1, - shutdown_timer_s: 4 * 60 * 60 * 110 / 100, - // led2_timer_ms: 100, - }; + let mut interfaces = InsertCoin::new(core_config, pwm_core); + interfaces.set_active(true); + // insert_coin.init(); - let app_config = Config { - system_tick_rate_hz: tick_rate_hz, - timers: timer_config, - }; + let mut settings = Settings::default(); - // 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 mut led0_index = 0; + let led0_dcs = [0u8, 25u8, 50u8, 75u8, 100u8, 75u8, 50u8, 25u8]; - // let coin_sound = include_bytes!("../audio/coin5.raw"); + let mut led1_index = 0; + let led1_dcs = [0u8, 25u8, 50u8, 75u8, 100u8]; + + // tick timer 0 + let tt0_fire_rate_hz = 9; + let tt0_tick_per_service = interfaces.config.tick_rate_hz / (tt0_fire_rate_hz * 2); + let tt0_service_data = TickServiceData::new(tt0_tick_per_service); + let mut tt0 = TickTimerService::new(tt0_service_data, true); + + // tick timer 1 + let tt1_fire_rate_hz = 3; + let tt1_tick_per_service = interfaces.config.tick_rate_hz / (tt1_fire_rate_hz * 2); + let tt1_service_data = TickServiceData::new(tt1_tick_per_service); + let mut tt1 = TickTimerService::new(tt1_service_data, true); + + // short press timer + let sp_ticks = 2 * interfaces.config.tick_rate_hz; + let sp_timer_data = TickServiceData::new(sp_ticks); + let mut sp_timer = TickTimerService::new(sp_timer_data, false); + sp_timer.reset(); + + // long press timer + let lp_ticks = 5 * interfaces.config.tick_rate_hz; + let lp_timer_data = TickServiceData::new(lp_ticks); + let mut lp_timer = TickTimerService::new(lp_timer_data, false); + lp_timer.reset(); + + // battery read timer + let adc1_ticks = 5 * interfaces.config.tick_rate_hz; + let adc1_timer_data = TickServiceData::new(adc1_ticks); + let mut adc1_timer = TickTimerService::new(adc1_timer_data, false); + adc1_timer.reset(); + adc1_timer.enable(true); + + let tick_interval_us = 1000000 / interfaces.config.tick_rate_hz - 10; + + // dac data // let coin_sound = include_bytes!("../audio/coin2.raw"); + // let coin_sound = include_bytes!("../audio/sweep_dpcm_u4.raw"); + // let coin_sound = include_bytes!("../audio/button_1.raw"); - let sample_player = DacService::new(ch32_hal::timer::Channel::Ch4, dac_service_data); - // sample_player.load_data(coin_sound); + // let button_sound_1 = include_bytes!("../audio/button_1.raw"); + // let button_sound_2 = include_bytes!("../audio/button_2.raw"); + // let button_sound_3 = include_bytes!("../audio/button_3.raw"); - let sequencer = app::sequencer::DynamicSequence::new(&SEQUENCE_LIST[0].0, tick_rate_hz); + let mut system_state = SystemState::Active; - 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, - sequencer, - }; + interfaces.led0.set_amplitude(0); + interfaces.led1.set_amplitude(0); + interfaces.service(); - let app_sequences = Sequences { - led0: BasicSequence::new(&LED0_SEQ), - led1: BasicSequence::new(&LED0_SEQ), - // led2: BasicSequence::new(&LED0_SEQ), - audio: &SEQUENCE_LIST, - }; - - let app_interfaces = Interfaces { - pwm_core, - adc_core, - amp, - usb, - }; - - let mut app = App::new( - app_config, - app_services, - app_sequences, - app_interfaces, - app_settings, - ); - - let need_sound = unsafe { - #[allow(static_mut_refs)] - if INPUT_FLAGS.main_btn_flag.active() { - #[allow(static_mut_refs)] - INPUT_FLAGS.main_btn_flag.clear(); - true - } else { - false - } - }; - - // init systick - systick_init(tick_rate_hz); - - // set up interrupts unsafe { use hal::pac::Interrupt; - use qingke::interrupt::Priority; - use qingke_rt::CoreInterrupt; + // use qingke_rt::CoreInterrupt; + // qingke::pfic::unpend_interrupt(Interrupt::EXTI7_0 as u8); system::clear_interrupt(2, 6); - - qingke::pfic::set_priority(CoreInterrupt::SysTick as u8, Priority::P15 as u8); - qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8); - qingke::pfic::enable_interrupt(CoreInterrupt::SysTick as u8); + // qingke::pfic::enable_interrupt(CoreInterrupt::SysTick as u8); } // MAIN APPLICATION @@ -453,159 +582,214 @@ fn app_main(mut p: hal::Peripherals, app_settings: Settings) -> Settings { // -depress the big button for approx 2s and it puts the led into low light mode. Just making it dimmer than usual. // -depress the big button for 5s and it goes into deep sleep, everything off with the low sleep current draw - // #[cfg(feature = "enable_print")] - // println!("begin"); + #[cfg(feature = "enable_print")] + println!("begin"); + let mut volume_btn_prev = volume_btn_input.is_high_immediate(); let mut light_ctrl_btn_prev = light_ctrl_btn_input.is_high_immediate(); - - app.init(); - if need_sound { - app.main_button_click(); - } loop { - // system servicing - - // volume edge detector + // edge detector if !volume_btn_input.active() { let volume_btn_curr = volume_btn_input.is_high_immediate(); if volume_btn_prev != volume_btn_curr { - volume_btn_input.begin(); volume_btn_prev = volume_btn_curr; + unsafe { + INPUT_FLAGS.volume_btn_flag = true; + } } } - volume_btn_input.service(); - if volume_btn_input.ready() { - // #[cfg(feature = "enable_print")] - // println!("volume btn value: {}", volume_btn_input.value()); - if !volume_btn_input.value() { - app.volume_button(); - } - volume_btn_input.reset(); - } - - // brightness edge detector if !light_ctrl_btn_input.active() { let light_ctrl_btn_curr = light_ctrl_btn_input.is_high_immediate(); if light_ctrl_btn_prev != light_ctrl_btn_curr { - light_ctrl_btn_input.begin(); light_ctrl_btn_prev = light_ctrl_btn_curr; + unsafe { + INPUT_FLAGS.light_ctrl_btn_flag = true; + } } } - - light_ctrl_btn_input.service(); - if light_ctrl_btn_input.ready() { - #[cfg(feature = "enable_print")] - println!("brightness btn value: {}", light_ctrl_btn_input.value()); - if !light_ctrl_btn_input.value() { - app.brightness_button(); - } - 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(); - sense_coin_input.begin(); - } - sense_coin_input.service(); - if sense_coin_input.ready() { - sense_coin_input.reset(); - app.coin_detect(); - } - } - - // main button handling - unsafe { - #[allow(static_mut_refs)] - if INPUT_FLAGS.main_btn_flag.active() { - #[allow(static_mut_refs)] - INPUT_FLAGS.main_btn_flag.clear(); - main_btn_input.begin(); - } - } - main_btn_input.service(); - if main_btn_input.ready() { - let value = main_btn_input.value(); - main_btn_input.reset(); - // #[cfg(feature = "enable_print")] - // println!("main button", value); - - match value { - true => app.main_button_press(), - false => app.main_button_release(), - } - } - - // systick tick - if unsafe { - #[allow(static_mut_refs)] - INPUT_FLAGS.systick_flag.active() - } { + { + // system input servicing unsafe { - #[allow(static_mut_refs)] - INPUT_FLAGS.systick_flag.clear(); + if INPUT_FLAGS.sense_coin_flag { + #[cfg(feature = "enable_print")] + println!("coin flag active"); + INPUT_FLAGS.sense_coin_flag = false; + sense_coin_input.begin(); + // enter the active state + system_state = SystemState::Active; + + // todo: enter active + tt0.enable(true); + tt1.enable(true); + // interfaces.dac.load_data(coin_sound); + } + if INPUT_FLAGS.main_btn_flag { + #[cfg(feature = "enable_print")] + println!("button flag active"); + INPUT_FLAGS.main_btn_flag = false; + main_btn_input.begin(); + } + if INPUT_FLAGS.volume_btn_flag { + #[cfg(feature = "enable_print")] + println!("volume btn triggered"); + INPUT_FLAGS.volume_btn_flag = false; + volume_btn_input.begin(); + } + if INPUT_FLAGS.light_ctrl_btn_flag { + #[cfg(feature = "enable_print")] + println!("light ctrl btn triggered!"); + INPUT_FLAGS.light_ctrl_btn_flag = false; + light_ctrl_btn_input.begin(); + } } - // app tick - app.tick(); - } - app.service(); + // debouncer + sense_coin_input.service(); + main_btn_input.service(); + volume_btn_input.service(); + light_ctrl_btn_input.service(); - match app.get_state() { - // enter standby - app::State::DeepSleep => { - app.shut_down(); - return app.get_settings(); + if sense_coin_input.ready() { + #[cfg(feature = "enable_print")] + println!("debounced coin_input value: {}", sense_coin_input.value()); + sense_coin_input.reset(); } - _ => {} - } - } -} + if main_btn_input.ready() { + let value = main_btn_input.value(); + main_btn_input.reset(); + #[cfg(feature = "enable_print")] + println!("debounced button_input value: {}", value); -use ch32_hal::timer::low_level::{OutputCompareMode, Timer}; -use ch32_hal::timer::Channel; + if !value { + // interfaces.dac.load_data(match settings.button_sound_index { + // 0 => button_sound_1, + // 1 => button_sound_2, + // 2 => button_sound_3, + // _ => button_sound_1, + // }); + // interfaces + // .dac + // .load_data(button_sounds[settings.button_sound_index]); -// fn shutdown_main(p: Peripherals) { -fn shutdown_main(p: hal::Peripherals) { - systick_stop(); - // LED0 output setup - let led0_pin = OutputOpenDrain::new(p.PC3, Level::Low, Default::default()); - let led1_pin = OutputOpenDrain::new(p.PD2, Level::High, Default::default()); - let led2_pin = OutputOpenDrain::new(p.PA1, Level::High, Default::default()); - let dac_pin = OutputOpenDrain::new(p.PC4, Level::Low, Default::default()); - let mut amp_pin = OutputOpenDrain::new(p.PC5, Level::Low, Default::default()); - amp_pin.set_high(); - let volume_btn_pin = OutputOpenDrain::new(p.PC6, Level::Low, Default::default()); - let light_ctrl_btn_pin = OutputOpenDrain::new(p.PC7, Level::Low, Default::default()); - let usb_detect_input = OutputOpenDrain::new(p.PD5, Level::Low, Default::default()); + settings.button_sound_index += 1; + if settings.button_sound_index > 2 { + // if settings.button_sound_index > button_sounds.len() - 1 { + settings.button_sound_index = 0; + } + #[cfg(feature = "enable_print")] + println!("reset hold timers + enable"); + sp_timer.reset(); + sp_timer.enable(true); + lp_timer.reset(); + lp_timer.enable(true); + } else { + sp_timer.reset(); + lp_timer.reset(); + } + } + if volume_btn_input.ready() { + #[cfg(feature = "enable_print")] + println!("volume btn value: {}", volume_btn_input.value()); + settings.volume.next(); + volume_btn_input.reset(); + } + if light_ctrl_btn_input.ready() { + #[cfg(feature = "enable_print")] + println!("light_ctrl_btn value: {}", light_ctrl_btn_input.value()); + settings.brightness.next(); + light_ctrl_btn_input.reset(); + } - let sense_coin_pin = p.PC2; - let main_btn_pin = p.PD6; + // timers + sp_timer.tick(); + lp_timer.tick(); + adc1_timer.tick(); - unsafe { system::init_gpio_irq(sense_coin_pin.pin(), sense_coin_pin.port(), true, false) }; - unsafe { system::init_gpio_irq(main_btn_pin.pin(), main_btn_pin.port(), true, false) }; + if sp_timer.need_service() { + #[cfg(feature = "enable_print")] + println!("sp detect!"); + sp_timer.reset(); - let sense_coin_pin = Input::new(sense_coin_pin, Pull::None); - let main_btn_pin = Input::new(main_btn_pin, Pull::None); + // todo enter idle + system_state = SystemState::Idle; + // TODO: fix polarity + interfaces.led0.set_amplitude(10); + interfaces.led1.set_amplitude(10); + interfaces.service(); + } - riscv::asm::delay(1_000_000); + if lp_timer.need_service() { + #[cfg(feature = "enable_print")] + println!("lp detect!"); + lp_timer.reset(); - loop { - unsafe { system::enter_standby() }; - riscv::asm::wfi(); - unsafe { - #[allow(static_mut_refs)] - if (INPUT_FLAGS.sense_coin_flag.active() || INPUT_FLAGS.main_btn_flag.active()) - // && app.should_wake() - { - break; + // todo enter deepsleep + system_state = SystemState::DeepSleep; + // TODO: fix polarity + interfaces.led0.set_amplitude(0); + interfaces.led1.set_amplitude(0); + interfaces.service(); + } + + if adc1_timer.need_service() { + let val = adc.convert(&mut batt_monitor_pin, hal::adc::SampleTime::CYCLES241); + let val = adc.convert(&mut usb_detect_pin, hal::adc::SampleTime::CYCLES241); + #[cfg(feature = "enable_print")] + println!("ADC value: {}", val); + + adc1_timer.reset(); + adc1_timer.enable(true); } } + + match system_state { + SystemState::DeepSleep => { + // TODO: make this REALLY deep sleep + unsafe { system::enter_standby() }; + loop { + riscv::asm::wfi(); + let mut config = hal::Config::default(); + config.rcc = hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSI; + unsafe { + hal::rcc::init(config.rcc); + } + unsafe { + if INPUT_FLAGS.sense_coin_flag { + system_state = SystemState::Active; + break; + } + }; + } + } + SystemState::Idle => {} + SystemState::Active => { + tt0.tick(); + tt1.tick(); + + if tt0.need_service() { + interfaces.led0.set_amplitude(led0_dcs[led0_index]); + led0_index += 1; + if led0_index > led0_dcs.len() - 1 { + led0_index = 0; + } + tt0.service(); + } + + if tt1.need_service() { + interfaces.led1.set_amplitude(led1_dcs[led1_index]); + led1_index += 1; + if led1_index > led1_dcs.len() - 1 { + led1_index = 0; + } + tt1.service() + } + + interfaces.service(); + } + } + + delay.delay_us(tick_interval_us as u32); } } @@ -619,26 +803,12 @@ fn main() -> ! { let mut p = hal::init(config); // delay to let the debugger attach - // println!("pre"); + println!("pre"); riscv::asm::delay(20_000_000); - // println!("post"); - // debug_main(p); + println!("post"); + debug_main(p); - let mut app_settings = Settings::default(); - - loop { - unsafe { - hal::rcc::init(hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSI); - } - let mut p = unsafe { hal::Peripherals::steal() }; - app_settings = app_main(p, app_settings); - - unsafe { - hal::rcc::init(hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSI); - } - let mut p = unsafe { hal::Peripherals::steal() }; - shutdown_main(p); - } + // app_main(p, delay); } #[panic_handler] diff --git a/ch32v-insert-coin/src/sequences.rs b/ch32v-insert-coin/src/sequences.rs deleted file mode 100644 index 4cf6e4c..0000000 --- a/ch32v-insert-coin/src/sequences.rs +++ /dev/null @@ -1,346 +0,0 @@ -use crate::app::sequencer::SequenceEntry; - -pub static TEST_SEQ: [SequenceEntry; 2] = [ - SequenceEntry { - frequency_hz: 440, - duration_ms: 1000, - }, - SequenceEntry { - frequency_hz: 220, - duration_ms: 1000, - }, -]; - -pub static TEST_SEQ1: [SequenceEntry; 2] = [ - SequenceEntry { - frequency_hz: 440, - duration_ms: 100, - }, - SequenceEntry { - frequency_hz: 220, - duration_ms: 100, - }, -]; - -// play twice -pub static WAHWAH: [SequenceEntry; 9] = [ - SequenceEntry { - frequency_hz: 100, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 200, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 300, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 400, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 500, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 600, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 700, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 800, - duration_ms: 25, - }, - SequenceEntry { - frequency_hz: 900, - duration_ms: 25, - }, -]; - -pub static DECENDING_TONES: [SequenceEntry; 21] = [ - SequenceEntry { - frequency_hz: 1100, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1050, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1000, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 950, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 900, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 850, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 800, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 750, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 700, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 650, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 600, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 550, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 500, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 450, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 400, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 350, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 300, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 250, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 200, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 150, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 100, - duration_ms: 50, - }, -]; - -// PLAY ONCE -pub static COIN_CHIRP: [SequenceEntry; 2] = [ - SequenceEntry { - frequency_hz: 1000, - duration_ms: 100, - }, - SequenceEntry { - frequency_hz: 1500, - duration_ms: 500, - }, -]; - -// PLAY ONCE -pub static SOUND_8_BIT_GAME_4: [SequenceEntry; 4] = [ - SequenceEntry { - frequency_hz: 220, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 440, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 660, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 880, - duration_ms: 50, - }, -]; - -// PLAY TWICE -// TODO: this isn't working quite right with the 0hz "non note" for a rest... -pub static SOUND_8_BIT_GAME_1: [SequenceEntry; 3] = [ - SequenceEntry { - frequency_hz: 440, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1500, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 0, - duration_ms: 50, - }, -]; - -// PLAY 3 TIMES -pub static SOUND_8_BIT_GAME_3: [SequenceEntry; 3] = [ - SequenceEntry { - frequency_hz: 440, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 660, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1000, - duration_ms: 50, - }, -]; - -// PLAY 1 TIMES -pub static ASCENDING_TONES: [SequenceEntry; 29] = [ - SequenceEntry { - frequency_hz: 100, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 150, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 200, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 250, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 300, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 350, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 400, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 450, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 500, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 550, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 600, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 650, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 700, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 750, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 800, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 850, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 900, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 950, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1000, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1050, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1100, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1150, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1200, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1250, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1300, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1350, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1400, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1450, - duration_ms: 50, - }, - SequenceEntry { - frequency_hz: 1500, - duration_ms: 1000, - }, -]; - -pub static SEQUENCE_LIST: [(&'static [SequenceEntry], usize); 7] = [ - (&SOUND_8_BIT_GAME_3, 2), - (&SOUND_8_BIT_GAME_4, 0), - (&ASCENDING_TONES, 0), - (&COIN_CHIRP, 0), - (&WAHWAH, 5), - (&DECENDING_TONES, 0), - (&SOUND_8_BIT_GAME_1, 1), - // &TEST_SEQ, -]; diff --git a/ch32v-insert-coin/src/synthesizer.rs b/ch32v-insert-coin/src/synthesizer.rs index 810336e..ad265c1 100644 --- a/ch32v-insert-coin/src/synthesizer.rs +++ b/ch32v-insert-coin/src/synthesizer.rs @@ -9,58 +9,48 @@ const SQUARE_WAVETABLE: [u8; 2] = [0, 100]; // 100, 100, 100, 100, 100, 100, 100, // ]; -pub struct SynthesizerService { - pub synth: SimpleWavetableSynthesizer>, - pub enabled: bool, - pub need_service: bool, +pub struct AppSynthesizers<'a, T: GeneralInstance16bit> { + pub square: SimpleWavetableSynthesizer>, + output: SimplePwmCore<'a, T>, } -impl SynthesizerService { - pub fn new(clock_freq_hz: usize) -> Self { +impl<'a, T: GeneralInstance16bit> AppSynthesizers<'a, T> { + pub fn new(clock_freq_hz: usize, output: SimplePwmCore<'a, T>) -> Self { let square_wt = SimpleWavetable::new(&SQUARE_WAVETABLE); - let synth = SimpleWavetableSynthesizer::new(square_wt, clock_freq_hz); + let square = SimpleWavetableSynthesizer::new(square_wt, clock_freq_hz); - Self { - synth, - enabled: true, - need_service: false, - } + Self { square, output } } pub fn tick(&mut self) { - if self.enabled { - self.synth.tick(); + self.square.tick(); + if self.square.has_new_output() { + let out = self.square.get_output(); + // println!("OUTPUT: {out}"); + + // println!("new out"); + self.output.write_amplitude( + ch32_hal::timer::Channel::Ch4, + out / 2, + // (out as f32 * (u8::MAX as f32 / u32::MAX as f32)) as u8, + ); } + + // println!("{}{}", self.square.counter, self.square.has_new_output()); } - pub fn need_service(&self) -> bool { - self.need_service || (self.enabled && self.synth.has_new_output()) - } + pub fn service(&mut self) { + // println!("HERE"); + if self.square.has_new_output() { + let out = self.square.get_output(); + // println!("OUTPUT: {out}"); - pub fn service(&mut self) -> Option { - self.need_service = false; - if self.enabled { - Some(self.synth.get_output()) - } else { - None + // println!("new out"); + self.output.write_amplitude( + ch32_hal::timer::Channel::Ch4, + out / 2, + // (out as f32 * (u8::MAX as f32 / u32::MAX as f32)) as u8, + ); } } } - -impl SynthesizerService { - pub fn set_freq(&mut self, freq_hz: usize) { - self.synth.set_freq(freq_hz); - } - - pub fn enable(&mut self) { - self.enabled = true; - self.need_service = true; - // TODO: write the enable function - } - - pub fn disable(&mut self) { - self.enabled = false; - self.need_service = true; - // TODO: write the disable function - } -} diff --git a/ch32v-insert-coin/src/system.rs b/ch32v-insert-coin/src/system.rs index 484d513..0ee18a6 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) -> [bool; 2] { - let mut output = [false, false]; +pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> crate::InputFlags { + let mut input_flags = crate::InputFlags::default(); let exti = &hal::pac::EXTI; @@ -35,23 +35,53 @@ pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> [bool; 2] { // 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!"); - output[0] = true; + input_flags.sense_coin_flag = true; } // button_flag if (bits & (0x1 << button_pin)) != 0x0 { #[cfg(feature = "enable_print")] println!("main_btn irq!"); - output[1] = true; + 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}"); + // // } + // } } + // 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); @@ -64,7 +94,7 @@ pub fn clear_interrupt(coin_pin: u8, button_pin: u8) -> [bool; 2] { exti.intenr().modify(|w| w.set_mr(coin_pin, true)); // enable interrupt exti.intenr().modify(|w| w.set_mr(button_pin, true)); // enable interrupt - output + input_flags } /// enter standby (SLEEPDEEP) mode, with WFE enabled.