Skip to content

Commit

Permalink
Merge pull request #777 from stm32-rs/gpio-field-arrays
Browse files Browse the repository at this point in the history
use GPIO pac fields instead of raw write
  • Loading branch information
therealprof authored Jul 27, 2024
2 parents ae82c7b + 8c9fe0c commit ad969d2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Bump MSRV to 1.62
- Use `stm32f4-staging` until `stm32f4` is released [#706]
- use GPIO pac fields instead of raw write
- RTIC2 monotonics fix: CC1 instead of CC3
- Allow different lengths of buffers in hal_1 SpiBus impl [#566]
- Clean SPI write impls
Expand Down
56 changes: 37 additions & 19 deletions src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

use core::marker::PhantomData;

use crate::pac;
pub mod alt;
mod convert;
pub use convert::PinMode;
Expand Down Expand Up @@ -115,7 +116,7 @@ pub struct Alternate<const A: u8, Otype = PushPull>(PhantomData<Otype>);
pub struct Input;

/// Pull setting for an input.
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Pull {
/// Floating
Expand All @@ -126,6 +127,16 @@ pub enum Pull {
Down = 2,
}

impl From<Pull> for pac::gpioa::pupdr::PUPDR0 {
fn from(value: Pull) -> Self {
match value {
Pull::Down => Self::PullDown,
Pull::Up => Self::PullUp,
Pull::None => Self::Floating,
}
}
}

/// Open drain input or output (type state)
#[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down Expand Up @@ -195,6 +206,17 @@ pub enum Speed {
VeryHigh = 3,
}

impl From<Speed> for pac::gpioa::ospeedr::OSPEEDR0 {
fn from(value: Speed) -> Self {
match value {
Speed::Low => Self::LowSpeed,
Speed::Medium => Self::MediumSpeed,
Speed::High => Self::HighSpeed,
Speed::VeryHigh => Self::VeryHighSpeed,
}
}
}

/// GPIO interrupt trigger edge selection
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -318,13 +340,9 @@ where
{
/// Set pin speed
pub fn set_speed(&mut self, speed: Speed) {
let offset = 2 * { N };

unsafe {
(*gpiox::<P>())
.ospeedr()
.modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)));
}
unsafe { &(*gpiox::<P>()) }
.ospeedr()
.modify(|_, w| w.ospeedr(N).variant(speed.into()));
}

/// Set pin speed
Expand All @@ -350,13 +368,9 @@ where
{
/// Set the internal pull-up and pull-down resistor
pub fn set_internal_resistor(&mut self, resistor: Pull) {
let offset = 2 * { N };
let value = resistor as u32;
unsafe {
(*gpiox::<P>())
.pupdr()
.modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)));
}
unsafe { &(*gpiox::<P>()) }
.pupdr()
.modify(|_, w| w.pupdr(N).variant(resistor.into()));
}

/// Set the internal pull-up and pull-down resistor
Expand Down Expand Up @@ -435,22 +449,26 @@ impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
#[inline(always)]
fn _set_high(&mut self) {
// NOTE(unsafe) atomic write to a stateless register
unsafe { (*gpiox::<P>()).bsrr().write(|w| w.bits(1 << N)) }
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.bsrr().write(|w| w.bs(N).set_bit())
}
#[inline(always)]
fn _set_low(&mut self) {
// NOTE(unsafe) atomic write to a stateless register
unsafe { (*gpiox::<P>()).bsrr().write(|w| w.bits(1 << (16 + N))) }
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.bsrr().write(|w| w.br(N).set_bit())
}
#[inline(always)]
fn _is_set_low(&self) -> bool {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*gpiox::<P>()).odr().read().bits() & (1 << N) == 0 }
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.odr().read().odr(N).bit_is_clear()
}
#[inline(always)]
fn _is_low(&self) -> bool {
// NOTE(unsafe) atomic read with no side effects
unsafe { (*gpiox::<P>()).idr().read().bits() & (1 << N) == 0 }
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.idr().read().idr(N).bit_is_clear()
}
}

