Skip to content
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

Add embedded-hal 1.0.0 support #58

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ name: Continuous integration

jobs:
ci-linux:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
continue-on-error: ${{ matrix.experimental || false }}
strategy:
matrix:
# All generated code should be running on stable now, MRSV is 1.60.0
rust: [nightly, stable, 1.60.0]
# All generated code should be running on stable now, MRSV is 1.62.0
rust: [nightly, stable, 1.62.0]

include:
# Nightly is only for reference and allowed to fail
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rustfmt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ name: Code formatting check
jobs:
fmt:
name: Rustfmt
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
Expand Down
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Use `portable-atomic` to allow builds on `riscv32imc-unknown-none-elf`` targets when needed.
### Added
- Added `embedded-io` dependency to fill in basic traits for `embedded-hal` version `1.0`

### Changed
- Use `portable-atomic` to allow builds on `riscv32imc-unknown-none-elf`` targets when needed
- Update `embedded-hal` version to `1.0` changing `delay`, `spi`, `i2c`, `gpio` and `pwm` modules to match
- `I2c::free` renamed to `I2c::release`
- Update `riscv` to `0.11`
- Bumped MSRV to `1.62`

### Removed
- Removed `nb` dependency

## [v0.10.0] - 2023-03-28

Expand Down
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ description = "HAL for the E310x family of microcontrollers."
keywords = ["riscv", "e310", "hal"]
license = "ISC"
edition = "2018"
rust-version = "1.59"
rust-version = "1.62"

[dependencies]
embedded-hal = { version = "0.2.6", features = ["unproven"] }
nb = "1.0.0"
riscv = { version = "0.10.1", features = ["critical-section-single-hart"] }
embedded-hal = "1.0.0"
embedded-io = "0.6.1"
riscv = { version = "0.11.1", features = ["critical-section-single-hart"] }
e310x = { version = "0.11.0", features = ["rt", "critical-section"] }

[target.'cfg(not(target_has_atomic = "32"))'.dependencies]
portable-atomic = { version = "1.4", default-features = false, features = ["unsafe-assume-single-core"] }
portable-atomic = { version = "1.6", default-features = false, features = ["unsafe-assume-single-core"] }

[features]
g002 = ["e310x/g002"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team].

## Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.60.0 and up. It *might*
This crate is guaranteed to compile on stable Rust 1.62.0 and up. It *might*
compile with older versions but that may change in any new patch release.

## License
Expand Down
93 changes: 8 additions & 85 deletions src/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::clock::Clocks;
use crate::core::clint::{MTIME, MTIMECMP};
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::delay::DelayNs;
use riscv::register::{mie, mip};

/// Machine timer (mtime) as a busyloop delay provider
Expand All @@ -17,68 +17,16 @@ impl Delay {
}
}

impl DelayUs<u32> for Delay {
fn delay_us(&mut self, us: u32) {
let ticks = (us as u64) * TICKS_PER_SECOND / 1_000_000;
impl DelayNs for Delay {
fn delay_ns(&mut self, ns: u32) {
let ticks = (ns as u64) * TICKS_PER_SECOND / 1_000_000_000;

let mtime = MTIME;
let t = mtime.mtime() + ticks;
while mtime.mtime() < t {}
}
}

// This is a workaround to allow `delay_us(42)` construction without specifying a type.
impl DelayUs<i32> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: i32) {
assert!(us >= 0);
self.delay_us(us as u32);
}
}

impl DelayUs<u16> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: u16) {
self.delay_us(u32::from(us));
}
}

impl DelayUs<u8> for Delay {
#[inline(always)]
fn delay_us(&mut self, us: u8) {
self.delay_us(u32::from(us));
}
}

impl DelayMs<u32> for Delay {
fn delay_ms(&mut self, ms: u32) {
self.delay_us(ms * 1000);
}
}

// This is a workaround to allow `delay_ms(42)` construction without specifying a type.
impl DelayMs<i32> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: i32) {
assert!(ms >= 0);
self.delay_ms(ms as u32);
}
}

impl DelayMs<u16> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: u16) {
self.delay_ms(u32::from(ms));
}
}

impl DelayMs<u8> for Delay {
#[inline(always)]
fn delay_ms(&mut self, ms: u8) {
self.delay_ms(u32::from(ms));
}
}

/// Machine timer (mtime) as a sleep delay provider using mtimecmp
pub struct Sleep {
clock_freq: u32,
Expand All @@ -95,9 +43,9 @@ impl Sleep {
}
}

impl DelayMs<u32> for Sleep {
fn delay_ms(&mut self, ms: u32) {
let ticks = (ms as u64) * (self.clock_freq as u64) / 1000;
impl DelayNs for Sleep {
fn delay_ns(&mut self, ns: u32) {
let ticks = (ns as u64) * (self.clock_freq as u64) / 1_000_000_000;
let t = MTIME.mtime() + ticks;

self.mtimecmp.set_mtimecmp(t);
Expand All @@ -112,9 +60,7 @@ impl DelayMs<u32> for Sleep {
// after which empty handler gets called and we go into the
// next iteration of this loop
loop {
unsafe {
riscv::asm::wfi();
}
riscv::asm::wfi();

// check if we got the right interrupt cause, otherwise just loop back to wfi
if mip::read().mtimer() {
Expand All @@ -128,26 +74,3 @@ impl DelayMs<u32> for Sleep {
}
}
}

// This is a workaround to allow `delay_ms(42)` construction without specifying a type.
impl DelayMs<i32> for Sleep {
#[inline(always)]
fn delay_ms(&mut self, ms: i32) {
assert!(ms >= 0);
self.delay_ms(ms as u32);
}
}

impl DelayMs<u16> for Sleep {
#[inline(always)]
fn delay_ms(&mut self, ms: u16) {
self.delay_ms(u32::from(ms));
}
}

impl DelayMs<u8> for Sleep {
#[inline(always)]
fn delay_ms(&mut self, ms: u8) {
self.delay_ms(u32::from(ms));
}
}
29 changes: 9 additions & 20 deletions src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ macro_rules! gpio {
use core::marker::PhantomData;
use core::convert::Infallible;

use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin,
ToggleableOutputPin};
use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin};
use e310x::$GPIOX;
use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert,
NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess};
Expand Down Expand Up @@ -189,6 +188,10 @@ macro_rules! gpio {
const INDEX: usize = $i;
}

impl<MODE> embedded_hal::digital::ErrorType for $PXi<MODE> {
type Error = Infallible;
}

impl<MODE> $PXi<MODE> {
/// Configures the pin to serve as alternate function 0 (AF0)
pub fn into_iof0(self) -> $PXi<IOF0<NoInvert>> {
Expand Down Expand Up @@ -280,31 +283,27 @@ macro_rules! gpio {
}

impl<MODE> InputPin for $PXi<Input<MODE>> {
type Error = Infallible;

fn is_high(&self) -> Result<bool, Infallible> {
fn is_high(&mut self) -> Result<bool, Infallible> {
Ok($GPIOX::input_value(Self::INDEX))

}

fn is_low(&self) -> Result<bool, Infallible> {
fn is_low(&mut self) -> Result<bool, Infallible> {
Ok(!self.is_high()?)
}
}

impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Infallible> {
fn is_set_high(&mut self) -> Result<bool, Infallible> {
Ok($GPIOX::input_value(Self::INDEX))
}

fn is_set_low(&self) -> Result<bool, Infallible> {
fn is_set_low(&mut self) -> Result<bool, Infallible> {
Ok(!self.is_set_high()?)
}
}

impl<MODE> OutputPin for $PXi<Output<MODE>> {
type Error = Infallible;

fn set_high(&mut self) -> Result<(), Infallible> {
$GPIOX::set_output_value(Self::INDEX, true);
Ok(())
Expand All @@ -315,16 +314,6 @@ macro_rules! gpio {
Ok(())
}
}

impl<MODE> ToggleableOutputPin for $PXi<Output<MODE>> {
type Error = Infallible;

/// Toggles the pin state.
fn toggle(&mut self) -> Result<(), Infallible> {
$GPIOX::toggle_pin(Self::INDEX);
Ok(())
}
}
)+
}
}
Expand Down
49 changes: 35 additions & 14 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::time::Bps;
use core::mem;
use core::ops::Deref;
use e310x::{i2c0, I2C0};
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
use embedded_hal::i2c::{ErrorKind, ErrorType, I2c as I2cTrait, Operation};

/// SDA pin - DO NOT IMPLEMENT THIS TRAIT
pub unsafe trait SdaPin<I2C> {}
Expand All @@ -27,7 +27,7 @@ unsafe impl<T> SdaPin<I2C0> for gpio0::Pin12<IOF0<T>> {}
unsafe impl<T> SclPin<I2C0> for gpio0::Pin13<IOF0<T>> {}

/// I2C error
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Error {
/// Invalid peripheral state
InvalidState,
Expand Down Expand Up @@ -98,7 +98,7 @@ impl<SDA, SCL> I2c<I2C0, (SDA, SCL)> {

impl<I2C, PINS> I2c<I2C, PINS> {
/// Releases the I2C peripheral and associated pins
pub fn free(self) -> (I2C, PINS) {
pub fn release(self) -> (I2C, PINS) {
(self.i2c, self.pins)
}
}
Expand Down Expand Up @@ -179,9 +179,23 @@ impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> I2c<I2C, PINS> {
const FLAG_READ: u8 = 1;
const FLAG_WRITE: u8 = 0;

impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> Read for I2c<I2C, PINS> {
// e-h 1.0

impl embedded_hal::i2c::Error for Error {
fn kind(&self) -> ErrorKind {
match *self {
Error::ArbitrationLost => ErrorKind::ArbitrationLoss,
Error::NoAck => ErrorKind::NoAcknowledge(embedded_hal::i2c::NoAcknowledgeSource::Data),
Error::InvalidState => ErrorKind::Other,
}
}
}

impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> ErrorType for I2c<I2C, PINS> {
type Error = Error;
}

impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> I2cTrait for I2c<I2C, PINS> {
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.reset();

Expand Down Expand Up @@ -212,10 +226,6 @@ impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> Read for I2c<I2C, PINS> {
}
Ok(())
}
}

impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> Write for I2c<I2C, PINS> {
type Error = Error;

fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.reset();
Expand Down Expand Up @@ -244,10 +254,6 @@ impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> Write for I2c<I2C, PINS> {
}
Ok(())
}
}

impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> WriteRead for I2c<I2C, PINS> {
type Error = Error;

fn write_read(
&mut self,
Expand All @@ -262,9 +268,9 @@ impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> WriteRead for I2c<I2C, PINS
}

if !bytes.is_empty() && buffer.is_empty() {
self.write(address, bytes)
I2cTrait::write(self, address, bytes)
} else if !buffer.is_empty() && bytes.is_empty() {
self.read(address, buffer)
I2cTrait::read(self, address, buffer)
} else if bytes.is_empty() && buffer.is_empty() {
Ok(())
} else {
Expand Down Expand Up @@ -308,4 +314,19 @@ impl<I2C: Deref<Target = i2c0::RegisterBlock>, PINS> WriteRead for I2c<I2C, PINS
Ok(())
}
}

fn transaction(
&mut self,
address: u8,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
for op in operations {
match op {
Operation::Read(buf) => I2cTrait::read(self, address, buf)?,
Operation::Write(buf) => I2cTrait::write(self, address, buf)?,
}
}

Ok(())
}
}
6 changes: 0 additions & 6 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,3 @@ pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt;
pub use crate::stdout::Write as _e310x_hal_stdout_Write;
pub use crate::time::U32Ext as _e310x_hal_time_U32Ext;
pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt;
pub use embedded_hal::digital::v2::{
InputPin as _embedded_hal_digital_v2_InputPin, OutputPin as _embedded_hal_digital_v2_OutputPin,
StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin,
ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin,
};
pub use embedded_hal::prelude::*;
Loading
Loading