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}