Skip to content

Commit

Permalink
embedded-io implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
romancardenas committed Dec 2, 2024
1 parent df544aa commit 9ff56af
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 98 deletions.
9 changes: 5 additions & 4 deletions e310x-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ edition = "2021"
rust-version = "1.76"

[dependencies]
embedded-hal = { version = "1.0.0" }
embedded-hal-nb = { version = "1.0.0" }
nb = "1.0.0"
riscv = { version = "0.12.1", features = ["critical-section-single-hart"] }
embedded-hal = "1.0.0"
embedded-hal-nb = "1.0.0"
embedded-io = "0.6.1"
e310x = { path = "../e310x", version = "0.12.0", features = ["rt", "critical-section"] }
nb = "1.0.0"
portable-atomic = { version = "1.9", default-features = false}
riscv = { version = "0.12.1", features = ["critical-section-single-hart"] }

[features]
g002 = ["e310x/g002"]
Expand Down
6 changes: 5 additions & 1 deletion e310x-hal/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub use e310x::interrupt::{
PriorityNumber,
};
pub use embedded_hal::{
self,
delay::DelayNs,
digital::{InputPin, OutputPin, StatefulOutputPin},
i2c::I2c as _embedded_hal_i2c_I2c,
Expand All @@ -19,6 +20,9 @@ pub use embedded_hal::{
};

pub use embedded_hal_nb::{
serial::{Read, Write},
self,
serial::{Read as _embedded_hal_nb_Read, Write as _embedded_hal_nb_Write},
spi::FullDuplex,
};

pub use embedded_io;
137 changes: 116 additions & 21 deletions e310x-hal/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
use core::ops::Deref;
use e310x::{uart0, Uart0, Uart1};
use embedded_hal_nb::serial::{ErrorKind, ErrorType, Read, Write};
use nb;
use embedded_hal_nb::serial;

use crate::{clock::Clocks, time::Bps};

Expand Down Expand Up @@ -73,12 +72,17 @@ impl<UART, PIN> Rx<UART, PIN> {
}
}

