Skip to content

Commit d26c531

Browse files
authored
i2c: Add I2C Controller implementation (#27)
This adds the I2C Controller driver implementation for the STM32H5. It implements a blocking, and non-blocking API, as well as the embedded-hal 1.0 traits. It borrows a lot from the STM32H7 HAL (particularly the TIMINGR configuration, which is a bit inscrutable in the reference manual), but it borrows the `Instance` concept from the STM32F4 project to minimize the need for macros. It uses the updated terminology of Controller/Target from the latest version of the I2C spec (Rev. 7.0)
1 parent 38bb75b commit d26c531

File tree

8 files changed

+1396
-1
lines changed

8 files changed

+1396
-1
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ opt-level = "s" # optimize for binary size
8787
[[example]]
8888
name = "blinky"
8989
required-features = ["stm32h503"]
90+
91+
[[example]]
92+
name = "i2c"
93+
required-features = ["stm32h503"]

examples/i2c.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
#[macro_use]
6+
mod utilities;
7+
use embedded_hal::{delay::DelayNs, i2c::I2c};
8+
use fugit::SecsDurationU32;
9+
use stm32h5xx_hal::{delay::Delay, pac, prelude::*};
10+
11+
use cortex_m_rt::entry;
12+
13+
use log::info;
14+
15+
#[entry]
16+
fn main() -> ! {
17+
utilities::logger::init();
18+
log::set_max_level(log::LevelFilter::Debug);
19+
let cp = cortex_m::Peripherals::take().unwrap();
20+
let dp = pac::Peripherals::take().unwrap();
21+
22+
// Constrain and Freeze power
23+
info!("Setup PWR... ");
24+
let pwr = dp.PWR.constrain();
25+
let pwrcfg = pwr.freeze();
26+
27+
// Constrain and Freeze clock
28+
info!("Setup RCC... ");
29+
let rcc = dp.RCC.constrain();
30+
let ccdr = rcc.sys_ck(100.MHz()).freeze(pwrcfg, &dp.SBS);
31+
32+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
33+
34+
let mut delay = Delay::new(cp.SYST, &ccdr.clocks);
35+
let duration = SecsDurationU32::secs(1).to_millis();
36+
37+
// Configure the SCL and the SDA pin for our I2C bus
38+
let scl = gpiob.pb5.into_alternate_open_drain();
39+
let sda = gpiob.pb3.into_alternate_open_drain();
40+
41+
info!("");
42+
info!("stm32h5xx-hal example - I2C");
43+
info!("");
44+
45+
let mut i2c =
46+
dp.I2C2
47+
.i2c((scl, sda), 100.kHz(), ccdr.peripheral.I2C2, &ccdr.clocks);
48+
49+
// The STM32H503 NUCLEO board does not have any I2C peripherals, so put in the address of
50+
// whatever peripheral you connect
51+
let device_addr: u8 = 0x18;
52+
// This implements a typical 8-bit register read operation, writing the register address and
53+
// then issuing a repeat start to read the register value. Tweak these settings to read the
54+
// desired amount of bytes from the register address.
55+
let register_addr = 0x02;
56+
let write = &[register_addr];
57+
let mut read = [0u8; 1];
58+
59+
loop {
60+
i2c.write_read(device_addr, write, &mut read).unwrap();
61+
info!("Read reg {register_addr}: {read:X?}");
62+
delay.delay_ms(duration);
63+
}
64+
}

0 commit comments

Comments
 (0)