Skip to content

Support for both embedded-hals (0.2.x and 1.0.0-alpha) #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Support of embedded-hal 1.0.0-alpha.6 [#388]

[#388]: https://github.com/stm32-rs/stm32f4xx-hal/pull/388

### Changed

- Add inherent impl of `embedded_hal::Pwm` methods on `Pwm`s [#439]
Expand All @@ -18,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Pwm channels now constants [#432]
- Add channel events, make Event use bitflags (simplify interrupt handling) [#425]
- reexport `digital::v2::PinState` again [#428]
- reexport `digital::v2::PinState` again
- Timer impls with time based on `fugit` moved to `fugit` module, added `Pwm` and `fugit-timer` impls [#423]

### Fixed
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ embedded-storage = "0.2"
version = "0.3"
default-features = false

[dependencies.embedded-hal-one]
version = "=1.0.0-alpha.6"
package = "embedded-hal"

[dependencies.stm32_i2s_v12x]
version = "0.2.0"
optional = true
Expand Down
16 changes: 16 additions & 0 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ macro_rules! adc_pins {
type ID = u8;
fn channel() -> u8 { $chan }
}

impl embedded_hal_one::adc::nb::Channel<pac::$adc> for $pin {
type ID = u8;
fn channel(&self) -> u8 { $chan }
}
)+
};
}
Expand Down Expand Up @@ -1070,6 +1075,17 @@ macro_rules! adc {
}
}

impl<PIN> embedded_hal_one::adc::nb::OneShot<pac::$adc_type, u16, PIN> for Adc<pac::$adc_type>
where
PIN: embedded_hal::adc::Channel<pac::$adc_type, ID=u8> + embedded_hal_one::adc::nb::Channel<pac::$adc_type, ID=u8>,
{
type Error = ();

fn read(&mut self, pin: &mut PIN) -> nb::Result<u16, Self::Error> {
self.read::<PIN>(pin)
}
}

unsafe impl PeriAddress for Adc<pac::$adc_type> {
#[inline(always)]
fn address(&self) -> u32 {
Expand Down
96 changes: 96 additions & 0 deletions src/delay/hal_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//! Delay implementation based on general-purpose 32 bit timers and System timer (SysTick).
//!
//! TIM2 and TIM5 are a general purpose 32-bit auto-reload up/downcounter with
//! a 16-bit prescaler.

use cast::u16;
use core::convert::Infallible;
use cortex_m::peripheral::SYST;
use embedded_hal_one::delay::blocking::DelayUs;

use super::{Delay, Wait};

impl DelayUs for Delay<SYST> {
type Error = Infallible;

fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
const MAX_RVR: u32 = 0x00FF_FFFF;

let mut total_rvr = us * (self.clk.0 / 8_000_000);

while total_rvr != 0 {
let current_rvr = if total_rvr <= MAX_RVR {
total_rvr
} else {
MAX_RVR
};

self.tim.set_reload(current_rvr);
self.tim.clear_current();
self.tim.enable_counter();

// Update the tracking variable while we are waiting...
total_rvr -= current_rvr;

while !self.tim.has_wrapped() {}

self.tim.disable_counter();
}

Ok(())
}

fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
self.delay_us(ms * 1_000)
}
}

impl<TIM> DelayUs for Delay<TIM>
where
Self: Wait,
{
type Error = Infallible;

/// Sleep for up to 2^32-1 microseconds (~71 minutes).
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
// Set up prescaler so that a tick takes exactly 1 µs.
//
// For example, if the clock is set to 48 MHz, with a prescaler of 48
// we'll get ticks that are 1 µs long. This means that we can write the
// delay value directly to the auto-reload register (ARR).
let psc = u16(self.clk.0 / 1_000_000).expect("Prescaler does not fit in u16");
let arr = us;
self.wait(psc, arr);

Ok(())
}

/// Sleep for up to (2^32)/2-1 milliseconds (~24 days).
/// If the `ms` value is larger than 2147483647, the code will panic.
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
// See next section for explanation why the usable range is reduced.
assert!(ms <= 2_147_483_647); // (2^32)/2-1

// Set up prescaler so that a tick takes exactly 0.5 ms.
//
// For example, if the clock is set to 48 MHz, with a prescaler of 24'000
// we'll get ticks that are 0.5 ms long. This means that we can write the
// delay value multipled by two to the auto-reload register (ARR).
//
// Note that we cannot simply use a prescaler value where the tick corresponds
// to 1 ms, because then a clock of 100 MHz would correspond to a prescaler
// value of 100'000, which doesn't fit in the 16-bit PSC register.
//
// Unfortunately this means that only one half of the full 32-bit range
// can be used, but 24 days should be plenty of usable delay time.
let psc = u16(self.clk.0 / 1000 / 2).expect("Prescaler does not fit in u16");

// Since PSC = 0.5 ms, double the value for the ARR
let arr = ms << 1;

self.wait(psc, arr);

Ok(())
}
}
1 change: 1 addition & 0 deletions src/delay/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Delays

mod hal_02;
mod hal_1;

use crate::{
pac,
Expand Down
20 changes: 20 additions & 0 deletions src/dwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ impl<T: Into<u64>> embedded_hal::blocking::delay::DelayMs<T> for Delay {
}
}

impl embedded_hal_one::delay::blocking::DelayUs for Delay {
type Error = core::convert::Infallible;

fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
// Convert us to ticks
let start = DWT::cycle_count();
let ticks = (us as u64 * self.clock.0 as u64) / 1_000_000;
Delay::delay_ticks(start, ticks);
Ok(())
}

fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
// Convert ms to ticks
let start = DWT::cycle_count();
let ticks = (ms as u64 * self.clock.0 as u64) / 1_000;
Delay::delay_ticks(start, ticks);
Ok(())
}
}

/// Very simple stopwatch which reads from DWT Cycle Counter to record timing.
///
/// Since DWT Cycle Counter is a 32-bit counter that wraps around to 0 on overflow,
Expand Down
43 changes: 24 additions & 19 deletions src/fmpi2c.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use core::ops::Deref;

use crate::gpio::{Const, OpenDrain, PinA, SetAlternate};
use crate::i2c::{Error, Scl, Sda};
use crate::i2c::{Error, Pins};
use crate::pac::{fmpi2c1, FMPI2C1, RCC};
use crate::rcc::{Enable, Reset};
use crate::time::{Hertz, U32Ext};

mod hal_02;
mod hal_1;

/// I2C FastMode+ abstraction
pub struct FMPI2c<I2C, PINS> {
Expand Down Expand Up @@ -67,12 +67,11 @@ where
}
}

impl<SCL, SDA, const SCLA: u8, const SDAA: u8> FMPI2c<FMPI2C1, (SCL, SDA)>
impl<PINS> FMPI2c<FMPI2C1, PINS>
where
SCL: PinA<Scl, FMPI2C1, A = Const<SCLA>> + SetAlternate<OpenDrain, SCLA>,
SDA: PinA<Sda, FMPI2C1, A = Const<SDAA>> + SetAlternate<OpenDrain, SDAA>,
PINS: Pins<FMPI2C1>,
{
pub fn new<M: Into<FmpMode>>(i2c: FMPI2C1, mut pins: (SCL, SDA), mode: M) -> Self {
pub fn new<M: Into<FmpMode>>(i2c: FMPI2C1, mut pins: PINS, mode: M) -> Self {
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());
Expand All @@ -84,17 +83,15 @@ where
rcc.dckcfgr2.modify(|_, w| w.fmpi2c1sel().hsi());
}

pins.0.set_alt_mode();
pins.1.set_alt_mode();
pins.set_alt_mode();

let i2c = FMPI2c { i2c, pins };
i2c.i2c_init(mode);
i2c
}

pub fn release(mut self) -> (FMPI2C1, (SCL, SDA)) {
self.pins.0.restore_mode();
self.pins.1.restore_mode();
pub fn release(mut self) -> (FMPI2C1, PINS) {
self.pins.restore_mode();

(self.i2c, self.pins)
}
Expand Down Expand Up @@ -181,21 +178,24 @@ where
// Wait until we're ready for sending
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear()
} {}

// Push out a byte of data
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });

self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;
Ok(())
}

fn recv_byte(&self) -> Result<u8, Error> {
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.rxne().bit_is_clear()
} {}

Expand Down Expand Up @@ -226,7 +226,8 @@ where
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand All @@ -253,7 +254,8 @@ where
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand All @@ -277,7 +279,8 @@ where
// Wait until the transmit buffer is empty and there hasn't been any error condition
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
} {}

Expand All @@ -289,7 +292,8 @@ where
// Wait until data was sent
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.tc().bit_is_clear()
} {}

Expand All @@ -315,7 +319,8 @@ where
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down
Loading