Skip to content

Commit

Permalink
apply_config
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Nov 4, 2024
1 parent 3777a72 commit 6efc6da
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 36 deletions.
3 changes: 3 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split()` to obtain peripheral interconnect signals. (#2418)
- `gpio::Input::{split(), into_peripheral_output()}` when used with output pins. (#2418)
- `gpio::Output::peripheral_input()` (#2418)
- `I2c::{apply_config(), with_sda(), with_scl()}` (#2437)
- `I2c` now implements `embassy_embedded_hal::SetConfig` (#2437)

### Changed

Expand Down Expand Up @@ -74,6 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388)
- Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430)
- The `configure_for_async` DMA functions have been removed (#2430)
- `I2c::new()` no longer takes `frequency` and pins as parameters. (#2437)

## [0.21.1]

Expand Down
1 change: 1 addition & 0 deletions esp-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ defmt = { version = "0.3.8", optional = true }
delegate = "0.12.0"
digest = { version = "0.10.7", default-features = false, optional = true }
document-features = "0.2.10"
embassy-embedded-hal = "0.2.0"
embassy-futures = "0.1.1"
embassy-sync = "0.6.0"
embassy-usb-driver = { version = "0.1.0", optional = true }
Expand Down
27 changes: 27 additions & 0 deletions esp-hal/MIGRATING-0.21.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,30 @@ The previous signal function have been replaced by `split`. This change affects

`into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to
the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead.

## Changes to peripheral configuration

### I2C drivers can now be configured using `i2c::Config`

- The old methods to change configuration have been removed.
- The `new` and `new_typed` constructor no longer takes `frequency` and pins.
- The default configuration is now:
- bus frequency: 100 kHz
- timeout: `None`
- There are new constructors (`new_with_config`, `new_typed_with_config`) and a new `apply_config` method to apply custom configuration.
- Pins can now be configured using `with_sda` and `with_scl`

```diff
-use esp_hal::i2c::I2c;
+use esp_hal::i2c::{Config, I2c};
-I2c::new(I2C0, sda, scl, 100.kHz());
+I2c::new_with_config(
+ I2C0,
+ Config {
+ frequency: 400.kHz(),
+ ..Config::default()
+ },
+)
+.with_sda(sda)
+.with_scl(scl);
```
95 changes: 70 additions & 25 deletions esp-hal/src/i2c/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
mod support;
mod version;

use core::marker::PhantomData;
use core::{convert::Infallible, marker::PhantomData};

use embassy_embedded_hal::SetConfig;
use embassy_sync::waitqueue::AtomicWaker;
use fugit::HertzU32;
use version::{I2C_CHUNK_SIZE, I2C_LL_INTR_MASK};
Expand Down Expand Up @@ -205,12 +206,44 @@ impl From<Ack> for u32 {
}
}

/// I2C driver configuration
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config {
/// The I2C clock frequency.
pub frequency: HertzU32,

/// The I2C timeout.
// TODO: explain this function better - what's the unit, what happens on
// timeout, and just what exactly is a timeout in this context?
pub timeout: Option<u32>,
}

impl Default for Config {
fn default() -> Self {
use fugit::RateExtU32;
Config {
frequency: 100.kHz(),
timeout: None,
}
}
}

/// I2C driver
pub struct I2c<'d, DM: Mode, T = AnyI2c> {
i2c: PeripheralRef<'d, T>,
phantom: PhantomData<DM>,
frequency: HertzU32,
timeout: Option<u32>,
config: Config,
}

impl<T: Instance, DM: Mode> SetConfig for I2c<'_, DM, T> {
type Config = Config;
type ConfigError = Infallible;

fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.apply_config(config);
Ok(())
}
}

impl<'d, T, DM: Mode> I2c<'d, DM, T>
Expand All @@ -228,16 +261,13 @@ where
PeripheralClockControl::reset(self.i2c.peripheral());
PeripheralClockControl::enable(self.i2c.peripheral());

self.driver().setup(self.frequency, self.timeout);
self.driver().setup(&self.config);
}

/// Set the I2C timeout.
// TODO: explain this function better - what's the unit, what happens on
// timeout, and just what exactly is a timeout in this context?
pub fn with_timeout(mut self, timeout: Option<u32>) -> Self {
self.timeout = timeout;
self.driver().setup(self.frequency, self.timeout);
self
/// Applies a new configuration.
pub fn apply_config(&mut self, config: &Config) {
self.config = *config;
self.driver().setup(&self.config);
}

fn transaction_impl<'a>(
Expand Down Expand Up @@ -335,35 +365,52 @@ where
}

