mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-09-27 12:21:02 +00:00
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:
parent
b388e67e1f
commit
b739c46b12
@ -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]
|
||||
|
@ -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?}");
|
||||
}
|
||||
}
|
||||
|
@ -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 _);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
44
src/gpio.rs
44
src/gpio.rs
@ -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
|
||||
}
|
||||
}
|
||||
|
26
src/i2c.rs
26
src/i2c.rs
@ -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 {
|
||||
|
61
src/ledc.rs
61
src/ledc.rs
@ -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;
|
||||
|
51
src/lib.rs
51
src/lib.rs
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
458
src/spi.rs
458
src/spi.rs
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user