stm32l1xx_hal/
i2c.rs

1//! I2C
2use hal::blocking::i2c::{Read, Write, WriteRead};
3
4use crate::gpio::gpiob::{PB10, PB11, PB6, PB7};
5use crate::gpio::{AltMode, OpenDrain, Output};
6use crate::prelude::*;
7use crate::rcc::Rcc;
8use crate::stm32::{I2C1, I2C2};
9use crate::time::Hertz;
10
11/// I2C abstraction
12pub struct I2c<I2C, PINS> {
13    i2c: I2C,
14    pins: PINS,
15}
16
17pub trait Pins<I2c> {
18    fn setup(&self);
19}
20
21impl Pins<I2C1> for (PB6<Output<OpenDrain>>, PB7<Output<OpenDrain>>) {
22    fn setup(&self) {
23        self.0.set_alt_mode(AltMode::I2C);
24        self.1.set_alt_mode(AltMode::I2C);
25    }
26}
27
28impl Pins<I2C2> for (PB10<Output<OpenDrain>>, PB11<Output<OpenDrain>>) {
29    fn setup(&self) {
30        self.0.set_alt_mode(AltMode::I2C);
31        self.1.set_alt_mode(AltMode::I2C);
32    }
33}
34
35#[derive(Debug)]
36pub enum Error {
37    OVERRUN,
38    NACK,
39}
40
41macro_rules! i2c {
42    ($I2CX:ident, $i2cx:ident, $i2cxen:ident, $i2crst:ident) => {
43        impl<PINS> I2c<$I2CX, PINS> {
44            pub fn $i2cx(i2c: $I2CX, pins: PINS, speed: Hertz, rcc: &mut Rcc) -> Self
45            where
46                PINS: Pins<$I2CX>,
47            {
48                pins.setup();
49                let speed: Hertz = speed.into();
50
51                // Enable clock for I2C
52                rcc.rb.apb1enr.modify(|_, w| w.$i2cxen().set_bit());
53
54                // Reset I2C
55                rcc.rb.apb1rstr.modify(|_, w| w.$i2crst().set_bit());
56                rcc.rb.apb1rstr.modify(|_, w| w.$i2crst().clear_bit());
57
58                // Make sure the I2C unit is disabled so we can configure it
59                i2c.cr1.modify(|_, w| w.pe().clear_bit());
60
61                // Calculate settings for I2C speed modes
62                let clock = rcc.clocks.apb1_clk().0;
63                let freq = clock / 1_000_000;
64                assert!(freq >= 2 && freq <= 50);
65
66                // Configure bus frequency into I2C peripheral
67                i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
68
69                let trise = if speed <= 100_u32.khz().into() {
70                    freq + 1
71                } else {
72                    (freq * 300) / 1000 + 1
73                };
74
75                // Configure correct rise times
76                i2c.trise.write(|w| w.trise().bits(trise as u8));
77
78                // I2C clock control calculation
79                if speed <= 100_u32.khz().into() {
80                    let ccr = {
81                        let ccr = clock / (speed.0 * 2);
82                        if ccr < 4 {
83                            4
84                        } else {
85                            ccr
86                        }
87                    };
88
89                    // Set clock to standard mode with appropriate parameters for selected speed
90                    i2c.ccr.write(|w| unsafe {
91                        w.f_s()
92                            .clear_bit()
93                            .duty()
94                            .clear_bit()
95                            .ccr()
96                            .bits(ccr as u16)
97                    });
98                } else {
99                    const DUTYCYCLE: u8 = 0;
100                    if DUTYCYCLE == 0 {
101                        let ccr = clock / (speed.0 * 3);
102                        let ccr = if ccr < 1 { 1 } else { ccr };
103
104                        // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
105                        i2c.ccr.write(|w| unsafe {
106                            w.f_s().set_bit().duty().clear_bit().ccr().bits(ccr as u16)
107                        });
108                    } else {
109                        let ccr = clock / (speed.0 * 25);
110                        let ccr = if ccr < 1 { 1 } else { ccr };
111
112                        // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
113                        i2c.ccr.write(|w| unsafe {
114                            w.f_s().set_bit().duty().set_bit().ccr().bits(ccr as u16)
115                        });
116                    }
117                }
118
119                // Enable the I2C processing
120                i2c.cr1.modify(|_, w| w.pe().set_bit());
121
122                I2c { i2c, pins }
123            }
124
125            pub fn release(self) -> ($I2CX, PINS) {
126                (self.i2c, self.pins)
127            }
128
129            fn send_byte(&self, byte: u8) -> Result<(), Error> {
130                // Wait until we're ready for sending
131                while self.i2c.sr1.read().tx_e().bit_is_clear() {}
132
133                // Push out a byte of data
134                self.i2c.dr.write(|w| unsafe { w.bits(u32::from(byte)) });
135
136                // While until byte is transferred
137                while {
138                    let sr1 = self.i2c.sr1.read();
139
140                    // If we received a NACK, then this is an error
141                    if sr1.af().bit_is_set() {
142                        return Err(Error::NACK);
143                    }
144
145                    sr1.btf().bit_is_clear()
146                } {}
147
148                Ok(())
149            }
150
151            fn recv_byte(&self) -> Result<u8, Error> {
152                while self.i2c.sr1.read().rx_ne().bit_is_clear() {}
153                let value = self.i2c.dr.read().bits() as u8;
154                Ok(value)
155            }
156        }
157
158        impl<PINS> WriteRead for I2c<$I2CX, PINS> {
159            type Error = Error;
160
161            fn write_read(
162                &mut self,
163                addr: u8,
164                bytes: &[u8],
165                buffer: &mut [u8],
166            ) -> Result<(), Self::Error> {
167                self.write(addr, bytes)?;
168                self.read(addr, buffer)?;
169
170                Ok(())
171            }
172        }
173
174        impl<PINS> Write for I2c<$I2CX, PINS> {
175            type Error = Error;
176
177            fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
178                // Send a START condition
179                self.i2c.cr1.modify(|_, w| w.start().set_bit());
180
181                // Wait until START condition was generated
182                while {
183                    let sr1 = self.i2c.sr1.read();
184                    sr1.sb().bit_is_clear()
185                } {}
186
187                // Also wait until signalled we're master and everything is waiting for us
188                while {
189                    let sr2 = self.i2c.sr2.read();
190                    sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
191                } {}
192
193                // Set up current address, we're trying to talk to
194                self.i2c
195                    .dr
196                    .write(|w| unsafe { w.bits(u32::from(addr) << 1) });
197
198                // Wait until address was sent
199                while {
200                    let sr1 = self.i2c.sr1.read();
201                    sr1.addr().bit_is_clear()
202                } {}
203
204                // Clear condition by reading SR2
205                self.i2c.sr2.read();
206
207                // Send bytes
208                for c in bytes {
209                    self.send_byte(*c)?;
210                }
211
212                // Fallthrough is success
213                Ok(())
214            }
215        }
216
217        impl<PINS> Read for I2c<$I2CX, PINS> {
218            type Error = Error;
219
220            fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
221                // Send a START condition and set ACK bit
222                self.i2c
223                    .cr1
224                    .modify(|_, w| w.start().set_bit().ack().set_bit());
225
226                // Wait until START condition was generated
227                while {
228                    let sr1 = self.i2c.sr1.read();
229                    sr1.sb().bit_is_clear()
230                } {}
231
232                // Also wait until signalled we're master and everything is waiting for us
233                while {
234                    let sr2 = self.i2c.sr2.read();
235                    sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
236                } {}
237
238                // Set up current address, we're trying to talk to
239                self.i2c
240                    .dr
241                    .write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) });
242
243                // Wait until address was sent
244                while {
245                    let sr1 = self.i2c.sr1.read();
246                    sr1.addr().bit_is_clear()
247                } {}
248
249                // Clear condition by reading SR2
250                self.i2c.sr2.read();
251
252                // Receive bytes into buffer
253                for c in buffer {
254                    *c = self.recv_byte()?;
255                }
256
257                // Send STOP condition
258                self.i2c.cr1.modify(|_, w| w.stop().set_bit());
259
260                // Fallthrough is success
261                Ok(())
262            }
263        }
264
265        impl I2cExt<$I2CX> for $I2CX {
266            fn i2c<PINS, T>(self, pins: PINS, speed: T, rcc: &mut Rcc) -> I2c<$I2CX, PINS>
267            where
268                PINS: Pins<$I2CX>,
269                T: Into<Hertz>,
270            {
271                I2c::$i2cx(self, pins, speed.into(), rcc)
272            }
273        }
274    };
275}
276
277pub trait I2cExt<I2C> {
278    fn i2c<PINS, T>(self, pins: PINS, speed: T, rcc: &mut Rcc) -> I2c<I2C, PINS>
279    where
280        PINS: Pins<I2C>,
281        T: Into<Hertz>;
282}
283
284i2c!(I2C1, i2c1, i2c1en, i2c1rst);
285i2c!(I2C2, i2c2, i2c2en, i2c2rst);