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// }