Skip to content

Commit 8b7f4ee

Browse files
authored
Merge pull request #244 from davidlattimore/i2c-config-struct
Pass a Config struct when initializing i2c
2 parents aa1b554 + c62164b commit 8b7f4ee

File tree

2 files changed

+86
-52
lines changed

2 files changed

+86
-52
lines changed

examples/i2c_write.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern crate stm32l4xx_hal as hal;
1414

1515
use crate::hal::prelude::*;
1616

17+
use crate::hal::i2c;
1718
use crate::hal::i2c::I2c;
1819
use crate::rt::entry;
1920
use crate::rt::ExceptionFrame;
@@ -50,7 +51,12 @@ fn main() -> ! {
5051
sda.internal_pull_up(&mut gpioa.pupdr, true);
5152
let sda = sda.into_af4(&mut gpioa.moder, &mut gpioa.afrh);
5253

53-
let mut i2c = I2c::i2c1(dp.I2C1, (scl, sda), 100.khz(), clocks, &mut rcc.apb1r1);
54+
let mut i2c = I2c::i2c1(
55+
dp.I2C1,
56+
(scl, sda),
57+
i2c::Config::new(100.khz(), clocks),
58+
&mut rcc.apb1r1,
59+
);
5460

5561
// i2c.write(0x3C, &[0xCC, 0xAA]).unwrap();
5662
let mut buffer = [0u8; 2];

src/i2c.rs

Lines changed: 79 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -58,56 +58,18 @@ pub struct I2c<I2C, PINS> {
5858
pins: PINS,
5959
}
6060

61-
macro_rules! hal {
62-
($i2c_type: ident, $enr: ident, $rstr: ident, $i2cX: ident, $i2cXen: ident, $i2cXrst: ident) => {
63-
impl<SCL, SDA> I2c<$i2c_type, (SCL, SDA)> {
64-
pub fn $i2cX<F>(
65-
i2c: $i2c_type,
66-
pins: (SCL, SDA),
67-
freq: F,
68-
clocks: Clocks,
69-
apb1: &mut APB1R1,
70-
) -> Self
71-
where
72-
F: Into<Hertz>,
73-
SCL: SclPin<$i2c_type>,
74-
SDA: SdaPin<$i2c_type>,
75-
{
76-
apb1.$enr().modify(|_, w| w.$i2cXen().set_bit());
77-
apb1.$rstr().modify(|_, w| w.$i2cXrst().set_bit());
78-
apb1.$rstr().modify(|_, w| w.$i2cXrst().clear_bit());
79-
Self::new(i2c, pins, freq, clocks)
80-
}
81-
}
82-
};
61+
pub struct Config {
62+
presc: u8,
63+
sclh: u8,
64+
scll: u8,
65+
scldel: u8,
66+
sdadel: u8,
8367
}
8468

85-
hal!(I2C1, enr, rstr, i2c1, i2c1en, i2c1rst);
86-
hal!(I2C2, enr, rstr, i2c2, i2c2en, i2c2rst);
87-
hal!(I2C3, enr, rstr, i2c3, i2c3en, i2c3rst);
88-
89-
// This peripheral is not present on
90-
// STM32L471XX and STM32L431XX
91-
// STM32L432XX and STM32l442XX
92-
// STM32L486XX and STM32L476XX
93-
#[cfg(any(feature = "stm32l4x1", feature = "stm32l4x2", feature = "stm32l4x6"))]
94-
hal!(I2C4, enr2, rstr2, i2c4, i2c4en, i2c4rst);
95-
96-
impl<SCL, SDA, I2C> I2c<I2C, (SCL, SDA)>
97-
where
98-
I2C: Deref<Target = i2c1::RegisterBlock>,
99-
{
100-
/// Configures the I2C peripheral to work in master mode
101-
fn new<F>(i2c: I2C, pins: (SCL, SDA), freq: F, clocks: Clocks) -> Self
102-
where
103-
F: Into<Hertz>,
104-
SCL: SclPin<I2C>,
105-
SDA: SdaPin<I2C>,
106-
{
69+
impl Config {
70+
pub fn new<F: Into<Hertz>>(freq: F, clocks: Clocks) -> Self {
10771
let freq = freq.into().0;
10872
assert!(freq <= 1_000_000);
109-
// Make sure the I2C unit is disabled so we can configure it
110-
i2c.cr1.modify(|_, w| w.pe().clear_bit());
11173

11274
// TODO review compliance with the timing requirements of I2C
11375
// t_I2CCLK = 1 / PCLK1
@@ -177,18 +139,84 @@ where
177139
let sclh = u8_or_panic!(sclh, "I2C sclh");
178140
let scll = u8_or_panic!(scll, "I2C scll");
179141

142+
Self {
143+
presc,
144+
sclh,
145+
scll,
146+
scldel,
147+
sdadel,
148+
}
149+
}
150+
151+
/// For the layout of `timing_bits`, see RM0394 section 37.7.5.
152+
pub fn with_timing(timing_bits: u32) -> Self {
153+
Self {
154+
presc: ((timing_bits >> 28) & 0xf) as u8,
155+
scldel: ((timing_bits >> 20) & 0xf) as u8,
156+
sdadel: ((timing_bits >> 16) & 0xf) as u8,
157+
sclh: ((timing_bits >> 8) & 0xff) as u8,
158+
scll: (timing_bits & 0xff) as u8,
159+
}
160+
}
161+
}
162+
163+
macro_rules! hal {
164+
($i2c_type: ident, $enr: ident, $rstr: ident, $i2cX: ident, $i2cXen: ident, $i2cXrst: ident) => {
165+
impl<SCL, SDA> I2c<$i2c_type, (SCL, SDA)> {
166+
pub fn $i2cX(
167+
i2c: $i2c_type,
168+
pins: (SCL, SDA),
169+
config: Config,
170+
apb1: &mut APB1R1,
171+
) -> Self
172+
where
173+
SCL: SclPin<$i2c_type>,
174+
SDA: SdaPin<$i2c_type>,
175+
{
176+
apb1.$enr().modify(|_, w| w.$i2cXen().set_bit());
177+
apb1.$rstr().modify(|_, w| w.$i2cXrst().set_bit());
178+
apb1.$rstr().modify(|_, w| w.$i2cXrst().clear_bit());
179+
Self::new(i2c, pins, config)
180+
}
181+
}
182+
};
183+
}
184+
185+
hal!(I2C1, enr, rstr, i2c1, i2c1en, i2c1rst);
186+
hal!(I2C2, enr, rstr, i2c2, i2c2en, i2c2rst);
187+
hal!(I2C3, enr, rstr, i2c3, i2c3en, i2c3rst);
188+
189+
// This peripheral is not present on
190+
// STM32L471XX and STM32L431XX
191+
// STM32L432XX and STM32l442XX
192+
// STM32L486XX and STM32L476XX
193+
#[cfg(any(feature = "stm32l4x1", feature = "stm32l4x2", feature = "stm32l4x6"))]
194+
hal!(I2C4, enr2, rstr2, i2c4, i2c4en, i2c4rst);
195+
196+
impl<SCL, SDA, I2C> I2c<I2C, (SCL, SDA)>
197+
where
198+
I2C: Deref<Target = i2c1::RegisterBlock>,
199+
{
200+
/// Configures the I2C peripheral to work in master mode
201+
fn new(i2c: I2C, pins: (SCL, SDA), config: Config) -> Self
202+
where
203+
SCL: SclPin<I2C>,
204+
SDA: SdaPin<I2C>,
205+
{
206+
// Make sure the I2C unit is disabled so we can configure it
207+
i2c.cr1.modify(|_, w| w.pe().clear_bit());
180208
// Configure for "fast mode" (400 KHz)
181209
i2c.timingr.write(|w| {
182210
w.presc()
183-
.bits(presc)
211+
.bits(config.presc)
184212
.scll()
185-
.bits(scll)
213+
.bits(config.scll)
186214
.sclh()
187-
.bits(sclh)
215+
.bits(config.sclh)
188216
.sdadel()
189-
.bits(sdadel)
217+
.bits(config.sdadel)
190218
.scldel()
191-
.bits(scldel)
219+
.bits(config.scldel)
192220
});
193221

194222
// Enable the peripheral

0 commit comments

Comments
 (0)