I2C: Make non-async fn available in async-mode (#3056)

* I2C: Make non-async fn available in async-mode

* PR number
This commit is contained in:
Björn Quentin 2025-01-29 14:30:35 +01:00 committed by GitHub
parent 2ff28b14b5
commit bb1ad1485a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 113 additions and 100 deletions

View File

@ -31,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed features `psram-quad` and `psram-octal` - replaced by `psram` and the `ESP_HAL_CONFIG_PSRAM_MODE` (`quad`/`octal`) (#3001)
- I2C: Async functions are postfixed with `_async`, non-async functions are available in async-mode (#3056)
### Fixed
- `DmaDescriptor` is now `#[repr(C)]` (#2988)

View File

@ -200,3 +200,12 @@ The OutputOpenDrain driver has been removed. You can use `Output` instead with
.with_drive_mode(DriveMode::OpenDrain),
);
```
## I2C Changes
All async functions now include the `_async` postfix. Additionally the non-async functions are now available in async-mode.
```diff
- let result = i2c.write_read(0x77, &[0xaa], &mut data).await;
+ let result = i2c.write_read_async(0x77, &[0xaa], &mut data).await;
```

View File

@ -596,101 +596,6 @@ impl<'d, Dm: DriverMode> I2c<'d, Dm> {
*guard = OutputConnection::connect_with_guard(pin, output);
}
}
impl<'d> I2c<'d, Blocking> {
/// Create a new I2C instance.
///
/// # Errors
///
/// A [`ConfigError`] variant will be returned if bus frequency or timeout
/// passed in config is invalid.
pub fn new(
i2c: impl Peripheral<P = impl Instance> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
crate::into_mapped_ref!(i2c);
let guard = PeripheralGuard::new(i2c.info().peripheral);
let sda_pin = PinGuard::new_unconnected(i2c.info().sda_output);
let scl_pin = PinGuard::new_unconnected(i2c.info().scl_output);
let i2c = I2c {
i2c,
phantom: PhantomData,
config,
guard,
sda_pin,
scl_pin,
};
i2c.driver().setup(&i2c.config)?;
Ok(i2c)
}
#[cfg_attr(
not(multi_core),
doc = "Registers an interrupt handler for the peripheral."
)]
#[cfg_attr(
multi_core,
doc = "Registers an interrupt handler for the peripheral on the current core."
)]
#[doc = ""]
/// Note that this will replace any previously registered interrupt
/// handlers.
///
/// You can restore the default/unhandled interrupt handler by using
/// [crate::DEFAULT_INTERRUPT_HANDLER]
///
/// # Panics
///
/// Panics if passed interrupt handler is invalid (e.g. has priority
/// `None`)
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.i2c.info().set_interrupt_handler(handler);
}
/// Listen for the given interrupts
#[instability::unstable]
pub fn listen(&mut self, interrupts: impl Into<EnumSet<Event>>) {
self.i2c.info().enable_listen(interrupts.into(), true)
}
/// Unlisten the given interrupts
#[instability::unstable]
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<Event>>) {
self.i2c.info().enable_listen(interrupts.into(), false)
}
/// Gets asserted interrupts
#[instability::unstable]
pub fn interrupts(&mut self) -> EnumSet<Event> {
self.i2c.info().interrupts()
}
/// Resets asserted interrupts
#[instability::unstable]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<Event>) {
self.i2c.info().clear_interrupts(interrupts)
}
/// Configures the I2C peripheral to operate in asynchronous mode.
pub fn into_async(mut self) -> I2c<'d, Async> {
self.set_interrupt_handler(self.driver().info.async_handler);
I2c {
i2c: self.i2c,
phantom: PhantomData,
config: self.config,
guard: self.guard,
sda_pin: self.sda_pin,
scl_pin: self.scl_pin,
}
}
/// Writes bytes to slave with address `address`
/// ```rust, no_run
@ -826,6 +731,101 @@ impl<'d> I2c<'d, Blocking> {
}
}
impl<'d> I2c<'d, Blocking> {
/// Create a new I2C instance.
///
/// # Errors
///
/// A [`ConfigError`] variant will be returned if bus frequency or timeout
/// passed in config is invalid.
pub fn new(
i2c: impl Peripheral<P = impl Instance> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
crate::into_mapped_ref!(i2c);
let guard = PeripheralGuard::new(i2c.info().peripheral);
let sda_pin = PinGuard::new_unconnected(i2c.info().sda_output);
let scl_pin = PinGuard::new_unconnected(i2c.info().scl_output);
let i2c = I2c {
i2c,
phantom: PhantomData,
config,
guard,
sda_pin,
scl_pin,
};
i2c.driver().setup(&i2c.config)?;
Ok(i2c)
}
#[cfg_attr(
not(multi_core),
doc = "Registers an interrupt handler for the peripheral."
)]
#[cfg_attr(
multi_core,
doc = "Registers an interrupt handler for the peripheral on the current core."
)]
#[doc = ""]
/// Note that this will replace any previously registered interrupt
/// handlers.
///
/// You can restore the default/unhandled interrupt handler by using
/// [crate::DEFAULT_INTERRUPT_HANDLER]
///
/// # Panics
///
/// Panics if passed interrupt handler is invalid (e.g. has priority
/// `None`)
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.i2c.info().set_interrupt_handler(handler);
}
/// Listen for the given interrupts
#[instability::unstable]
pub fn listen(&mut self, interrupts: impl Into<EnumSet<Event>>) {
self.i2c.info().enable_listen(interrupts.into(), true)
}
/// Unlisten the given interrupts
#[instability::unstable]
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<Event>>) {
self.i2c.info().enable_listen(interrupts.into(), false)
}
/// Gets asserted interrupts
#[instability::unstable]
pub fn interrupts(&mut self) -> EnumSet<Event> {
self.i2c.info().interrupts()
}
/// Resets asserted interrupts
#[instability::unstable]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<Event>) {
self.i2c.info().clear_interrupts(interrupts)
}
/// Configures the I2C peripheral to operate in asynchronous mode.
pub fn into_async(mut self) -> I2c<'d, Async> {
self.set_interrupt_handler(self.driver().info.async_handler);
I2c {
i2c: self.i2c,
phantom: PhantomData,
config: self.config,
guard: self.guard,
sda_pin: self.sda_pin,
scl_pin: self.scl_pin,
}
}
}
impl private::Sealed for I2c<'_, Blocking> {}
impl InterruptConfigurable for I2c<'_, Blocking> {
@ -959,7 +959,7 @@ impl<'d> I2c<'d, Async> {
}
/// Writes bytes to slave with address `address`
pub async fn write<A: Into<I2cAddress>>(
pub async fn write_async<A: Into<I2cAddress>>(
&mut self,
address: A,
buffer: &[u8],
@ -976,7 +976,7 @@ impl<'d> I2c<'d, Async> {
///
/// The corresponding error variant from [`Error`] will be returned if the
/// passed buffer has zero length.
pub async fn read<A: Into<I2cAddress>>(
pub async fn read_async<A: Into<I2cAddress>>(
&mut self,
address: A,
buffer: &mut [u8],
@ -994,7 +994,7 @@ impl<'d> I2c<'d, Async> {
///
/// The corresponding error variant from [`Error`] will be returned if the
/// passed buffer has zero length.
pub async fn write_read<A: Into<I2cAddress>>(
pub async fn write_read_async<A: Into<I2cAddress>>(
&mut self,
address: A,
write_buffer: &[u8],
@ -1039,7 +1039,7 @@ impl<'d> I2c<'d, Async> {
///
/// The corresponding error variant from [`Error`] will be returned if the
/// buffer passed to an [`Operation`] has zero length.
pub async fn transaction<'a, A: Into<I2cAddress>>(
pub async fn transaction_async<'a, A: Into<I2cAddress>>(
&mut self,
address: A,
operations: impl IntoIterator<Item = &'a mut Operation<'a>>,

View File

@ -44,7 +44,9 @@ async fn main(_spawner: Spawner) {
loop {
let mut data = [0u8; 22];
i2c.write_read(0x77, &[0xaa], &mut data).await.unwrap();
i2c.write_read_async(0x77, &[0xaa], &mut data)
.await
.unwrap();
esp_println::println!("direct: {:02x?}", data);
read_data(&mut i2c).await;
Timer::after(Duration::from_millis(1000)).await;