bitbang_hal/
i2c.rs

1/*!
2  # Synchronous implementation of embedded-hal I2C traits based on GPIO bitbang
3
4  This implementation consumes the following hardware resources:
5  - A periodic timer to mark clock cycles
6  - Two GPIO pins for SDA and SCL lines.
7
8  Note that the current implementation does not support I2C clock stretching.
9
10  ## Hardware requirements
11
12  1. Configure GPIO pins as Open-Drain outputs.
13  2. Configure timer frequency to be twice the desired I2C clock frequency.
14
15  ## Blue Pill example
16
17  Here is a sample code for LM75A I2C temperature sensor
18  on Blue Pill or any other stm32f1xx board:
19
20  ```no_run
21    use stm32f1xx_hal as hal;
22    use hal::{prelude::*, timer::Timer, stm32};
23    use lm75::{Lm75, SlaveAddr};
24    use bitbang_hal;
25
26    // ...
27
28    let pdev = stm32::Peripherals::take().unwrap();
29
30    let mut flash = pdev.FLASH.constrain();
31    let mut rcc = pdev.RCC.constrain();
32    let mut gpioa = pdev.GPIOA.split(&mut rcc.apb2);
33
34    let clocks = rcc
35        .cfgr
36        .use_hse(8.mhz())
37        .sysclk(32.mhz())
38        .pclk1(16.mhz())
39        .freeze(&mut flash.acr);
40
41    let tmr = Timer::tim3(pdev.TIM3, &clocks, &mut rcc.apb1).start_count_down(200.khz());
42    let scl = gpioa.pa1.into_open_drain_output(&mut gpioa.crl);
43    let sda = gpioa.pa2.into_open_drain_output(&mut gpioa.crl);
44
45    let i2c = bitbang_hal::i2c::I2cBB::new(scl, sda, tmr);
46    let mut sensor = Lm75::new(i2c, SlaveAddr::default());
47    let temp = sensor.read_temperature().unwrap();
48
49    //...
50  ```
51*/
52
53use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
54use embedded_hal::digital::v2::{InputPin, OutputPin};
55use embedded_hal::timer::{CountDown, Periodic};
56use nb::block;
57
58/// I2C error
59#[derive(Debug, Eq, PartialEq)]
60pub enum Error<E> {
61    /// GPIO error
62    Bus(E),
63    /// No ack received
64    NoAck,
65    /// Invalid input
66    InvalidData,
67}
68
69/// Bit banging I2C device
70pub struct I2cBB<SCL, SDA, CLK>
71where
72    SCL: OutputPin,
73    SDA: OutputPin + InputPin,
74    CLK: CountDown + Periodic,
75{
76    scl: SCL,
77    sda: SDA,
78    clk: CLK,
79}
80
81impl<SCL, SDA, CLK, E> I2cBB<SCL, SDA, CLK>
82where
83    SCL: OutputPin<Error = E>,
84    SDA: OutputPin<Error = E> + InputPin<Error = E>,
85    CLK: CountDown + Periodic,
86{
87    /// Create instance
88    pub fn new(scl: SCL, sda: SDA, clk: CLK) -> Self {
89        I2cBB { scl, sda, clk }
90    }
91
92    /// Send a raw I2C start.
93    ///
94    /// **This is a low-level control function.** For normal I2C devices,
95    /// please use the embedded-hal traits [Read], [Write], or
96    /// [WriteRead].
97    pub fn raw_i2c_start(&mut self) -> Result<(), crate::i2c::Error<E>> {
98        self.set_scl_high()?;
99        self.set_sda_high()?;
100        self.wait_for_clk();
101
102        self.set_sda_low()?;
103        self.wait_for_clk();
104
105        self.set_scl_low()?;
106        self.wait_for_clk();
107
108        Ok(())
109    }
110
111    /// Send a raw I2C stop.
112    ///
113    /// **This is a low-level control function.** For normal I2C devices,
114    /// please use the embedded-hal traits [Read], [Write], or
115    /// [WriteRead].
116    pub fn raw_i2c_stop(&mut self) -> Result<(), crate::i2c::Error<E>> {
117        self.set_scl_high()?;
118        self.wait_for_clk();
119
120        self.set_sda_high()?;
121        self.wait_for_clk();
122
123        Ok(())
124    }
125
126    fn i2c_is_ack(&mut self) -> Result<bool, crate::i2c::Error<E>> {
127        self.set_sda_high()?;
128        self.set_scl_high()?;
129        self.wait_for_clk();
130
131        let ack = self.sda.is_low().map_err(Error::Bus)?;
132
133        self.set_scl_low()?;
134        self.set_sda_low()?;
135        self.wait_for_clk();
136
137        Ok(ack)
138    }
139
140    fn i2c_read_byte(&mut self, should_send_ack: bool) -> Result<u8, crate::i2c::Error<E>> {
141        let mut byte: u8 = 0;
142
143        self.set_sda_high()?;
144
145        for bit_offset in 0..8 {
146            self.set_scl_high()?;
147            self.wait_for_clk();
148
149            if self.sda.is_high().map_err(Error::Bus)? {
150                byte |= 1 << (7 - bit_offset);
151            }
152
153            self.set_scl_low()?;
154            self.wait_for_clk();
155        }
156
157        if should_send_ack {
158            self.set_sda_low()?;
159        } else {
160            self.set_sda_high()?;
161        }
162
163        self.set_scl_high()?;
164        self.wait_for_clk();
165
166        self.set_scl_low()?;
167        self.set_sda_low()?;
168        self.wait_for_clk();
169
170        Ok(byte)
171    }
172
173    fn i2c_write_byte(&mut self, byte: u8) -> Result<(), crate::i2c::Error<E>> {
174        for bit_offset in 0..8 {
175            let out_bit = (byte >> (7 - bit_offset)) & 0b1;
176
177            if out_bit == 1 {
178                self.set_sda_high()?;
179            } else {
180                self.set_sda_low()?;
181            }
182
183            self.set_scl_high()?;
184            self.wait_for_clk();
185
186            self.set_scl_low()?;
187            self.set_sda_low()?;
188            self.wait_for_clk();
189        }
190
191        Ok(())
192    }
193
194    /// Read raw bytes from the slave.
195    ///
196    /// **This is a low-level control function.** For normal I2C devices,
197    /// please use the embedded-hal traits [Read], [Write], or
198    /// [WriteRead].
199    #[inline]
200    pub fn raw_read_from_slave(&mut self, input: &mut [u8]) -> Result<(), crate::i2c::Error<E>> {
201        for i in 0..input.len() {
202            let should_send_ack = i != (input.len() - 1);
203            input[i] = self.i2c_read_byte(should_send_ack)?;
204        }
205        Ok(())
206    }
207
208    /// Send raw bytes to the slave.
209    ///
210    /// **This is a low-level control function.** For normal I2C devices,
211    /// please use the embedded-hal traits [Read], [Write], or
212    /// [WriteRead].
213    #[inline]
214    pub fn raw_write_to_slave(&mut self, output: &[u8]) -> Result<(), crate::i2c::Error<E>> {
215        for byte in output {
216            self.i2c_write_byte(*byte)?;
217            self.check_ack()?;
218        }
219        Ok(())
220    }
221
222    #[inline]
223    fn set_scl_high(&mut self) -> Result<(), crate::i2c::Error<E>> {
224        self.scl.set_high().map_err(Error::Bus)
225    }
226
227    #[inline]
228    fn set_scl_low(&mut self) -> Result<(), crate::i2c::Error<E>> {
229        self.scl.set_low().map_err(Error::Bus)
230    }
231
232    #[inline]
233    fn set_sda_high(&mut self) -> Result<(), crate::i2c::Error<E>> {
234        self.sda.set_high().map_err(Error::Bus)
235    }
236
237    #[inline]
238    fn set_sda_low(&mut self) -> Result<(), crate::i2c::Error<E>> {
239        self.sda.set_low().map_err(Error::Bus)
240    }
241
242    #[inline]
243    fn wait_for_clk(&mut self) {
244        block!(self.clk.wait()).ok();
245    }
246
247    #[inline]
248    fn check_ack(&mut self) -> Result<(), crate::i2c::Error<E>> {
249        if !self.i2c_is_ack()? {
250            Err(Error::NoAck)
251        } else {
252            Ok(())
253        }
254    }
255}
256
257impl<SCL, SDA, CLK, E> Write for I2cBB<SCL, SDA, CLK>
258where
259    SCL: OutputPin<Error = E>,
260    SDA: OutputPin<Error = E> + InputPin<Error = E>,
261    CLK: CountDown + Periodic,
262{
263    type Error = crate::i2c::Error<E>;
264
265    fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> {
266        // ST
267        self.raw_i2c_start()?;
268
269        // SAD + W
270        self.i2c_write_byte((addr << 1) | 0x0)?;
271        self.check_ack()?;
272
273        self.raw_write_to_slave(output)?;
274
275        // SP
276        self.raw_i2c_stop()
277    }
278}
279
280impl<SCL, SDA, CLK, E> Read for I2cBB<SCL, SDA, CLK>
281where
282    SCL: OutputPin<Error = E>,
283    SDA: OutputPin<Error = E> + InputPin<Error = E>,
284    CLK: CountDown + Periodic,
285{
286    type Error = crate::i2c::Error<E>;
287
288    fn read(&mut self, addr: u8, input: &mut [u8]) -> Result<(), Self::Error> {
289        if input.is_empty() {
290            return Ok(());
291        }
292
293        // ST
294        self.raw_i2c_start()?;
295
296        // SAD + R
297        self.i2c_write_byte((addr << 1) | 0x1)?;
298        self.check_ack()?;
299
300        self.raw_read_from_slave(input)?;
301
302        // SP
303        self.raw_i2c_stop()
304    }
305}
306
307impl<SCL, SDA, CLK, E> WriteRead for I2cBB<SCL, SDA, CLK>
308where
309    SCL: OutputPin<Error = E>,
310    SDA: OutputPin<Error = E> + InputPin<Error = E>,
311    CLK: CountDown + Periodic,
312{
313    type Error = crate::i2c::Error<E>;
314
315    fn write_read(&mut self, addr: u8, output: &[u8], input: &mut [u8]) -> Result<(), Self::Error> {
316        if output.is_empty() || input.is_empty() {
317            return Err(Error::InvalidData);
318        }
319
320        // ST
321        self.raw_i2c_start()?;
322
323        // SAD + W
324        self.i2c_write_byte((addr << 1) | 0x0)?;
325        self.check_ack()?;
326
327        self.raw_write_to_slave(output)?;
328
329        // SR
330        self.raw_i2c_start()?;
331
332        // SAD + R
333        self.i2c_write_byte((addr << 1) | 0x1)?;
334        self.check_ack()?;
335
336        self.raw_read_from_slave(input)?;
337
338        // SP
339        self.raw_i2c_stop()
340    }
341}