Embedded-Hal PR - incoorparate e-hal master changes in spi / i2c / gpio / delay (#224)

* embedded-hal::delay no longer returns Error

* embedded_hal::digital add generic GpioError

* spi: init work: from closure to Operation pattern

* first full implementation

* i2c: remove iter fn droped by e-hal master

* make ci work by temp. refere to e-hal master

* more ci fix

* make clippy happy

* more ci fighting

* gpio: cursed repair of ulp_processor

* fmt

* spi: repair example + get rid of generic's

* dep: change to new e-hal release

* fix e-hal 0.2 comp &  fix bus

* fmt

* clippy

* remove debug artifacts

* test ci with e-hal-nb-alpha.1

* e-hal-nb to alpha.2

* modified comments

* impl e-hal delay to general purpose provider

* use embedded_hal_error macro for riscv-ulp-hal

* typo

* impl pwm alpha10

* fixed wrong return error on async gpio

* duplicated impl error macro for ulp
This commit is contained in:
Frederick Vollbrecht 2023-05-08 19:59:45 +02:00 committed by GitHub
parent b388e67e1f
commit b739c46b12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 490 additions and 225 deletions

View File

@ -23,16 +23,16 @@ nightly = ["embedded-hal-async"]
[dependencies]
nb = "1.0.0"
embedded-can = "0.4.1"
embedded-hal = "=1.0.0-alpha.9"
embedded-hal = "=1.0.0-alpha.10"
embedded-hal-0-2 = { package = "embedded-hal", version = "0.2.7", features = ["unproven"] }
embedded-hal-nb = "=1.0.0-alpha.1"
embedded-hal-nb = "=1.0.0-alpha.2"
esp-idf-sys = { version = "0.32.1", optional = true, default-features = false, features = ["native"] }
critical-section = { version = "1.1", optional = true }
heapless = "0.7"
embassy-sync = { version = "0.1", optional = true }
edge-executor = { version = "0.3", optional = true, default-features = false }
enumset = { version = "1", default-features = false }
embedded-hal-async = { version = "0.2.0-alpha.0", optional = true }
embedded-hal-async = { version = "0.2.0-alpha.1", optional = true }
futures-util = { version = "0.3", default-features = false }
[build-dependencies]

View File

@ -12,6 +12,7 @@
//! This example transfers data via SPI.
//! Connect SDI and SDO pins to see the outgoing data is read as incoming data.
use embedded_hal::spi::Operation;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::prelude::*;
@ -42,16 +43,23 @@ fn main() -> anyhow::Result<()> {
let mut read = [0u8; 4];
let write = [0xde, 0xad, 0xbe, 0xef];
let mut in_place_buf = [0xde, 0xad, 0xbe, 0xef];
loop {
// we are using thread::sleep here to make sure the watchdog isn't triggered
FreeRtos::delay_ms(500);
device_1.transfer(&mut read, &write)?;
println!("Device 1: Wrote {write:x?}, read {read:x?}");
println!("Device 2: To write {in_place_buf:x?} ... ");
device_2.transaction(|bus| bus.transfer_in_place(&mut in_place_buf))?;
println!("... read {in_place_buf:x?}");
let write_buf = [0xde, 0xad, 0xbe, 0xef];
let mut write_in_place_buf = [0xde, 0xad, 0xbe, 0xef];
let mut read_buf = [0; 8];
println!("Device 2: To write {write_in_place_buf:x?} ... ");
// cascade multiple operations with different buffer length into one transaction
device_2.transaction(&mut [
Operation::Write(&write_buf),
Operation::TransferInPlace(&mut write_in_place_buf),
Operation::Read(&mut read_buf),
])?;
println!("... read {write_in_place_buf:x?}");
}
}

View File

@ -23,6 +23,16 @@ impl Delay {
}
}
impl embedded_hal::delay::DelayUs for Delay {
fn delay_us(&mut self, us: u32) {
Delay::delay_us(us)
}
fn delay_ms(&mut self, ms: u32) {
Delay::delay_ms(ms)
}
}
impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Delay {
fn delay_us(&mut self, us: u16) {
Delay::delay_us(us as _);

View File

@ -4,7 +4,6 @@
//! use [`Delay`]. Otherwise use [`Ets`] for delays <10ms and
//! [`FreeRtos`] for delays >=10ms.
use core::convert::Infallible;
use core::time::Duration;
use esp_idf_sys::*;
@ -123,18 +122,12 @@ impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for Ets {
}
impl embedded_hal::delay::DelayUs for Ets {
type Error = Infallible;
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
Ets::delay_us(us);
Ok(())
fn delay_us(&mut self, us: u32) {
Ets::delay_us(us)
}
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
Ets::delay_ms(ms);
Ok(())
fn delay_ms(&mut self, ms: u32) {
Ets::delay_ms(ms)
}
}
@ -199,17 +192,11 @@ impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for FreeRtos {
}
impl embedded_hal::delay::DelayUs for FreeRtos {
type Error = Infallible;
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
FreeRtos::delay_us(us);
Ok(())
fn delay_us(&mut self, us: u32) {
FreeRtos::delay_us(us)
}
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
FreeRtos::delay_ms(ms);
Ok(())
fn delay_ms(&mut self, ms: u32) {
FreeRtos::delay_ms(ms)
}
}

View File

@ -1107,8 +1107,19 @@ where
}
}
use crate::embedded_hal_error;
embedded_hal_error!(
GpioError,
embedded_hal::digital::Error,
embedded_hal::digital::ErrorKind
);
fn to_gpio_err(err: EspError) -> GpioError {
GpioError::other(err)
}
impl<'d, T: Pin, MODE> embedded_hal::digital::ErrorType for PinDriver<'d, T, MODE> {
type Error = EspError;
type Error = GpioError;
}
impl<'d, T: Pin, MODE> embedded_hal::digital::InputPin for PinDriver<'d, T, MODE>
@ -1128,14 +1139,14 @@ impl<'d, T: Pin, MODE> embedded_hal_0_2::digital::v2::OutputPin for PinDriver<'d
where
MODE: OutputMode,
{
type Error = EspError;
type Error = GpioError;
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_level(Level::High)
self.set_level(Level::High).map_err(to_gpio_err)
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_level(Level::Low)
self.set_level(Level::Low).map_err(to_gpio_err)
}
}
@ -1144,11 +1155,11 @@ where
MODE: OutputMode,
{
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_level(Level::High)
self.set_level(Level::High).map_err(to_gpio_err)
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_level(Level::Low)
self.set_level(Level::Low).map_err(to_gpio_err)
}
}
@ -1195,6 +1206,7 @@ where
{
fn toggle(&mut self) -> Result<(), Self::Error> {
self.set_level(Level::from(!bool::from(self.get_output_level())))
.map_err(to_gpio_err)
}
}
@ -1379,27 +1391,27 @@ macro_rules! pin {
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))]
impl<T: Pin, MODE: InputMode> PinDriver<'_, T, MODE> {
pub async fn wait_for_high(&mut self) -> Result<(), EspError> {
pub async fn wait_for_high(&mut self) -> Result<(), GpioError> {
InputFuture::new(self, InterruptType::HighLevel)?.await;
Ok(())
}
pub async fn wait_for_low(&mut self) -> Result<(), EspError> {
pub async fn wait_for_low(&mut self) -> Result<(), GpioError> {
InputFuture::new(self, InterruptType::LowLevel)?.await;
Ok(())
}
pub async fn wait_for_rising_edge(&mut self) -> Result<(), EspError> {
pub async fn wait_for_rising_edge(&mut self) -> Result<(), GpioError> {
InputFuture::new(self, InterruptType::PosEdge)?.await;
Ok(())
}
pub async fn wait_for_falling_edge(&mut self) -> Result<(), EspError> {
pub async fn wait_for_falling_edge(&mut self) -> Result<(), GpioError> {
InputFuture::new(self, InterruptType::NegEdge)?.await;
Ok(())
}
pub async fn wait_for_any_edge(&mut self) -> Result<(), EspError> {
pub async fn wait_for_any_edge(&mut self) -> Result<(), GpioError> {
InputFuture::new(self, InterruptType::AnyEdge)?.await;
Ok(())
}
@ -1453,23 +1465,23 @@ mod asynch {
mod eha_wait_impl {
use super::*;
impl<T: Pin, MODE: InputMode> embedded_hal_async::digital::Wait for PinDriver<'_, T, MODE> {
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
async fn wait_for_high(&mut self) -> Result<(), GpioError> {
self.wait_for_high().await
}
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
async fn wait_for_low(&mut self) -> Result<(), GpioError> {
self.wait_for_low().await
}
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
async fn wait_for_rising_edge(&mut self) -> Result<(), GpioError> {
self.wait_for_rising_edge().await
}
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
async fn wait_for_falling_edge(&mut self) -> Result<(), GpioError> {
self.wait_for_falling_edge().await
}
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
async fn wait_for_any_edge(&mut self) -> Result<(), GpioError> {
self.wait_for_any_edge().await
}
}

View File

@ -378,25 +378,6 @@ impl<'d> embedded_hal::i2c::I2c<embedded_hal::i2c::SevenBitAddress> for I2cDrive
I2cDriver::write_read(self, addr, bytes, buffer, BLOCK).map_err(to_i2c_err)
}
fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
todo!()
}
fn write_iter_read<B>(
&mut self,
_address: u8,
_bytes: B,
_buffer: &mut [u8],
) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
todo!()
}
fn transaction(
&mut self,
address: u8,
@ -404,13 +385,6 @@ impl<'d> embedded_hal::i2c::I2c<embedded_hal::i2c::SevenBitAddress> for I2cDrive
) -> Result<(), Self::Error> {
I2cDriver::transaction(self, address, operations, BLOCK).map_err(to_i2c_err)
}
fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
where
O: IntoIterator<Item = embedded_hal::i2c::Operation<'a>>,
{
todo!()
}
}
fn to_i2c_err(err: EspError) -> I2cError {

View File

@ -45,6 +45,12 @@ const IDLE_LEVEL: u32 = 0;
static FADE_FUNC_INSTALLED: AtomicBool = AtomicBool::new(false);
static FADE_FUNC_INSTALLED_CS: CriticalSection = CriticalSection::new();
crate::embedded_hal_error!(
PwmError,
embedded_hal::pwm::Error,
embedded_hal::pwm::ErrorKind
);
/// Types for configuring the LED Control peripheral
pub mod config {
use super::*;
@ -310,31 +316,46 @@ impl<'d> Drop for LedcDriver<'d> {
unsafe impl<'d> Send for LedcDriver<'d> {}
// PwmPin temporarily removed from embedded-hal-1.0.alpha7 in anticipation of e-hal 1.0 release
// impl<'d> embedded_hal::pwm::blocking::PwmPin for LedcDriver<'d> {
// type Duty = Duty;
// type Error = EspError;
impl<'d> embedded_hal::pwm::ErrorType for LedcDriver<'d> {
type Error = PwmError;
}
// fn disable(&mut self) -> Result<(), Self::Error> {
// self.disable()
// }
fn to_pwm_err(err: EspError) -> PwmError {
PwmError::other(err)
}
// fn enable(&mut self) -> Result<(), Self::Error> {
// self.enable()
// }
impl<'d> embedded_hal::pwm::SetDutyCycle for LedcDriver<'d> {
fn get_max_duty_cycle(&self) -> u16 {
let duty = self.get_max_duty();
let duty_cap: u16 = if duty > u16::MAX as u32 {
u16::MAX
} else {
duty as u16
};
duty_cap
}
// fn get_duty(&self) -> Result<Self::Duty, Self::Error> {
// Ok(self.get_duty())
// }
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), PwmError> {
self.set_duty(duty as u32).map_err(to_pwm_err)
}
// fn get_max_duty(&self) -> Result<Self::Duty, Self::Error> {
// Ok(self.get_max_duty())
// }
fn set_duty_cycle_fully_on(&mut self) -> Result<(), PwmError> {
self.set_duty(self.get_max_duty()).map_err(to_pwm_err)
}
// fn set_duty(&mut self, duty: Duty) -> Result<(), Self::Error> {
// self.set_duty(duty)
// }
// }
fn set_duty_cycle_fully_off(&mut self) -> Result<(), PwmError> {
self.set_duty(0).map_err(to_pwm_err)
}
fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), PwmError> {
let duty = num as u32 * self.get_max_duty_cycle() as u32 / denom as u32;
self.set_duty_cycle(duty as u16)
}
fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), PwmError> {
self.set_duty_cycle_fraction(percent as u16, 100)
}
}
impl<'d> embedded_hal_0_2::PwmPin for LedcDriver<'d> {
type Duty = Duty;

View File

@ -79,6 +79,7 @@ pub use crate::riscv_ulp_hal::delay;
//
// Example:
// embedded_hal_error!(I2cError, embedded_hal::i2c::Error, embedded_hal::i2c::ErrorKind)
#[cfg(not(feature = "riscv-ulp-hal"))]
#[allow(unused_macros)]
macro_rules! embedded_hal_error {
($error:ident, $errortrait:ty, $kind:ty) => {
@ -92,16 +93,13 @@ macro_rules! embedded_hal_error {
pub fn new(kind: $kind, cause: esp_idf_sys::EspError) -> Self {
Self { kind, cause }
}
pub fn other(cause: esp_idf_sys::EspError) -> Self {
Self::new(<$kind>::Other, cause)
}
pub fn cause(&self) -> esp_idf_sys::EspError {
self.cause
}
}
impl From<esp_idf_sys::EspError> for $error {
fn from(e: esp_idf_sys::EspError) -> Self {
Self::other(e)
@ -131,6 +129,53 @@ macro_rules! embedded_hal_error {
};
}
#[cfg(feature = "riscv-ulp-hal")]
#[allow(unused_macros)]
macro_rules! embedded_hal_error {
($error:ident, $errortrait:ty, $kind:ty) => {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct $error {
kind: $kind,
cause: crate::riscv_ulp_hal::sys::EspError,
}
impl $error {
pub fn new(kind: $kind, cause: crate::riscv_ulp_hal::sys::EspError) -> Self {
Self { kind, cause }
}
pub fn other(cause: crate::riscv_ulp_hal::sys::EspError) -> Self {
Self::new(<$kind>::Other, cause)
}
pub fn cause(&self) -> crate::riscv_ulp_hal::sys::EspError {
self.cause
}
}
impl From<crate::riscv_ulp_hal::sys::EspError> for $error {
fn from(e: crate::riscv_ulp_hal::sys::EspError) -> Self {
Self::other(e)
}
}
impl $errortrait for $error {
fn kind(&self) -> $kind {
self.kind
}
}
impl core::fmt::Display for $error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{} {{ kind: {}, cause: {} }}",
stringify!($error),
self.kind,
self.cause()
)
}
}
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! into_ref {

View File

@ -40,16 +40,12 @@ impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for Ulp {
}
impl embedded_hal::delay::DelayUs for Ulp {
type Error = core::convert::Infallible;
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
delay_cycles(us * ULP_RISCV_CYCLES_PER_US_NUM / ULP_RISCV_CYCLES_PER_US_DENUM);
Ok(())
fn delay_us(&mut self, us: u32) {
delay_cycles(us * ULP_RISCV_CYCLES_PER_US_NUM / ULP_RISCV_CYCLES_PER_US_DENUM)
}
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
delay_cycles(ms * ULP_RISCV_CYCLES_PER_MS);
Ok(())
fn delay_ms(&mut self, ms: u32) {
delay_cycles(ms * ULP_RISCV_CYCLES_PER_MS)
}
}

View File

@ -32,11 +32,14 @@
use core::borrow::{Borrow, BorrowMut};
use core::cell::UnsafeCell;
use core::cmp::{max, min, Ordering};
use core::cmp::{min, Ordering};
use core::marker::PhantomData;
use core::ptr;
use core::{ptr, u8};
use embedded_hal::spi::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite, SpiDevice};
use embedded_hal::spi::{
Operation, SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite, SpiDevice, SpiDeviceRead,
SpiDeviceWrite,
};
use esp_idf_sys::*;
@ -258,6 +261,7 @@ pub struct SpiBusDriver<T> {
_driver: T,
trans_len: usize,
hardware_cs: bool,
keep_cs_active: bool,
}
impl<T> SpiBusDriver<T> {
@ -294,36 +298,71 @@ impl<T> SpiBusDriver<T> {
_driver: driver,
trans_len,
hardware_cs: false,
keep_cs_active: false,
})
}
// Full-Duplex Mode:
// The internal hardware 16*4 u8 FIFO buffer (shared for read/write) is not cleared
// between transactions (read/write/transfer)
// This can lead to rewriting the internal buffer to MOSI on a read call
pub fn read(&mut self, words: &mut [u8]) -> Result<(), EspError> {
for chunk in words.chunks_mut(self.trans_len) {
self.polling_transmit(chunk.as_mut_ptr(), ptr::null(), chunk.len(), chunk.len())?;
let mut it = words.chunks_mut(self.trans_len).peekable();
while let Some(read_chunk) = it.next() {
self.polling_transmit(
read_chunk.as_mut_ptr(),
ptr::null(),
read_chunk.len(),
read_chunk.len(),
it.peek().is_some(),
)?;
}
Ok(())
}
// Full-Duplex Mode:
// The internal hardware 16*4 u8 FIFO buffer (shared for read/write) is not cleared
// between transactions ( read/write/transfer)
// This can lead to re-reading the last internal buffer MOSI msg, in case the Slave failes to send a msg
pub fn write(&mut self, words: &[u8]) -> Result<(), EspError> {
for chunk in words.chunks(self.trans_len) {
self.polling_transmit(ptr::null_mut(), chunk.as_ptr(), chunk.len(), 0)?;
let mut it = words.chunks(self.trans_len).peekable();
while let Some(write_chunk) = it.next() {
self.polling_transmit(
ptr::null_mut(),
write_chunk.as_ptr(),
write_chunk.len(),
0,
it.peek().is_some(),
)?;
}
Ok(())
}
// In non-DMA mode, it will internally split the transfers every 64 bytes (max_transf_len).
// -1: If the read and write buffers are not of the same length, it will first transfer the common buffer length
// and then (separately aligned) the remaining buffer.
// -2: Expect a delay time between every internally split (64-byte or remainder) package.
// Half-Duplex & Half-3-Duplex Mode:
// Data will be split into 64-byte write/read sections.
// Example: write: [u8;96] - read [u8; 160]
// Package 1: write 64, read 64 -> Package 2: write 32, read 32 -> Package 3: write 0, read 64.
// Note that the first "package" is a 128-byte clock out while the later are respectively 64 bytes.
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
let more_chunks = read.len() != write.len();
let common_length = min(read.len(), write.len());
let common_read = read[0..common_length].chunks_mut(self.trans_len);
let common_write = write[0..common_length].chunks(self.trans_len);
for (read_chunk, write_chunk) in common_read.zip(common_write) {
let mut it = common_read.zip(common_write).peekable();
while let Some((read_chunk, write_chunk)) = it.next() {
self.polling_transmit(
read_chunk.as_mut_ptr(),
write_chunk.as_ptr(),
max(read_chunk.len(), write_chunk.len()),
read_chunk.len(), //read/write chunk implicitly always same length because of common_length
read_chunk.len(),
it.peek().is_some() || more_chunks,
)?;
}
@ -343,10 +382,11 @@ impl<T> SpiBusDriver<T> {
}
pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), EspError> {
for chunk in words.chunks_mut(self.trans_len) {
let mut it = words.chunks_mut(self.trans_len).peekable();
while let Some(chunk) = it.next() {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
self.polling_transmit(ptr, ptr, len, len)?;
self.polling_transmit(ptr, ptr, len, len, it.peek().is_some())?;
}
Ok(())
@ -365,6 +405,7 @@ impl<T> SpiBusDriver<T> {
write: *const u8,
transaction_length: usize,
rx_length: usize,
keep_cs_active: bool,
) -> Result<(), EspError> {
polling_transmit(
self.handle.0,
@ -372,14 +413,9 @@ impl<T> SpiBusDriver<T> {
write,
transaction_length,
rx_length,
self.hardware_cs,
(self.hardware_cs && self.keep_cs_active) || keep_cs_active,
)
}
/// Empty transaction to de-assert CS.
fn finish(&mut self) -> Result<(), EspError> {
polling_transmit(self.handle.0, ptr::null_mut(), ptr::null(), 0, 0, false)
}
}
impl<T> embedded_hal::spi::ErrorType for SpiBusDriver<T> {
@ -623,13 +659,7 @@ where
self.handle.0
}
pub fn transaction<R, E>(
&mut self,
f: impl FnOnce(&mut SpiBusDriver<()>) -> Result<R, E>,
) -> Result<R, E>
where
E: From<EspError>,
{
pub fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), EspError> {
// if DMA used -> get trans length info from driver
let trans_len = self.driver.borrow().max_transfer_size;
@ -639,16 +669,26 @@ where
_driver: (),
trans_len,
hardware_cs: self.with_cs_pin,
keep_cs_active: true,
};
let trans_result = f(&mut bus);
let mut op_result = Ok(());
// #99 is partially resolved by allowing software CS to ignore this bus.finish() work around
let finish_result = if self.with_cs_pin {
bus.finish()
} else {
Ok(())
};
let mut it = operations.iter_mut().peekable();
while let Some(op) = it.next() {
if it.peek().is_none() {
bus.keep_cs_active = false;
}
if let Err(e) = match op {
Operation::Read(words) => bus.read(words),
Operation::Write(words) => bus.write(words),
Operation::Transfer(read, write) => bus.transfer(read, write),
Operation::TransferInPlace(words) => bus.transfer_in_place(words),
} {
op_result = Err(e);
break;
};
}
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
@ -656,27 +696,26 @@ where
drop(bus);
let result = trans_result?;
finish_result?;
flush_result?;
op_result?;
Ok(result)
Ok(())
}
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.transfer(read, write))
self.transaction(&mut [Operation::Transfer(read, write)])
}
pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.write(write))
self.transaction(&mut [Operation::Write(write)])
}
pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.read(read))
self.transaction(&mut [Operation::Read(read)])
}
pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.transfer_in_place(buf))
self.transaction(&mut [Operation::TransferInPlace(buf)])
}
fn lock_bus(&self) -> Result<Lock, EspError> {
@ -690,17 +729,104 @@ impl<'d, T> embedded_hal::spi::ErrorType for SpiDeviceDriver<'d, T> {
type Error = SpiError;
}
impl<'d, T> SpiDeviceRead for SpiDeviceDriver<'d, T>
where
T: Borrow<SpiDriver<'d>> + 'd,
{
fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
// if DMA used -> get trans length info from driver
let trans_len = self.driver.borrow().max_transfer_size;
let mut bus = SpiBusDriver {
_lock: self.lock_bus()?,
handle: Device(self.handle.0, false),
_driver: (),
trans_len,
hardware_cs: self.with_cs_pin,
keep_cs_active: true,
};
let mut op_result = Ok(());
let mut it = operations.iter_mut().peekable();
while let Some(op) = it.next() {
if it.peek().is_none() {
bus.keep_cs_active = false;
}
if let Err(e) = bus.read(op) {
op_result = Err(e);
break;
}
}
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
let flush_result = bus.flush();
drop(bus);
flush_result?;
op_result?;
Ok(())
}
fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
self.read_transaction(&mut [buf])
}
}
impl<'d, T> SpiDeviceWrite for SpiDeviceDriver<'d, T>
where
T: Borrow<SpiDriver<'d>> + 'd,
{
fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
// if DMA used -> get trans length info from driver
let trans_len = self.driver.borrow().max_transfer_size;
let mut bus = SpiBusDriver {
_lock: self.lock_bus()?,
handle: Device(self.handle.0, false),
_driver: (),
trans_len,
hardware_cs: self.with_cs_pin,
keep_cs_active: true,
};
let mut op_result = Ok(());
let mut it = operations.iter().peekable();
while let Some(op) = it.next() {
if it.peek().is_none() {
bus.keep_cs_active = false;
}
if let Err(e) = bus.write(op) {
op_result = Err(e);
break;
}
}
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
let flush_result = bus.flush();
drop(bus);
flush_result?;
op_result?;
Ok(())
}
fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write_transaction(&[buf])
}
}
impl<'d, T> SpiDevice for SpiDeviceDriver<'d, T>
where
T: Borrow<SpiDriver<'d>> + 'd,
{
type Bus = SpiBusDriver<()>;
fn transaction<R>(
&mut self,
f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as embedded_hal::spi::ErrorType>::Error>,
) -> Result<R, Self::Error> {
Self::transaction(self, f)
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
Self::transaction(self, operations).map_err(to_spi_err)
}
}
@ -711,17 +837,7 @@ where
type Error = SpiError;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
let _lock = self.lock_bus()?;
let mut chunks = words
.chunks_mut(self.driver.borrow().max_transfer_size)
.peekable();
while let Some(chunk) = chunks.next() {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
polling_transmit(self.handle.0, ptr, ptr, len, len, chunks.peek().is_some())?;
}
self.transfer_in_place(words)?;
Ok(words)
}
}
@ -733,26 +849,13 @@ where
type Error = SpiError;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let _lock = self.lock_bus()?;
let mut chunks = words
.chunks(self.driver.borrow().max_transfer_size)
.peekable();
while let Some(chunk) = chunks.next() {
polling_transmit(
self.handle.0,
ptr::null_mut(),
chunk.as_ptr(),
chunk.len(),
0,
chunks.peek().is_some(),
)?;
}
self.write(words)?;
Ok(())
}
}
/// Only use this in NON DMA Mode
/// Reason -> All Data is chunked into max(iter.len(), 64)
impl<'d, T> embedded_hal_0_2::blocking::spi::WriteIter<u8> for SpiDeviceDriver<'d, T>
where
T: Borrow<SpiDriver<'d>> + 'd,
@ -763,31 +866,55 @@ where
where
WI: IntoIterator<Item = u8>,
{
let mut words = words.into_iter();
// if DMA used -> get trans length info from driver
let trans_len = self.driver.borrow().max_transfer_size;
let mut bus = SpiBusDriver {
_lock: self.lock_bus()?,
handle: Device(self.handle.0, false),
_driver: (),
trans_len,
hardware_cs: self.with_cs_pin,
keep_cs_active: true,
};
let mut op_result = Ok(());
let mut words = words.into_iter().peekable();
let mut buf = [0_u8; TRANS_LEN];
loop {
let mut offset = 0_usize;
self.transaction(|bus| {
loop {
let mut offset = 0_usize;
while offset < buf.len() {
if let Some(word) = words.next() {
buf[offset] = word;
offset += 1;
} else {
break;
}
}
if offset == 0 {
while offset < buf.len() {
if let Some(word) = words.next() {
buf[offset] = word;
offset += 1;
} else {
break;
}
bus.write(&buf[..offset])?;
}
Ok(())
})
if offset == 0 {
break;
}
if words.peek().is_none() {
bus.keep_cs_active = false;
}
if let Err(e) = bus.write(&buf[..offset]) {
op_result = Err(e);
break;
}
}
let flush_result = bus.flush();
drop(bus);
flush_result?;
op_result?;
Ok(())
}
}
@ -801,18 +928,46 @@ where
&mut self,
operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'_, u8>],
) -> Result<(), Self::Error> {
self.transaction(|bus| {
for operation in operations {
match operation {
embedded_hal_0_2::blocking::spi::Operation::Write(write) => bus.write(write),
embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
bus.transfer_in_place(words)
}
}?;
}
// if DMA used -> get trans length info from driver
let trans_len = self.driver.borrow().max_transfer_size;
Ok(())
})
let mut bus = SpiBusDriver {
_lock: self.lock_bus()?,
handle: Device(self.handle.0, false),
_driver: (),
trans_len,
hardware_cs: self.with_cs_pin,
keep_cs_active: true,
};
let mut op_result = Ok(());
let mut it = operations.iter_mut().peekable();
while let Some(op) = it.next() {
if it.peek().is_none() {
bus.keep_cs_active = false;
}
if let Err(e) = match op {
embedded_hal_0_2::blocking::spi::Operation::Write(words) => bus.write(words),
embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
bus.transfer_in_place(words)
}
} {
op_result = Err(e);
break;
};
}
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
let flush_result = bus.flush();
drop(bus);
flush_result?;
op_result?;
Ok(())
}
}
@ -902,13 +1057,7 @@ where
self
}
pub fn transaction<R, E>(
&mut self,
f: impl FnOnce(&mut SpiBusDriver<()>) -> Result<R, E>,
) -> Result<R, E>
where
E: From<EspError>,
{
pub fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), EspError> {
let cs_pin = &mut self.cs_pin;
let pre_delay_us = self.pre_delay_us;
let post_delay_us = self.post_delay_us;
@ -919,8 +1068,7 @@ where
if let Some(delay) = pre_delay_us {
Ets::delay_us(delay);
}
let trans_result = device.transaction(f);
let trans_result = device.transaction(operations);
if let Some(delay) = post_delay_us {
Ets::delay_us(delay);
@ -928,24 +1076,25 @@ where
cs_pin.toggle()?;
trans_result
trans_result?;
Ok(())
})
}
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.transfer(read, write))
self.transaction(&mut [Operation::Transfer(read, write)])
}
pub fn write(&mut self, write: &[u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.write(write))
self.transaction(&mut [Operation::Write(write)])
}
pub fn read(&mut self, read: &mut [u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.read(read))
self.transaction(&mut [Operation::Read(read)])
}
pub fn transfer_in_place(&mut self, buf: &mut [u8]) -> Result<(), EspError> {
self.transaction(|bus| bus.transfer_in_place(buf))
self.transaction(&mut [Operation::TransferInPlace(buf)])
}
}
@ -957,18 +1106,81 @@ where
type Error = SpiError;
}
impl<'d, DEVICE, DRIVER> SpiDeviceRead for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
where
DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
DRIVER: Borrow<SpiDriver<'d>> + 'd,
{
fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
let cs_pin = &mut self.cs_pin;
let pre_delay_us = self.pre_delay_us;
let post_delay_us = self.post_delay_us;
self.shared_device.borrow().lock(|device| {
cs_pin.toggle()?;
if let Some(delay) = pre_delay_us {
Ets::delay_us(delay);
}
let trans_result = device.read_transaction(operations);
if let Some(delay) = post_delay_us {
Ets::delay_us(delay);
}
cs_pin.toggle()?;
trans_result?;
Ok(())
})
}
fn read(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
self.read_transaction(&mut [buf])
}
}
impl<'d, DEVICE, DRIVER> SpiDeviceWrite for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
where
DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
DRIVER: Borrow<SpiDriver<'d>> + 'd,
{
fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
let cs_pin = &mut self.cs_pin;
let pre_delay_us = self.pre_delay_us;
let post_delay_us = self.post_delay_us;
self.shared_device.borrow().lock(|device| {
cs_pin.toggle()?;
if let Some(delay) = pre_delay_us {
Ets::delay_us(delay);
}
let trans_result = device.write_transaction(operations);
if let Some(delay) = post_delay_us {
Ets::delay_us(delay);
}
cs_pin.toggle()?;
trans_result?;
Ok(())
})
}
fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write_transaction(&[buf])
}
}
impl<'d, DEVICE, DRIVER> SpiDevice for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
where
DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
DRIVER: Borrow<SpiDriver<'d>> + 'd,
{
type Bus = SpiBusDriver<()>;
fn transaction<R>(
&mut self,
f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as embedded_hal::spi::ErrorType>::Error>,
) -> Result<R, Self::Error> {
Self::transaction(self, f)
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
Self::transaction(self, operations).map_err(to_spi_err)
}
}