Reimplement blocking trait for async i2c (#2343)
This commit is contained in:
parent
0dc8dcf8e2
commit
ef7842fab4
@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Restored blocking `embedded_hal` compatibility for async I2C driver (#2343)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
## [0.21.0]
|
## [0.21.0]
|
||||||
|
|||||||
@ -63,7 +63,10 @@ use crate::{
|
|||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::i2c0::{RegisterBlock, COMD},
|
peripherals::i2c0::{RegisterBlock, COMD},
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
@ -229,14 +232,77 @@ impl From<Ack> for u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// I2C driver
|
/// I2C driver
|
||||||
pub struct I2c<'d, T, DM: crate::Mode> {
|
pub struct I2c<'d, T, DM: Mode> {
|
||||||
peripheral: PeripheralRef<'d, T>,
|
peripheral: PeripheralRef<'d, T>,
|
||||||
phantom: PhantomData<DM>,
|
phantom: PhantomData<DM>,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
timeout: Option<u32>,
|
timeout: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> I2c<'_, T, crate::Blocking>
|
impl<T, DM> I2c<'_, T, DM>
|
||||||
|
where
|
||||||
|
T: Instance,
|
||||||
|
DM: Mode,
|
||||||
|
{
|
||||||
|
fn transaction_impl<'a>(
|
||||||
|
&mut self,
|
||||||
|
address: u8,
|
||||||
|
operations: impl Iterator<Item = Operation<'a>>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut last_op: Option<OpKind> = None;
|
||||||
|
// filter out 0 length read operations
|
||||||
|
let mut op_iter = operations
|
||||||
|
.filter(|op| op.is_write() || !op.is_empty())
|
||||||
|
.peekable();
|
||||||
|
|
||||||
|
while let Some(op) = op_iter.next() {
|
||||||
|
let next_op = op_iter.peek().map(|v| v.kind());
|
||||||
|
let kind = op.kind();
|
||||||
|
// Clear all I2C interrupts
|
||||||
|
self.peripheral.clear_all_interrupts();
|
||||||
|
|
||||||
|
let cmd_iterator = &mut self.peripheral.register_block().comd_iter();
|
||||||
|
match op {
|
||||||
|
Operation::Write(buffer) => {
|
||||||
|
// execute a write operation:
|
||||||
|
// - issue START/RSTART if op is different from previous
|
||||||
|
// - issue STOP if op is the last one
|
||||||
|
self.peripheral
|
||||||
|
.write_operation(
|
||||||
|
address,
|
||||||
|
buffer,
|
||||||
|
!matches!(last_op, Some(OpKind::Write)),
|
||||||
|
next_op.is_none(),
|
||||||
|
cmd_iterator,
|
||||||
|
)
|
||||||
|
.inspect_err(|_| self.internal_recover())?;
|
||||||
|
}
|
||||||
|
Operation::Read(buffer) => {
|
||||||
|
// execute a read operation:
|
||||||
|
// - issue START/RSTART if op is different from previous
|
||||||
|
// - issue STOP if op is the last one
|
||||||
|
// - will_continue is true if there is another read operation next
|
||||||
|
self.peripheral
|
||||||
|
.read_operation(
|
||||||
|
address,
|
||||||
|
buffer,
|
||||||
|
!matches!(last_op, Some(OpKind::Read)),
|
||||||
|
next_op.is_none(),
|
||||||
|
matches!(next_op, Some(OpKind::Read)),
|
||||||
|
cmd_iterator,
|
||||||
|
)
|
||||||
|
.inspect_err(|_| self.internal_recover())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_op = Some(kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> I2c<'_, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -361,66 +427,9 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.transaction_impl(address, operations.into_iter().map(Operation::from))
|
self.transaction_impl(address, operations.into_iter().map(Operation::from))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction_impl<'a>(
|
|
||||||
&mut self,
|
|
||||||
address: u8,
|
|
||||||
operations: impl Iterator<Item = Operation<'a>>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let mut last_op: Option<OpKind> = None;
|
|
||||||
// filter out 0 length read operations
|
|
||||||
let mut op_iter = operations
|
|
||||||
.filter(|op| op.is_write() || !op.is_empty())
|
|
||||||
.peekable();
|
|
||||||
|
|
||||||
while let Some(op) = op_iter.next() {
|
|
||||||
let next_op = op_iter.peek().map(|v| v.kind());
|
|
||||||
let kind = op.kind();
|
|
||||||
// Clear all I2C interrupts
|
|
||||||
self.peripheral.clear_all_interrupts();
|
|
||||||
|
|
||||||
let cmd_iterator = &mut self.peripheral.register_block().comd_iter();
|
|
||||||
match op {
|
|
||||||
Operation::Write(buffer) => {
|
|
||||||
// execute a write operation:
|
|
||||||
// - issue START/RSTART if op is different from previous
|
|
||||||
// - issue STOP if op is the last one
|
|
||||||
self.peripheral
|
|
||||||
.write_operation(
|
|
||||||
address,
|
|
||||||
buffer,
|
|
||||||
!matches!(last_op, Some(OpKind::Write)),
|
|
||||||
next_op.is_none(),
|
|
||||||
cmd_iterator,
|
|
||||||
)
|
|
||||||
.inspect_err(|_| self.internal_recover())?;
|
|
||||||
}
|
|
||||||
Operation::Read(buffer) => {
|
|
||||||
// execute a read operation:
|
|
||||||
// - issue START/RSTART if op is different from previous
|
|
||||||
// - issue STOP if op is the last one
|
|
||||||
// - will_continue is true if there is another read operation next
|
|
||||||
self.peripheral
|
|
||||||
.read_operation(
|
|
||||||
address,
|
|
||||||
buffer,
|
|
||||||
!matches!(last_op, Some(OpKind::Read)),
|
|
||||||
next_op.is_none(),
|
|
||||||
matches!(next_op, Some(OpKind::Read)),
|
|
||||||
cmd_iterator,
|
|
||||||
)
|
|
||||||
.inspect_err(|_| self.internal_recover())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_op = Some(kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, T, crate::Blocking>
|
impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -431,7 +440,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, T, crate::Blocking>
|
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -442,7 +451,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, T, crate::Blocking>
|
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -458,11 +467,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, DM: crate::Mode> embedded_hal::i2c::ErrorType for I2c<'_, T, DM> {
|
impl<T, DM: Mode> embedded_hal::i2c::ErrorType for I2c<'_, T, DM> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal::i2c::I2c for I2c<'_, T, crate::Blocking>
|
impl<T, DM: Mode> embedded_hal::i2c::I2c for I2c<'_, T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -475,7 +484,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T, DM: crate::Mode> I2c<'d, T, DM>
|
impl<'d, T, DM: Mode> I2c<'d, T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -548,7 +557,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> I2c<'d, T, crate::Blocking>
|
impl<'d, T> I2c<'d, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -581,9 +590,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> crate::private::Sealed for I2c<'d, T, crate::Blocking> where T: Instance {}
|
impl<'d, T> crate::private::Sealed for I2c<'d, T, Blocking> where T: Instance {}
|
||||||
|
|
||||||
impl<'d, T> InterruptConfigurable for I2c<'d, T, crate::Blocking>
|
impl<'d, T> InterruptConfigurable for I2c<'d, T, Blocking>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -592,7 +601,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> I2c<'d, T, crate::Async>
|
impl<'d, T> I2c<'d, T, Async>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -779,7 +788,7 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> I2c<'_, T, crate::Async>
|
impl<T> I2c<'_, T, Async>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -1110,11 +1119,11 @@ mod asynch {
|
|||||||
address: u8,
|
address: u8,
|
||||||
operations: impl IntoIterator<Item = &'a mut Operation<'a>>,
|
operations: impl IntoIterator<Item = &'a mut Operation<'a>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.transaction_impl(address, operations.into_iter().map(Operation::from))
|
self.transaction_impl_async(address, operations.into_iter().map(Operation::from))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn transaction_impl<'a>(
|
async fn transaction_impl_async<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
operations: impl Iterator<Item = Operation<'a>>,
|
operations: impl Iterator<Item = Operation<'a>>,
|
||||||
@ -1170,7 +1179,7 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, T, crate::Async>
|
impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, T, Async>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -1179,7 +1188,7 @@ mod asynch {
|
|||||||
address: u8,
|
address: u8,
|
||||||
operations: &mut [EhalOperation<'_>],
|
operations: &mut [EhalOperation<'_>],
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.transaction_impl(address, operations.iter_mut().map(Operation::from))
|
self.transaction_impl_async(address, operations.iter_mut().map(Operation::from))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use esp_hal::{
|
|||||||
i2c::{I2c, Operation},
|
i2c::{I2c, Operation},
|
||||||
peripherals::I2C0,
|
peripherals::I2C0,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
Async,
|
||||||
Blocking,
|
Blocking,
|
||||||
};
|
};
|
||||||
use hil_test as _;
|
use hil_test as _;
|
||||||
@ -17,6 +18,15 @@ use hil_test as _;
|
|||||||
struct Context {
|
struct Context {
|
||||||
i2c: I2c<'static, I2C0, Blocking>,
|
i2c: I2c<'static, I2C0, Blocking>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _async_driver_is_compatible_with_blocking_ehal() {
|
||||||
|
fn _with_driver(driver: I2c<'static, I2C0, Async>) {
|
||||||
|
_with_ehal(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _with_ehal(_: impl embedded_hal::i2c::I2c) {}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[embedded_test::tests]
|
#[embedded_test::tests]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user