Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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;
275 changes: 275 additions & 0 deletions e310x-hal/src/asynch/digital.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
//! # 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 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.
fn on_irq(pin_n: usize) {
let gpio_block = unsafe { Gpio0::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(e310x::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