Skip to content

Commit 4b6cc4d

Browse files
astapletonusbalbin
andauthored
i2c: Add target implementation (#45)
This extends the I2C driver to support target operation. It adds an I2cTarget type to represent the I2C operation as the target. Target operation can be operated in automatic ACKing mode, letting the hardware manage clock stretching and ACKing automatically, or it can be operated in manual ACK control mode, which lets the user of the driver determine when to ACK the end of a transaction. Manual ACK control allows for clock stretching while data is being processed or retrieved before ACK'ing the final byte of a transfer and initiating either the end of a transfer or a repeat start to read the processed/retrieved data. This implementation does not currently allow for ACKing individual or a subset of bytes manually, but extending the interface to do so can build upon what is implemented so far. This also adds role switching to the driver, enabling both controller and target implementation through choosing the appropriate initialization functions. --------- Co-authored-by: Albin Hedman <[email protected]>
1 parent cb0ea8a commit 4b6cc4d

File tree

7 files changed

+1152
-31
lines changed

7 files changed

+1152
-31
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,11 @@ name = "blinky"
9292
[[example]]
9393
name = "i2c"
9494
required-features = ["stm32h503"]
95+
96+
[[example]]
97+
name = "i2c_target"
98+
required-features = ["stm32h503"]
99+
100+
[[example]]
101+
name = "i2c_target_manual_ack"
102+
required-features = ["stm32h503"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ of support for peripherals is shown in the table below.
3636
|------------|----|---|---|
3737
| GPIO || - | |
3838
| ICache || - | |
39-
| I2C || - | Controller operation is done; Target is 🚧 |
39+
| I2C || - | |
4040
| CAN | 🚧 | - | |
4141
| Rng | 🚧 | [#34](https://github.com/stm32-rs/stm32h5xx-hal/issues/34)| |
4242
| SPI | 🚧 | [#36](https://github.com/stm32-rs/stm32h5xx-hal/issues/36) | |

examples/i2c_target.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
#[macro_use]
6+
mod utilities;
7+
use stm32h5xx_hal::{
8+
i2c::{TargetConfig, TargetListenEvent, Targetable},
9+
pac,
10+
prelude::*,
11+
};
12+
13+
use cortex_m_rt::entry;
14+
15+
use log::info;
16+
17+
#[entry]
18+
fn main() -> ! {
19+
utilities::logger::init();
20+
log::set_max_level(log::LevelFilter::Debug);
21+
let dp = pac::Peripherals::take().unwrap();
22+
23+
// Constrain and Freeze power
24+
info!("Setup PWR... ");
25+
let pwr = dp.PWR.constrain();
26+
let pwrcfg = pwr.freeze();
27+
28+
// Constrain and Freeze clock
29+
info!("Setup RCC... ");
30+
let rcc = dp.RCC.constrain();
31+
let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SBS);
32+
33+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
34+
35+
// Configure the SCL and the SDA pin for our I2C bus
36+
let scl = gpiob.pb5.into_alternate_open_drain();
37+
let sda = gpiob.pb3.into_alternate_open_drain();
38+
39+
info!("");
40+
info!("stm32h5xx-hal example - I2C Target");
41+
info!("");
42+
43+
let own_addr: u16 = 0x18;
44+
let bus_freq_hz: u32 = 100_000;
45+
let mut i2c = dp.I2C2.i2c_target_only(
46+
(scl, sda),
47+
TargetConfig::new(own_addr, bus_freq_hz),
48+
ccdr.peripheral.I2C2,
49+
&ccdr.clocks,
50+
);
51+
52+
i2c.enable_listen_event(TargetListenEvent::PrimaryAddress);
53+
let mut buf = [0u8; 2];
54+
55+
loop {
56+
let count = i2c.wait_for_target_read(&mut buf).unwrap();
57+
info!("Read {count} bytes: {:X?}", &buf[..count]);
58+
59+
let count = i2c.wait_for_target_write(b"Hello").unwrap();
60+
info!("Wrote {count} bytes");
61+
62+
i2c.wait_for_stop().unwrap();
63+
info!("==========");
64+
}
65+
}

examples/i2c_target_manual_ack.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
#[macro_use]
6+
mod utilities;
7+
use stm32h5xx_hal::{
8+
i2c::{TargetConfig, TargetEvent, TargetListenEvent, Targetable},
9+
pac,
10+
prelude::*,
11+
};
12+
13+
use cortex_m_rt::entry;
14+
15+
use log::info;
16+
17+
#[entry]
18+
fn main() -> ! {
19+
utilities::logger::init();
20+
log::set_max_level(log::LevelFilter::Info);
21+
let dp = pac::Peripherals::take().unwrap();
22+
23+
// Constrain and Freeze power
24+
info!("Setup PWR... ");
25+
let pwr = dp.PWR.constrain();
26+
let pwrcfg = pwr.freeze();
27+
28+
// Constrain and Freeze clock
29+
info!("Setup RCC... ");
30+
let rcc = dp.RCC.constrain();
31+
let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SBS);
32+
33+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
34+
35+
// Configure the SCL and the SDA pin for our I2C bus
36+
let scl = gpiob.pb5.into_alternate_open_drain();
37+
let sda = gpiob.pb3.into_alternate_open_drain();
38+
39+
info!("");
40+
info!("stm32h5xx-hal example - I2C Target");
41+
info!("");
42+
43+
let own_addr: u16 = 0x18;
44+
let bus_freq_hz: u32 = 100_000;
45+
let mut i2c = dp
46+
.I2C2
47+
.i2c_target_only(
48+
(scl, sda),
49+
TargetConfig::new(own_addr, bus_freq_hz),
50+
ccdr.peripheral.I2C2,
51+
&ccdr.clocks,
52+
)
53+
.with_manual_ack_control();
54+
55+
i2c.enable_listen_event(TargetListenEvent::PrimaryAddress);
56+
let mut buf = [0u8; 2];
57+
58+
loop {
59+
let event = i2c.wait_for_event().unwrap();
60+
let result = match event {
61+
TargetEvent::Read { address: _ } => i2c.write(b"Hello"),
62+
TargetEvent::Write { address: _ } => {
63+
let result = i2c.read(&mut buf);
64+
// An operation can be performed here while the clock is stretched low (ie.
65+
// calculating or fetching data)
66+
i2c.ack_transfer();
67+
result
68+
}
69+
TargetEvent::Stop => Ok(0),
70+
};
71+
72+
match result {
73+
Err(error) => info!("Error: {event:?} - {error:?}"),
74+
Ok(count) => match event {
75+
TargetEvent::Stop => info!("=========="),
76+
_ => info!("{event:?} ({count})"),
77+
},
78+
};
79+
}
80+
}

0 commit comments

Comments
 (0)