stm32f30x_hal/
i2c.rs

1//! Inter-Integrated Circuit (I2C) bus
2
3use cast::u8;
4use stm32f30x::{I2C1, I2C2};
5
6use gpio::gpioa::{PA10, PA9};
7use gpio::gpiob::{PB6, PB7, PB8, PB9};
8use gpio::gpiof::{PF0, PF1, PF6};
9use gpio::AF4;
10use hal::blocking::i2c::{Write, WriteRead};
11use rcc::{APB1, Clocks};
12use time::Hertz;
13
14/// I2C error
15#[derive(Debug)]
16pub enum Error {
17    /// Bus error
18    Bus,
19    /// Arbitration loss
20    Arbitration,
21    // Overrun, // slave mode only
22    // Pec, // SMBUS mode only
23    // Timeout, // SMBUS mode only
24    // Alert, // SMBUS mode only
25    #[doc(hidden)]
26    _Extensible,
27}
28
29// FIXME these should be "closed" traits
30/// SCL pin -- DO NOT IMPLEMENT THIS TRAIT
31pub unsafe trait SclPin<I2C> {}
32
33/// SDA pin -- DO NOT IMPLEMENT THIS TRAIT
34pub unsafe trait SdaPin<I2C> {}
35
36// unsafe impl SclPin<I2C1> for PA15<AF4> {}
37unsafe impl SclPin<I2C1> for PB6<AF4> {}
38unsafe impl SclPin<I2C1> for PB8<AF4> {}
39
40unsafe impl SclPin<I2C2> for PA9<AF4> {}
41unsafe impl SclPin<I2C2> for PF1<AF4> {}
42unsafe impl SclPin<I2C2> for PF6<AF4> {}
43
44// unsafe impl SdaPin<I2C1> for PA14<AF4> {}
45unsafe impl SdaPin<I2C1> for PB7<AF4> {}
46unsafe impl SdaPin<I2C1> for PB9<AF4> {}
47
48unsafe impl SdaPin<I2C2> for PA10<AF4> {}
49unsafe impl SdaPin<I2C2> for PF0<AF4> {}
50
51/// I2C peripheral operating in master mode
52pub struct I2c<I2C, PINS> {
53    i2c: I2C,
54    pins: PINS,
55}
56
57macro_rules! busy_wait {
58    ($i2c:expr, $flag:ident) => {
59        loop {
60            let isr = $i2c.isr.read();
61
62            if isr.berr().bit_is_set() {
63                return Err(Error::Bus);
64            } else if isr.arlo().bit_is_set() {
65                return Err(Error::Arbitration);
66            } else if isr.$flag().bit_is_set() {
67                break;
68            } else {
69                // try again
70            }
71        }
72    };
73}
74
75macro_rules! hal {
76    ($($I2CX:ident: ($i2cX:ident, $i2cXen:ident, $i2cXrst:ident),)+) => {
77        $(
78            impl<SCL, SDA> I2c<$I2CX, (SCL, SDA)> {
79                /// Configures the I2C peripheral to work in master mode
80                pub fn $i2cX<F>(
81                    i2c: $I2CX,
82                    pins: (SCL, SDA),
83                    freq: F,
84                    clocks: Clocks,
85                    apb1: &mut APB1,
86                ) -> Self where
87                    F: Into<Hertz>,
88                    SCL: SclPin<$I2CX>,
89                    SDA: SdaPin<$I2CX>,
90                {
91                    apb1.enr().modify(|_, w| w.$i2cXen().enabled());
92                    apb1.rstr().modify(|_, w| w.$i2cXrst().set_bit());
93                    apb1.rstr().modify(|_, w| w.$i2cXrst().clear_bit());
94
95                    let freq = freq.into().0;
96
97                    assert!(freq <= 1_000_000);
98
99                    // TODO review compliance with the timing requirements of I2C
100                    // t_I2CCLK = 1 / PCLK1
101                    // t_PRESC  = (PRESC + 1) * t_I2CCLK
102                    // t_SCLL   = (SCLL + 1) * t_PRESC
103                    // t_SCLH   = (SCLH + 1) * t_PRESC
104                    //
105                    // t_SYNC1 + t_SYNC2 > 4 * t_I2CCLK
106                    // t_SCL ~= t_SYNC1 + t_SYNC2 + t_SCLL + t_SCLH
107                    let i2cclk = clocks.pclk1().0;
108                    let ratio = i2cclk / freq - 4;
109                    let (presc, scll, sclh, sdadel, scldel) = if freq >= 100_000 {
110                        // fast-mode or fast-mode plus
111                        // here we pick SCLL + 1 = 2 * (SCLH + 1)
112                        let presc = ratio / 387;
113
114                        let sclh = ((ratio / (presc + 1)) - 3) / 3;
115                        let scll = 2 * (sclh + 1) - 1;
116
117                        let (sdadel, scldel) = if freq > 400_000 {
118                            // fast-mode plus
119                            let sdadel = 0;
120                            let scldel = i2cclk / 4_000_000 / (presc + 1) - 1;
121
122                            (sdadel, scldel)
123                        } else {
124                            // fast-mode
125                            let sdadel = i2cclk / 8_000_000 / (presc + 1);
126                            let scldel = i2cclk / 2_000_000 / (presc + 1) - 1;
127
128                            (sdadel, scldel)
129                        };
130
131                        (presc, scll, sclh, sdadel, scldel)
132                    } else {
133                        // standard-mode
134                        // here we pick SCLL = SCLH
135                        let presc = ratio / 514;
136
137                        let sclh = ((ratio / (presc + 1)) - 2) / 2;
138                        let scll = sclh;
139
140                        let sdadel = i2cclk / 2_000_000 / (presc + 1);
141                        let scldel = i2cclk / 800_000 / (presc + 1) - 1;
142
143                        (presc, scll, sclh, sdadel, scldel)
144                    };
145
146                    let presc = u8(presc).unwrap();
147                    assert!(presc < 16);
148                    let scldel = u8(scldel).unwrap();
149                    assert!(scldel < 16);
150                    let sdadel = u8(sdadel).unwrap();
151                    assert!(sdadel < 16);
152                    let sclh = u8(sclh).unwrap();
153                    let scll = u8(scll).unwrap();
154
155                    // Configure for "fast mode" (400 KHz)
156                    i2c.timingr.write(|w| unsafe {
157                        w.presc()
158                            .bits(presc)
159                            .scll()
160                            .bits(scll)
161                            .sclh()
162                            .bits(sclh)
163                            .sdadel()
164                            .bits(sdadel)
165                            .scldel()
166                            .bits(scldel)
167                    });
168
169                    // Enable the peripheral
170                    i2c.cr1.write(|w| w.pe().set_bit());
171
172                    I2c { i2c, pins }
173                }
174
175                /// Releases the I2C peripheral and associated pins
176                pub fn free(self) -> ($I2CX, (SCL, SDA)) {
177                    (self.i2c, self.pins)
178                }
179            }
180
181            impl<PINS> Write for I2c<$I2CX, PINS> {
182                type Error = Error;
183
184                fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
185                    // TODO support transfers of more than 255 bytes
186                    assert!(bytes.len() < 256 && bytes.len() > 0);
187
188                    // START and prepare to send `bytes`
189                    self.i2c.cr2.write(|w| {
190                        w.sadd1()
191                            .bits(addr)
192                            .rd_wrn()
193                            .clear_bit()
194                            .nbytes()
195                            .bits(bytes.len() as u8)
196                            .start()
197                            .set_bit()
198                            .autoend()
199                            .set_bit()
200                    });
201
202                    for byte in bytes {
203                        // Wait until we are allowed to send data (START has been ACKed or last byte
204                        // when through)
205                        busy_wait!(self.i2c, txis);
206
207                        // put byte on the wire
208                        self.i2c.txdr.write(|w| w.txdata().bits(*byte));
209                    }
210
211                    // Wait until the last transmission is finished ???
212                    // busy_wait!(self.i2c, busy);
213
214                    // automatic STOP
215
216                    Ok(())
217                }
218            }
219
220            impl<PINS> WriteRead for I2c<$I2CX, PINS> {
221                type Error = Error;
222
223                fn write_read(
224                    &mut self,
225                    addr: u8,
226                    bytes: &[u8],
227                    buffer: &mut [u8],
228                ) -> Result<(), Error> {
229                    // TODO support transfers of more than 255 bytes
230                    assert!(bytes.len() < 256 && bytes.len() > 0);
231                    assert!(buffer.len() < 256 && buffer.len() > 0);
232
233                    // TODO do we have to explicitly wait here if the bus is busy (e.g. another
234                    // master is communicating)?
235
236                    // START and prepare to send `bytes`
237                    self.i2c.cr2.write(|w| {
238                        w.sadd1()
239                            .bits(addr)
240                            .rd_wrn()
241                            .clear_bit()
242                            .nbytes()
243                            .bits(bytes.len() as u8)
244                            .start()
245                            .set_bit()
246                            .autoend()
247                            .clear_bit()
248                    });
249
250                    for byte in bytes {
251                        // Wait until we are allowed to send data (START has been ACKed or last byte
252                        // when through)
253                        busy_wait!(self.i2c, txis);
254
255                        // put byte on the wire
256                        self.i2c.txdr.write(|w| w.txdata().bits(*byte));
257                    }
258
259                    // Wait until the last transmission is finished
260                    busy_wait!(self.i2c, tc);
261
262                    // reSTART and prepare to receive bytes into `buffer`
263                    self.i2c.cr2.write(|w| {
264                        w.sadd1()
265                            .bits(addr)
266                            .rd_wrn()
267                            .set_bit()
268                            .nbytes()
269                            .bits(buffer.len() as u8)
270                            .start()
271                            .set_bit()
272                            .autoend()
273                            .set_bit()
274                    });
275
276                    for byte in buffer {
277                        // Wait until we have received something
278                        busy_wait!(self.i2c, rxne);
279
280                        *byte = self.i2c.rxdr.read().rxdata().bits();
281                    }
282
283                    // automatic STOP
284
285                    Ok(())
286                }
287            }
288        )+
289    }
290}
291
292hal! {
293    I2C1: (i2c1, i2c1en, i2c1rst),
294    I2C2: (i2c2, i2c2en, i2c2rst),
295}