impl<'d> I2c<'d, Blocking> {
/// Create a new I2C instance
/// Creates a new I2C instance.
///
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new(i2c: impl Peripheral<P = impl Instance> + 'd) -> Self {
Self::new_with_config(i2c.map_into(), Config::default())
}

/// Creates a new I2C instance with a given configuration.
///
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new(i2c: impl Peripheral<P = impl Instance> + 'd, frequency: HertzU32) -> Self {
Self::new_typed(i2c.map_into(), frequency)
pub fn new_with_config(i2c: impl Peripheral<P = impl Instance> + 'd, config: Config) -> Self {
Self::new_typed_with_config(i2c.map_into(), config)
}
}

impl<'d, T> I2c<'d, Blocking, T>
where
T: Instance,
{
/// Create a new I2C instance
/// Creates a new I2C instance with a given configuration.
///
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_typed(i2c: impl Peripheral<P = T> + 'd) -> Self {
Self::new_typed_with_config(i2c, Config::default())
}

/// Creates a new I2C instance with a given configuration.
///
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_typed(i2c: impl Peripheral<P = T> + 'd, frequency: HertzU32) -> Self {
pub fn new_typed_with_config(i2c: impl Peripheral<P = T> + 'd, config: Config) -> Self {
crate::into_ref!(i2c);

let i2c = I2c {
i2c,
phantom: PhantomData,
frequency,
timeout: None,
config,
};

PeripheralClockControl::reset(i2c.i2c.peripheral());
PeripheralClockControl::enable(i2c.i2c.peripheral());

i2c.driver().setup(frequency, None);
i2c.driver().setup(&i2c.config);
i2c
}

Expand All @@ -376,8 +423,7 @@ where
I2c {
i2c: self.i2c,
phantom: PhantomData,
frequency: self.frequency,
timeout: self.timeout,
config: self.config,
}
}

Expand Down Expand Up @@ -532,8 +578,7 @@ where
I2c {
i2c: self.i2c,
phantom: PhantomData,
frequency: self.frequency,
timeout: self.timeout,
config: self.config,
}
}

Expand Down Expand Up @@ -867,7 +912,7 @@ struct Driver<'a> {
impl Driver<'_> {
/// Configures the I2C peripheral with the specified frequency, clocks, and
/// optional timeout.
fn setup(&self, frequency: HertzU32, timeout: Option<u32>) {
fn setup(&self, config: &Config) {
self.info.register_block().ctr().write(|w| {
// Set I2C controller to master mode
w.ms_mode().set_bit();
Expand All @@ -888,7 +933,7 @@ impl Driver<'_> {
self.set_filter(Some(7), Some(7));

// Configure frequency
self.set_frequency(frequency, timeout);
self.set_frequency(config.frequency, config.timeout);

self.update_config();

Expand Down
2 changes: 1 addition & 1 deletion examples/src/bin/embassy_i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {

let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);

let i2c0 = I2c::new(peripherals.I2C0, 400.kHz())
let i2c0 = I2c::new(peripherals.I2C0)
.with_sda(io.pins.gpio4)
.with_scl(io.pins.gpio5)
.into_async();
Expand Down
2 changes: 1 addition & 1 deletion examples/src/bin/embassy_i2c_bmp180_calibration_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {

let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);

let mut i2c = I2c::new(peripherals.I2C0, 400.kHz())
let mut i2c = I2c::new(peripherals.I2C0)
.with_sda(io.pins.gpio4)
.with_scl(io.pins.gpio5)
.into_async();
Expand Down
2 changes: 1 addition & 1 deletion examples/src/bin/i2c_bmp180_calibration_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn main() -> ! {

// Create a new peripheral object with the described wiring and standard
// I2C clock speed:
let mut i2c = I2c::new(peripherals.I2C0, 100.kHz())
let mut i2c = I2c::new(peripherals.I2C0)
.with_sda(io.pins.gpio4)
.with_scl(io.pins.gpio5);

Expand Down
2 changes: 1 addition & 1 deletion examples/src/bin/i2c_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() -> ! {

// Create a new peripheral object with the described wiring
// and standard I2C clock speed
let i2c = I2c::new(peripherals.I2C0, 100.kHz())
let i2c = I2c::new(peripherals.I2C0)
.with_sda(io.pins.gpio4)
.with_scl(io.pins.gpio5);

Expand Down
2 changes: 1 addition & 1 deletion examples/src/bin/lcd_cam_ov2640.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn main() -> ! {

delay.delay_millis(500u32);

let i2c = I2c::new(peripherals.I2C0, 100u32.kHz())
let i2c = I2c::new(peripherals.I2C0)
.with_sda(cam_siod)
.with_scl(cam_sioc);

Expand Down
9 changes: 3 additions & 6 deletions hil-test/tests/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use esp_hal::{
gpio::Io,
i2c::{I2c, Operation},
prelude::*,
Async,
Blocking,
};
Expand Down Expand Up @@ -40,11 +39,9 @@ mod tests {

// Create a new peripheral object with the described wiring and standard
// I2C clock speed:
let i2c = I2c::new(peripherals.I2C0, 100.kHz())
.with_sda(sda)
.with_scl(scl);

Context { i2c }
Context {
i2c: I2c::new(peripherals.I2C0).with_sda(sda).with_scl(scl),
}
}

#[test]
Expand Down

0 comments on commit 6efc6da

Please sign in to comment.