Skip to content

Commit

Permalink
Support for I2C (stm32-rs#26)
Browse files Browse the repository at this point in the history
* Add support for I2C.

Most of this code is taken from stm32g0xx-hal, with only minor changes to
the way pins are initialized and to the interaction with RCC.

* Improve the I2C documentation.

* Fix compiler error for devices without I2C4.

* Add an I2C/MPU6050 example (the timing is still broken).

* Fix the I2C bit rate.

The std::max() meant that scll was always set to 255, resulting in bit
rates that were far too slow. Also, the documentation states that the
clock is divided by PRESC+1, not by 2^(PRESC+1).
  • Loading branch information
mgottschlag authored and Luctius committed Sep 17, 2021
1 parent a847e75 commit 6fb5e69
Show file tree
Hide file tree
Showing 6 changed files with 596 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cortex-m-log = { version = "0.7", features = ["log-integration"] }
cfg-if = "0.1.10"
rtt-target = { version = "0.3.0", features = ["cortex-m"] }
panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
mpu6050 = "0.1.4"

[features]
default = ["rt"]
Expand Down
44 changes: 44 additions & 0 deletions examples/i2c-mpu6050.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]

use hal::i2c::Config;
use hal::prelude::*;
use hal::stm32;
use stm32g4xx_hal as hal;

use cortex_m_rt::entry;
use log::info;
use mpu6050::*;

#[macro_use]
mod utils;

#[entry]
fn main() -> ! {
utils::logger::init();

let dp = stm32::Peripherals::take().expect("cannot take peripherals");
let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals");

let mut rcc = dp.RCC.constrain();
let gpiob = dp.GPIOB.split(&mut rcc);

let sda = gpiob.pb9.into_alternate_open_drain();
let scl = gpiob.pb8.into_alternate_open_drain();

let i2c = dp.I2C1.i2c(sda, scl, Config::new(100.khz()), &mut rcc);

let mut mpu = Mpu6050::new(i2c);
let mut delay = cp.SYST.delay(&rcc.clocks);
mpu.init(&mut delay).expect("cannot initialize the MPU6050");

loop {
let acc = mpu.get_acc().expect("cannot read accelerometer");
let gyro = mpu.get_gyro().expect("cannot read gyro");
let temp = mpu.get_temp().expect("cannot read temperature");
info!("acc: {:?}, gyro: {:?}, temp: {:?}C", acc, gyro, temp);
delay.delay(250.ms());
}
}
42 changes: 42 additions & 0 deletions examples/i2c.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![deny(warnings)]
#![deny(unsafe_code)]
#![no_main]
#![no_std]

use hal::i2c::Config;
use hal::prelude::*;
use hal::stm32;
use stm32g4xx_hal as hal;

use cortex_m_rt::entry;
use log::info;

#[macro_use]
mod utils;

#[entry]
fn main() -> ! {
utils::logger::init();

let dp = stm32::Peripherals::take().expect("cannot take peripherals");
let mut rcc = dp.RCC.constrain();
let gpiob = dp.GPIOB.split(&mut rcc);

let sda = gpiob.pb9.into_alternate_open_drain();
let scl = gpiob.pb8.into_alternate_open_drain();

let mut i2c = dp.I2C1.i2c(sda, scl, Config::new(40.khz()), &mut rcc);
// Alternatively, it is possible to specify the exact timing as follows (see the documentation
// of with_timing() for an explanation of the constant):
//let mut i2c = dp
// .I2C1
// .i2c(sda, scl, Config::with_timing(0x3042_0f13), &mut rcc);

let buf: [u8; 1] = [0];
loop {
match i2c.write(0x3c, &buf) {
Ok(_) => info!("ok"),
Err(err) => info!("error: {:?}", err),
}
}
}
Loading

0 comments on commit 6fb5e69

Please sign in to comment.