impl<UART: UartX, PIN: RxPin<UART>> ErrorType for Rx<UART, PIN> {
type Error = ErrorKind;
impl<UART: UartX, PIN: RxPin<UART>> serial::ErrorType for Rx<UART, PIN> {
type Error = serial::ErrorKind;
}

impl<UART: UartX, PIN: RxPin<UART>> Read for Rx<UART, PIN> {
fn read(&mut self) -> nb::Result<u8, ErrorKind> {
impl<UART: UartX, PIN: RxPin<UART>> embedded_io::ErrorType for Rx<UART, PIN> {
type Error = embedded_io::ErrorKind;
}

impl<UART: UartX, PIN: RxPin<UART>> serial::Read for Rx<UART, PIN> {
#[inline]
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let rxdata = self.uart.rxdata().read();

if rxdata.empty().bit_is_set() {
Expand All @@ -89,6 +93,28 @@ impl<UART: UartX, PIN: RxPin<UART>> Read for Rx<UART, PIN> {
}
}

impl<UART: UartX, PIN: RxPin<UART>> embedded_io::Read for Rx<UART, PIN> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
buf[0] = nb::block!(serial::Read::read(self)).unwrap(); // first byte may block
let mut count = 1;
for byte in buf.iter_mut().skip(1) {
match serial::Read::read(self) {
Ok(b) => {
*byte = b;
count += 1
}
Err(nb::Error::WouldBlock) => break,
_ => unreachable!(),
}
}
Ok(count)
}
}

/// Serial transmitter half
pub struct Tx<UART, PIN> {
uart: UART,
Expand All @@ -102,23 +128,34 @@ impl<UART, PIN> Tx<UART, PIN> {
}
}

impl<UART: UartX, PIN: TxPin<UART>> ErrorType for Tx<UART, PIN> {
type Error = ErrorKind;
impl<UART: UartX, PIN: TxPin<UART>> Tx<UART, PIN> {
/// Returns true if the transmit buffer is full
fn is_buffer_full(&self) -> bool {
self.uart.txdata().read().full().bit_is_set()
}
}

impl<UART: UartX, PIN: TxPin<UART>> Write for Tx<UART, PIN> {
fn write(&mut self, byte: u8) -> nb::Result<(), ErrorKind> {
let txdata = self.uart.txdata().read();
impl<UART: UartX, PIN: TxPin<UART>> serial::ErrorType for Tx<UART, PIN> {
type Error = serial::ErrorKind;
}

if txdata.full().bit_is_set() {
Err(::nb::Error::WouldBlock)
impl<UART: UartX, PIN: TxPin<UART>> embedded_io::ErrorType for Tx<UART, PIN> {
type Error = embedded_io::ErrorKind;
}

impl<UART: UartX, PIN: TxPin<UART>> serial::Write for Tx<UART, PIN> {
#[inline]
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
if self.is_buffer_full() {
Err(nb::Error::WouldBlock)
} else {
self.uart.txdata().write(|w| unsafe { w.data().bits(byte) });
Ok(())
}
}

fn flush(&mut self) -> nb::Result<(), ErrorKind> {
#[inline]
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.uart.ip().read().txwm().bit_is_set() {
// FIFO count is below the receive watermark (1)
Ok(())
Expand All @@ -128,6 +165,38 @@ impl<UART: UartX, PIN: TxPin<UART>> Write for Tx<UART, PIN> {
}
}

impl<UART: UartX, PIN: TxPin<UART>> embedded_io::WriteReady for Tx<UART, PIN> {
#[inline]
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(!self.is_buffer_full())
}
}

impl<UART: UartX, PIN: TxPin<UART>> embedded_io::Write for Tx<UART, PIN> {
#[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
nb::block!(serial::Write::write(self, buf[0])).unwrap(); // first byte may block
let mut count = 1;
for byte in buf.iter().skip(1) {
match serial::Write::write(self, *byte) {
Ok(()) => count += 1,
Err(nb::Error::WouldBlock) => break,
_ => unreachable!(),
}
}
Ok(count)
}

#[inline]
fn flush(&mut self) -> Result<(), Self::Error> {
nb::block!(serial::Write::flush(self)).unwrap();
Ok(())
}
}

/// Serial abstraction
pub struct Serial<UART, TX, RX> {
uart: UART,
Expand Down Expand Up @@ -186,22 +255,48 @@ impl<UART: UartX, TX: TxPin<UART>, RX: RxPin<UART>> Serial<UART, TX, RX> {
}
}

impl<UART, TX, RX> ErrorType for Serial<UART, TX, RX> {
type Error = ErrorKind;
impl<UART: UartX, TX, RX> serial::ErrorType for Serial<UART, TX, RX> {
type Error = serial::ErrorKind;
}

impl<UART: UartX, TX, RX: RxPin<UART>> Read for Serial<UART, TX, RX> {
fn read(&mut self) -> nb::Result<u8, ErrorKind> {
impl<UART: UartX, TX, RX: RxPin<UART>> serial::Read for Serial<UART, TX, RX> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}

impl<UART: UartX, TX: TxPin<UART>, RX> Write for Serial<UART, TX, RX> {
fn write(&mut self, byte: u8) -> nb::Result<(), ErrorKind> {
impl<UART: UartX, TX: TxPin<UART>, RX> serial::Write for Serial<UART, TX, RX> {
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
self.tx.write(byte)
}

fn flush(&mut self) -> nb::Result<(), ErrorKind> {
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
}

impl<UART, TX, RX> embedded_io::ErrorType for Serial<UART, TX, RX> {
type Error = embedded_io::ErrorKind;
}

impl<UART: UartX, TX, RX: RxPin<UART>> embedded_io::Read for Serial<UART, TX, RX> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.read(buf)
}
}

impl<UART: UartX, TX: TxPin<UART>, RX> embedded_io::WriteReady for Serial<UART, TX, RX> {
fn write_ready(&mut self) -> Result<bool, Self::Error> {
self.tx.write_ready()
}
}

impl<UART: UartX, TX: TxPin<UART>, RX> embedded_io::Write for Serial<UART, TX, RX> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.write(buf)
}

fn flush(&mut self) -> Result<(), Self::Error> {
self.tx.flush()
}
}
Expand Down
13 changes: 10 additions & 3 deletions e310x-hal/src/spi/bus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use embedded_hal::spi::{self, ErrorKind, ErrorType, Phase, Polarity};
use embedded_hal::{
delay::DelayNs,
spi::{self, ErrorKind, ErrorType, Phase, Polarity},
};
use embedded_hal_nb::spi::FullDuplex;

use super::{Pins, PinsFull, PinsNoCS, SharedBus, SpiConfig, SpiExclusiveDevice, SpiX};
Expand Down Expand Up @@ -76,8 +79,12 @@ impl<SPI: SpiX, PINS: Pins<SPI>> SpiBus<SPI, PINS> {
}

/// Create a new [`SpiExclusiveDevice`] for exclusive use on this bus
pub fn new_device(self, config: &SpiConfig) -> SpiExclusiveDevice<SPI, PINS> {
SpiExclusiveDevice::new(self, config)
pub fn new_device<D: DelayNs>(
self,
config: &SpiConfig,
delay: D,
) -> SpiExclusiveDevice<SPI, PINS, D> {
SpiExclusiveDevice::new(self, config, delay)
}

/// Configure the [`SpiBus`] with given [`SpiConfig`]
Expand Down
51 changes: 37 additions & 14 deletions e310x-hal/src/spi/exclusive_device.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,54 @@
use embedded_hal::spi::{ErrorKind, ErrorType, Operation, SpiBus, SpiDevice};
use embedded_hal::{
delay::DelayNs,
spi::{self, ErrorType, Operation, SpiBus, SpiDevice},
};

use crate::spi::SpiConfig;

use super::{Pins, PinsFull, SpiBus as Bus, SpiX};

/// SPI exclusive device abstraction
pub struct SpiExclusiveDevice<SPI, PINS> {
/// SPI exclusive device abstraction with delay support.
pub struct SpiExclusiveDevice<SPI, PINS, D> {
bus: Bus<SPI, PINS>,
delay: D,
}

impl<SPI: SpiX, PINS: Pins<SPI>> SpiExclusiveDevice<SPI, PINS> {
/// Create [`SpiExclusiveDevice`] using existing [`SpiBus`](Bus) with the given [`SpiConfig`]
pub fn new(mut bus: Bus<SPI, PINS>, config: &SpiConfig) -> Self {
impl<SPI, PINS, D> SpiExclusiveDevice<SPI, PINS, D>
where
SPI: SpiX,
PINS: Pins<SPI>,
D: DelayNs,
{
/// Create [`SpiDelayedExclusiveDevice`] using existing [`SpiBus`](Bus) with the given [`SpiConfig`]
pub fn new(mut bus: Bus<SPI, PINS>, config: &SpiConfig, delay: D) -> Self {
// Safety: valid CS index
unsafe { bus.configure(config, PINS::CS_INDEX) };

Self { bus }
Self { bus, delay }
}

/// Releases the Bus back deconstructing it
pub fn release(self) -> (SPI, PINS) {
self.bus.release()
/// Releases the Bus and Delay back deconstructing it
pub fn release(self) -> (SPI, PINS, D) {
let (spi, pins) = self.bus.release();
(spi, pins, self.delay)
}
}

impl<SPI: SpiX, PINS: Pins<SPI>> ErrorType for SpiExclusiveDevice<SPI, PINS> {
type Error = ErrorKind;
impl<SPI, PINS, D> ErrorType for SpiExclusiveDevice<SPI, PINS, D>
where
SPI: SpiX,
PINS: Pins<SPI>,
D: DelayNs,
{
type Error = spi::ErrorKind;
}

impl<SPI: SpiX, PINS: PinsFull<SPI>> SpiDevice for SpiExclusiveDevice<SPI, PINS> {
impl<SPI, PINS, D> SpiDevice for SpiExclusiveDevice<SPI, PINS, D>
where
SPI: SpiX,
PINS: PinsFull<SPI>,
D: DelayNs,
{
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
self.bus.start_frame();

Expand All @@ -39,7 +59,10 @@ impl<SPI: SpiX, PINS: PinsFull<SPI>> SpiDevice for SpiExclusiveDevice<SPI, PINS>
Operation::Write(write) => self.bus.write(write),
Operation::Transfer(read, write) => self.bus.transfer(read, write),
Operation::TransferInPlace(read_write) => self.bus.transfer_in_place(read_write),
Operation::DelayNs(_ns) => todo!(),
Operation::DelayNs(ns) => {
self.delay.delay_ns(*ns);
Ok(())
}
};
if res.is_err() {
break;
Expand Down
9 changes: 6 additions & 3 deletions e310x-hal/src/spi/shared_bus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::cell::RefCell;
use core::ops::Deref;
use embedded_hal::delay::DelayNs;
use riscv::interrupt;

use super::{PinCS, PinsNoCS, SpiBus, SpiConfig, SpiSharedDevice, SpiX};
Expand All @@ -18,15 +19,17 @@ where
}

/// Create a new shared device on this SPI bus.
pub fn new_device<'bus, CS>(
pub fn new_device<'bus, CS, D>(
&'bus self,
cs: CS,
config: &SpiConfig,
) -> SpiSharedDevice<'bus, SPI, PINS, CS>
delay: D,
) -> SpiSharedDevice<'bus, SPI, PINS, CS, D>
where
CS: PinCS<SPI>,
D: DelayNs,
{
SpiSharedDevice::new(self, cs, config)
SpiSharedDevice::new(self, cs, config, delay)
}
}

Expand Down
Loading

0 comments on commit 9ff56af

Please sign in to comment.