soft_i2c/
soft_i2c.rs

1use embedded_hal::{
2    delay::DelayNs,
3    digital::OutputPin,
4    i2c::{NoAcknowledgeSource, SevenBitAddress, TenBitAddress},
5};
6
7use super::OpenDrainPin;
8
9/// Represents errors that can occur during I2C communication.
10#[derive(Debug, PartialEq, Eq, Clone, Copy)]
11pub enum SoftI2CError {
12    /// Error when addressing the device.
13    Address,
14    /// Error when writing data.
15    WriteData,
16}
17
18/// Represents I2C addresses.
19#[derive(Debug, Clone, Copy)]
20pub enum SoftI2CAddr {
21    /// A 7-bit address.
22    SevenBitAddress(u8),
23    /// A 10-bit address.
24    TenBitAddress(u16),
25}
26
27/// A software implementation of the I2C interface.
28#[derive(Debug)]
29pub struct SoftI2C<'a, C, D, Delay, const CLK_HZ: u32> {
30    /// SCL pin.
31    scl: &'a mut C,
32    /// SDA pin.
33    sda: &'a mut D,
34    /// Delay utility for timing.
35    delay: &'a mut Delay,
36}
37
38impl<'a, C, D, Delay, const CLK_HZ: u32> SoftI2C<'a, C, D, Delay, CLK_HZ>
39where
40    C: OutputPin,
41    D: OpenDrainPin,
42    Delay: DelayNs,
43{
44    /// Creates a new `SoftI2C` instance with the given SCL and SDA pins.
45    pub fn new(scl: &'a mut C, sda: &'a mut D, delay: &'a mut Delay) -> Self {
46        scl.set_high().ok();
47        sda.set(true);
48
49        SoftI2C { scl, sda, delay }
50    }
51
52    /// Delays for a short period.
53    #[inline]
54    fn i2c_delay(&mut self) {
55        self.delay.delay_ns(500_000_000 / CLK_HZ);
56    }
57
58    /// Sets the SCL line high.
59    fn scl_hi(&mut self) {
60        self.scl.set_high().ok();
61        self.i2c_delay();
62    }
63
64    /// Sets the SCL line low.
65    fn scl_lo(&mut self) {
66        self.scl.set_low().ok();
67        self.i2c_delay();
68    }
69
70    /// Sets the SDA line high.
71    fn sda_hi(&mut self) {
72        self.sda.set(true);
73        self.i2c_delay();
74    }
75
76    /// Sets the SDA line low.
77    fn sda_lo(&mut self) {
78        self.sda.set(false);
79        self.i2c_delay();
80    }
81
82    /// Set the SDA pin high to free pull low ctrl.
83    #[inline]
84    fn sda_free(&mut self) {
85        self.sda.set(true);
86    }
87    /// Generates a START condition.
88    fn start(&mut self) {
89        self.sda.set(true);
90        self.scl_hi();
91        self.sda_lo();
92        self.scl_lo();
93    }
94
95    /// Generates a STOP condition.
96    fn stop(&mut self) {
97        self.sda_lo();
98        self.scl_hi();
99        self.sda.set(true);
100    }
101
102    /// Generates a clock pulse.
103    fn clock_pulse(&mut self) {
104        self.scl_hi();
105        self.scl_lo();
106    }
107
108    /// Writes a byte to the I2C bus.
109    fn write_byte(&mut self, mut data_byte: u8) {
110        for _ in 0..8 {
111            self.sda.set(data_byte & 0x80 != 0);
112            data_byte <<= 1;
113            self.clock_pulse();
114        }
115    }
116
117    /// Reads a single bit from the I2C bus.
118    fn read_bit(&mut self) -> bool {
119        self.scl_hi();
120        let sda_bit = self.sda.get();
121        self.scl_lo();
122
123        sda_bit
124    }
125
126    /// Reads a byte from the I2C bus.
127    fn read_byte(&mut self) -> u8 {
128        let mut out_byte = 0;
129
130        self.sda_free();
131        for _ in 0..8 {
132            out_byte <<= 1;
133            out_byte |= (self.read_bit() as u8) & 1;
134        }
135
136        out_byte
137    }
138
139    /// Reads an acknowledge bit.
140    fn read_ack(&mut self, err: SoftI2CError) -> Result<(), SoftI2CError> {
141        self.sda_free();
142        if self.read_bit() {
143            self.stop();
144            Err(err)
145        } else {
146            Ok(())
147        }
148    }
149
150    /// Generates a repeated start condition.
151    fn mak(&mut self) {
152        self.sda_lo();
153        self.clock_pulse();
154    }
155
156    /// Generates a repeated stop condition.
157    fn nmak(&mut self) {
158        self.sda_hi();
159        self.clock_pulse();
160    }
161
162    /// Sends the device address over the I2C bus.
163    fn address(&mut self, address: SoftI2CAddr, is_read: bool) -> Result<(), SoftI2CError> {
164        let r_w_bit = if is_read { 1 } else { 0 };
165
166        match address {
167            SoftI2CAddr::SevenBitAddress(addr) => {
168                self.write_byte((addr << 1) | r_w_bit);
169                self.read_ack(SoftI2CError::Address)?
170            }
171            SoftI2CAddr::TenBitAddress(addr) => {
172                let h_addr = ((((addr >> 7) as u8 & 0xFE) | r_w_bit) & 0x07) | 0xF0;
173                let l_addr = (addr & 0xFF) as u8;
174                for byte in [h_addr, l_addr] {
175                    self.write_byte(byte);
176                    self.read_ack(SoftI2CError::Address)?
177                }
178            }
179        }
180        Ok(())
181    }
182
183    /// Writes bytes and reads bytes over the I2C bus.
184    ///
185    /// # Examples
186    /// ```
187    /// let mut buffer = [0; 4];
188    /// i2c.soft_i2c_write_read(SoftI2CAddr::SevenBitAddress(0x48), &[0x00, 0x01], &mut buffer)?;
189    /// assert_eq!(buffer, [0x02, 0x03, 0x04, 0x05]);
190    /// ```
191    /// ``` text
192    /// Master: ST SAD+W     O0     O1     ... OM     SR SAD+R        MAK    MAK ...    NMAK SP
193    /// Slave:           SAK    SAK    SAK ...    SAK          SAK I0     I1     ... IN
194    /// ```
195    pub fn soft_i2c_write_read(
196        &mut self,
197        address: SoftI2CAddr,
198        write: &[u8],
199        read: &mut [u8],
200    ) -> Result<(), SoftI2CError> {
201        self.start();
202        self.address(address, false)?;
203
204        for i in 0..write.len() {
205            self.write_byte(write[i]);
206            self.read_ack(SoftI2CError::WriteData)?;
207        }
208
209        self.soft_i2c_read(address, read)
210    }
211
212    /// Writes bytes over the I2C bus.
213    ///
214    /// # Examples
215    /// ```
216    /// i2c.soft_i2c_write(SoftI2CAddr::SevenBitAddress(0x48), &[0x00, 0x01])?;
217    /// ```
218    ///  ``` text
219    /// Master: ST SAD+W     B0     B1     ... BN     SP
220    /// Slave:           SAK    SAK    SAK ...    SAK
221    /// ```
222    pub fn soft_i2c_write(
223        &mut self,
224        address: SoftI2CAddr,
225        write: &[u8],
226    ) -> Result<(), SoftI2CError> {
227        self.start();
228        self.address(address, false)?;
229
230        for i in 0..write.len() {
231            self.write_byte(write[i]);
232            self.read_ack(SoftI2CError::WriteData)?;
233        }
234        self.stop();
235
236        Ok(())
237    }
238
239    /// Reads bytes over the I2C bus.
240    ///
241    /// # Examples
242    /// ```
243    /// let mut buffer = [0; 4];
244    /// i2c.soft_i2c_read(SoftI2CAddr::SevenBitAddress(0x48), &mut buffer)?;
245    /// assert_eq!(buffer, [0x02, 0x03, 0x04, 0x05]);
246    /// ```
247    /// ``` text
248    /// Master: ST SAD+R        MAK    MAK ...    NMAK SP
249    /// Slave:           SAK B0     B1     ... BN
250    /// ```
251    pub fn soft_i2c_read(
252        &mut self,
253        address: SoftI2CAddr,
254        read: &mut [u8],
255    ) -> Result<(), SoftI2CError> {
256        self.start();
257        self.address(address, true)?;
258
259        for i in 0..read.len() {
260            read[i] = self.read_byte();
261            if i < read.len() - 1 {
262                self.mak();
263            } else {
264                self.nmak();
265            }
266        }
267        self.stop();
268
269        Ok(())
270    }
271}
272
273impl embedded_hal::i2c::Error for SoftI2CError {
274    fn kind(&self) -> embedded_hal::i2c::ErrorKind {
275        match *self {
276            SoftI2CError::Address => {
277                embedded_hal::i2c::ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address)
278            }
279            SoftI2CError::WriteData => {
280                embedded_hal::i2c::ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data)
281            }
282        }
283    }
284}
285
286impl<'a, C: OutputPin, D: OpenDrainPin, Delay: DelayNs, const CLK_HZ: u32>
287    embedded_hal::i2c::ErrorType for SoftI2C<'a, C, D, Delay, CLK_HZ>
288{
289    type Error = SoftI2CError;
290}
291
292impl<'a, C: OutputPin, D: OpenDrainPin, Delay: DelayNs, const CLK_HZ: u32>
293    embedded_hal::i2c::I2c<SevenBitAddress> for SoftI2C<'a, C, D, Delay, CLK_HZ>
294{
295    fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
296        self.soft_i2c_read(SoftI2CAddr::SevenBitAddress(address), read)
297    }
298
299    fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
300        self.soft_i2c_write(SoftI2CAddr::SevenBitAddress(address), write)
301    }
302
303    fn write_read(
304        &mut self,
305        address: u8,
306        write: &[u8],
307        read: &mut [u8],
308    ) -> Result<(), Self::Error> {
309        self.soft_i2c_write_read(SoftI2CAddr::SevenBitAddress(address), write, read)
310    }
311
312    fn transaction(
313        &mut self,
314        address: u8,
315        operations: &mut [embedded_hal::i2c::Operation<'_>],
316    ) -> Result<(), Self::Error> {
317        for op in operations {
318            match op {
319                embedded_hal::i2c::Operation::Write(data) => {
320                    self.soft_i2c_write(SoftI2CAddr::SevenBitAddress(address), data)?;
321                }
322                embedded_hal::i2c::Operation::Read(data) => {
323                    self.soft_i2c_read(SoftI2CAddr::SevenBitAddress(address), data)?;
324                }
325            }
326        }
327        Ok(())
328    }
329}
330
331impl<'a, C: OutputPin, D: OpenDrainPin, Delay: DelayNs, const CLK_HZ: u32>
332    embedded_hal::i2c::I2c<TenBitAddress> for SoftI2C<'a, C, D, Delay, CLK_HZ>
333{
334    fn read(&mut self, address: u16, read: &mut [u8]) -> Result<(), Self::Error> {
335        self.soft_i2c_read(SoftI2CAddr::TenBitAddress(address), read)
336    }
337
338    fn write(&mut self, address: u16, write: &[u8]) -> Result<(), Self::Error> {
339        self.soft_i2c_write(SoftI2CAddr::TenBitAddress(address), write)
340    }
341
342    fn write_read(
343        &mut self,
344        address: u16,
345        write: &[u8],
346        read: &mut [u8],
347    ) -> Result<(), Self::Error> {
348        self.soft_i2c_write_read(SoftI2CAddr::TenBitAddress(address), write, read)
349    }
350
351    fn transaction(
352        &mut self,
353        address: u16,
354        operations: &mut [embedded_hal::i2c::Operation<'_>],
355    ) -> Result<(), Self::Error> {
356        for op in operations {
357            match op {
358                embedded_hal::i2c::Operation::Write(data) => {
359                    self.soft_i2c_write(SoftI2CAddr::TenBitAddress(address), data)?;
360                }
361                embedded_hal::i2c::Operation::Read(data) => {
362                    self.soft_i2c_read(SoftI2CAddr::TenBitAddress(address), data)?;
363                }
364            }
365        }
366        Ok(())
367    }
368}