diff --git a/ch32v-insert-coin/audio/coin.raw b/ch32v-insert-coin/audio/coin.raw new file mode 100644 index 0000000..2a0af56 Binary files /dev/null and b/ch32v-insert-coin/audio/coin.raw differ diff --git a/ch32v-insert-coin/audio/coin8ksps.raw b/ch32v-insert-coin/audio/coin8ksps.raw new file mode 100644 index 0000000..72caab0 Binary files /dev/null and b/ch32v-insert-coin/audio/coin8ksps.raw differ diff --git a/ch32v-insert-coin/audio/coinMixTest1_dpcm_u4.raw b/ch32v-insert-coin/audio/coinMixTest1_dpcm_u4.raw new file mode 100644 index 0000000..36cc103 Binary files /dev/null and b/ch32v-insert-coin/audio/coinMixTest1_dpcm_u4.raw 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/riscv32ec-unknown-none-elf.json b/ch32v-insert-coin/riscv32ec-unknown-none-elf.json index e394eb4..b2022a5 100644 --- a/ch32v-insert-coin/riscv32ec-unknown-none-elf.json +++ b/ch32v-insert-coin/riscv32ec-unknown-none-elf.json @@ -14,5 +14,5 @@ "max-atomic-width": 32, "panic-strategy": "abort", "relocation-model": "static", - "target-pointer-width": "32" -} \ No newline at end of file + "target-pointer-width": 32 +} diff --git a/ch32v-insert-coin/src/insert_coin/insert_coin.rs b/ch32v-insert-coin/src/insert_coin/insert_coin.rs index 3d0dacb..90d98c2 100644 --- a/ch32v-insert-coin/src/insert_coin/insert_coin.rs +++ b/ch32v-insert-coin/src/insert_coin/insert_coin.rs @@ -184,4 +184,4 @@ impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> { pub fn set_active(&mut self, active: bool) { self.core.active = active; } -} \ No newline at end of file +} diff --git a/ch32v-insert-coin/src/main.rs b/ch32v-insert-coin/src/main.rs index 81d8d09..a50cda8 100644 --- a/ch32v-insert-coin/src/main.rs +++ b/ch32v-insert-coin/src/main.rs @@ -5,11 +5,10 @@ mod insert_coin; use ch32_hal::{adc::AdcChannel, interrupt::typelevel::Handler, timer::low_level::OutputPolarity}; -use insert_coin::{InsertCoin, SimplePwmCore, CoreConfig}; +use insert_coin::{CoreConfig, InsertCoin, SimplePwmCore}; - -use {ch32_hal as hal}; -use hal::{bind_interrupts}; +use ch32_hal as hal; +use hal::bind_interrupts; use hal::delay::Delay; use hal::gpio::{AnyPin, Input, Pin, Pull}; use hal::time::Hertz; @@ -20,7 +19,6 @@ use hal::println; use qingke::riscv; - struct DebouncedGPIO<'a> { input: Input<'a>, // value of the GPIO @@ -28,7 +26,7 @@ struct DebouncedGPIO<'a> { // GPIO is ready (debounced) ready: bool, // debounce timer - timer: TickTimerService, + timer: TickTimerService, } impl<'a> DebouncedGPIO<'a> { @@ -38,7 +36,10 @@ impl<'a> DebouncedGPIO<'a> { input: Input::new(pin, Pull::Up), value: false, ready: false, - timer: TickTimerService::new(TickServiceData::new(system_tick_rate_hz * debounce_time_ms / 1000), false), + timer: TickTimerService::new( + TickServiceData::new(system_tick_rate_hz * debounce_time_ms / 1000), + false, + ), } } @@ -70,10 +71,9 @@ impl<'a> DebouncedGPIO<'a> { } } - // DeepSleep --coin button irq--> Active -// Active --2s button--> Idle -// Idle/Active --5s button--> DeepSleep +// Active --2s button--> Idle +// Idle/Active --5s button--> DeepSleep pub enum SystemState { // system is asleep, waiting for wake from coin insertion @@ -84,7 +84,7 @@ pub enum SystemState { Active, } -/// enter standby (SLEEPDEEP) mode, with WFE enabled. +/// enter standby (SLEEPDEEP) mode, with WFE enabled. /// from CH32V003 reference manual 2.3.1: /// entry: /// 1. configure core register control bit: SLEEPDEEP=1 | PDDS = 1 @@ -95,7 +95,6 @@ pub enum SystemState { /// 1. any interrupt/event (set in external interrupt register) unsafe fn enter_standby(pin: usize) { critical_section::with(|_| { - use hal::pac::Interrupt; use qingke_rt::CoreInterrupt; @@ -122,7 +121,6 @@ unsafe fn enter_standby(pin: usize) { // let bits = 0xFFFFFFFF; // exti.intfr().write(|w| w.0 = bits); - // // enable all exti interrupts // let exti = &hal::pac::EXTI; @@ -133,14 +131,13 @@ unsafe fn enter_standby(pin: usize) { // }); unsafe { - // qingke::pfic::disable_interrupt(Interrupt::EXTI7_0 as u8); + // qingke::pfic::disable_interrupt(Interrupt::EXTI7_0 as u8); // qingke::pfic::disable_interrupt(CoreInterrupt::SysTick as u8); // qingke::pfic::disable_interrupt(CoreInterrupt::SysTick as u8); qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8); - } + } - - // execute WFI + // execute WFI println!("WFI CONFIGURED HOPEFULLY"); // core::arch::asm!("wfi"); @@ -148,29 +145,27 @@ unsafe fn enter_standby(pin: usize) { // pfic. // qingke::pfic:: }); - } unsafe fn init_gpio_irq(pin: u8, port: u8, rising: bool, falling: bool) { critical_section::with(|_| { - println!("init_gpio_irq"); - let exti = &hal::pac::EXTI; - let afio = &hal::pac::AFIO; + println!("init_gpio_irq"); + let exti = &hal::pac::EXTI; + let afio = &hal::pac::AFIO; - let port = port as u8; - let pin = pin as usize; + let port = port as u8; + let pin = pin as usize; - // let b = afio.exticr().read(); - afio.exticr().modify(|w| w.set_exti(pin, port)); + // let b = afio.exticr().read(); + afio.exticr().modify(|w| w.set_exti(pin, port)); - exti.intenr().modify(|w| w.set_mr(pin, true)); // enable interrupt - exti.rtenr().modify(|w| w.set_tr(pin, rising)); - exti.ftenr().modify(|w| w.set_tr(pin, falling)); + exti.intenr().modify(|w| w.set_mr(pin, true)); // enable interrupt + exti.rtenr().modify(|w| w.set_tr(pin, rising)); + exti.ftenr().modify(|w| w.set_tr(pin, falling)); }); } - -fn clear_interrupt (coin_pin: u8, button_pin: u8) { +fn clear_interrupt(coin_pin: u8, button_pin: u8) { let exti = &hal::pac::EXTI; let coin_pin = coin_pin as usize; @@ -179,7 +174,6 @@ fn clear_interrupt (coin_pin: u8, button_pin: u8) { exti.intenr().modify(|w| w.set_mr(coin_pin, false)); // disable interrupt exti.intenr().modify(|w| w.set_mr(button_pin, false)); // disable interrupt - let bits = exti.intfr().read(); // We don't handle or change any EXTI lines above 24. @@ -188,40 +182,44 @@ fn clear_interrupt (coin_pin: u8, button_pin: u8) { // coin_flag if (bits & (0x1 << coin_pin)) != 0x0 { println!("coin irq!"); - unsafe { INPUT_FLAGS.coin_flag = true; } + unsafe { + INPUT_FLAGS.coin_flag = true; + } } - // button_flag if (bits & (0x1 << button_pin)) != 0x0 { println!("button irq!"); - unsafe { INPUT_FLAGS.button_flag = true; } + unsafe { + INPUT_FLAGS.button_flag = true; + } } - // Clear pending - Clears the EXTI's line pending bits. exti.intfr().write(|w| w.0 = bits); use hal::pac::Interrupt; - unsafe { qingke::pfic::unpend_interrupt(Interrupt::EXTI7_0 as u8); }; - + unsafe { + qingke::pfic::unpend_interrupt(Interrupt::EXTI7_0 as u8); + }; // exti.intenr().modify(|w| w.0 = w.0 & !bits); exti.intenr().modify(|w| w.set_mr(coin_pin, true)); // enable interrupt exti.intenr().modify(|w| w.set_mr(button_pin, true)); // enable interrupt } - #[derive(Debug)] struct InputFlags { coin_flag: bool, button_flag: bool, } -static mut INPUT_FLAGS: InputFlags = InputFlags{coin_flag: false, button_flag: false}; +static mut INPUT_FLAGS: InputFlags = InputFlags { + coin_flag: false, + button_flag: false, +}; -struct Test { -} +struct Test {} impl Handler for Test { unsafe fn on_interrupt() { println!("on_interrupt()"); @@ -235,11 +233,9 @@ bind_interrupts!(struct Irqs { EXTI7_0 => Test; }); - - // TODO: remove -use insert_coin::{TickService, TickServiceData}; use insert_coin::TickTimerService; +use insert_coin::{TickService, TickServiceData}; #[qingke_rt::entry] fn main() -> ! { @@ -252,7 +248,6 @@ fn main() -> ! { let mut delay = Delay; delay.delay_ms(1000); - // === output setup === // LED0 output setup @@ -267,15 +262,12 @@ fn main() -> ! { let 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 timer setup let mut pwm = SimplePwm::new( p.TIM1, @@ -296,7 +288,6 @@ fn main() -> ! { let core_config = CoreConfig::new(tick_rate_hz); - // === input setup === // adc @@ -307,29 +298,32 @@ fn main() -> ! { let adc_cal = adc.calibrate(); println!("ADC calibration value: {}", adc_cal); - - // definitions let coin_pin = p.PC2; let button_pin = p.PD6; - println!("coin pin: {} | coin port: {}", coin_pin.pin(), coin_pin.port()); - println!("push pin: {} | push port: {}", button_pin.pin(), button_pin.port()); + // println!( + // "coin pin: {} | coin port: {}", + // coin_pin.pin(), + // coin_pin.port() + // ); + // println!( + // "push pin: {} | push port: {}", + // button_pin.pin(), + // button_pin.port() + // ); //2025-09-10 00:32:23.514: coin pin: 4 | coin port: 3 // 2025-09-10 00:32:23.515: push pin: 6 | push port: 3 - // set up interrupts - unsafe {init_gpio_irq(coin_pin.pin(), coin_pin.port(), false, true)}; - unsafe {init_gpio_irq(button_pin.pin(), button_pin.port(), true, true)}; + unsafe { init_gpio_irq(coin_pin.pin(), coin_pin.port(), false, true) }; + unsafe { init_gpio_irq(button_pin.pin(), button_pin.port(), true, true) }; // coin debouncer (100ms) let mut coin_input = DebouncedGPIO::new(coin_pin.degrade(), core_config.tick_rate_hz, 100); // button debouncer (100ms) let mut button_input = DebouncedGPIO::new(button_pin.degrade(), core_config.tick_rate_hz, 100); - - let pwm_core = SimplePwmCore::new(pwm); let mut interfaces = InsertCoin::new(core_config, pwm_core); @@ -341,65 +335,60 @@ fn main() -> ! { 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_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_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 + // 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 + // 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 + // 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; + let tick_interval_us = 1000000 / interfaces.config.tick_rate_hz - 10; // dac data - let coin_sound = include_bytes!("../audio/sweep_dpcm_u4.raw"); - let button_sound = include_bytes!("../audio/sweep_dpcm_u4.raw"); + let coin_sound = include_bytes!("../audio/coin.raw"); + // let button_sound = include_bytes!("../audio/coinMixTest1_dpcm_u4.raw"); let mut system_state = SystemState::Active; interfaces.led0.set_amplitude(0); interfaces.led1.set_amplitude(0); interfaces.service(); - + unsafe { use hal::pac::Interrupt; // use qingke_rt::CoreInterrupt; - // qingke::pfic::unpend_interrupt(Interrupt::EXTI7_0 as u8); clear_interrupt(4, 6); - qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8); - // qingke::pfic::enable_interrupt(CoreInterrupt::SysTick as u8); + qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8); + // qingke::pfic::enable_interrupt(CoreInterrupt::SysTick as u8); } - // MAIN APPLICATION // process // -depress big button (insert coin button) and it wakes up and turns on led one led at a fixed brightness @@ -424,7 +413,6 @@ fn main() -> ! { tt0.enable(true); tt1.enable(true); interfaces.dac.load_data(coin_sound); - } if INPUT_FLAGS.button_flag { println!("button flag active"); @@ -434,35 +422,30 @@ fn main() -> ! { } // debouncer - coin_input.service(); + coin_input.service(); button_input.service(); - if coin_input.ready() { println!("debounced coin_input value: {}", coin_input.value()); coin_input.reset(); - } if button_input.ready() { - let value = button_input.value(); button_input.reset(); println!("debounced button_input value: {}", value); - + if !value { - interfaces.dac.load_data(button_sound); - + // interfaces.dac.load_data(button_sound); + println!("reset hold timers + enable"); sp_timer.reset(); sp_timer.enable(true); lp_timer.reset(); lp_timer.enable(true); - } - else { + } else { sp_timer.reset(); lp_timer.reset(); } - } // timers @@ -486,7 +469,7 @@ fn main() -> ! { println!("lp detect!"); lp_timer.reset(); - // todo enter deepsleep + // todo enter deepsleep system_state = SystemState::DeepSleep; // TODO: fix polarity interfaces.led0.set_amplitude(0); @@ -500,27 +483,23 @@ fn main() -> ! { adc1_timer.reset(); adc1_timer.enable(true); - - } } match system_state { SystemState::DeepSleep => { - // TODO: make this REALLY deep sleep - unsafe{enter_standby(4)}; - loop { - riscv::asm::wfi(); - unsafe{ - if INPUT_FLAGS.coin_flag { - break; - } - }; - } - }, - SystemState::Idle => { - - }, + // TODO: make this REALLY deep sleep + unsafe { enter_standby(4) }; + loop { + riscv::asm::wfi(); + unsafe { + if INPUT_FLAGS.coin_flag { + break; + } + }; + } + } + SystemState::Idle => {} SystemState::Active => { tt0.tick(); tt1.tick(); @@ -544,16 +523,14 @@ fn main() -> ! { } interfaces.service(); - }, + } } delay.delay_us(tick_interval_us as u32); } } - #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } -