implement embedded-hal 1.0.0-alpha.5 (#131)

* implement embedded-hal 1.0.0-alpha.5

* Depend on specific alpha version of embedded-hal.

* enable feature eh1_0_alpha for CI check
This commit is contained in:
Jan Niehusmann 2021-10-02 07:36:40 +02:00 committed by GitHub
parent da89888ccb
commit 2b6de3a3c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 438 additions and 1 deletions

View file

@ -19,7 +19,7 @@ jobs:
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: check command: check
args: --workspace --examples args: --workspace --examples --features eh1_0_alpha
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: test command: test

View file

@ -12,6 +12,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
cortex-m = "0.7.2" cortex-m = "0.7.2"
embedded-hal = { version = "0.2.5", features = ["unproven"] } embedded-hal = { version = "0.2.5", features = ["unproven"] }
eh1_0_alpha = { version = "=1.0.0-alpha.5", package="embedded-hal", optional=true }
embedded-time = "0.12.0" embedded-time = "0.12.0"
itertools = { version = "0.10.1", default-features = false } itertools = { version = "0.10.1", default-features = false }
nb = "1.0" nb = "1.0"

View file

@ -90,6 +90,18 @@ volatile until a 1.0.0 release.
See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of
proposed features (and known issues). proposed features (and known issues).
### Support for embedded-hal 1.0
We plan to support embedded-hal 1.0 soon after it is released.
For now, there is preliminary support for alpha versions of embedded-hal, which can
be enabled with the feature `eh1_0_alpha`. Please note that this support does not
provide any semver compatibility guarantees: With that feature activated, there
will be breaking changes even in minor versions of rp2040-hal.
Support for embedded-hal 1.0(-alpha) exists in parallel to support for
embedded-hal 0.2: Traits of both versions are implemented and can be used
at the same time.
<!-- CONTRIBUTING --> <!-- CONTRIBUTING -->
## Contributing ## Contributing

View file

@ -103,6 +103,15 @@ macro_rules! channel {
$channel $channel
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1_0_alpha::adc::nb::Channel<Adc> for Pin<$pin, FloatingInput> {
type ID = u8; // ADC channels are identified numerically
fn channel(&self) -> u8 {
$channel
}
}
}; };
} }
@ -124,6 +133,15 @@ impl Channel<Adc> for TempSense {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1_0_alpha::adc::nb::Channel<Adc> for TempSense {
type ID = u8; // ADC channels are identified numerically
fn channel(&self) -> u8 {
TEMPERATURE_SENSOR_CHANNEL
}
}
impl<WORD, PIN> OneShot<Adc, WORD, PIN> for Adc impl<WORD, PIN> OneShot<Adc, WORD, PIN> for Adc
where where
WORD: From<u16>, WORD: From<u16>,
@ -153,3 +171,34 @@ where
Ok(self.device.result.read().result().bits().into()) Ok(self.device.result.read().result().bits().into())
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<WORD, PIN> eh1_0_alpha::adc::nb::OneShot<Adc, WORD, PIN> for Adc
where
WORD: From<u16>,
PIN: eh1_0_alpha::adc::nb::Channel<Adc, ID = u8>,
{
type Error = ();
fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
let chan = PIN::channel(pin);
if chan == 4 {
self.device.cs.modify(|_, w| w.ts_en().set_bit())
}
while !self.device.cs.read().ready().bit_is_set() {
cortex_m::asm::nop();
}
self.device
.cs
.modify(|_, w| unsafe { w.ainsel().bits(chan).start_once().set_bit() });
while !self.device.cs.read().ready().bit_is_set() {
cortex_m::asm::nop();
}
Ok(self.device.result.read().result().bits().into())
}
}

View file

@ -78,6 +78,8 @@ use super::pin::{Pin, PinId, PinMode, ValidPinMode};
use super::reg::RegisterInterface; use super::reg::RegisterInterface;
use core::convert::TryFrom; use core::convert::TryFrom;
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::digital::blocking as eh1;
use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
//============================================================================== //==============================================================================
@ -541,3 +543,50 @@ impl StatefulOutputPin for DynPin {
self._is_set_low() self._is_set_low()
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1::OutputPin for DynPin {
type Error = Error;
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high()
}
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low()
}
}
#[cfg(feature = "eh1_0_alpha")]
impl eh1::InputPin for DynPin {
type Error = Error;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
self._is_high()
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
self._is_low()
}
}
#[cfg(feature = "eh1_0_alpha")]
impl eh1::ToggleableOutputPin for DynPin {
type Error = Error;
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle()
}
}
#[cfg(feature = "eh1_0_alpha")]
impl eh1::StatefulOutputPin for DynPin {
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
self._is_set_high()
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
self._is_set_low()
}
}

View file

@ -103,6 +103,8 @@ use core::convert::Infallible;
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::gpio::dynpin::DynFunction; use crate::gpio::dynpin::DynFunction;
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::digital::blocking as eh1;
use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
use core::mem::transmute; use core::mem::transmute;
@ -792,6 +794,88 @@ where
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::OutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
type Error = Infallible;
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high();
Ok(())
}
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low();
Ok(())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I> eh1::InputPin for Pin<I, ReadableOutput>
where
I: PinId,
{
type Error = Infallible;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::InputPin for Pin<I, Input<C>>
where
I: PinId,
C: InputConfig,
{
type Error = Infallible;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::ToggleableOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
type Error = Infallible;
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle();
Ok(())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::StatefulOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_high())
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_low())
}
}
//============================================================================== //==============================================================================
// Pin definitions // Pin definitions
//============================================================================== //==============================================================================

View file

@ -52,6 +52,8 @@ use crate::{
resets::SubsystemReset, resets::SubsystemReset,
typelevel::Sealed, typelevel::Sealed,
}; };
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::i2c::blocking as eh1;
use embedded_time::rate::Hertz; use embedded_time::rate::Hertz;
use hal::blocking::i2c::{Read, Write, WriteRead}; use hal::blocking::i2c::{Read, Write, WriteRead};
use rp2040_pac::{I2C0, I2C1, RESETS}; use rp2040_pac::{I2C0, I2C1, RESETS};
@ -490,6 +492,30 @@ macro_rules! hal {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<PINS> eh1::Write for I2C<$I2CX, PINS> {
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
Write::write(self, addr, bytes)
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<PINS> eh1::WriteRead for I2C<$I2CX, PINS> {
type Error = Error;
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
WriteRead::write_read(self, addr, bytes, buffer)
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<PINS> eh1::Read for I2C<$I2CX, PINS> {
type Error = Error;
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
Read::read(self, addr, buffer)
}
}
)+ )+
} }
} }

View file

@ -87,6 +87,8 @@ use crate::{
resets::SubsystemReset, resets::SubsystemReset,
typelevel::Sealed, typelevel::Sealed,
}; };
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::pwm::blocking as eh1;
use embedded_hal::PwmPin; use embedded_hal::PwmPin;
use pac::PWM; use pac::PWM;
@ -551,6 +553,38 @@ impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, A> {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<S: SliceId, M: SliceMode> eh1::PwmPin for Channel<S, M, A> {
type Duty = u16;
type Error = core::convert::Infallible;
/// We cant disable the channel without disturbing the other channel.
/// So this just sets the duty cycle to zero
fn disable(&mut self) -> Result<(), Self::Error> {
self.duty_cycle = self.regs.read_cc_a();
self.regs.write_cc_a(0);
Ok(())
}
fn enable(&mut self) -> Result<(), Self::Error> {
self.regs.write_cc_a(self.duty_cycle);
Ok(())
}
fn get_duty(&self) -> Result<Self::Duty, Self::Error> {
Ok(self.regs.read_cc_a())
}
fn get_max_duty(&self) -> Result<Self::Duty, Self::Error> {
Ok(self.regs.read_top())
}
fn set_duty(&mut self, duty: Self::Duty) -> Result<(), Self::Error> {
self.regs.write_cc_a(duty);
Ok(())
}
}
impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, B> { impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, B> {
type Duty = u16; type Duty = u16;
@ -577,6 +611,37 @@ impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, B> {
self.regs.write_cc_b(duty) self.regs.write_cc_b(duty)
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<S: SliceId, M: SliceMode> eh1::PwmPin for Channel<S, M, B> {
type Duty = u16;
type Error = core::convert::Infallible;
/// We cant disable the channel without disturbing the other channel.
/// So this just sets the duty cycle to zero
fn disable(&mut self) -> Result<(), Self::Error> {
self.duty_cycle = self.regs.read_cc_b();
self.regs.write_cc_b(0);
Ok(())
}
fn enable(&mut self) -> Result<(), Self::Error> {
self.regs.write_cc_b(self.duty_cycle);
Ok(())
}
fn get_duty(&self) -> Result<Self::Duty, Self::Error> {
Ok(self.regs.read_cc_b())
}
fn get_max_duty(&self) -> Result<Self::Duty, Self::Error> {
Ok(self.regs.read_top())
}
fn set_duty(&mut self, duty: Self::Duty) -> Result<(), Self::Error> {
self.regs.write_cc_b(duty);
Ok(())
}
}
impl<S: SliceId, M: SliceMode + ValidSliceMode<S>> Channel<S, M, A> { impl<S: SliceId, M: SliceMode + ValidSliceMode<S>> Channel<S, M, A> {
/// Capture a gpio pin and use it as pwm output for channel A /// Capture a gpio pin and use it as pwm output for channel A

View file

@ -21,6 +21,8 @@
use crate::resets::SubsystemReset; use crate::resets::SubsystemReset;
use core::{convert::Infallible, marker::PhantomData, ops::Deref}; use core::{convert::Infallible, marker::PhantomData, ops::Deref};
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::spi as eh1;
use embedded_hal::blocking::spi; use embedded_hal::blocking::spi;
use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity}; use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity};
use embedded_time::rate::*; use embedded_time::rate::*;
@ -217,6 +219,32 @@ macro_rules! impl_write {
impl<D: SpiDevice> spi::transfer::Default<$type> for Spi<Enabled, D, $nr> {} impl<D: SpiDevice> spi::transfer::Default<$type> for Spi<Enabled, D, $nr> {}
impl<D: SpiDevice> spi::write_iter::Default<$type> for Spi<Enabled, D, $nr> {} impl<D: SpiDevice> spi::write_iter::Default<$type> for Spi<Enabled, D, $nr> {}
#[cfg(feature = "eh1_0_alpha")]
impl<D: SpiDevice> eh1::nb::FullDuplex<$type> for Spi<Enabled, D, $nr> {
type Error = Infallible;
fn read(&mut self) -> Result<$type, nb::Error<Infallible>> {
if !self.is_readable() {
return Err(nb::Error::WouldBlock);
}
Ok(self.device.sspdr.read().data().bits() as $type)
}
fn write(&mut self, word: $type) -> Result<(), nb::Error<Infallible>> {
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
// is full, PL022 inhibits RX pushes, and sets a sticky flag on
// push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
if !self.is_writable() {
return Err(nb::Error::WouldBlock);
}
self.device
.sspdr
.write(|w| unsafe { w.data().bits(word as u16) });
Ok(())
}
}
)+ )+
}; };

View file

@ -77,7 +77,39 @@ impl embedded_hal::timer::CountDown for CountDown<'_> {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1_0_alpha::timer::nb::CountDown for CountDown<'_> {
type Time = embedded_time::duration::Microseconds<u64>;
type Error = &'static str;
fn start<T>(&mut self, count: T) -> Result<(), Self::Error>
where
T: Into<Self::Time>,
{
self.period = count.into();
self.next_end = Some(self.timer.get_counter().wrapping_add(self.period.0));
Ok(())
}
fn wait(&mut self) -> nb::Result<(), Self::Error> {
if let Some(end) = self.next_end {
let ts = self.timer.get_counter();
if ts >= end {
self.next_end = Some(end.wrapping_add(self.period.0));
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
} else {
panic!("CountDown is not running!");
}
}
}
impl embedded_hal::timer::Periodic for CountDown<'_> {} impl embedded_hal::timer::Periodic for CountDown<'_> {}
#[cfg(feature = "eh1_0_alpha")]
impl eh1_0_alpha::timer::Periodic for CountDown<'_> {}
impl embedded_hal::timer::Cancel for CountDown<'_> { impl embedded_hal::timer::Cancel for CountDown<'_> {
type Error = &'static str; type Error = &'static str;
@ -90,3 +122,14 @@ impl embedded_hal::timer::Cancel for CountDown<'_> {
} }
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1_0_alpha::timer::nb::Cancel for CountDown<'_> {
fn cancel(&mut self) -> Result<(), Self::Error> {
if self.next_end.is_none() {
Err("CountDown is not running.")
} else {
self.next_end = None;
Ok(())
}
}
}

View file

