insert-coin/ch32v-insert-coin/ext/patches/optional-exti.patch

652 lines
18 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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-Px23x=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-Px23x=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);
});