stm32f030_hal/
i2c.rs

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