add interrupts for most handlers
This commit is contained in:
parent
e3235b34a4
commit
a71c7986e6
15 changed files with 1028 additions and 280 deletions
5
.gitmodules
vendored
5
.gitmodules
vendored
|
|
@ -3,4 +3,7 @@
|
|||
url = ssh://git@git.glyphs.tech:222/sigil-03/adpcm-pwm-dac.git
|
||||
[submodule "ch32v-insert-coin/ext/ch32-hal"]
|
||||
path = ch32v-insert-coin/ext/ch32-hal
|
||||
url = git@github.com:ch32-rs/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 = git@github.com:ch32-rs/qingke.git
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ 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"
|
||||
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"
|
||||
|
|
|
|||
56
ch32v-insert-coin/Cargo.lock
generated
56
ch32v-insert-coin/Cargo.lock
generated
|
|
@ -18,27 +18,6 @@ version = "0.10.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitfields"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcdbce6688e3ab66aff2ab413b762ccde9f37990e27bba0bb38a4b2ad1b5d877"
|
||||
dependencies = [
|
||||
"bitfields-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitfields-impl"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57413e4b276d883b77fb368b7b33ae6a5eb97692852d49a5394d4f72ba961827"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
|
|
@ -71,7 +50,7 @@ dependencies = [
|
|||
"futures",
|
||||
"nb 1.1.0",
|
||||
"proc-macro2",
|
||||
"qingke",
|
||||
"qingke 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"qingke-rt",
|
||||
"quote",
|
||||
"rand_core",
|
||||
|
|
@ -92,11 +71,12 @@ name = "ch32v-insert-coin"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"adpcm-pwm-dac",
|
||||
"bitfields",
|
||||
"ch32-hal",
|
||||
"critical-section",
|
||||
"embassy-executor",
|
||||
"embedded-hal 1.0.0",
|
||||
"panic-halt",
|
||||
"qingke 0.5.0",
|
||||
"qingke-rt",
|
||||
]
|
||||
|
||||
|
|
@ -487,6 +467,14 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qingke"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"riscv 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qingke"
|
||||
version = "0.5.0"
|
||||
|
|
@ -504,7 +492,7 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b955c60adac70c6d40205b1dbe9f57e1151d06aa842069cdbaef7bc07ad283fd"
|
||||
dependencies = [
|
||||
"qingke",
|
||||
"qingke 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"qingke-rt-macros",
|
||||
]
|
||||
|
||||
|
|
@ -615,26 +603,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ embedded-hal = "1.0.0"
|
|||
|
||||
qingke-rt = { version = "*", features = ["highcode"] }
|
||||
|
||||
qingke = {path = "ext/qingke"}
|
||||
|
||||
adpcm-pwm-dac = { path = "ext/adpcm-pwm-dac/" }
|
||||
bitfields = "1.0.0"
|
||||
|
||||
critical-section = { version = "1.2.0" }
|
||||
|
||||
[profile.release]
|
||||
strip = false # symbols are not flashed to the microcontroller, so don't strip them.
|
||||
|
|
|
|||
BIN
ch32v-insert-coin/audio/sweep_dpcm_u4.raw
Normal file
BIN
ch32v-insert-coin/audio/sweep_dpcm_u4.raw
Normal file
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
Subproject commit ba25b7c89f4deb52426d97fd35eb13496f183775
|
||||
Subproject commit e4bb93e0399f27024434adf2558a893574fbfef3
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b8e1c864ba5545ee65b1c77dcb17c86a471b70c
|
||||
Subproject commit 412b9f5ee3a3708de8602d6103ec83c6dd436b63
|
||||
652
ch32v-insert-coin/ext/patches/optional-exti.patch
Normal file
652
ch32v-insert-coin/ext/patches/optional-exti.patch
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
From 7b086336e3820714c564aac13dc44fbaf7f5bc17 Mon Sep 17 00:00:00 2001
|
||||
From: mindshub <info@mindshub.com>
|
||||
Date: Sat, 9 Aug 2025 10:16:33 +0200
|
||||
Subject: [PATCH] optional exti
|
||||
|
||||
---
|
||||
Cargo.toml | 3 +-
|
||||
src/exti.rs | 548 ++++++++++++++++++++++++++--------------------------
|
||||
src/lib.rs | 1 +
|
||||
3 files changed, 281 insertions(+), 271 deletions(-)
|
||||
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index ec451bf..55fa288 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -56,7 +56,7 @@ proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
|
||||
[features]
|
||||
-default = ["embassy", "rt"]
|
||||
+default = ["embassy", "rt", "exti"]
|
||||
rt = ["dep:qingke-rt"]
|
||||
highcode = ["qingke-rt/highcode"]
|
||||
embassy = [
|
||||
@@ -66,6 +66,7 @@ embassy = [
|
||||
]
|
||||
defmt = ["dep:defmt"]
|
||||
memory-x = ["ch32-metapac/memory-x"]
|
||||
+exti = []
|
||||
|
||||
|
||||
# Features starting with `_` are for internal use only. They're not intended
|
||||
diff --git a/src/exti.rs b/src/exti.rs
|
||||
index a2458d1..3d613ea 100644
|
||||
--- a/src/exti.rs
|
||||
+++ b/src/exti.rs
|
||||
@@ -1,37 +1,11 @@
|
||||
-use core::future::Future;
|
||||
-use core::marker::PhantomData;
|
||||
-use core::pin::Pin;
|
||||
-use core::task::{Context, Poll};
|
||||
-
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
-use qingke_rt::interrupt;
|
||||
|
||||
-use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull};
|
||||
-use crate::{impl_peripheral, into_ref, peripherals, Peripheral};
|
||||
+use crate::{impl_peripheral, peripherals};
|
||||
|
||||
const EXTI_COUNT: usize = 24;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT];
|
||||
|
||||
-pub unsafe fn on_irq() {
|
||||
- let exti = &crate::pac::EXTI;
|
||||
-
|
||||
- let bits = exti.intfr().read();
|
||||
-
|
||||
- // We don't handle or change any EXTI lines above 24.
|
||||
- let bits = bits.0 & 0x00FFFFFF;
|
||||
-
|
||||
- // Clear pending - Clears the EXTI's line pending bits.
|
||||
- exti.intfr().write(|w| w.0 = bits);
|
||||
-
|
||||
- exti.intenr().modify(|w| w.0 = w.0 & !bits);
|
||||
-
|
||||
- // Wake the tasks
|
||||
- for pin in BitIter(bits) {
|
||||
- EXTI_WAKERS[pin as usize].wake();
|
||||
- }
|
||||
-}
|
||||
-
|
||||
struct BitIter(u32);
|
||||
|
||||
impl Iterator for BitIter {
|
||||
@@ -48,150 +22,6 @@ impl Iterator for BitIter {
|
||||
}
|
||||
}
|
||||
|
||||
-/// EXTI input driver
|
||||
-pub struct ExtiInput<'d> {
|
||||
- pin: Input<'d>,
|
||||
-}
|
||||
-
|
||||
-impl<'d> Unpin for ExtiInput<'d> {}
|
||||
-
|
||||
-impl<'d> ExtiInput<'d> {
|
||||
- pub fn new<T: GpioPin>(
|
||||
- pin: impl Peripheral<P = T> + 'd,
|
||||
- ch: impl Peripheral<P = T::ExtiChannel> + 'd,
|
||||
- pull: Pull,
|
||||
- ) -> Self {
|
||||
- into_ref!(pin, ch);
|
||||
- // Needed if using AnyPin+AnyChannel.
|
||||
- assert_eq!(pin.pin(), ch.number());
|
||||
-
|
||||
- Self {
|
||||
- pin: Input::new(pin, pull),
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- pub fn is_high(&self) -> bool {
|
||||
- self.pin.is_high()
|
||||
- }
|
||||
-
|
||||
- pub fn is_low(&self) -> bool {
|
||||
- self.pin.is_low()
|
||||
- }
|
||||
-
|
||||
- pub fn get_level(&self) -> Level {
|
||||
- self.pin.get_level()
|
||||
- }
|
||||
-
|
||||
- pub async fn wait_for_high<'a>(&'a mut self) {
|
||||
- let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
|
||||
- if self.is_high() {
|
||||
- return;
|
||||
- }
|
||||
- fut.await
|
||||
- }
|
||||
-
|
||||
- pub async fn wait_for_low<'a>(&'a mut self) {
|
||||
- let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
|
||||
- if self.is_low() {
|
||||
- return;
|
||||
- }
|
||||
- fut.await
|
||||
- }
|
||||
-
|
||||
- pub async fn wait_for_rising_edge<'a>(&'a mut self) {
|
||||
- ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
|
||||
- }
|
||||
-
|
||||
- pub async fn wait_for_falling_edge<'a>(&'a mut self) {
|
||||
- ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
|
||||
- }
|
||||
-
|
||||
- pub async fn wait_for_any_edge<'a>(&'a mut self) {
|
||||
- ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
-struct ExtiInputFuture<'a> {
|
||||
- pin: u8,
|
||||
- phantom: PhantomData<&'a mut AnyPin>,
|
||||
-}
|
||||
-
|
||||
-// EXTI0-EXTI23 Px0-Px23(x=A/B/C)
|
||||
-impl<'a> ExtiInputFuture<'a> {
|
||||
- fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
|
||||
- critical_section::with(|_| {
|
||||
- let exti = &crate::pac::EXTI;
|
||||
- let afio = &crate::pac::AFIO;
|
||||
-
|
||||
- let port = port as u8;
|
||||
- let pin = pin as usize;
|
||||
-
|
||||
- #[cfg(afio_v0)]
|
||||
- {
|
||||
- // AFIO_EXTICR
|
||||
- // stride: 2, len: 15, 8 lines
|
||||
- afio.exticr().modify(|w| w.set_exti(pin, port));
|
||||
- }
|
||||
- // V1, V2, V3, L1
|
||||
- #[cfg(any(afio_v3, afio_l1))]
|
||||
- {
|
||||
- // AFIO_EXTICRx
|
||||
- // stride: 4, len: 4, 16 lines
|
||||
- afio.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
|
||||
- }
|
||||
- #[cfg(afio_x0)]
|
||||
- {
|
||||
- // stride: 2, len: 15, 24 lines
|
||||
- afio.exticr(pin / 16).modify(|w| w.set_exti(pin % 16, port));
|
||||
- }
|
||||
- #[cfg(afio_ch641)]
|
||||
- {
|
||||
- // single register
|
||||
- afio.exticr().modify(|w| w.set_exti(pin, port != 0));
|
||||
- }
|
||||
-
|
||||
- // See-also: 7.4.3
|
||||
- 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));
|
||||
- });
|
||||
-
|
||||
- Self {
|
||||
- pin,
|
||||
- phantom: PhantomData,
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-impl<'a> Drop for ExtiInputFuture<'a> {
|
||||
- fn drop(&mut self) {
|
||||
- critical_section::with(|_| {
|
||||
- let exti = &crate::pac::EXTI;
|
||||
- let pin = self.pin;
|
||||
- exti.intenr().modify(|w| w.0 = w.0 & !(1 << pin));
|
||||
- });
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-impl<'a> Future for ExtiInputFuture<'a> {
|
||||
- type Output = ();
|
||||
-
|
||||
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
- let exti = &crate::pac::EXTI;
|
||||
-
|
||||
- EXTI_WAKERS[self.pin as usize].register(cx.waker());
|
||||
-
|
||||
- if exti.intenr().read().mr(self.pin as _) == false {
|
||||
- // intenr cleared by on_irq, then we can assume it is triggered
|
||||
- Poll::Ready(())
|
||||
- } else {
|
||||
- Poll::Pending
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
trait SealedChannel {}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
@@ -207,6 +37,7 @@ pub trait Channel: SealedChannel + Sized {
|
||||
pub struct AnyChannel {
|
||||
number: u8,
|
||||
}
|
||||
+
|
||||
impl_peripheral!(AnyChannel);
|
||||
impl SealedChannel for AnyChannel {}
|
||||
impl Channel for AnyChannel {
|
||||
@@ -267,128 +98,305 @@ mod _exti_24lines {
|
||||
impl_exti!(EXTI23, 23);
|
||||
}
|
||||
|
||||
-/*
|
||||
-EXTI0
|
||||
-EXTI1
|
||||
-EXTI2
|
||||
-EXTI3
|
||||
-EXTI4
|
||||
-EXTI9_5
|
||||
-EXTI15_10
|
||||
-EXTI7_0
|
||||
-EXTI15_8
|
||||
-EXTI25_16
|
||||
-*/
|
||||
-
|
||||
-/// safety: must be called only once
|
||||
-#[cfg(gpio_x0)]
|
||||
-mod irq_impl {
|
||||
- use super::*;
|
||||
+#[cfg(feature = "exti")]
|
||||
+pub use exti_inner::*;
|
||||
+
|
||||
+#[cfg(feature = "exti")]
|
||||
+mod exti_inner {
|
||||
+ use super::{BitIter, Channel, EXTI_WAKERS};
|
||||
+ use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull};
|
||||
+ use crate::{into_ref, Peripheral};
|
||||
+ use core::future::Future;
|
||||
+ use core::marker::PhantomData;
|
||||
+ use core::pin::Pin;
|
||||
+ use core::task::{Context, Poll};
|
||||
+ use qingke_rt::interrupt;
|
||||
+
|
||||
+ /// EXTI input driver
|
||||
+ pub struct ExtiInput<'d> {
|
||||
+ pin: Input<'d>,
|
||||
+ }
|
||||
+
|
||||
+ impl<'d> Unpin for ExtiInput<'d> {}
|
||||
+
|
||||
+ impl<'d> ExtiInput<'d> {
|
||||
+ pub fn new<T: GpioPin>(
|
||||
+ pin: impl Peripheral<P = T> + 'd,
|
||||
+ ch: impl Peripheral<P = T::ExtiChannel> + 'd,
|
||||
+ pull: Pull,
|
||||
+ ) -> Self {
|
||||
+ into_ref!(pin, ch);
|
||||
+ // Needed if using AnyPin+AnyChannel.
|
||||
+ assert_eq!(pin.pin(), ch.number());
|
||||
+
|
||||
+ Self {
|
||||
+ pin: Input::new(pin, pull),
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI7_0() {
|
||||
- on_irq();
|
||||
- }
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI15_8() {
|
||||
- on_irq();
|
||||
- }
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI25_16() {
|
||||
- on_irq();
|
||||
- }
|
||||
+ pub fn is_high(&self) -> bool {
|
||||
+ self.pin.is_high()
|
||||
+ }
|
||||
|
||||
- pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
- use crate::pac::Interrupt;
|
||||
+ pub fn is_low(&self) -> bool {
|
||||
+ self.pin.is_low()
|
||||
+ }
|
||||
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI15_8 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI25_16 as u8);
|
||||
- }
|
||||
-}
|
||||
+ pub fn get_level(&self) -> Level {
|
||||
+ self.pin.get_level()
|
||||
+ }
|
||||
|
||||
-#[cfg(all(gpio_v3, not(ch641)))]
|
||||
-mod irq_impl {
|
||||
- use super::*;
|
||||
+ pub async fn wait_for_high<'a>(&'a mut self) {
|
||||
+ let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
|
||||
+ if self.is_high() {
|
||||
+ return;
|
||||
+ }
|
||||
+ fut.await
|
||||
+ }
|
||||
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI0() {
|
||||
- on_irq();
|
||||
- }
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI1() {
|
||||
- on_irq();
|
||||
- }
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI2() {
|
||||
- on_irq();
|
||||
- }
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI3() {
|
||||
- on_irq();
|
||||
+ pub async fn wait_for_low<'a>(&'a mut self) {
|
||||
+ let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
|
||||
+ if self.is_low() {
|
||||
+ return;
|
||||
+ }
|
||||
+ fut.await
|
||||
+ }
|
||||
+
|
||||
+ pub async fn wait_for_rising_edge<'a>(&'a mut self) {
|
||||
+ ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
|
||||
+ }
|
||||
+
|
||||
+ pub async fn wait_for_falling_edge<'a>(&'a mut self) {
|
||||
+ ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
|
||||
+ }
|
||||
+
|
||||
+ pub async fn wait_for_any_edge<'a>(&'a mut self) {
|
||||
+ ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
|
||||
+ }
|
||||
}
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI4() {
|
||||
- on_irq();
|
||||
+
|
||||
+ pub unsafe fn on_irq() {
|
||||
+ let exti = &crate::pac::EXTI;
|
||||
+
|
||||
+ let bits = exti.intfr().read();
|
||||
+
|
||||
+ // We don't handle or change any EXTI lines above 24.
|
||||
+ let bits = bits.0 & 0x00FFFFFF;
|
||||
+
|
||||
+ // Clear pending - Clears the EXTI's line pending bits.
|
||||
+ exti.intfr().write(|w| w.0 = bits);
|
||||
+
|
||||
+ exti.intenr().modify(|w| w.0 = w.0 & !bits);
|
||||
+
|
||||
+ // Wake the tasks
|
||||
+ for pin in BitIter(bits) {
|
||||
+ EXTI_WAKERS[pin as usize].wake();
|
||||
+ }
|
||||
}
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI9_5() {
|
||||
- on_irq();
|
||||
+
|
||||
+ #[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
+ struct ExtiInputFuture<'a> {
|
||||
+ pin: u8,
|
||||
+ phantom: PhantomData<&'a mut AnyPin>,
|
||||
+ }
|
||||
+
|
||||
+ // EXTI0-EXTI23 Px0-Px23(x=A/B/C)
|
||||
+ impl<'a> ExtiInputFuture<'a> {
|
||||
+ fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
|
||||
+ critical_section::with(|_| {
|
||||
+ let exti = &crate::pac::EXTI;
|
||||
+ let afio = &crate::pac::AFIO;
|
||||
+
|
||||
+ let port = port as u8;
|
||||
+ let pin = pin as usize;
|
||||
+
|
||||
+ #[cfg(afio_v0)]
|
||||
+ {
|
||||
+ // AFIO_EXTICR
|
||||
+ // stride: 2, len: 15, 8 lines
|
||||
+ afio.exticr().modify(|w| w.set_exti(pin, port));
|
||||
+ }
|
||||
+ // V1, V2, V3, L1
|
||||
+ #[cfg(any(afio_v3, afio_l1))]
|
||||
+ {
|
||||
+ // AFIO_EXTICRx
|
||||
+ // stride: 4, len: 4, 16 lines
|
||||
+ afio.exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
|
||||
+ }
|
||||
+ #[cfg(afio_x0)]
|
||||
+ {
|
||||
+ // stride: 2, len: 15, 24 lines
|
||||
+ afio.exticr(pin / 16).modify(|w| w.set_exti(pin % 16, port));
|
||||
+ }
|
||||
+ #[cfg(afio_ch641)]
|
||||
+ {
|
||||
+ // single register
|
||||
+ afio.exticr().modify(|w| w.set_exti(pin, port != 0));
|
||||
+ }
|
||||
+
|
||||
+ // See-also: 7.4.3
|
||||
+ 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));
|
||||
+ });
|
||||
+
|
||||
+ Self {
|
||||
+ pin,
|
||||
+ phantom: PhantomData,
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI15_10() {
|
||||
- on_irq();
|
||||
+
|
||||
+ impl<'a> Drop for ExtiInputFuture<'a> {
|
||||
+ fn drop(&mut self) {
|
||||
+ critical_section::with(|_| {
|
||||
+ let exti = &crate::pac::EXTI;
|
||||
+ let pin = self.pin;
|
||||
+ exti.intenr().modify(|w| w.0 = w.0 & !(1 << pin));
|
||||
+ });
|
||||
+ }
|
||||
}
|
||||
|
||||
- pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
- use crate::pac::Interrupt;
|
||||
+ impl<'a> Future for ExtiInputFuture<'a> {
|
||||
+ type Output = ();
|
||||
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI0 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI1 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI2 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI3 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI4 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI9_5 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI15_10 as u8);
|
||||
- }
|
||||
-}
|
||||
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
+ let exti = &crate::pac::EXTI;
|
||||
|
||||
-#[cfg(gpio_v0)]
|
||||
-mod irq_impl {
|
||||
- use super::*;
|
||||
+ EXTI_WAKERS[self.pin as usize].register(cx.waker());
|
||||
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI7_0() {
|
||||
- on_irq();
|
||||
+ if exti.intenr().read().mr(self.pin as _) == false {
|
||||
+ // intenr cleared by on_irq, then we can assume it is triggered
|
||||
+ Poll::Ready(())
|
||||
+ } else {
|
||||
+ Poll::Pending
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
- pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
- use crate::pac::Interrupt;
|
||||
+ /*
|
||||
+ EXTI0
|
||||
+ EXTI1
|
||||
+ EXTI2
|
||||
+ EXTI3
|
||||
+ EXTI4
|
||||
+ EXTI9_5
|
||||
+ EXTI15_10
|
||||
+ EXTI7_0
|
||||
+ EXTI15_8
|
||||
+ EXTI25_16
|
||||
+ */
|
||||
+
|
||||
+ /// safety: must be called only once
|
||||
+ #[cfg(gpio_x0)]
|
||||
+ mod irq_impl {
|
||||
+ use super::*;
|
||||
+
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI7_0() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI15_8() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI25_16() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+
|
||||
+ pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
+ use crate::pac::Interrupt;
|
||||
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI15_8 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI25_16 as u8);
|
||||
+ }
|
||||
}
|
||||
-}
|
||||
|
||||
-#[cfg(all(gpio_v3, ch641))]
|
||||
-mod irq_impl {
|
||||
- use super::*;
|
||||
+ #[cfg(all(gpio_v3, not(ch641)))]
|
||||
+ mod irq_impl {
|
||||
+ use super::*;
|
||||
+
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI0() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI1() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI2() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI3() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI4() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI9_5() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI15_10() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI7_0() {
|
||||
- on_irq();
|
||||
+ pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
+ use crate::pac::Interrupt;
|
||||
+
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI0 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI1 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI2 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI3 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI4 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI9_5 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI15_10 as u8);
|
||||
+ }
|
||||
}
|
||||
|
||||
- #[interrupt]
|
||||
- unsafe fn EXTI15_8() {
|
||||
- on_irq();
|
||||
+ #[cfg(gpio_v0)]
|
||||
+ mod irq_impl {
|
||||
+ use super::*;
|
||||
+
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI7_0() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+
|
||||
+ pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
+ use crate::pac::Interrupt;
|
||||
+
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
+ }
|
||||
}
|
||||
|
||||
- pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
- use crate::pac::Interrupt;
|
||||
+ #[cfg(all(gpio_v3, ch641))]
|
||||
+ mod irq_impl {
|
||||
+ use super::*;
|
||||
+
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI7_0() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+
|
||||
+ #[interrupt]
|
||||
+ unsafe fn EXTI15_8() {
|
||||
+ on_irq();
|
||||
+ }
|
||||
+
|
||||
+ pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
+ use crate::pac::Interrupt;
|
||||
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
- qingke::pfic::enable_interrupt(Interrupt::EXTI15_8 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 as u8);
|
||||
+ qingke::pfic::enable_interrupt(Interrupt::EXTI15_8 as u8);
|
||||
+ }
|
||||
}
|
||||
+ pub(crate) use irq_impl::*;
|
||||
}
|
||||
-
|
||||
-pub(crate) use irq_impl::*;
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
index 997da34..b451a55 100644
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -140,6 +140,7 @@ pub fn init(config: Config) -> Peripherals {
|
||||
::critical_section::with(|cs| unsafe {
|
||||
gpio::init(cs);
|
||||
dma::init(cs, config.dma_interrupt_priority);
|
||||
+ #[cfg(feature = "exti")]
|
||||
exti::init(cs);
|
||||
});
|
||||
|
||||
|
||||
1
ch32v-insert-coin/ext/qingke
Submodule
1
ch32v-insert-coin/ext/qingke
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2443891811d7351d62e78085bcf60fa78c063c08
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
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, TickService, TickServiceData, Service};
|
||||
|
||||
|
|
@ -40,9 +38,9 @@ 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);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -61,7 +59,7 @@ impl CoreConfig {
|
|||
|
||||
#[derive(Default)]
|
||||
struct Core {
|
||||
tick: usize,
|
||||
_tick: usize,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +71,7 @@ pub struct InsertCoin<'a, T: GeneralInstance16bit> {
|
|||
pub led1: LedService,
|
||||
// led2: LedService,
|
||||
|
||||
dac: DacService<'a>,
|
||||
pub dac: DacService<'a>,
|
||||
}
|
||||
|
||||
impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> {
|
||||
|
|
@ -82,25 +80,17 @@ impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> {
|
|||
|
||||
|
||||
// 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 = TickServiceData::new(led0_tick_per_service);
|
||||
let led0 = LedService::new(ch32_hal::timer::Channel::Ch3, led0_service_data);
|
||||
let led0 = LedService::new(ch32_hal::timer::Channel::Ch3);
|
||||
|
||||
// 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 = TickServiceData::new(led1_tick_per_service);
|
||||
let led1 = LedService::new(ch32_hal::timer::Channel::Ch1, led1_service_data);
|
||||
let led1 = LedService::new(ch32_hal::timer::Channel::Ch1);
|
||||
|
||||
|
||||
// DAC servicer setup
|
||||
let dac_sample_rate_hz = 16000;
|
||||
let dac_tick_per_service = (config.tick_rate_hz/(dac_sample_rate_hz));
|
||||
let dac_tick_per_service = config.tick_rate_hz/(dac_sample_rate_hz);
|
||||
let dac_service_data = TickServiceData::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,
|
||||
|
|
@ -110,11 +100,6 @@ impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> {
|
|||
led1,
|
||||
// led2,
|
||||
dac,
|
||||
// led1: Led {
|
||||
// channel: hal::timer::Channel::Ch1,
|
||||
// amplitude: 0,
|
||||
// need_service: false,
|
||||
// },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,55 +129,53 @@ impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> {
|
|||
|
||||
}
|
||||
|
||||
/// consumes self and runs
|
||||
pub fn run(mut self) -> ! {
|
||||
let mut delay = Delay;
|
||||
let tick_interval_us = 1000000/self.config.tick_rate_hz;
|
||||
// /// 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 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];
|
||||
// let mut led1_index = 0;
|
||||
// let led1_dcs = [0u8, 25u8, 50u8, 75u8, 100u8];
|
||||
|
||||
loop {
|
||||
self.dac.tick();
|
||||
// loop {
|
||||
// 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);
|
||||
// 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();
|
||||
}
|
||||
// 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);
|
||||
// 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();
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// delay.delay_us(tick_interval_us as u32);
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.core.active
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
mod insert_coin;
|
||||
mod services;
|
||||
use services::LedService;
|
||||
|
||||
pub use services::TickTimerService;
|
||||
|
||||
pub use services::{TickService, TickServiceData, Service};
|
||||
pub use services::{TickService, TickServiceData};
|
||||
pub use insert_coin::{InsertCoin, CoreConfig, SimplePwmCore};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::insert_coin::services::{TickServiceData, TickService};
|
||||
|
||||
|
||||
use adpcm_pwm_dac::{dac::{DpcmDac, DpcmDecoder}, interface::DacInterface};
|
||||
use adpcm_pwm_dac::dac::DpcmDecoder;
|
||||
use ch32_hal::timer::Channel;
|
||||
|
||||
pub struct DacService<'a> {
|
||||
|
|
@ -23,6 +23,7 @@ impl<'a> DacService<'a> {
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn set_amplitude(&self, amplitude: usize) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use ch32_hal::timer::Channel;
|
||||
|
||||
use crate::insert_coin::services::{Service, TickService, TickServiceData};
|
||||
use crate::insert_coin::services::{Service};
|
||||
|
||||
pub struct LedService {
|
||||
// need_service: core::cell::RefCell<bool>,
|
||||
|
|
@ -10,7 +10,7 @@ pub struct LedService {
|
|||
}
|
||||
|
||||
impl LedService {
|
||||
pub fn new(channel: Channel, service_data: TickServiceData) -> Self {
|
||||
pub fn new(channel: Channel) -> Self {
|
||||
Self {
|
||||
// service_data: core::cell::RefCell::new(service_data),
|
||||
need_service: false,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use ch32_hal::timer::Channel;
|
||||
|
||||
use crate::insert_coin::services::{TickServiceData, TickService};
|
||||
|
||||
pub struct TickTimerService {
|
||||
service_data: core::cell::RefCell<TickServiceData>,
|
||||
auto_reset: bool,
|
||||
_auto_reset: bool,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
|
|
@ -12,18 +10,18 @@ impl TickTimerService {
|
|||
pub fn new(service_data: TickServiceData, auto_reset: bool) -> Self {
|
||||
Self {
|
||||
service_data: core::cell::RefCell::new(service_data),
|
||||
auto_reset,
|
||||
_auto_reset: auto_reset,
|
||||
enabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
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_per_service = sd.ticks_remaining;
|
||||
sd.ticks_remaining = sd.ticks_per_service;
|
||||
self.enabled = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,85 +4,167 @@
|
|||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
mod insert_coin;
|
||||
use ch32_hal::{interrupt::typelevel::Handler, timer::low_level::OutputPolarity};
|
||||
use insert_coin::{InsertCoin, SimplePwmCore, CoreConfig};
|
||||
|
||||
|
||||
use adpcm_pwm_dac::dac::DpcmDac;
|
||||
use {ch32_hal as hal};
|
||||
use hal::peripherals::EXTI4;
|
||||
use hal::{bind_interrupts, interrupt};
|
||||
use hal::{bind_interrupts};
|
||||
use hal::delay::Delay;
|
||||
use hal::gpio::{AnyPin, Level, Input, Output, 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};
|
||||
use hal::timer::{Channel, GeneralInstance16bit};
|
||||
|
||||
// #[qingke_rt::interrupt]
|
||||
// fn EXTI4(){
|
||||
// unsafe{IRQ1_FLAG = true;};
|
||||
// }
|
||||
// bind_interrupts!(struct Irqs {
|
||||
// EXTI4 => button_press();
|
||||
// });
|
||||
use hal::println;
|
||||
|
||||
use qingke::riscv;
|
||||
|
||||
|
||||
// const DAC_DATA: [u8; 4] = [0x0, 0x80, 0xFF, 0x80];
|
||||
const DAC_DATA: [u8; 8] = [0, 25, 50, 75, 100, 75, 50, 25];
|
||||
struct DebouncedGPIO<'a> {
|
||||
input: Input<'a>,
|
||||
// value of the GPIO
|
||||
value: bool,
|
||||
// GPIO is ready (debounced)
|
||||
ready: bool,
|
||||
// debounce timer
|
||||
timer: TickTimerService,
|
||||
}
|
||||
|
||||
// DPCS DATA
|
||||
// step size: 5
|
||||
// 0
|
||||
// + 25 -> [1, 0, 1, 1] -> 0xB
|
||||
// + 25 -> 0xB
|
||||
// + 25 -> 0xB
|
||||
// + 25 -> 0xB
|
||||
// - 25 -> 0xA
|
||||
// - 25 -> 0xA
|
||||
// - 25 -> 0xA
|
||||
const DPCM_DAC_DATA: [u8; 4] = [0xBB, 0xBB, 0xAA, 0xAA];
|
||||
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,
|
||||
timer: TickTimerService::new(TickServiceData::new(system_tick_rate_hz * debounce_time_ms / 1000), false),
|
||||
}
|
||||
}
|
||||
|
||||
static mut IRQ1_FLAG: bool = false;
|
||||
pub fn ready(&self) -> bool {
|
||||
self.ready
|
||||
}
|
||||
|
||||
pub fn value(&self) -> bool {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn begin(&mut self) {
|
||||
self.reset();
|
||||
self.timer.enable(true);
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.timer.reset();
|
||||
self.ready = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// struct SimplePwmHandle<'a, 'c, T: GeneralInstance16bit>{
|
||||
// core: &'a SimplePwmCore<'c, T>,
|
||||
// channel: Channel,
|
||||
// }
|
||||
// DeepSleep --coin button irq--> Active
|
||||
// Active --2s button--> Idle
|
||||
// Idle/Active --5s button--> DeepSleep
|
||||
|
||||
// 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 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,
|
||||
}
|
||||
|
||||
// pub fn disable(&'a self) {
|
||||
// self.core.disable(self.channel);
|
||||
// }
|
||||
// }
|
||||
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;
|
||||
|
||||
// struct SimplePwmDacHandle<'d, T: GeneralInstance16bit>{
|
||||
// pin: core::cell::RefCell<SimplePwm<'d, T>>,
|
||||
// ch: Channel,
|
||||
// }
|
||||
let port = port as u8;
|
||||
let pin = pin as usize;
|
||||
|
||||
// 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));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// use adpcm_pwm_dac::{interface::DacInterface, dac::Dac};
|
||||
fn clear_interrupt (coin_pin: u8, button_pin: u8) {
|
||||
let exti = &hal::pac::EXTI;
|
||||
|
||||
let coin_pin = coin_pin as usize;
|
||||
let button_pin = button_pin as usize;
|
||||
|
||||
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.
|
||||
let bits = bits.0 & 0x00FFFFFF;
|
||||
|
||||
// coin_flag
|
||||
if (bits & (0x1 << coin_pin)) != 0x0 {
|
||||
println!("coin irq!");
|
||||
unsafe { INPUT_FLAGS.coin_flag = true; }
|
||||
}
|
||||
|
||||
|
||||
// button_flag
|
||||
if (bits & (0x1 << button_pin)) != 0x0 {
|
||||
println!("button irq!");
|
||||
unsafe { INPUT_FLAGS.button_flag = true; }
|
||||
}
|
||||
|
||||
|
||||
// Clear pending - Clears the EXTI's line pending bits.
|
||||
exti.intfr().write(|w| w.0 = bits);
|
||||
|
||||
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};
|
||||
|
||||
struct Test {
|
||||
}
|
||||
impl Handler<hal::interrupt::typelevel::EXTI7_0> for Test {
|
||||
unsafe fn on_interrupt() {
|
||||
println!("on_interrupt()");
|
||||
critical_section::with(|_| {
|
||||
clear_interrupt(4, 6);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
EXTI7_0 => Test;
|
||||
});
|
||||
|
||||
// impl<T> 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);
|
||||
// }
|
||||
// }
|
||||
|
||||
// TODO: remove
|
||||
use insert_coin::{TickService, TickServiceData};
|
||||
|
|
@ -90,23 +172,28 @@ use insert_coin::TickTimerService;
|
|||
|
||||
#[qingke_rt::entry]
|
||||
fn main() -> ! {
|
||||
hal::debug::SDIPrint::enable();
|
||||
let mut config = hal::Config::default();
|
||||
config.rcc = hal::rcc::Config::SYSCLK_FREQ_48MHZ_HSE;
|
||||
let p = hal::init(config);
|
||||
|
||||
// coin button input setup
|
||||
let coin_button = Input::new(p.PD4, Pull::Up);
|
||||
// delay to let the debugger attach
|
||||
let mut delay = Delay;
|
||||
delay.delay_ms(1000);
|
||||
|
||||
// p.EXTI4
|
||||
// let ei = hal::exti::ExtiInput::new(p.PD4, p.EXTI4, Pull::Up);
|
||||
|
||||
|
||||
// === output setup ===
|
||||
|
||||
// LED0 output setup
|
||||
let mut led0_pin = PwmPin::new_ch3::<0>(p.PC3);
|
||||
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 mut led1_pin = PwmPin::new_ch1::<0>(p.PD2);
|
||||
let led1_pin = PwmPin::new_ch1::<0>(p.PD2);
|
||||
let led1_ch = hal::timer::Channel::Ch1;
|
||||
|
||||
|
||||
|
|
@ -114,7 +201,7 @@ fn main() -> ! {
|
|||
|
||||
// DAC output setup
|
||||
let dac_pin = PwmPin::new_ch4::<0>(p.PC4);
|
||||
let dac_ch = hal::timer::Channel::Ch4;
|
||||
// let dac_ch = hal::timer::Channel::Ch4;
|
||||
|
||||
|
||||
|
||||
|
|
@ -129,15 +216,38 @@ fn main() -> ! {
|
|||
CountingMode::default(),
|
||||
);
|
||||
|
||||
pwm.set_polarity(led0_ch, OutputPolarity::ActiveLow);
|
||||
pwm.set_polarity(led1_ch, OutputPolarity::ActiveLow);
|
||||
|
||||
let sample_rate_hz = 16000;
|
||||
let dac_tick_per_service = 5;
|
||||
let tick_rate_hz = sample_rate_hz * dac_tick_per_service;
|
||||
|
||||
let config = CoreConfig::new(tick_rate_hz);
|
||||
let core_config = CoreConfig::new(tick_rate_hz);
|
||||
|
||||
|
||||
// === input setup ===
|
||||
|
||||
// definitions
|
||||
let coin_pin = p.PD4;
|
||||
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());
|
||||
|
||||
// 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)};
|
||||
|
||||
// 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(config, pwm_core);
|
||||
let mut interfaces = InsertCoin::new(core_config, pwm_core);
|
||||
interfaces.set_active(true);
|
||||
// insert_coin.init();
|
||||
|
||||
|
|
@ -149,22 +259,16 @@ fn main() -> ! {
|
|||
|
||||
// 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_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_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);
|
||||
|
||||
// debounce timer
|
||||
// let db_ticks = interfaces.config.tick_rate_hz / 100;
|
||||
let db_ticks = interfaces.config.tick_rate_hz / 100;
|
||||
let db_timer_data = TickServiceData::new(db_ticks);
|
||||
let mut db_timer = TickTimerService::new(db_timer_data, false);
|
||||
db_timer.reset();
|
||||
|
||||
// short press timer
|
||||
let sp_ticks = 2 * interfaces.config.tick_rate_hz;
|
||||
|
|
@ -179,49 +283,44 @@ fn main() -> ! {
|
|||
lp_timer.reset();
|
||||
|
||||
let mut delay = Delay;
|
||||
let tick_interval_us = 1000000/interfaces.config.tick_rate_hz;
|
||||
|
||||
interfaces.led0.set_amplitude(100);
|
||||
interfaces.led1.set_amplitude(100);
|
||||
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 mut system_state = SystemState::DeepSleep;
|
||||
|
||||
interfaces.led0.set_amplitude(0);
|
||||
interfaces.led1.set_amplitude(0);
|
||||
interfaces.service();
|
||||
|
||||
unsafe {
|
||||
use hal::pac::Interrupt;
|
||||
|
||||
qingke::pfic::enable_interrupt(Interrupt::EXTI7_0 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
|
||||
// -we will want one sound, the coin insert sound, to play when coin button is pressed. (This is when they insert a coin)
|
||||
// -We will want a different sound or potentially multiple different sounds played in a rotating fashion when someone presses the button. Probably do some led blinking as well.(This is when they depress the big insert to play button)
|
||||
// -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
|
||||
|
||||
println!("begin");
|
||||
loop {
|
||||
// wait for button to be released if it's pressed
|
||||
if (coin_button.is_low()) {
|
||||
loop {
|
||||
if coin_button.is_high() && !db_timer.is_enabled() {
|
||||
db_timer.enable(true);
|
||||
}
|
||||
if db_timer.need_service() {
|
||||
db_timer.reset();
|
||||
if coin_button.is_high() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
db_timer.tick();
|
||||
delay.delay_us(tick_interval_us as u32);
|
||||
}
|
||||
}
|
||||
// wait for button input
|
||||
loop {
|
||||
if coin_button.is_low() && !db_timer.is_enabled() {
|
||||
db_timer.enable(true);
|
||||
}
|
||||
if db_timer.need_service() {
|
||||
db_timer.reset();
|
||||
if coin_button.is_low() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
db_timer.tick();
|
||||
delay.delay_us(tick_interval_us as u32);
|
||||
}
|
||||
match system_state {
|
||||
SystemState::DeepSleep => {
|
||||
// TODO: make this REALLY deep sleep
|
||||
riscv::asm::wfi();
|
||||
},
|
||||
SystemState::Idle => {
|
||||
|
||||
let mut active = true;
|
||||
tt0.enable(true);
|
||||
tt1.enable(true);
|
||||
loop {
|
||||
if active {
|
||||
},
|
||||
SystemState::Active => {
|
||||
tt0.tick();
|
||||
tt1.tick();
|
||||
|
||||
|
|
@ -243,61 +342,102 @@ fn main() -> ! {
|
|||
tt1.service()
|
||||
}
|
||||
|
||||
}
|
||||
interfaces.service();
|
||||
},
|
||||
}
|
||||
|
||||
// buttons
|
||||
|
||||
// SP
|
||||
if coin_button.is_low() && !sp_timer.is_enabled() {
|
||||
sp_timer.reset();
|
||||
sp_timer.enable(true);
|
||||
}
|
||||
if sp_timer.need_service() {
|
||||
sp_timer.reset();
|
||||
if coin_button.is_low() {
|
||||
active = false;
|
||||
// TODO: fix polarity
|
||||
interfaces.led0.set_amplitude(90);
|
||||
interfaces.led1.set_amplitude(90);
|
||||
|
||||
{
|
||||
// system input servicing
|
||||
unsafe {
|
||||
if INPUT_FLAGS.coin_flag {
|
||||
println!("coin flag active");
|
||||
INPUT_FLAGS.coin_flag = false;
|
||||
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.button_flag {
|
||||
println!("button flag active");
|
||||
INPUT_FLAGS.button_flag = false;
|
||||
button_input.begin();
|
||||
}
|
||||
}
|
||||
if coin_button.is_high() && sp_timer.is_enabled() {
|
||||
sp_timer.reset();
|
||||
|
||||
// debouncer
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// timers
|
||||
sp_timer.tick();
|
||||
|
||||
|
||||
// LP
|
||||
if coin_button.is_low() && !lp_timer.is_enabled() {
|
||||
lp_timer.reset();
|
||||
lp_timer.enable(true);
|
||||
}
|
||||
if lp_timer.need_service() {
|
||||
lp_timer.reset();
|
||||
if coin_button.is_low() {
|
||||
interfaces.led0.set_amplitude(100);
|
||||
interfaces.led1.set_amplitude(100);
|
||||
// break;
|
||||
}
|
||||
}
|
||||
if coin_button.is_high() && lp_timer.is_enabled() {
|
||||
lp_timer.reset();
|
||||
}
|
||||
lp_timer.tick();
|
||||
|
||||
interfaces.service();
|
||||
delay.delay_us(tick_interval_us as u32);
|
||||
if sp_timer.need_service() {
|
||||
println!("sp detect!");
|
||||
sp_timer.reset();
|
||||
|
||||
// todo enter idle
|
||||
system_state = SystemState::Idle;
|
||||
// TODO: fix polarity
|
||||
interfaces.led0.set_amplitude(10);
|
||||
interfaces.led1.set_amplitude(10);
|
||||
interfaces.service();
|
||||
}
|
||||
|
||||
if lp_timer.need_service() {
|
||||
println!("lp detect!");
|
||||
lp_timer.reset();
|
||||
|
||||
// todo enter deepsleep
|
||||
system_state = SystemState::DeepSleep;
|
||||
// TODO: fix polarity
|
||||
interfaces.led0.set_amplitude(0);
|
||||
interfaces.led1.set_amplitude(0);
|
||||
interfaces.service();
|
||||
}
|
||||
}
|
||||
|
||||
delay.delay_us(tick_interval_us 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;
|
||||
}
|
||||
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue