Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/e310x-hal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
build-riscv:
strategy:
matrix:
# All generated code should be running on stable now, MRSV is 1.76.0
toolchain: [ stable, nightly, 1.76.0 ]
# All generated code should be running on stable now, MRSV is 1.79.0
toolchain: [ stable, nightly, 1.79.0 ]
include:
# Nightly is only for reference and allowed to fail
- toolchain: nightly
Expand Down Expand Up @@ -47,4 +47,4 @@ jobs:
run: cargo test --package e310x-hal
- name: Build (all features)
run: cargo test --package e310x-hal --all-features


6 changes: 3 additions & 3 deletions .github/workflows/hifive1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
build-riscv:
strategy:
matrix:
# All generated code should be running on stable now, MRSV is 1.76.0
toolchain: [nightly, stable, 1.76.0]
# All generated code should be running on stable now, MRSV is 1.79.0
toolchain: [nightly, stable, 1.79.0]
board: [hifive1, hifive1-revb, redv, lofive, lofive-r1]
include:
# Nightly is only for reference and allowed to fail
Expand Down Expand Up @@ -49,4 +49,4 @@ jobs:
run: cargo test --package hifive1 --features board-${{ matrix.board }}
- name: Build (vectored)
run: cargo test --package hifive1 --features board-${{ matrix.board }},v-trap


1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"e310x-hal",
"hifive1",
"hifive1-examples",
"hifive1-async-examples",
]
default-members = [
"e310x",
Expand Down
1 change: 1 addition & 0 deletions e310x-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Update `e310x` dependency and adapt code
- Add interrupt managing methods to `e310x-hal::gpio` module
- Add embedded-hal-async digital module support to `e310x-hal::gpio` module

## [v0.12.0] - 2024-12-10

Expand Down
8 changes: 7 additions & 1 deletion e310x-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description = "HAL for the E310x family of microcontrollers."
keywords = ["riscv", "e310", "hal"]
license = "ISC"
edition = "2021"
rust-version = "1.76"
rust-version = "1.79"

[dependencies]
embedded-hal = "1.0.0"
Expand All @@ -19,9 +19,15 @@ nb = "1.0.0"
portable-atomic = { version = "1.9", default-features = false }
riscv = { workspace = true, features = ["critical-section-single-hart"] }

# Async HAL dependencies
riscv-rt = { workspace = true, optional = true }
embedded-hal-async = { version = "1.0.0", optional = true }
critical-section = { workspace = true, optional = true }

[features]
g002 = ["e310x/g002"]
v-trap = ["e310x/v-trap"]
async = ["riscv-rt", "embedded-hal-async", "critical-section"]

[package.metadata.docs.rs]
features = ["g002"]
2 changes: 1 addition & 1 deletion e310x-hal/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.72.0 and up. It *might*
This crate is guaranteed to compile on stable Rust 1.79.0 and up. It *might*
compile with older versions but that may change in any new patch release.

## License
Expand Down
9 changes: 9 additions & 0 deletions e310x-hal/src/asynch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Asynchronous HAL for the E310x family of microcontrollers
//!
//! This is an implementation of the [`embedded-hal-async`] traits for the E310x
//! family of microcontrollers.

#![deny(missing_docs)]

pub mod digital;
pub mod prelude;
277 changes: 277 additions & 0 deletions e310x-hal/src/asynch/digital.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
//! # Digital I/O
//! # Note
//!
//! Implementation of the Async Embedded HAL I/O functionality.
//!

macro_rules! gpio_async {
($GPIOX:ident, [
$($PXi:ident: ($pxi:ident, $i:expr, $handle:ident),)+
]) => {
use core::cell::RefCell;
use core::task::{Poll, Waker};
use core::future::poll_fn;
use critical_section::Mutex;
use crate::gpio::*;
use crate::gpio::gpio0::*;
use e310x::$GPIOX;
use e310x::interrupt::ExternalInterrupt;
use embedded_hal::digital::{Error, ErrorKind, ErrorType, InputPin};
use embedded_hal_async::digital::Wait;

/// Error type for wait trait.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DigitalError {
/// Error indicating that a wait operation was already in progress.
AlreadyWaiting,
/// Other errors.
Other,
}

const N_PINS: usize = 32;
static PIN_WAKERS: Mutex<RefCell<[Option<Waker>; N_PINS]>> =
Mutex::new(RefCell::new([const{None}; N_PINS]));

impl Error for DigitalError {
fn kind(&self) -> ErrorKind {
ErrorKind::Other
}
}

/// Interrupt handler for GPIO pins.
#[inline]
fn on_irq(pin_n: usize) {
let gpio_block = unsafe { $GPIOX::steal() };
let pin_mask = 1 << pin_n;

// Disable the interrupt for the pin
unsafe{
gpio_block.high_ie().modify(|r, w| w.bits(r.bits() &! pin_mask));
gpio_block.low_ie().modify(|r, w| w.bits(r.bits() &! pin_mask));
gpio_block.rise_ie().modify(|r, w| w.bits(r.bits() &! pin_mask));
gpio_block.fall_ie().modify(|r, w| w.bits(r.bits() &! pin_mask));
}

// Wake the pin if possible
critical_section::with(|cs| {
let mut pin_wakers = PIN_WAKERS.borrow_ref_mut(cs);
if let Some(pinwaker) = pin_wakers[pin_n].take() {
pinwaker.wake();
}
});

// Clear pending pin interrupts
unsafe{
gpio_block.high_ip().write(|w| w.bits(pin_mask));
gpio_block.low_ip().write(|w| w.bits(pin_mask));
gpio_block.rise_ip().write(|w| w.bits(pin_mask));
gpio_block.fall_ip().write(|w| w.bits(pin_mask));
}
}

/// GPIO
$(
impl<MODE> ErrorType for $PXi<Input<MODE>> {
type Error = DigitalError;
}
/// Wait trait implementation
impl<MODE> Wait for $PXi<Input<MODE>> {
#[inline]
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
// If the pin is already high, no need to wait.
if self.is_high().unwrap() {
return Ok(());
}

// Prevent concurrent waiters.
if critical_section::with(|cs| {
PIN_WAKERS.borrow_ref(cs)[$i].is_some()
}){
return Err(DigitalError::AlreadyWaiting);
}

// Clear previous high interrupts for the pin.
self.clear_interrupt(EventType::High);

// Enable the high interrupt for the pin.
self.enable_interrupt(EventType::High);

// Await until an interrupt indicates that the pin has transitioned high.
poll_fn(|cx| {
if !self.is_interrupt_enabled(EventType::High) {
Poll::Ready(Ok(()))
} else {
critical_section::with(|cs| {
let mut pinwaker = PIN_WAKERS.borrow_ref_mut(cs);
pinwaker[$i] = Some(cx.waker().clone());
});
Poll::Pending
}
}).await
}

#[inline]
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
// If the pin is already low, no need to wait.
if self.is_low().unwrap() {
return Ok(());
}

// Prevent concurrent waiters.
if critical_section::with(|cs| {
PIN_WAKERS.borrow_ref(cs)[$i].is_some()
}){
return Err(DigitalError::AlreadyWaiting);
}

// Clear previous low interrupts for the pin.
self.clear_interrupt(EventType::Low);

// Enable the low interrupt for the pin.
self.enable_interrupt(EventType::Low);

// Await until an interrupt indicates that the pin has transitioned high.
poll_fn(|cx| {
if !self.is_interrupt_enabled(EventType::Low) {
Poll::Ready(Ok(()))
} else {
critical_section::with(|cs| {
let mut pinwaker = PIN_WAKERS.borrow_ref_mut(cs);
pinwaker[$i] = Some(cx.waker().clone());
});
Poll::Pending
}
}).await
}

#[inline]
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
// Prevent concurrent waiters.
if critical_section::with(|cs| {
PIN_WAKERS.borrow_ref(cs)[$i].is_some()
}){
return Err(DigitalError::AlreadyWaiting);
}

// Clear previous rising edge interrupts for the pin.
self.clear_interrupt(EventType::Rise);

// Enable the rising edge interrupt for the pin.
self.enable_interrupt(EventType::Rise);

// Await until an interrupt indicates that the pin has transitioned high.
poll_fn(|cx| {
if !self.is_interrupt_enabled(EventType::Rise) {
Poll::Ready(Ok(()))
} else {
critical_section::with(|cs| {
let mut pinwaker = PIN_WAKERS.borrow_ref_mut(cs);
pinwaker[$i] = Some(cx.waker().clone());
});
Poll::Pending
}
}).await
}

#[inline]
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
// Prevent concurrent waiters.
if critical_section::with(|cs| {
PIN_WAKERS.borrow_ref(cs)[$i].is_some()
}){
return Err(DigitalError::AlreadyWaiting);
}

// Clear previous falling edge interrupts for the pin.
self.clear_interrupt(EventType::Fall);

// Enable the falling edge interrupt for the pin.
self.enable_interrupt(EventType::Fall);

// Await until an interrupt indicates that the pin has transitioned high.
poll_fn(|cx| {
if !self.is_interrupt_enabled(EventType::Fall) {
Poll::Ready(Ok(()))
} else {
critical_section::with(|cs| {
let mut pinwaker = PIN_WAKERS.borrow_ref_mut(cs);
pinwaker[$i] = Some(cx.waker().clone());
});
Poll::Pending
}
}).await
}

