alt_stm32f30x_hal/i2c.rs
1//! Inter-Integrated Circuit (I2C) bus
2
3use cast::u8;
4use crate::pac::{I2C1, I2C2, RCC};
5
6use crate::gpio::{AltFn, PinMode, PullType};
7use crate::gpio::{HighSpeed, PushPull, AF4};
8use crate::gpio::{PA10, PA14, PA15, PA9};
9use crate::gpio::{PB6, PB7, PB8, PB9};
10use crate::gpio::{PF0, PF1, PF6};
11use crate::rcc::Clocks;
12use crate::time::Hertz;
13use hal::blocking::i2c::{Read, Write, WriteRead};
14
15/// I2C error
16#[derive(Debug)]
17pub enum Error {
18 /// NACK received, i.e. communication not acknowledged by peripheral
19 NACK,
20 /// Bus error
21 Bus,
22 /// Arbitration loss
23 Arbitration,
24 // Overrun, // slave mode only
25 // Pec, // SMBUS mode only
26 // Timeout, // SMBUS mode only
27 // Alert, // SMBUS mode only
28 #[doc(hidden)]
29 _Extensible,
30}
31
32/// I2c peripheral operating in master mode
33pub struct I2c<I2C, PINS> {
34 i2c: I2C,
35 pins: PINS,
36}
37
38/// I2c extension for I2C
39pub trait I2cExt<I2C, ISCL, ISDA, SCL, SDA> {
40 /// Configures the I2c peripheral to work in master mode
41 /// Consumes I2c peripheral and pair of (SCL, SDA) pins.
42 /// Returns [`I2c`].
43 ///
44 /// [`I2c`]: ./struct.I2c.html
45 fn i2c<F>(self,
46 pins: (ISCL, ISDA),
47 freq: F,
48 clocks: Clocks)
49 -> I2c<I2C, (SCL, SDA)>
50 where F: Into<Hertz<u32>>;
51}
52
53macro_rules! busy_wait {
54 ($i2c:expr, $flag:ident) => {
55 loop {
56 let isr = $i2c.isr.read();
57
58 if isr.berr().bit_is_set() {
59 return Err(Error::Bus);
60 } else if isr.arlo().bit_is_set() {
61 return Err(Error::Arbitration);
62 } else if isr.nackf().bit_is_set() {
63 return Err(Error::NACK);
64 } else if isr.$flag().bit_is_set() {
65 break;
66 } else {
67 // try again
68 }
69 }
70 };
71}
72
73macro_rules! i2c {
74 ($I2CX:ident,
75 $i2cXen:ident,
76 $i2cXrst:ident,
77 $afn:ident,
78 $speed:ident,
79 scl: [$($scl: ident, )+],
80 sda: $sda: tt
81 ) => {
82 i2c!{
83 $I2CX,
84 $i2cXen,
85 $i2cXrst,
86 $afn,
87 $speed,
88 [$(
89 ($scl, $sda),
90 )+]
91 }
92 };
93 ($I2CX:ident,
94 $i2cXen:ident,
95 $i2cXrst:ident,
96 $afn:ident,
97 $speed:ident,
98 [$(($scl: ident, [$($sda:ident, )+]),)+]
99 ) => {
100 $(
101 $(
102 impl<PT: PullType, PM: PinMode>
103 I2cExt<$I2CX,
104 $scl<PT, PM>,
105 $sda<PT, PM>,
106 $scl<PT, AltFn<$afn, PushPull, $speed>>,
107 $sda<PT, AltFn<$afn, PushPull, $speed>>> for $I2CX
108 {
109 fn i2c<F>(
110 self,
111 pins: ($scl<PT, PM>, $sda<PT, PM>),
112 freq: F,
113 clocks: Clocks)
114 -> I2c<$I2CX,
115 ($scl<PT, AltFn<$afn, PushPull, $speed>>,
116 $sda<PT, AltFn<$afn, PushPull, $speed>>)> where
117 F: Into<Hertz<u32>>,
118 {
119 let outpins = (pins.0.alternating($afn).output_speed($speed),
120 pins.1.alternating($afn).output_speed($speed));
121 let apbenr = unsafe { &(*RCC::ptr()).apb1enr };
122 let apbrstr = unsafe { &(*RCC::ptr()).apb1rstr };
123
124 apbenr.modify(|_, w| w.$i2cXen().enabled());
125 apbrstr.modify(|_, w| w.$i2cXrst().set_bit());
126 apbrstr.modify(|_, w| w.$i2cXrst().clear_bit());
127
128 let freq = freq.into().0;
129
130 // TODO: remove assert, return error?
131 assert!(freq <= 1_000_000);
132
133 // TODO review compliance with the timing requirements of I2C
134 // t_I2CCLK = 1 / PCLK1
135 // t_PRESC = (PRESC + 1) * t_I2CCLK
136 // t_SCLL = (SCLL + 1) * t_PRESC
137 // t_SCLH = (SCLH + 1) * t_PRESC
138 //
139 // t_SYNC1 + t_SYNC2 > 4 * t_I2CCLK
140 // t_SCL ~= t_SYNC1 + t_SYNC2 + t_SCLL + t_SCLH
141 let i2cclk = clocks.pclk1().0;
142 let ratio = i2cclk / freq - 4;
143 let (presc, scll, sclh, sdadel, scldel) = if freq >= 100_000 {
144 // fast-mode or fast-mode plus
145 // here we pick SCLL + 1 = 2 * (SCLH + 1)
146 let presc = ratio / 387;
147 let sclh = ((ratio / (presc + 1)) - 3) / 3;
148 let scll = 2 * (sclh + 1) - 1;
149 let (sdadel, scldel) = if freq > 400_000 {
150 // fast-mode plus
151 let sdadel = 0;
152 let scldel = i2cclk / 4_000_000 / (presc + 1) - 1;
153 (sdadel, scldel)
154 } else {
155 // fast-mode
156 let sdadel = i2cclk / 8_000_000 / (presc + 1);
157 let scldel = i2cclk / 2_000_000 / (presc + 1) - 1;
158 (sdadel, scldel)
159 };
160 (presc, scll, sclh, sdadel, scldel)
161 } else {
162 // standard-mode
163 // here we pick SCLL = SCLH
164 let presc = ratio / 514;
165 let sclh = ((ratio / (presc + 1)) - 2) / 2;
166 let scll = sclh;
167 let sdadel = i2cclk / 2_000_000 / (presc + 1);
168 let scldel = i2cclk / 800_000 / (presc + 1) - 1;
169 (presc, scll, sclh, sdadel, scldel)
170 };
171 // TODO: remove asserts
172 let presc = u8(presc).unwrap();
173 assert!(presc < 16);
174 let scldel = u8(scldel).unwrap();
175 assert!(scldel < 16);
176 let sdadel = u8(sdadel).unwrap();
177 assert!(sdadel < 16);
178 let sclh = u8(sclh).unwrap();
179 let scll = u8(scll).unwrap();
180
181 // Configure for "fast mode" (400 KHz)
182 self.timingr.write(|w|
183 w.presc()
184 .bits(presc)
185 .scll()
186 .bits(scll)
187 .sclh()
188 .bits(sclh)
189 .sdadel()
190 .bits(sdadel)
191 .scldel()
192 .bits(scldel)
193 );
194
195 // Enable the peripheral
196 self.cr1.write(|w| w.pe().set_bit());
197
198 I2c { i2c: self, pins: outpins }
199 }
200 }
201 )+
202 )+
203
204 impl<SCL, SDA> I2c<$I2CX, (SCL, SDA)> {
205 /// Releases the I2C peripheral and associated pins
206 pub fn free(self) -> ($I2CX, (SCL, SDA)) {
207 (self.i2c, self.pins)
208 }
209 }
210
211 impl<PINS> Write for I2c<$I2CX, PINS> {
212 type Error = Error;
213
214 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
215 // TODO support transfers of more than 255 bytes
216 assert!(bytes.len() < 256 && bytes.len() > 0);
217
218 // START and prepare to send `bytes`
219 self.i2c.cr2.write(|w| {
220 w.sadd()
221 .bits((addr << 1) as u16)
222 .rd_wrn()
223 .clear_bit()
224 .nbytes()
225 .bits(bytes.len() as u8)
226 .start()
227 .set_bit()
228 .autoend()
229 .set_bit()
230 });
231
232 for byte in bytes {
233 // Wait until we are allowed to send data (START has been ACKed or last byte
234 // when through)
235 busy_wait!(self.i2c, txis);
236
237 // put byte on the wire
238 self.i2c.txdr.write(|w| w.txdata().bits(*byte));
239 }
240
241 // Wait until the last transmission is finished ???
242 // busy_wait!(self.i2c, busy);
243
244 // automatic STOP
245
246 Ok(())
247 }
248 }
249
250 impl<PINS> WriteRead for I2c<$I2CX, PINS> {
251 type Error = Error;
252
253 fn write_read(
254 &mut self,
255 addr: u8,
256 bytes: &[u8],
257 buffer: &mut [u8],
258 ) -> Result<(), Error> {
259 // TODO support transfers of more than 255 bytes
260 assert!(bytes.len() < 256 && bytes.len() > 0);
261 assert!(buffer.len() < 256 && buffer.len() > 0);
262
263 // TODO do we have to explicitly wait here if the bus is busy (e.g. another
264 // master is communicating)?
265
266 // START and prepare to send `bytes`
267 self.i2c.cr2.write(|w| {
268 w.sadd()
269 .bits((addr << 1) as u16)
270 .rd_wrn()
271 .clear_bit()
272 .nbytes()
273 .bits(bytes.len() as u8)
274 .start()
275 .set_bit()
276 .autoend()
277 .clear_bit()
278 });
279
280 for byte in bytes {
281 // Wait until we are allowed to send data (START has been ACKed or last byte
282 // when through)
283 busy_wait!(self.i2c, txis);
284
285 // put byte on the wire
286 self.i2c.txdr.write(|w| w.txdata().bits(*byte));
287 }
288
289 // Wait until the last transmission is finished
290 busy_wait!(self.i2c, tc);
291
292 // reSTART and prepare to receive bytes into `buffer`
293 self.i2c.cr2.write(|w| {
294 w.sadd()
295 .bits((addr << 1) as u16)
296 .rd_wrn()
297 .set_bit()
298 .nbytes()
299 .bits(buffer.len() as u8)
300 .start()
301 .set_bit()
302 .autoend()
303 .set_bit()
304 });
305
306 for byte in buffer {
307 // Wait until we have received something
308 busy_wait!(self.i2c, rxne);
309
310 *byte = self.i2c.rxdr.read().rxdata().bits();
311 }
312
313 // automatic STOP
314
315 Ok(())
316 }
317 }
318
319
320 impl<PINS> Read for I2c<$I2CX, PINS> {
321 type Error = Error;
322
323 fn read(
324 &mut self,
325 addr: u8,
326 buffer: &mut [u8],
327 ) -> Result<(), Error> {
328 // TODO support transfers of more than 255 bytes
329 assert!(buffer.len() < 256 && buffer.len() > 0);
330
331 // TODO do we have to explicitly wait here if the bus is busy (e.g. another
332 // master is communicating)?
333
334 // reSTART and prepare to receive bytes into `buffer`
335 self.i2c.cr2.write(|w| {
336 w.sadd()
337 .bits((addr << 1) as u16)
338 .rd_wrn()
339 .set_bit()
340 .nbytes()
341 .bits(buffer.len() as u8)
342 .start()
343 .set_bit()
344 .autoend()
345 .set_bit()
346 });
347
348 for byte in buffer {
349 // Wait until we have received something
350 busy_wait!(self.i2c, rxne);
351
352 *byte = self.i2c.rxdr.read().rxdata().bits();
353 }
354
355 // automatic STOP
356
357 Ok(())
358 }
359 }
360 }
361}
362
363i2c!(I2C1, i2c1en, i2c1rst, AF4, HighSpeed,
364 scl: [PB6, PB8, PA15, ],
365 sda: [PB7, PB9, PA14, ]);
366i2c!(I2C2, i2c2en, i2c2rst, AF4, HighSpeed,
367 scl: [PA9, PF1, PF6, ],
368 sda: [PA10, PF0, ]);
369
370// hal! {
371// I2C1: (i2c1, i2c1en, i2c1rst),
372// I2C2: (i2c2, i2c2en, i2c2rst),
373// }