Skip to content

Commit 907e553

Browse files
committed
Add support for GPIO interrupts
1 parent 1ffac2e commit 907e553

File tree

1 file changed

+116
-36
lines changed

1 file changed

+116
-36
lines changed

src/gpio.rs

Lines changed: 116 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
3131
use core::{convert::Infallible, marker::PhantomData};
3232

33-
use crate::{hal::digital::v2::OutputPin, rcc::AHB};
33+
use crate::{hal::digital::v2::OutputPin, pac::EXTI, rcc::AHB, syscfg::SysCfg};
3434

3535
#[cfg(feature = "unproven")]
3636
use crate::hal::digital::v2::{toggleable, InputPin, StatefulOutputPin};
@@ -87,6 +87,7 @@ mod private {
8787
type Reg: GpioRegExt + ?Sized;
8888

8989
fn ptr(&self) -> *const Self::Reg;
90+
fn port_index(&self) -> u8;
9091
}
9192
}
9293

@@ -129,12 +130,13 @@ pub trait Readable {}
129130
/// Marker trait for slew rate configurable pin modes
130131
pub trait OutputSpeed {}
131132

132-
/// Marker trait for internal resistor enabled pin modes
133-
pub trait InternalResistor {}
133+
/// Marker trait for active pin modes
134+
pub trait Active {}
134135

135136
/// Runtime defined GPIO port (type state)
136137
pub struct Gpiox {
137138
ptr: *const dyn GpioRegExt,
139+
index: u8,
138140
}
139141

