stm32f042_hal/
i2c.rs

1use stm32::{I2C1, RCC};
2
3use hal::blocking::i2c::{Write, WriteRead};
4
5use core::cmp;
6use gpio::gpioa::{PA10, PA11, PA12, PA9};
7use gpio::gpiob::{PB10, PB11, PB13, PB14, PB6, PB7, PB8, PB9};
8use gpio::gpiof::{PF0, PF1};
9use gpio::{Alternate, AF1, AF4, AF5};
10use time::{KiloHertz, U32Ext};
11
12/// I2C abstraction
13pub struct I2c<I2C, PINS> {
14    i2c: I2C,
15    pins: PINS,
16}
17
18pub trait Pins<I2c> {}
19
20impl Pins<I2C1> for (PA9<Alternate<AF4>>, PA10<Alternate<AF4>>) {}
21impl Pins<I2C1> for (PA11<Alternate<AF5>>, PA12<Alternate<AF5>>) {}
22impl Pins<I2C1> for (PB6<Alternate<AF1>>, PB7<Alternate<AF1>>) {}
23impl Pins<I2C1> for (PB8<Alternate<AF1>>, PB9<Alternate<AF1>>) {}
24impl Pins<I2C1> for (PB10<Alternate<AF1>>, PB11<Alternate<AF1>>) {}
25impl Pins<I2C1> for (PB13<Alternate<AF5>>, PB14<Alternate<AF5>>) {}
26impl Pins<I2C1> for (PF1<Alternate<AF1>>, PF0<Alternate<AF1>>) {}
27
28#[derive(Debug)]
29pub enum Error {
30    OVERRUN,
31    NACK,
32}
33
34impl<PINS> I2c<I2C1, PINS> {
35    pub fn i2c1(i2c: I2C1, pins: PINS, speed: KiloHertz) -> Self
36    where
37        PINS: Pins<I2C1>,
38    {
39        // NOTE(unsafe) This executes only during initialisation
40        let rcc = unsafe { &(*RCC::ptr()) };
41
42        /* Enable clock for I2C1 */
43        rcc.apb1enr.modify(|_, w| w.i2c1en().set_bit());
44
45        /* Reset I2C1 */
46        rcc.apb1rstr.modify(|_, w| w.i2c1rst().set_bit());
47        rcc.apb1rstr.modify(|_, w| w.i2c1rst().clear_bit());
48
49        /* Make sure the I2C unit is disabled so we can configure it */
50        i2c.cr1.modify(|_, w| w.pe().clear_bit());
51
52        // Calculate settings for I2C speed modes
53        let presc;
54        let scldel;
55        let sdadel;
56        let sclh;
57        let scll;
58
59        // We're using HSI here which runs at a fixed 8MHz
60        const FREQ: u32 = 8_000_000;
61
62        // Normal I2C speeds use a different scaling than fast mode below
63        if speed <= 100_u32.khz() {
64            presc = 1;
65            scll = cmp::max((((FREQ >> presc) >> 1) / speed.0) - 1, 255) as u8;
66            sclh = scll - 4;
67            sdadel = 2;
68            scldel = 4;
69        } else {
70            presc = 0;
71            scll = cmp::max((((FREQ >> presc) >> 1) / speed.0) - 1, 255) as u8;
72            sclh = scll - 6;
73            sdadel = 1;
74            scldel = 3;
75        }
76
77        /* Enable I2C signal generator, and configure I2C for 400KHz full speed */
78        i2c.timingr.write(|w| {
79            w.presc()
80                .bits(presc)
81                .scldel()
82                .bits(scldel)
83                .sdadel()
84                .bits(sdadel)
85                .sclh()
86                .bits(sclh)
87                .scll()
88                .bits(scll)
89        });
90
91        /* Enable the I2C processing */
92        i2c.cr1.modify(|_, w| w.pe().set_bit());
93
94        I2c { i2c, pins }
95    }
96
97    pub fn release(self) -> (I2C1, PINS) {
98        (self.i2c, self.pins)
99    }
100
101    fn send_byte(&self, byte: u8) -> Result<(), Error> {
102        /* Wait until we're ready for sending */
103        while self.i2c.isr.read().txis().bit_is_clear() {}
104
105        /* Push out a byte of data */
106        self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });
107
108        /* If we received a NACK, then this is an error */
109        if self.i2c.isr.read().nackf().bit_is_set() {
110            self.i2c
111                .icr
112                .write(|w| w.stopcf().set_bit().nackcf().set_bit());
113            return Err(Error::NACK);
114        }
115
116        Ok(())
117    }
118
119    fn recv_byte(&self) -> Result<u8, Error> {
120        while self.i2c.isr.read().rxne().bit_is_clear() {}
121        let value = self.i2c.rxdr.read().bits() as u8;
122        Ok(value)
123    }
124}
125
126impl<PINS> WriteRead for I2c<I2C1, PINS> {
127    type Error = Error;
128
129    fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
130        /* Set up current address, we're trying a "read" command and not going to set anything
131         * and make sure we end a non-NACKed read (i.e. if we found a device) properly */
132        self.i2c.cr2.modify(|_, w| {
133            w.sadd()
134                .bits(u16::from(addr) << 1)
135                .nbytes()
136                .bits(bytes.len() as u8)
137                .rd_wrn()
138                .clear_bit()
139                .autoend()
140                .clear_bit()
141        });
142
143        /* Send a START condition */
144        self.i2c.cr2.modify(|_, w| w.start().set_bit());
145
146        /* Wait until the transmit buffer is empty and there hasn't been either a NACK or STOP
147         * being received */
148        let mut isr;
149        while {
150            isr = self.i2c.isr.read();
151            isr.txis().bit_is_clear()
152                && isr.nackf().bit_is_clear()
153                && isr.stopf().bit_is_clear()
154                && isr.tc().bit_is_clear()
155        } {}
156
157        /* If we received a NACK, then this is an error */
158        if isr.nackf().bit_is_set() {
159            self.i2c
160                .icr
161                .write(|w| w.stopcf().set_bit().nackcf().set_bit());
162            return Err(Error::NACK);
163        }
164
165        for c in bytes {
166            self.send_byte(*c)?;
167        }
168
169        /* Wait until data was sent */
170        while self.i2c.isr.read().tc().bit_is_clear() {}
171
172        /* Set up current address, we're trying a "read" command and not going to set anything
173         * and make sure we end a non-NACKed read (i.e. if we found a device) properly */
174        self.i2c.cr2.modify(|_, w| {
175            w.sadd()
176                .bits(u16::from(addr) << 1)
177                .nbytes()
178                .bits(buffer.len() as u8)
179                .rd_wrn()
180                .set_bit()
181        });
182
183        /* Send a START condition */
184        self.i2c.cr2.modify(|_, w| w.start().set_bit());
185
186        /* Send the autoend after setting the start to get a restart */
187        self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
188
189        /* Read in all bytes */
190        for c in buffer.iter_mut() {
191            *c = self.recv_byte()?;
192        }
193
194        /* Clear flags if they somehow ended up set */
195        self.i2c
196            .icr
197            .write(|w| w.stopcf().set_bit().nackcf().set_bit());
198
199        Ok(())
200    }
201}
202
203impl<PINS> Write for I2c<I2C1, PINS> {
204    type Error = Error;
205
206    fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
207        /* Set up current address, we're trying a "read" command and not going to set anything
208         * and make sure we end a non-NACKed read (i.e. if we found a device) properly */
209        self.i2c.cr2.modify(|_, w| {
210            w.sadd()
211                .bits(u16::from(addr) << 1)
212                .nbytes()
213                .bits(bytes.len() as u8)
214                .rd_wrn()
215                .clear_bit()
216                .autoend()
217                .set_bit()
218        });
219
220        /* Send a START condition */
221        self.i2c.cr2.modify(|_, w| w.start().set_bit());
222
223        for c in bytes {
224            self.send_byte(*c)?;
225        }
226
227        /* Fallthrough is success */
228        self.i2c
229            .icr
230            .write(|w| w.stopcf().set_bit().nackcf().set_bit());
231        Ok(())
232    }
233}