@ -37,6 +37,8 @@ use embedded_time::fixed_point::FixedPoint;
use embedded_time::rate::Baud; use embedded_time::rate::Baud;
use embedded_time::rate::Hertz; use embedded_time::rate::Hertz;
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::serial::nb as eh1;
use embedded_hal::serial::{Read, Write}; use embedded_hal::serial::{Read, Write};
use nb::Error::{Other, WouldBlock}; use nb::Error::{Other, WouldBlock};
@ -65,6 +67,7 @@ pub struct ReadError<'err> {
} }
/// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register" /// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register"
#[cfg_attr(feature = "eh1_0_alpha", derive(Debug))]
pub enum ReadErrorType { pub enum ReadErrorType {
/// Triggered when the FIFO (or shift-register) is overflowed. /// Triggered when the FIFO (or shift-register) is overflowed.
Overrun, Overrun,
@ -495,6 +498,23 @@ impl<D: UartDevice> Read<u8> for UartPeripheral<Enabled, D> {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<D: UartDevice> eh1::Read<u8> for UartPeripheral<Enabled, D> {
type Error = ReadErrorType;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let byte: &mut [u8] = &mut [0; 1];
match self.read_raw(byte) {
Ok(_) => Ok(byte[0]),
Err(e) => match e {
Other(inner) => Err(Other(inner.err_type)),
WouldBlock => Err(WouldBlock),
},
}
}
}
impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> { impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
type Error = Infallible; type Error = Infallible;
@ -511,6 +531,23 @@ impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl<D: UartDevice> eh1::Write<u8> for UartPeripheral<Enabled, D> {
type Error = Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.write_raw(&[word]).is_err() {
Err(WouldBlock)
} else {
Ok(())
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.transmit_flushed()
}
}
impl<D: UartDevice> fmt::Write for UartPeripheral<Enabled, D> { impl<D: UartDevice> fmt::Write for UartPeripheral<Enabled, D> {
fn write_str(&mut self, s: &str) -> fmt::Result { fn write_str(&mut self, s: &str) -> fmt::Result {
s.bytes() s.bytes()

View file

@ -35,6 +35,8 @@
//! See [examples/watchdog.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples/watchdog.rs) for a more complete example //! See [examples/watchdog.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples/watchdog.rs) for a more complete example
use crate::pac::WATCHDOG; use crate::pac::WATCHDOG;
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::watchdog::blocking as eh1;
use embedded_hal::watchdog; use embedded_hal::watchdog;
use embedded_time::{duration, fixed_point::FixedPoint}; use embedded_time::{duration, fixed_point::FixedPoint};
@ -97,6 +99,15 @@ impl watchdog::Watchdog for Watchdog {
self.load_counter(self.delay_ms) self.load_counter(self.delay_ms)
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1::Watchdog for Watchdog {
type Error = core::convert::Infallible;
fn feed(&mut self) -> Result<(), Self::Error> {
self.load_counter(self.delay_ms);
Ok(())
}
}
impl watchdog::WatchdogEnable for Watchdog { impl watchdog::WatchdogEnable for Watchdog {
type Time = duration::Microseconds; type Time = duration::Microseconds;
@ -117,9 +128,41 @@ impl watchdog::WatchdogEnable for Watchdog {
self.enable(true); self.enable(true);
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1::Enable for Watchdog {
type Error = core::convert::Infallible;
type Target = Self;
type Time = duration::Microseconds;
fn start<T: Into<Self::Time>>(mut self, period: T) -> Result<Self::Target, Self::Error> {
const MAX_PERIOD: u32 = 0xFFFFFF;
// Due to a logic error, the watchdog decrements by 2 and
// the load value must be compensated; see RP2040-E1
self.delay_ms = period.into().integer() * 2;
if self.delay_ms > MAX_PERIOD {
panic!("Period cannot exceed maximum load value of {}", MAX_PERIOD);
}
self.enable(false);
self.load_counter(self.delay_ms);
self.enable(true);
Ok(self)
}
}
impl watchdog::WatchdogDisable for Watchdog { impl watchdog::WatchdogDisable for Watchdog {
fn disable(&mut self) { fn disable(&mut self) {
self.enable(false) self.enable(false)
} }
} }
#[cfg(feature = "eh1_0_alpha")]
impl eh1::Disable for Watchdog {
type Error = core::convert::Infallible;
type Target = Self;
fn disable(self) -> Result<Self::Target, Self::Error> {
self.enable(false);
Ok(self)
}
}