#[inline]
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
// Prevent concurrent waiters.
if critical_section::with(|cs| {
PIN_WAKERS.borrow_ref(cs)[$i].is_some()
}){
return Err(DigitalError::AlreadyWaiting);
}

// Clear previous rising and falling edge interrupts for the pin.
self.clear_interrupt(EventType::BothEdges);

// Enable the rising and falling edge interrupts for the pin.
self.enable_interrupt(EventType::BothEdges);

// Await until an interrupt indicates that the pin has transitioned high.
poll_fn(|cx| {
if !self.is_interrupt_enabled(EventType::BothEdges) {
Poll::Ready(Ok(()))
} else {
critical_section::with(|cs| {
let mut pinwaker = PIN_WAKERS.borrow_ref_mut(cs);
pinwaker[$i] = Some(cx.waker().clone());
});
Poll::Pending
}
}).await
}
}

/// Pin Interrupt Handler
#[riscv_rt::external_interrupt(ExternalInterrupt::$handle)]
fn $pxi() {
on_irq($i);
}
)+
}
}

gpio_async!(Gpio0, [
Pin0: (pin0, 0, GPIO0),
Pin1: (pin1, 1, GPIO1),
Pin2: (pin2, 2, GPIO2),
Pin3: (pin3, 3, GPIO3),
Pin4: (pin4, 4, GPIO4),
Pin5: (pin5, 5, GPIO5),
Pin6: (pin6, 6, GPIO6),
Pin7: (pin7, 7, GPIO7),
Pin8: (pin8, 8, GPIO8),
Pin9: (pin9, 9, GPIO9),
Pin10: (pin10, 10, GPIO10),
Pin11: (pin11, 11, GPIO11),
Pin12: (pin12, 12, GPIO12),
Pin13: (pin13, 13, GPIO13),
Pin14: (pin14, 14, GPIO14),
Pin15: (pin15, 15, GPIO15),
Pin16: (pin16, 16, GPIO16),
Pin17: (pin17, 17, GPIO17),
Pin18: (pin18, 18, GPIO18),
Pin19: (pin19, 19, GPIO19),
Pin20: (pin20, 20, GPIO20),
Pin21: (pin21, 21, GPIO21),
Pin22: (pin22, 22, GPIO22),
Pin23: (pin23, 23, GPIO23),
Pin24: (pin24, 24, GPIO24),
Pin25: (pin25, 25, GPIO25),
Pin26: (pin26, 26, GPIO26),
Pin27: (pin27, 27, GPIO27),
Pin28: (pin28, 28, GPIO28),
Pin29: (pin29, 29, GPIO29),
Pin30: (pin30, 30, GPIO30),
Pin31: (pin31, 31, GPIO31),
]);
2 changes: 2 additions & 0 deletions e310x-hal/src/asynch/prelude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//! Prelude
pub use embedded_hal_async::digital::Wait as _eha_Wait;
1 change: 1 addition & 0 deletions e310x-hal/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ macro_rules! gpio {
}
}

#[cfg(not(feature = "async"))]
impl<MODE> ErrorType for $PXi<Input<MODE>> {
type Error = Infallible;
}
Expand Down
3 changes: 3 additions & 0 deletions e310x-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@ pub mod wdog;
#[cfg(feature = "g002")]
pub mod i2c;

#[cfg(feature = "async")]
pub mod asynch;

pub use device::DeviceResources;
Loading