From 51af5c334337d4a59221a9d86a545fa8ec789f4d Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Sat, 16 Aug 2025 17:03:29 -0600 Subject: [PATCH] move to modular servicer design --- ch32v-insert-coin/.cargo/config.toml | 4 +- ch32v-insert-coin/ext/adpcm-pwm-dac | 2 +- .../src/insert_coin/insert_coin.rs | 165 +++++++++++++ ch32v-insert-coin/src/insert_coin/mod.rs | 5 + .../src/insert_coin/services/dac.rs | 51 ++++ .../src/insert_coin/services/led.rs | 42 ++++ .../src/insert_coin/services/mod.rs | 8 + .../src/insert_coin/services/services.rs | 25 ++ ch32v-insert-coin/src/main.rs | 223 ++++++------------ 9 files changed, 371 insertions(+), 154 deletions(-) create mode 100644 ch32v-insert-coin/src/insert_coin/insert_coin.rs create mode 100644 ch32v-insert-coin/src/insert_coin/mod.rs create mode 100644 ch32v-insert-coin/src/insert_coin/services/dac.rs create mode 100644 ch32v-insert-coin/src/insert_coin/services/led.rs create mode 100644 ch32v-insert-coin/src/insert_coin/services/mod.rs create mode 100644 ch32v-insert-coin/src/insert_coin/services/services.rs diff --git a/ch32v-insert-coin/.cargo/config.toml b/ch32v-insert-coin/.cargo/config.toml index 57920f5..cf4d2cd 100644 --- a/ch32v-insert-coin/.cargo/config.toml +++ b/ch32v-insert-coin/.cargo/config.toml @@ -6,12 +6,12 @@ target = "riscv32ec-unknown-none-elf.json" # runner = "riscv64-elf-gdb -q -x openocd.gdb" # runner = "riscv-none-embed-gdb -q -x openocd.gdb" # runner = "gdb -q -x openocd.gdb" -# runner = "wlink -v flash" +runner = "wlink -v flash" # runner = "wlink -v flash --enable-sdi-print --watch-serial" # Flash and debug chip with probe-rs. https://probe.rs/ -runner = "probe-rs run --chip ch32v003" +# runner = "probe-rs run --chip ch32v003" [unstable] build-std = ["core"] diff --git a/ch32v-insert-coin/ext/adpcm-pwm-dac b/ch32v-insert-coin/ext/adpcm-pwm-dac index 714715b..c8d33b3 160000 --- a/ch32v-insert-coin/ext/adpcm-pwm-dac +++ b/ch32v-insert-coin/ext/adpcm-pwm-dac @@ -1 +1 @@ -Subproject commit 714715b4aae512d1384b7387e3d2f695ea9b348e +Subproject commit c8d33b3c41bf4b53ff76837a9557f7960f508df5 diff --git a/ch32v-insert-coin/src/insert_coin/insert_coin.rs b/ch32v-insert-coin/src/insert_coin/insert_coin.rs new file mode 100644 index 0000000..b67200d --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/insert_coin.rs @@ -0,0 +1,165 @@ +use adpcm_pwm_dac::dac; +use ch32_hal::timer::GeneralInstance16bit; +use ch32_hal::timer::simple_pwm::SimplePwm; +use ch32_hal::timer::Channel; +use ch32_hal::delay::Delay; + +use crate::insert_coin::services::{DacService, LedService, Service, ServiceData}; + + +pub struct SimplePwmCore<'d, T: GeneralInstance16bit> { + pwm: core::cell::RefCell>, +} + +impl<'d, T: GeneralInstance16bit> SimplePwmCore<'d, T> { + pub fn new(pwm: SimplePwm<'d, T>) -> Self { + Self { + pwm: core::cell::RefCell::new(pwm), + } + } + + // pub fn get_handle(&'d self, ch: Channel) -> SimplePwmHandle<'d, '_, T> { + // SimplePwmHandle { + // core: &self, + // channel: ch, + // } + // } + + pub fn write_amplitude(&self, ch: Channel, amplitude: u8) { + if !self.pwm.borrow().is_enabled(ch) { + self.pwm.borrow_mut().enable(ch); + } + let max_duty = self.pwm.borrow().get_max_duty(); + let dc = amplitude as u32 * max_duty / 100; + self.pwm.borrow_mut().set_duty(ch, dc); + } + + pub fn disable(&self, ch: Channel) { + self.pwm.borrow_mut().disable(ch); + } +} + + + + +pub struct CoreConfig { + tick_rate_hz: usize, +} +impl CoreConfig { + pub fn new(tick_rate_hz: usize) -> Self { + Self { + tick_rate_hz, + } + } +} + +#[derive(Default)] +struct Core { + tick: usize, +} + +pub struct InsertCoin<'a, T: GeneralInstance16bit> { + core: Core, + config: CoreConfig, + pwm_core: SimplePwmCore<'a, T>, + led0: LedService, + led1: LedService, + // led2: LedService, + + dac: DacService<'a>, +} + +impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> { + + pub fn new(config: CoreConfig, pwm_core: SimplePwmCore<'a, T>) -> Self { + + + // LED0 servicer setup + let led0_blink_rate_hz = 9; + let led0_tick_per_service = (config.tick_rate_hz/(led0_blink_rate_hz * 2)); + let led0_service_data = ServiceData::new(led0_tick_per_service); + let led0 = LedService::new(ch32_hal::timer::Channel::Ch3, led0_service_data); + + // LED1 servicer setup + let led1_blink_rate_hz = 3; + let led1_tick_per_service = (config.tick_rate_hz/(led1_blink_rate_hz * 2)); + let led1_service_data = ServiceData::new(led1_tick_per_service); + let led1 = LedService::new(ch32_hal::timer::Channel::Ch1, led1_service_data); + + + // DAC servicer setup + let dac_sample_rate_hz = 16000; + let dac_tick_per_service = (config.tick_rate_hz/(dac_sample_rate_hz)); + let dac_service_data = ServiceData::new(dac_tick_per_service); + let dac = DacService::new(ch32_hal::timer::Channel::Ch4, dac_service_data); + let data = include_bytes!("../../../../dpcm-encoder-decoder/sweep_dpcm_u4.raw"); + dac.load_data(data); + + Self { + config, + core: Default::default(), + pwm_core, + led0, + led1, + // led2, + dac, + // led1: Led { + // channel: hal::timer::Channel::Ch1, + // amplitude: 0, + // need_service: false, + // }, + } + } + + /// consumes self and runs + pub fn run(mut self) -> ! { + let mut delay = Delay; + let tick_interval_us = 1000000/self.config.tick_rate_hz; + + + let mut led0_index = 0; + let led0_dcs = [0u8, 25u8, 50u8, 75u8, 100u8, 75u8, 50u8, 25u8]; + + let mut led1_index = 0; + let led1_dcs = [0u8, 25u8, 50u8, 75u8, 100u8]; + + loop { + self.led0.tick(); + self.led1.tick(); + self.dac.tick(); + + + if(self.led0.need_service()) { + self.led0.set_amplitude(led0_dcs[led0_index]); + self.pwm_core.write_amplitude(self.led0.channel, self.led0.amplitude); + + led0_index += 1; + if led0_index > led0_dcs.len() - 1 { + led0_index = 0; + } + self.led0.service(); + } + + if(self.led1.need_service()) { + self.led1.set_amplitude(led1_dcs[led1_index]); + self.pwm_core.write_amplitude(self.led1.channel, self.led1.amplitude); + + led1_index += 1; + if led1_index > led1_dcs.len() - 1 { + led1_index = 0; + } + self.led1.service(); + } + + if(self.dac.need_service()) { + self.dac.service(); + // TODO: adpcm-pwm-dac:e4c811653781e69e40b63fd27a8c1e20 + self.pwm_core.write_amplitude(self.dac.channel, self.dac.get_amplitude() as u8); + } + + + + delay.delay_us(tick_interval_us as u32); + } + } +} \ No newline at end of file diff --git a/ch32v-insert-coin/src/insert_coin/mod.rs b/ch32v-insert-coin/src/insert_coin/mod.rs new file mode 100644 index 0000000..a4bc002 --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/mod.rs @@ -0,0 +1,5 @@ +mod insert_coin; +mod services; +use services::LedService; + +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 new file mode 100644 index 0000000..ec2ee85 --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/services/dac.rs @@ -0,0 +1,51 @@ +use crate::insert_coin::services::{ServiceData, Service}; + + +use adpcm_pwm_dac::{dac::{DpcmDac, DpcmDecoder}, interface::DacInterface}; +use ch32_hal::timer::Channel; + +pub struct DacService<'a> { + service_data: core::cell::RefCell, + dpcm_decoder: core::cell::RefCell>, + amplitude: core::cell::RefCell, + pub channel: Channel, +} + +impl<'a> DacService<'a> { + pub fn new(channel: Channel, service_data: ServiceData) -> Self { + Self { + service_data: core::cell::RefCell::new(service_data), + dpcm_decoder: core::cell::RefCell::new(DpcmDecoder::new()), + amplitude: core::cell::RefCell::new(0), + channel, + } + } + + pub fn load_data(&self, data: &'a [u8]) { + self.dpcm_decoder.borrow_mut().load_data(data); + } + + pub fn set_amplitude(&self, amplitude: usize) { + self.amplitude.replace(amplitude); + } + pub fn get_amplitude(&self) -> usize { + *self.amplitude.borrow() + } +} + +impl<'a> Service for DacService<'a> { + fn tick(&self) { + let mut tc = self.service_data.borrow_mut(); + tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1); + } + + fn need_service(&self) -> bool { + 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; + 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 new file mode 100644 index 0000000..f63934b --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/services/led.rs @@ -0,0 +1,42 @@ +use ch32_hal::timer::Channel; + +use crate::insert_coin::services::{ServiceData, Service}; + +pub struct LedService { + service_data: core::cell::RefCell, + pub channel: Channel, + pub amplitude: u8, +} + +impl LedService { + pub fn new(channel: Channel, service_data: ServiceData) -> Self { + Self { + service_data: core::cell::RefCell::new(service_data), + channel, + amplitude: 0, + } + } + + pub fn set_amplitude(&mut self, amplitude: u8) { + self.amplitude = amplitude; + } +} + + +impl Service for LedService { + fn tick(&self) { + let mut tc = self.service_data.borrow_mut(); + tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1); + } + + fn need_service(&self) -> bool { + 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; + } +} + + diff --git a/ch32v-insert-coin/src/insert_coin/services/mod.rs b/ch32v-insert-coin/src/insert_coin/services/mod.rs new file mode 100644 index 0000000..ba70192 --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/services/mod.rs @@ -0,0 +1,8 @@ +mod services; +pub use services::{Service, ServiceData}; + +mod led; +pub use led::LedService; + +mod dac; +pub use dac::DacService; \ No newline at end of file diff --git a/ch32v-insert-coin/src/insert_coin/services/services.rs b/ch32v-insert-coin/src/insert_coin/services/services.rs new file mode 100644 index 0000000..002edca --- /dev/null +++ b/ch32v-insert-coin/src/insert_coin/services/services.rs @@ -0,0 +1,25 @@ +pub struct ServiceData { + pub ticks_per_service: usize, + pub ticks_remaining: usize, +} + +impl ServiceData { + pub fn new(ticks_per_service: usize) -> Self { + Self { + ticks_per_service, + ticks_remaining: 0, + } + } +} + +pub trait Service { + /// indicate to the service that a tick has occurred + fn tick(&self); + + /// return true if service needs the service() routine run + fn need_service(&self) -> bool; + + /// service routine - handle what needs to be done (non blocking) when + /// the service needs to be serviced here + fn service(&self); +} diff --git a/ch32v-insert-coin/src/main.rs b/ch32v-insert-coin/src/main.rs index 5d05bcc..a2131af 100644 --- a/ch32v-insert-coin/src/main.rs +++ b/ch32v-insert-coin/src/main.rs @@ -3,6 +3,10 @@ #![feature(type_alias_impl_trait)] #![feature(impl_trait_in_assoc_type)] +mod insert_coin; +use insert_coin::{InsertCoin, SimplePwmCore, CoreConfig}; + + use adpcm_pwm_dac::dac::DpcmDac; use {ch32_hal as hal}; use hal::peripherals::EXTI4; @@ -14,6 +18,15 @@ use hal::timer::low_level::CountingMode; use hal::timer::simple_pwm::{PwmPin, SimplePwm}; use hal::timer::{Channel, GeneralInstance16bit}; +// #[qingke_rt::interrupt] +// fn EXTI4(){ +// unsafe{IRQ1_FLAG = true;}; +// } +// bind_interrupts!(struct Irqs { +// EXTI4 => button_press(); +// }); + + // const DAC_DATA: [u8; 4] = [0x0, 0x80, 0xFF, 0x80]; const DAC_DATA: [u8; 8] = [0, 25, 50, 75, 100, 75, 50, 25]; @@ -29,90 +42,47 @@ const DAC_DATA: [u8; 8] = [0, 25, 50, 75, 100, 75, 50, 25]; // - 25 -> 0xA const DPCM_DAC_DATA: [u8; 4] = [0xBB, 0xBB, 0xAA, 0xAA]; -// const DATA2: [u8; 1] = [0x00u8]; - - static mut IRQ1_FLAG: bool = false; -struct SimplePwmDacPin<'d, T: GeneralInstance16bit>{ - pin: SimplePwm<'d, T>, - ch: Channel, -} +// struct SimplePwmHandle<'a, 'c, T: GeneralInstance16bit>{ +// core: &'a SimplePwmCore<'c, T>, +// channel: Channel, +// } -use adpcm_pwm_dac::{interface::DacInterface, dac::Dac}; - -impl DacInterface for SimplePwmDacPin<'_, T> -where T: GeneralInstance16bit { - fn write_amplitude(&mut self, amplitude: u8) { - if !self.pin.is_enabled(self.ch) { - self.pin.enable(self.ch); - } - let max_duty = self.pin.get_max_duty(); - let dc = amplitude as u32 * max_duty / 100; - self.pin.set_duty(self.ch, dc); - } - - fn disable(&mut self) { - self.pin.disable(self.ch); - } -} - -fn blink(pin: AnyPin, interval_ms: u64) { - let mut led = Output::new(pin, Level::Low, Default::default()); - - let mut delay = Delay; - - loop { - let hb_count = 3; - let hb_period_ms = 1000; - for _ in 0..hb_count { - led.set_low(); - delay.delay_ms((interval_ms/2) as u32); - led.set_high(); - delay.delay_ms((interval_ms/2) as u32); - } - delay.delay_ms((hb_period_ms - (interval_ms * hb_count)) as u32); - } -} - -fn pwm_blink(mut pwm_dac_pin: SimplePwmDacPin<'_, T>) { - let mut delay = Delay; - - - - let interval_ms = 1000u32; - loop { - pwm_dac_pin.write_amplitude(75); - delay.delay_ms((interval_ms/2) as u32); - pwm_dac_pin.write_amplitude(50); - delay.delay_ms((interval_ms/2) as u32); - pwm_dac_pin.write_amplitude(25); - delay.delay_ms((interval_ms/2) as u32); - } -} - -// // fn dac_run(mut dac: Dac<'_, T>, sample_rate: usize) { -// fn dac_run(mut dac: DpcmDac<'_, T>, sample_rate: usize) { - - -// dac.load_data(data); -// // dac.load_data(&DAC_DATA); - -// let interval_us = 1000000/sample_rate as u32; -// loop { +// impl<'a, 'c, T: GeneralInstance16bit> SimplePwmHandle<'a, 'c, T> { +// pub fn write_amplitude(&'a self, amplitude: u8) { +// self.core.write_amplitude(self.channel, amplitude); +// } +// pub fn disable(&'a self) { +// self.core.disable(self.channel); // } // } +// struct SimplePwmDacHandle<'d, T: GeneralInstance16bit>{ +// pin: core::cell::RefCell>, +// ch: Channel, +// } -#[qingke_rt::interrupt] -fn EXTI4(){ - unsafe{IRQ1_FLAG = true;}; -} -// bind_interrupts!(struct Irqs { -// EXTI4 => button_press(); -// }); + +// use adpcm_pwm_dac::{interface::DacInterface, dac::Dac}; + +// impl DacInterface for SimplePwmDacHandle<'_, T> +// where T: GeneralInstance16bit { +// fn write_amplitude(&mut self, amplitude: u8) { +// if !self.pin.borrow().is_enabled(self.ch) { +// self.pin.get_mut().enable(self.ch); +// } +// let max_duty = self.pin.borrow().get_max_duty(); +// let dc = amplitude as u32 * max_duty / 100; +// self.pin.get_mut().set_duty(self.ch, dc); +// } + +// fn disable(&mut self) { +// self.pin.get_mut().disable(self.ch); +// } +// } #[qingke_rt::entry] fn main() -> ! { @@ -120,108 +90,59 @@ fn main() -> ! { config.rcc = hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSE; let p = hal::init(config); - // button 1 setup // let b1 = Input::new(p.PA2, Pull::Up); // p.EXTI4 // let ei = hal::exti::ExtiInput::new(p.PD4, p.EXTI4, Pull::Up); - // let led_pin = PwmPin::new_ch4::<0>(p.PD0); - // let ch = hal::timer::Channel::Ch4; - // let mut pwm = SimplePwm::new( - // p.TIM1, - // None, - // None, - // None, - // Some(pin), - // Hertz::khz(100), - // CountingMode::default(), - // ); - // pwm.enable(ch); - - // - // LED output setup - let mut led = Output::new(p.PD0, Level::Low, Default::default()); + // LED0 output setup + let mut led0_pin = PwmPin::new_ch3::<0>(p.PC3); + let led0_ch = hal::timer::Channel::Ch3; // LED1 output setup - let mut led1 = Output::new(p.PD6, Level::High, Default::default()); + let mut led1_pin = PwmPin::new_ch1::<0>(p.PD2); + let led1_ch = hal::timer::Channel::Ch1; + + + // LED2 output setup + + // DAC output setup + let dac_pin = PwmPin::new_ch4::<0>(p.PC4); + let dac_ch = hal::timer::Channel::Ch4; + - // PWM DAC output pin setup - let pin = PwmPin::new_ch4::<0>(p.PC4); - let ch = hal::timer::Channel::Ch4; + // PWM timer setup let mut pwm = SimplePwm::new( p.TIM1, + Some(led1_pin), None, - None, - None, - Some(pin), + Some(led0_pin), + Some(dac_pin), Hertz::khz(100), CountingMode::default(), ); - pwm.enable(ch); - let mut pwm_dac_pin = SimplePwmDacPin{pin: pwm, ch}; - - let mut delay = Delay; - - - - // DAC setup - let mut dac = DpcmDac::new(pwm_dac_pin); - let data = include_bytes!("../../../dpcm-encoder-decoder/sweep_dpcm_u4.raw"); - dac.load_data(data); - - - // DAC servicer computations - let mut dac_active = true; let sample_rate_hz = 16000; let dac_tick_per_service = 5; let tick_rate_hz = sample_rate_hz * dac_tick_per_service; - let tick_interval = 1000000/(tick_rate_hz); - // LED servicer computations - let mut led_active = true; - let led_blink_rate_hz = 3; - let led_tick_per_service = (tick_rate_hz/(led_blink_rate_hz * 2)); + let config = CoreConfig::new(tick_rate_hz); - // LED1 servicer vars - let mut led1_need_service = false; + let pwm_core = SimplePwmCore::new(pwm); + let app = InsertCoin::new(config, pwm_core); - // pwm_blink(pwm_dac_pin); - let mut tick: usize = 0; - loop{ - // handle IRQ flags - // unsafe { - // if(IRQ1_FLAG) { - // led1_need_service = true; - // // led_active = true; - // IRQ1_FLAG = false; - // } - // } + // insert_coin.init(); + + app.run(); - let dac_need_service = ((tick % dac_tick_per_service) == 0); - if(dac_need_service && dac_active) { - // dac_active = dac.output_next(); - dac.output_next(); - } - - let led_need_service = ((tick % led_tick_per_service) == 0); - if(led_need_service && led_active) { - led.toggle(); - } - - if led1_need_service { - led1.set_low(); - led1_need_service = false; - } - - tick = tick.wrapping_add(1); - delay.delay_us(tick_interval as u32); - }; + // // DAC servicer setup + // let mut pwm_dac_interface = SimplePwmDacHandle{pin: core::cell::RefCell::new(pwm), ch: dac_ch}; + // let mut dac = DpcmDac::new(pwm_dac_interface); + // let mut dac_active = true; }