mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-09-28 04:41: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]
|
[dependencies]
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
embedded-can = "0.4.1"
|
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-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"] }
|
esp-idf-sys = { version = "0.32.1", optional = true, default-features = false, features = ["native"] }
|
||||||
critical-section = { version = "1.1", optional = true }
|
critical-section = { version = "1.1", optional = true }
|
||||||
heapless = "0.7"
|
heapless = "0.7"
|
||||||
embassy-sync = { version = "0.1", optional = true }
|
embassy-sync = { version = "0.1", optional = true }
|
||||||
edge-executor = { version = "0.3", optional = true, default-features = false }
|
edge-executor = { version = "0.3", optional = true, default-features = false }
|
||||||
enumset = { version = "1", 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 }
|
futures-util = { version = "0.3", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
//! This example transfers data via SPI.
|
//! This example transfers data via SPI.
|
||||||
//! Connect SDI and SDO pins to see the outgoing data is read as incoming data.
|
//! 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::delay::FreeRtos;
|
||||||
use esp_idf_hal::peripherals::Peripherals;
|
use esp_idf_hal::peripherals::Peripherals;
|
||||||
use esp_idf_hal::prelude::*;
|
use esp_idf_hal::prelude::*;
|
||||||
@ -42,16 +43,23 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let mut read = [0u8; 4];
|
let mut read = [0u8; 4];
|
||||||
let write = [0xde, 0xad, 0xbe, 0xef];
|
let write = [0xde, 0xad, 0xbe, 0xef];
|
||||||
|
|
||||||
let mut in_place_buf = [0xde, 0xad, 0xbe, 0xef];
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// we are using thread::sleep here to make sure the watchdog isn't triggered
|
// we are using thread::sleep here to make sure the watchdog isn't triggered
|
||||||
FreeRtos::delay_ms(500);
|
FreeRtos::delay_ms(500);
|
||||||
device_1.transfer(&mut read, &write)?;
|
device_1.transfer(&mut read, &write)?;
|
||||||
println!("Device 1: Wrote {write:x?}, read {read:x?}");
|
println!("Device 1: Wrote {write:x?}, read {read:x?}");
|
||||||
|
|
||||||
println!("Device 2: To write {in_place_buf:x?} ... ");
|
let write_buf = [0xde, 0xad, 0xbe, 0xef];
|
||||||
device_2.transaction(|bus| bus.transfer_in_place(&mut in_place_buf))?;
|
let mut write_in_place_buf = [0xde, 0xad, 0xbe, 0xef];
|
||||||
println!("... read {in_place_buf:x?}");
|
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 {
|
impl embedded_hal_0_2::blocking::delay::DelayUs<u16> for Delay {
|
||||||
fn delay_us(&mut self, us: u16) {
|
fn delay_us(&mut self, us: u16) {
|
||||||
Delay::delay_us(us as _);
|
Delay::delay_us(us as _);
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
//! use [`Delay`]. Otherwise use [`Ets`] for delays <10ms and
|
//! use [`Delay`]. Otherwise use [`Ets`] for delays <10ms and
|
||||||
//! [`FreeRtos`] for delays >=10ms.
|
//! [`FreeRtos`] for delays >=10ms.
|
||||||
|
|
||||||
use core::convert::Infallible;
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use esp_idf_sys::*;
|
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 {
|
impl embedded_hal::delay::DelayUs for Ets {
|
||||||
type Error = Infallible;
|
fn delay_us(&mut self, us: u32) {
|
||||||
|
Ets::delay_us(us)
|
||||||
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
|
|
||||||
Ets::delay_us(us);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
fn delay_ms(&mut self, ms: u32) {
|
||||||
Ets::delay_ms(ms);
|
Ets::delay_ms(ms)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,17 +192,11 @@ impl embedded_hal_0_2::blocking::delay::DelayMs<u8> for FreeRtos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl embedded_hal::delay::DelayUs for FreeRtos {
|
impl embedded_hal::delay::DelayUs for FreeRtos {
|
||||||
type Error = Infallible;
|
fn delay_us(&mut self, us: u32) {
|
||||||
|
FreeRtos::delay_us(us)
|
||||||
fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
|
|
||||||
FreeRtos::delay_us(us);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
fn delay_ms(&mut self, ms: u32) {
|
||||||
FreeRtos::delay_ms(ms);
|
FreeRtos::delay_ms(ms)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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> {
|
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>
|
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
|
where
|
||||||
MODE: OutputMode,
|
MODE: OutputMode,
|
||||||
{
|
{
|
||||||
type Error = EspError;
|
type Error = GpioError;
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
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> {
|
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,
|
MODE: OutputMode,
|
||||||
{
|
{
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
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> {
|
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> {
|
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||||
self.set_level(Level::from(!bool::from(self.get_output_level())))
|
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"))]
|
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))]
|
||||||
impl<T: Pin, MODE: InputMode> PinDriver<'_, T, MODE> {
|
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;
|
InputFuture::new(self, InterruptType::HighLevel)?.await;
|
||||||
Ok(())
|
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;
|
InputFuture::new(self, InterruptType::LowLevel)?.await;
|
||||||
Ok(())
|
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;
|
InputFuture::new(self, InterruptType::PosEdge)?.await;
|
||||||
Ok(())
|
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;
|
InputFuture::new(self, InterruptType::NegEdge)?.await;
|
||||||
Ok(())
|
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;
|
InputFuture::new(self, InterruptType::AnyEdge)?.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1453,23 +1465,23 @@ mod asynch {
|
|||||||
mod eha_wait_impl {
|
mod eha_wait_impl {
|
||||||
use super::*;
|
use super::*;
|
||||||
impl<T: Pin, MODE: InputMode> embedded_hal_async::digital::Wait for PinDriver<'_, T, MODE> {
|
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
|
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
|
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
|
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
|
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
|
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)
|
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(
|
fn transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
@ -404,13 +385,6 @@ impl<'d> embedded_hal::i2c::I2c<embedded_hal::i2c::SevenBitAddress> for I2cDrive
|
|||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
I2cDriver::transaction(self, address, operations, BLOCK).map_err(to_i2c_err)
|
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 {
|
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: AtomicBool = AtomicBool::new(false);
|
||||||
static FADE_FUNC_INSTALLED_CS: CriticalSection = CriticalSection::new();
|
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
|
/// Types for configuring the LED Control peripheral
|
||||||
pub mod config {
|
pub mod config {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -310,31 +316,46 @@ impl<'d> Drop for LedcDriver<'d> {
|
|||||||
|
|
||||||
unsafe impl<'d> Send 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::ErrorType for LedcDriver<'d> {
|
||||||
// impl<'d> embedded_hal::pwm::blocking::PwmPin for LedcDriver<'d> {
|
type Error = PwmError;
|
||||||
// type Duty = Duty;
|
}
|
||||||
// type Error = EspError;
|
|
||||||
|
|
||||||
// fn disable(&mut self) -> Result<(), Self::Error> {
|
fn to_pwm_err(err: EspError) -> PwmError {
|
||||||
// self.disable()
|
PwmError::other(err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn enable(&mut self) -> Result<(), Self::Error> {
|
impl<'d> embedded_hal::pwm::SetDutyCycle for LedcDriver<'d> {
|
||||||
// self.enable()
|
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> {
|
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), PwmError> {
|
||||||
// Ok(self.get_duty())
|
self.set_duty(duty as u32).map_err(to_pwm_err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn get_max_duty(&self) -> Result<Self::Duty, Self::Error> {
|
fn set_duty_cycle_fully_on(&mut self) -> Result<(), PwmError> {
|
||||||
// Ok(self.get_max_duty())
|
self.set_duty(self.get_max_duty()).map_err(to_pwm_err)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn set_duty(&mut self, duty: Duty) -> Result<(), Self::Error> {
|
fn set_duty_cycle_fully_off(&mut self) -> Result<(), PwmError> {
|
||||||
// self.set_duty(duty)
|
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> {
|
impl<'d> embedded_hal_0_2::PwmPin for LedcDriver<'d> {
|
||||||
type Duty = Duty;
|
type Duty = Duty;
|
||||||
|
51
src/lib.rs
51
src/lib.rs
@ -79,6 +79,7 @@ pub use crate::riscv_ulp_hal::delay;
|
|||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// embedded_hal_error!(I2cError, embedded_hal::i2c::Error, embedded_hal::i2c::ErrorKind)
|
// embedded_hal_error!(I2cError, embedded_hal::i2c::Error, embedded_hal::i2c::ErrorKind)
|
||||||
|
#[cfg(not(feature = "riscv-ulp-hal"))]
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! embedded_hal_error {
|
macro_rules! embedded_hal_error {
|
||||||
($error:ident, $errortrait:ty, $kind:ty) => {
|
($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 {
|
pub fn new(kind: $kind, cause: esp_idf_sys::EspError) -> Self {
|
||||||
Self { kind, cause }
|
Self { kind, cause }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn other(cause: esp_idf_sys::EspError) -> Self {
|
pub fn other(cause: esp_idf_sys::EspError) -> Self {
|
||||||
Self::new(<$kind>::Other, cause)
|
Self::new(<$kind>::Other, cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cause(&self) -> esp_idf_sys::EspError {
|
pub fn cause(&self) -> esp_idf_sys::EspError {
|
||||||
self.cause
|
self.cause
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<esp_idf_sys::EspError> for $error {
|
impl From<esp_idf_sys::EspError> for $error {
|
||||||
fn from(e: esp_idf_sys::EspError) -> Self {
|
fn from(e: esp_idf_sys::EspError) -> Self {
|
||||||
Self::other(e)
|
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]
|
#[macro_export]
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! into_ref {
|
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 {
|
impl embedded_hal::delay::DelayUs for Ulp {
|
||||||
type Error = core::convert::Infallible;
|
fn delay_us(&mut self, us: u32) {
|
||||||
|
delay_cycles(us * ULP_RISCV_CYCLES_PER_US_NUM / ULP_RISCV_CYCLES_PER_US_DENUM)
|
||||||
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_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
fn delay_ms(&mut self, ms: u32) {
|
||||||
delay_cycles(ms * ULP_RISCV_CYCLES_PER_MS);
|
delay_cycles(ms * ULP_RISCV_CYCLES_PER_MS)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
458
src/spi.rs
458
src/spi.rs
@ -32,11 +32,14 @@
|
|||||||
|
|
||||||
use core::borrow::{Borrow, BorrowMut};
|
use core::borrow::{Borrow, BorrowMut};
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::cmp::{max, min, Ordering};
|
use core::cmp::{min, Ordering};
|
||||||
use core::marker::PhantomData;
|
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::*;
|
use esp_idf_sys::*;
|
||||||
|
|
||||||
@ -258,6 +261,7 @@ pub struct SpiBusDriver<T> {
|
|||||||
_driver: T,
|
_driver: T,
|
||||||
trans_len: usize,
|
trans_len: usize,
|
||||||
hardware_cs: bool,
|
hardware_cs: bool,
|
||||||
|
keep_cs_active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SpiBusDriver<T> {
|
impl<T> SpiBusDriver<T> {
|
||||||
@ -294,36 +298,71 @@ impl<T> SpiBusDriver<T> {
|
|||||||
_driver: driver,
|
_driver: driver,
|
||||||
trans_len,
|
trans_len,
|
||||||
hardware_cs: false,
|
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> {
|
pub fn read(&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();
|
||||||
self.polling_transmit(chunk.as_mut_ptr(), ptr::null(), chunk.len(), chunk.len())?;
|
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(())
|
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> {
|
pub fn write(&mut self, words: &[u8]) -> Result<(), EspError> {
|
||||||
for chunk in words.chunks(self.trans_len) {
|
let mut it = words.chunks(self.trans_len).peekable();
|
||||||
self.polling_transmit(ptr::null_mut(), chunk.as_ptr(), chunk.len(), 0)?;
|
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(())
|
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> {
|
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_length = min(read.len(), write.len());
|
||||||
let common_read = read[0..common_length].chunks_mut(self.trans_len);
|
let common_read = read[0..common_length].chunks_mut(self.trans_len);
|
||||||
let common_write = write[0..common_length].chunks(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(
|
self.polling_transmit(
|
||||||
read_chunk.as_mut_ptr(),
|
read_chunk.as_mut_ptr(),
|
||||||
write_chunk.as_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(),
|
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> {
|
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 ptr = chunk.as_mut_ptr();
|
||||||
let len = chunk.len();
|
let len = chunk.len();
|
||||||
self.polling_transmit(ptr, ptr, len, len)?;
|
self.polling_transmit(ptr, ptr, len, len, it.peek().is_some())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -365,6 +405,7 @@ impl<T> SpiBusDriver<T> {
|
|||||||
write: *const u8,
|
write: *const u8,
|
||||||
transaction_length: usize,
|
transaction_length: usize,
|
||||||
rx_length: usize,
|
rx_length: usize,
|
||||||
|
keep_cs_active: bool,
|
||||||
) -> Result<(), EspError> {
|
) -> Result<(), EspError> {
|
||||||
polling_transmit(
|
polling_transmit(
|
||||||
self.handle.0,
|
self.handle.0,
|
||||||
@ -372,14 +413,9 @@ impl<T> SpiBusDriver<T> {
|
|||||||
write,
|
write,
|
||||||
transaction_length,
|
transaction_length,
|
||||||
rx_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> {
|
impl<T> embedded_hal::spi::ErrorType for SpiBusDriver<T> {
|
||||||
@ -623,13 +659,7 @@ where
|
|||||||
self.handle.0
|
self.handle.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transaction<R, E>(
|
pub fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), EspError> {
|
||||||
&mut self,
|
|
||||||
f: impl FnOnce(&mut SpiBusDriver<()>) -> Result<R, E>,
|
|
||||||
) -> Result<R, E>
|
|
||||||
where
|
|
||||||
E: From<EspError>,
|
|
||||||
{
|
|
||||||
// if DMA used -> get trans length info from driver
|
// if DMA used -> get trans length info from driver
|
||||||
let trans_len = self.driver.borrow().max_transfer_size;
|
let trans_len = self.driver.borrow().max_transfer_size;
|
||||||
|
|
||||||
@ -639,16 +669,26 @@ where
|
|||||||
_driver: (),
|
_driver: (),
|
||||||
trans_len,
|
trans_len,
|
||||||
hardware_cs: self.with_cs_pin,
|
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 mut it = operations.iter_mut().peekable();
|
||||||
let finish_result = if self.with_cs_pin {
|
while let Some(op) = it.next() {
|
||||||
bus.finish()
|
if it.peek().is_none() {
|
||||||
} else {
|
bus.keep_cs_active = false;
|
||||||
Ok(())
|
}
|
||||||
};
|
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.
|
// Flush whatever is pending.
|
||||||
// Note that this is done even when an error is returned from the transaction.
|
// Note that this is done even when an error is returned from the transaction.
|
||||||
@ -656,27 +696,26 @@ where
|
|||||||
|
|
||||||
drop(bus);
|
drop(bus);
|
||||||
|
|
||||||
let result = trans_result?;
|
|
||||||
finish_result?;
|
|
||||||
flush_result?;
|
flush_result?;
|
||||||
|
op_result?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
|
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> {
|
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> {
|
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> {
|
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> {
|
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;
|
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>
|
impl<'d, T> SpiDevice for SpiDeviceDriver<'d, T>
|
||||||
where
|
where
|
||||||
T: Borrow<SpiDriver<'d>> + 'd,
|
T: Borrow<SpiDriver<'d>> + 'd,
|
||||||
{
|
{
|
||||||
type Bus = SpiBusDriver<()>;
|
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
|
Self::transaction(self, operations).map_err(to_spi_err)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,17 +837,7 @@ where
|
|||||||
type Error = SpiError;
|
type Error = SpiError;
|
||||||
|
|
||||||
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
||||||
let _lock = self.lock_bus()?;
|
self.transfer_in_place(words)?;
|
||||||
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())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(words)
|
Ok(words)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -733,26 +849,13 @@ where
|
|||||||
type Error = SpiError;
|
type Error = SpiError;
|
||||||
|
|
||||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||||
let _lock = self.lock_bus()?;
|
self.write(words)?;
|
||||||
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(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
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>
|
impl<'d, T> embedded_hal_0_2::blocking::spi::WriteIter<u8> for SpiDeviceDriver<'d, T>
|
||||||
where
|
where
|
||||||
T: Borrow<SpiDriver<'d>> + 'd,
|
T: Borrow<SpiDriver<'d>> + 'd,
|
||||||
@ -763,31 +866,55 @@ where
|
|||||||
where
|
where
|
||||||
WI: IntoIterator<Item = u8>,
|
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];
|
let mut buf = [0_u8; TRANS_LEN];
|
||||||
|
loop {
|
||||||
|
let mut offset = 0_usize;
|
||||||
|
|
||||||
self.transaction(|bus| {
|
while offset < buf.len() {
|
||||||
loop {
|
if let Some(word) = words.next() {
|
||||||
let mut offset = 0_usize;
|
buf[offset] = word;
|
||||||
|
offset += 1;
|
||||||
while offset < buf.len() {
|
} else {
|
||||||
if let Some(word) = words.next() {
|
|
||||||
buf[offset] = word;
|
|
||||||
offset += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if offset == 0 {
|
|
||||||
break;
|
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,
|
&mut self,
|
||||||
operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'_, u8>],
|
operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'_, u8>],
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.transaction(|bus| {
|
// if DMA used -> get trans length info from driver
|
||||||
for operation in operations {
|
let trans_len = self.driver.borrow().max_transfer_size;
|
||||||
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)
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transaction<R, E>(
|
pub fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), EspError> {
|
||||||
&mut self,
|
|
||||||
f: impl FnOnce(&mut SpiBusDriver<()>) -> Result<R, E>,
|
|
||||||
) -> Result<R, E>
|
|
||||||
where
|
|
||||||
E: From<EspError>,
|
|
||||||
{
|
|
||||||
let cs_pin = &mut self.cs_pin;
|
let cs_pin = &mut self.cs_pin;
|
||||||
let pre_delay_us = self.pre_delay_us;
|
let pre_delay_us = self.pre_delay_us;
|
||||||
let post_delay_us = self.post_delay_us;
|
let post_delay_us = self.post_delay_us;
|
||||||
@ -919,8 +1068,7 @@ where
|
|||||||
if let Some(delay) = pre_delay_us {
|
if let Some(delay) = pre_delay_us {
|
||||||
Ets::delay_us(delay);
|
Ets::delay_us(delay);
|
||||||
}
|
}
|
||||||
|
let trans_result = device.transaction(operations);
|
||||||
let trans_result = device.transaction(f);
|
|
||||||
|
|
||||||
if let Some(delay) = post_delay_us {
|
if let Some(delay) = post_delay_us {
|
||||||
Ets::delay_us(delay);
|
Ets::delay_us(delay);
|
||||||
@ -928,24 +1076,25 @@ where
|
|||||||
|
|
||||||
cs_pin.toggle()?;
|
cs_pin.toggle()?;
|
||||||
|
|
||||||
trans_result
|
trans_result?;
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), EspError> {
|
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> {
|
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> {
|
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> {
|
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;
|
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>
|
impl<'d, DEVICE, DRIVER> SpiDevice for SpiSoftCsDeviceDriver<'d, DEVICE, DRIVER>
|
||||||
where
|
where
|
||||||
DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
|
DEVICE: Borrow<SpiSharedDeviceDriver<'d, DRIVER>> + 'd,
|
||||||
DRIVER: Borrow<SpiDriver<'d>> + 'd,
|
DRIVER: Borrow<SpiDriver<'d>> + 'd,
|
||||||
{
|
{
|
||||||
type Bus = SpiBusDriver<()>;
|
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
|
Self::transaction(self, operations).map_err(to_spi_err)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user