Expand Down
52 changes: 22 additions & 30 deletions src/gpio/convert.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::pac::gpioa::{moder::MODER0 as Mode, otyper::OT0 as OutputType};

impl<const P: char, const N: u8, const A: u8> Pin<P, N, Alternate<A, PushPull>> {
/// Turns pin alternate configuration pin into open drain
Expand Down Expand Up @@ -110,36 +111,27 @@ impl<const P: char, const N: u8, MODE: PinMode> Pin<P, N, MODE> {

macro_rules! change_mode {
($block:expr, $N:ident) => {
let offset = 2 * $N;
unsafe {
if MODE::OTYPER != M::OTYPER {
if let Some(otyper) = M::OTYPER {
$block
.otyper()
.modify(|r, w| w.bits(r.bits() & !(0b1 << $N) | (otyper << $N)));
$block.otyper().modify(|_, w| w.ot($N).variant(otyper));
}
}

if MODE::AFR != M::AFR {
if let Some(afr) = M::AFR {
if $N < 8 {
let offset2 = 4 * { $N };
$block.afrl().modify(|r, w| {
w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2))
});
$block.afrl().modify(|_, w| w.afr($N).bits(afr));
} else {
let offset2 = 4 * { $N - 8 };
$block.afrh().modify(|r, w| {
w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2))
});
$block.afrh().modify(|_, w| w.afr($N - 8).bits(afr));
}
}
}

if MODE::MODER != M::MODER {
$block
.moder()
.modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (M::MODER << offset)));
if let Some(mode) = M::MODER {
$block.moder().modify(|_, w| w.moder($N).variant(mode));
}
}
}
};
Expand Down Expand Up @@ -300,43 +292,43 @@ pub trait PinMode: crate::Sealed {
// They are not part of public API.

#[doc(hidden)]
const MODER: u32 = u32::MAX;
const MODER: Option<Mode> = None;
#[doc(hidden)]
const OTYPER: Option<u32> = None;
const OTYPER: Option<OutputType> = None;
#[doc(hidden)]
const AFR: Option<u32> = None;
const AFR: Option<u8> = None;
}

impl crate::Sealed for Input {}
impl PinMode for Input {
const MODER: u32 = 0b00;
const MODER: Option<Mode> = Some(Mode::Input);
}

impl crate::Sealed for Analog {}
impl PinMode for Analog {
const MODER: u32 = 0b11;
const MODER: Option<Mode> = Some(Mode::Analog);
}

impl<Otype> crate::Sealed for Output<Otype> {}
impl PinMode for Output<OpenDrain> {
const MODER: u32 = 0b01;
const OTYPER: Option<u32> = Some(0b1);
const MODER: Option<Mode> = Some(Mode::Output);
const OTYPER: Option<OutputType> = Some(OutputType::OpenDrain);
}

impl PinMode for Output<PushPull> {
const MODER: u32 = 0b01;
const OTYPER: Option<u32> = Some(0b0);
const MODER: Option<Mode> = Some(Mode::Output);
const OTYPER: Option<OutputType> = Some(OutputType::PushPull);
}

impl<const A: u8, Otype> crate::Sealed for Alternate<A, Otype> {}
impl<const A: u8> PinMode for Alternate<A, OpenDrain> {
const MODER: u32 = 0b10;
const OTYPER: Option<u32> = Some(0b1);
const AFR: Option<u32> = Some(A as _);
const MODER: Option<Mode> = Some(Mode::Alternate);
const OTYPER: Option<OutputType> = Some(OutputType::OpenDrain);
const AFR: Option<u8> = Some(A);
}

impl<const A: u8> PinMode for Alternate<A, PushPull> {
const MODER: u32 = 0b10;
const OTYPER: Option<u32> = Some(0b0);
const AFR: Option<u32> = Some(A as _);
const MODER: Option<Mode> = Some(Mode::Alternate);
const OTYPER: Option<OutputType> = Some(OutputType::PushPull);
const AFR: Option<u8> = Some(A);
}

0 comments on commit ad969d2

Please sign in to comment.