140142
impl private::Gpio for Gpiox {
@@ -143,6 +145,10 @@ impl private::Gpio for Gpiox {
143145
fn ptr(&self) -> *const Self::Reg {
144146
self.ptr
145147
}
148+
149+
fn port_index(&self) -> u8 {
150+
self.index
151+
}
146152
}
147153

148154
impl Gpio for Gpiox {}
@@ -174,9 +180,9 @@ impl Readable for Input {}
174180
impl Readable for Output<OpenDrain> {}
175181
impl<OTYPE> OutputSpeed for Output<OTYPE> {}
176182
impl<AF, OTYPE> OutputSpeed for Alternate<AF, OTYPE> {}
177-
impl InternalResistor for Input {}
178-
impl<OTYPE> InternalResistor for Output<OTYPE> {}
179-
impl<AF, OTYPE> InternalResistor for Alternate<AF, OTYPE> {}
183+
impl Active for Input {}
184+
impl<OTYPE> Active for Output<OTYPE> {}
185+
impl<AF, OTYPE> Active for Alternate<AF, OTYPE> {}
180186

181187
/// Slew rate configuration
182188
pub enum Speed {
@@ -226,6 +232,14 @@ pub struct Pin<GPIO, INDEX, MODE> {
226232
/// [examples/gpio_erased.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.6.0/examples/gpio_erased.rs
227233
pub type PXx<MODE> = Pin<Gpiox, Ux, MODE>;
228234

235+
macro_rules! modify_at {
236+
($xr:expr, $bits:expr, $i:expr, $val:expr) => {
237+
$xr.modify(|r, w| {
238+
w.bits(r.bits() & !(u32::MAX >> 32 - $bits << $bits * $i) | $val << $bits * $i)
239+
});
240+
};
241+
}
242+
229243
impl<GPIO, INDEX, MODE> Pin<GPIO, INDEX, MODE>
230244
where
231245
INDEX: Unsigned,
@@ -256,6 +270,7 @@ where
256270
PXx {
257271
gpio: Gpiox {
258272
ptr: self.gpio.ptr(),
273+
index: self.gpio.port_index(),
259274
},
260275
index: self.index,
261276
_mode: self._mode,
@@ -374,7 +389,7 @@ impl<GPIO, INDEX, MODE> Pin<GPIO, INDEX, MODE>
374389
where
375390
GPIO: GpioStatic,
376391
INDEX: Index,
377-
MODE: InternalResistor,
392+
MODE: Active,
378393
{
379394
/// Set the internal pull-up and pull-down resistor
380395
pub fn set_internal_resistor(&mut self, pupdr: &mut GPIO::PUPDR, resistor: Resistor) {
@@ -458,6 +473,77 @@ where
458473
{
459474
}
460475

476+
/// Return an EXTI register for the current CPU
477+
#[cfg(any(feature = "stm32f373", feature = "stm32f378"))]
478+
macro_rules! reg_for_cpu {
479+
($exti:expr, $xr:ident) => {
480+
$exti.$xr
481+
};
482+
}
483+
484+
/// Return an EXTI register for the current CPU
485+
#[cfg(not(any(feature = "stm32f373", feature = "stm32f378")))]
486+
macro_rules! reg_for_cpu {
487+
($exti:expr, $xr:ident) => {
488+
paste::paste! {
489+
$exti.[<$xr 1>]
490+
}
491+
};
492+
}
493+
494+
impl<GPIO, INDEX, MODE> Pin<GPIO, INDEX, MODE>
495+
where
496+
GPIO: Gpio,
497+
INDEX: Index,
498+
MODE: Active,
499+
{
500+
/// Make corresponding EXTI line sensitive to this pin
501+
pub fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) {
502+
let i = self.index.index() % 4;
503+
let extigpionr = self.gpio.port_index() as u32;
504+
match self.index.index() {
505+
0..=3 => unsafe { modify_at!(syscfg.exticr1, 4, i, extigpionr) },
506+
4..=7 => unsafe { modify_at!(syscfg.exticr2, 4, i, extigpionr) },
507+
8..=11 => unsafe { modify_at!(syscfg.exticr3, 4, i, extigpionr) },
508+
12..=15 => unsafe { modify_at!(syscfg.exticr4, 4, i, extigpionr) },
509+
_ => unreachable!(),
510+
}
511+
}
512+
513+
/// Generate interrupt on rising edge, falling edge, or both
514+
pub fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
515+
let (rise, fall) = match edge {
516+
Edge::Rising => (true, false),
517+
Edge::Falling => (false, true),
518+
Edge::RisingFalling => (true, true),
519+
};
520+
unsafe {
521+
modify_at!(reg_for_cpu!(exti, rtsr), 1, self.index.index(), rise as u32);
522+
modify_at!(reg_for_cpu!(exti, ftsr), 1, self.index.index(), fall as u32);
523+
}
524+
}
525+
526+
/// Enable external interrupts from this pin.
527+
pub fn enable_interrupt(&mut self, exti: &mut EXTI) {
528+
unsafe { modify_at!(reg_for_cpu!(exti, imr), 1, self.index.index(), 1) };
529+
}
530+
531+
/// Disable external interrupts from this pin
532+
pub fn disable_interrupt(&mut self, exti: &mut EXTI) {
533+
unsafe { modify_at!(reg_for_cpu!(exti, imr), 1, self.index.index(), 0) };
534+
}
535+
536+
/// Clear the interrupt pending bit for this pin
537+
pub fn clear_interrupt_pending_bit(&mut self) {
538+
unsafe { reg_for_cpu!((*EXTI::ptr()), pr).write(|w| w.bits(1 << self.index.index())) };
539+
}
540+
541+
/// Reads the interrupt pending bit for this pin
542+
pub fn check_interrupt(&self) -> bool {
543+
unsafe { reg_for_cpu!((*EXTI::ptr()), pr).read().bits() & (1 << self.index.index()) != 0 }
544+
}
545+
}
546+
461547
macro_rules! af {
462548
($i:literal, $Ui:ty, $AFi:ident, $IntoAfi:ident, $into_afi_push_pull:ident, $into_afi_open_drain:ident) => {
463549
paste::paste! {
@@ -545,22 +631,6 @@ macro_rules! gpio_trait {
545631
}
546632
}
547633
)+
548-
}
549-
}
550-
551-
macro_rules! afr_trait {
552-
($GPIOX:ident, $AFR:ty, $afr:ident, $offset:expr) => {
553-
impl Afr for $AFR {
554-
#[inline]
555-
fn afx(&mut self, i: u8, x: u8) {
556-
let i = i - $offset;
557-
unsafe {
558-
(*$GPIOX::ptr()).$afr.modify(|r, w| {
559-
w.bits(r.bits() & !(u32::MAX >> 32 - 4 << 4 * i) | (x as u32) << 4 * i)
560-
});
561-
}
562-
}
563-
}
564634
};
565635
}
566636

@@ -578,12 +648,7 @@ macro_rules! r_trait {
578648
#[inline]
579649
fn $fn(&mut self, i: u8) {
580650
unsafe {
581-
(*$GPIOX::ptr()).$xr.modify(|r, w| {
582-
w.bits(
583-
r.bits() & !(u32::MAX >> 32 - $bits << $bits * i)
584-
| ($gpioy::$xr::$enum::$VARIANT as u32) << $bits * i
585-
)
586-
});
651+
modify_at!((*$GPIOX::ptr()).$xr, $bits, i, $gpioy::$xr::$enum::$VARIANT as u32);
587652
}
588653
}
589654
)+
@@ -598,8 +663,8 @@ macro_rules! gpio {
598663
Gpio: $Gpiox:ty,
599664
port_index: $port_index:literal,
600665
gpio_mapped: $gpioy:ident,
601-
gpio_mapped_ioen: $iopxen:ident,
602-
gpio_mapped_iorst: $iopxrst:ident,
666+
iopen: $iopxen:ident,
667+
ioprst: $iopxrst:ident,
603668
partially_erased_pin: $PXx:ty,
604669
pins: {$(
605670
$PXi:ty: (
@@ -619,6 +684,11 @@ macro_rules! gpio {
619684
fn ptr(&self) -> *const Self::Reg {
620685
crate::pac::$GPIOX::ptr()
621686
}
687+
688+
#[inline(always)]
689+
fn port_index(&self) -> u8 {
690+
$port_index
691+
}
622692
}
623693

624694
impl Gpio for $Gpiox {}
@@ -704,12 +774,22 @@ macro_rules! gpio {
704774
/// Opaque AFRH register
705775
pub struct AFRH(());
706776

707-
afr_trait!($GPIOX, AFRH, afrh, 8);
777+
impl Afr for AFRH {
778+
#[inline]
779+
fn afx(&mut self, i: u8, x: u8) {
780+
unsafe { modify_at!((*$GPIOX::ptr()).afrh, 4, i - 8, x as u32); }
781+
}
782+
}
708783

709784
/// Opaque AFRL register
710785
pub struct AFRL(());
711786

712-
afr_trait!($GPIOX, AFRL, afrl, 0);
787+
impl Afr for AFRL {
788+
#[inline]
789+
fn afx(&mut self, i: u8, x: u8) {
790+
unsafe { modify_at!((*$GPIOX::ptr()).afrl, 4, i, x as u32); }
791+
}
792+
}
713793

714794
/// Opaque MODER register
715795
pub struct MODER(());
@@ -785,7 +865,7 @@ macro_rules! gpio {
785865
$i:literal => {
786866
reset: $MODE:ty,
787867
afr: $LH:ident,
788-
af: [$( $af:literal ),*]
868+
af: [$($af:literal),*]
789869
},
790870
)+],
791871
},
@@ -800,8 +880,8 @@ macro_rules! gpio {
800880
Gpio: [<Gpio $x>],
801881
port_index: $port_index,
802882
gpio_mapped: $gpioy,
803-
gpio_mapped_ioen: [<iop $x en>],
804-
gpio_mapped_iorst: [<iop $x rst>],
883+
iopen: [<iop $x en>],
884+
ioprst: [<iop $x rst>],
805885
partially_erased_pin: [<P $X x>],
806886
pins: {$(
807887
[<P $X $i>]: (

0 commit comments

Comments
 (0)