avr_hal_generic/
i2c.rs

1//! I2C Implementations
2//!
3//! Check the documentation of [`I2c`] for details.
4
5use embedded_hal::i2c::SevenBitAddress;
6
7use crate::port;
8use core::marker::PhantomData;
9
10/// TWI Status Codes
11pub mod twi_status {
12    // The status codes defined in the C header are meant to be used with the
13    // masked status value: (TWSR & TW_STATUS_MASK).  In our case, svd2rust
14    // already added code to shift it to just the status value, so all status
15    // codes need to be shifted to the right as well.
16
17    /// Start condition transmitted
18    pub const TW_START: u8 = 0x08 >> 3;
19
20    /// Repeated start condition transmitted
21    pub const TW_REP_START: u8 = 0x10 >> 3;
22
23    // Master Transmitter -----------------------------------------------------
24    /// SLA+W transmitted, ACK received
25    pub const TW_MT_SLA_ACK: u8 = 0x18 >> 3;
26
27    /// SLA+W transmitted, NACK received
28    pub const TW_MT_SLA_NACK: u8 = 0x20 >> 3;
29
30    /// Data transmitted, ACK received
31    pub const TW_MT_DATA_ACK: u8 = 0x28 >> 3;
32
33    /// Data transmitted, NACK received
34    pub const TW_MT_DATA_NACK: u8 = 0x30 >> 3;
35
36    /// Arbitration lost in SLA+W or data
37    pub const TW_MT_ARB_LOST: u8 = 0x38 >> 3;
38
39    // Master Receiver --------------------------------------------------------
40    /// Arbitration lost in SLA+R or NACK
41    pub const TW_MR_ARB_LOST: u8 = 0x38 >> 3;
42
43    /// SLA+R transmitted, ACK received
44    pub const TW_MR_SLA_ACK: u8 = 0x40 >> 3;
45
46    /// SLA+R transmitted, NACK received
47    pub const TW_MR_SLA_NACK: u8 = 0x48 >> 3;
48
49    /// Data received, ACK returned
50    pub const TW_MR_DATA_ACK: u8 = 0x50 >> 3;
51
52    /// Data received, NACK returned
53    pub const TW_MR_DATA_NACK: u8 = 0x58 >> 3;
54
55    // Slave Transmitter ------------------------------------------------------
56    /// SLA+R received, ACK returned
57    pub const TW_ST_SLA_ACK: u8 = 0xA8 >> 3;
58
59    /// Arbitration lost in SLA+RW, SLA+R received, ACK returned
60    pub const TW_ST_ARB_LOST_SLA_ACK: u8 = 0xB0 >> 3;
61
62    /// Data transmitted, ACK received
63    pub const TW_ST_DATA_ACK: u8 = 0xB8 >> 3;
64
65    /// Data transmitted, NACK received
66    pub const TW_ST_DATA_NACK: u8 = 0xC0 >> 3;
67
68    /// Last data byte transmitted, ACK received
69    pub const TW_ST_LAST_DATA: u8 = 0xC8 >> 3;
70
71    // Slave Receiver ---------------------------------------------------------
72    /// SLA+W received, ACK returned
73    pub const TW_SR_SLA_ACK: u8 = 0x60 >> 3;
74
75    /// Arbitration lost in SLA+RW, SLA+W received, ACK returned
76    pub const TW_SR_ARB_LOST_SLA_ACK: u8 = 0x68 >> 3;
77
78    /// General call received, ACK returned
79    pub const TW_SR_GCALL_ACK: u8 = 0x70 >> 3;
80
81    /// Arbitration lost in SLA+RW, general call received, ACK returned
82    pub const TW_SR_ARB_LOST_GCALL_ACK: u8 = 0x78 >> 3;
83
84    /// Data received, ACK returned
85    pub const TW_SR_DATA_ACK: u8 = 0x80 >> 3;
86
87    /// Data received, NACK returned
88    pub const TW_SR_DATA_NACK: u8 = 0x88 >> 3;
89
90    /// General call data received, ACK returned
91    pub const TW_SR_GCALL_DATA_ACK: u8 = 0x90 >> 3;
92
93    /// General call data received, NACK returned
94    pub const TW_SR_GCALL_DATA_NACK: u8 = 0x98 >> 3;
95
96    /// Stop or repeated start condition received while selected
97    pub const TW_SR_STOP: u8 = 0xA0 >> 3;
98
99    // Misc -------------------------------------------------------------------
100    /// No state information available
101    pub const TW_NO_INFO: u8 = 0xF8 >> 3;
102
103    /// Illegal start or stop condition
104    pub const TW_BUS_ERROR: u8 = 0x00 >> 3;
105}
106
107/// I2C Error
108#[derive(ufmt::derive::uDebug, Debug, Clone, Copy, Eq, PartialEq)]
109#[repr(u8)]
110pub enum Error {
111    /// Lost arbitration while trying to acquire bus
112    ArbitrationLost,
113    /// No slave answered for this address or a slave replied NACK
114    AddressNack,
115    /// Slave replied NACK to sent data
116    DataNack,
117    /// A bus-error occured
118    BusError,
119    /// An unknown error occured.  The bus might be in an unknown state.
120    Unknown,
121}
122
123impl embedded_hal::i2c::Error for Error {
124    fn kind(&self) -> embedded_hal::i2c::ErrorKind {
125        match *self {
126            Error::ArbitrationLost => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
127            Error::AddressNack => embedded_hal::i2c::ErrorKind::NoAcknowledge(
128                embedded_hal::i2c::NoAcknowledgeSource::Address,
129            ),
130            Error::DataNack => embedded_hal::i2c::ErrorKind::NoAcknowledge(
131                embedded_hal::i2c::NoAcknowledgeSource::Data,
132            ),
133            Error::BusError => embedded_hal::i2c::ErrorKind::Bus,
134            Error::Unknown => embedded_hal::i2c::ErrorKind::Other,
135        }
136    }
137}
138
139impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal::i2c::ErrorType
140    for I2c<H, I2C, SDA, SCL, CLOCK>
141{
142    type Error = Error;
143}
144
145/// I2C Transfer Direction
146#[derive(ufmt::derive::uDebug, Debug, Clone, Copy, Eq, PartialEq)]
147#[repr(u8)]
148pub enum Direction {
149    /// Write to a slave (LSB is 0)
150    Write,
151    /// Read from a slave (LSB is 1)
152    Read,
153}
154
155/// Internal trait for low-level I2C peripherals.
156///
157/// This trait defines the common interface for all I2C peripheral variants.  It is used as an
158/// intermediate abstraction ontop of which the [`I2c`] API is built.  **Prefer using the
159/// [`I2c`] API instead of this trait.**
160pub trait I2cOps<H, SDA, SCL> {
161    /// Setup the bus for operation at a certain speed.
162    ///
163    /// **Warning**: This is a low-level method and should not be called directly from user code.
164    fn raw_setup<CLOCK: crate::clock::Clock>(&mut self, speed: u32);
165
166    /// Start a bus transaction to a certain `address` in either read or write mode.
167    ///
168    /// If a previous transaction was not stopped via `raw_stop()`, this should generate a repeated
169    /// start condition.
170    ///
171    /// **Warning**: This is a low-level method and should not be called directly from user code.
172    fn raw_start(&mut self, address: u8, direction: Direction) -> Result<(), Error>;
173
174    /// Write some bytes to the bus.
175    ///
176    /// This method must only be called after a transaction in write mode was successfully started.
177    ///
178    /// **Warning**: This is a low-level method and should not be called directly from user code.
179    fn raw_write(&mut self, bytes: &[u8]) -> Result<(), Error>;
180
181    /// Read some bytes from the bus.
182    ///
183    /// This method must only be called after a transaction in read mode was successfully started.
184    /// If `last_read` is set then last byte will be nacked. Should be set to false if there will
185    /// be a subsequent read without a start (e.g. when using `transaction`).
186    ///
187    /// **Warning**: This is a low-level method and should not be called directly from user code.
188    fn raw_read(&mut self, buffer: &mut [u8], last_read: bool) -> Result<(), Error>;
189
190    /// Send a stop-condition and release the bus.
191    ///
192    /// This method must only be called after successfully starting a bus transaction.  This method
193    /// does not need to block until the stop condition has actually occured.
194    ///
195    /// **Warning**: This is a low-level method and should not be called directly from user code.
196    fn raw_stop(&mut self) -> Result<(), Error>;
197}
198
199/// I2C driver
200///
201/// # Example
202/// (for Arduino Uno)
203/// ```
204/// let dp = arduino_hal::Peripherals::take().unwrap();
205/// let pins = arduino_hal::pins!(dp);
206///
207/// let mut i2c = arduino_hal::I2c::new(
208///     dp.TWI,
209///     pins.a4.into_pull_up_input(),
210///     pins.a5.into_pull_up_input(),
211///     50000,
212/// );
213///
214/// // i2c implements the embedded-hal traits so it can be used with generic drivers.
215/// ```
216pub struct I2c<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> {
217    p: I2C,
218    #[allow(dead_code)]
219    sda: SDA,
220    #[allow(dead_code)]
221    scl: SCL,
222    _clock: PhantomData<CLOCK>,
223    _h: PhantomData<H>,
224}
225
226impl<H, I2C, SDAPIN, SCLPIN, CLOCK>
227    I2c<H, I2C, port::Pin<port::mode::Input, SDAPIN>, port::Pin<port::mode::Input, SCLPIN>, CLOCK>
228where
229    I2C: I2cOps<H, port::Pin<port::mode::Input, SDAPIN>, port::Pin<port::mode::Input, SCLPIN>>,
230    SDAPIN: port::PinOps,
231    SCLPIN: port::PinOps,
232    CLOCK: crate::clock::Clock,
233{
234    /// Initialize an I2C peripheral on the given pins.
235    ///
236    /// Note that the SDA and SCL pins are hardwired for each I2C peripheral and you *must* pass
237    /// the correct ones.  This is enforced at compile time.
238    ///
239    /// This method expects the internal pull-ups to be configured for both pins to comply with the
240    /// I2C specification.  If you have external pull-ups connected, use
241    /// [`I2c::with_external_pullup`] instead.
242    pub fn new(
243        p: I2C,
244        sda: port::Pin<port::mode::Input<port::mode::PullUp>, SDAPIN>,
245        scl: port::Pin<port::mode::Input<port::mode::PullUp>, SCLPIN>,
246        speed: u32,
247    ) -> Self {
248        let mut i2c = Self {
249            p,
250            sda: sda.forget_imode(),
251            scl: scl.forget_imode(),
252            _clock: PhantomData,
253            _h: PhantomData,
254        };
255        i2c.p.raw_setup::<CLOCK>(speed);
256        i2c
257    }
258
259    /// Initialize an I2C peripheral on the given pins.
260    ///
261    /// Note that the SDA and SCL pins are hardwired for each I2C peripheral and you *must* pass
262    /// the correct ones.  This is enforced at compile time.
263    ///
264    /// This method expects that external resistors pull up SDA and SCL.
265    pub fn with_external_pullup(
266        p: I2C,
267        sda: port::Pin<port::mode::Input<port::mode::Floating>, SDAPIN>,
268        scl: port::Pin<port::mode::Input<port::mode::Floating>, SCLPIN>,
269        speed: u32,
270    ) -> Self {
271        let mut i2c = Self {
272            p,
273            sda: sda.forget_imode(),
274            scl: scl.forget_imode(),
275            _clock: PhantomData,
276            _h: PhantomData,
277        };
278        i2c.p.raw_setup::<CLOCK>(speed);
279        i2c
280    }
281}
282
283impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> I2c<H, I2C, SDA, SCL, CLOCK>
284where
285    CLOCK: crate::clock::Clock,
286    crate::delay::Delay<CLOCK>: embedded_hal_v0::blocking::delay::DelayMs<u16>,
287{
288    /// Test whether a device answers on a certain address.
289    pub fn ping_device(&mut self, address: u8, direction: Direction) -> Result<bool, Error> {
290        match self.p.raw_start(address, direction) {
291            Ok(_) => {
292                if direction == Direction::Read {
293                    self.p.raw_read(&mut [0], true)?
294                }
295                self.p.raw_stop()?;
296                Ok(true)
297            }
298            Err(Error::AddressNack) => Ok(false),
299            Err(e) => Err(e),
300        }
301    }
302
303    /// Scan the bus for connected devices.  This method will output an summary in the format known
304    /// from [`i2cdetect(8)`][i2cdetect-linux] on the selected serial connection.  For example:
305    ///
306    /// ```text
307    /// -    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
308    /// 00:       -- -- -- -- -- -- -- -- -- -- -- -- -- --
309    /// 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
310    /// 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
311    /// 30: -- -- -- -- -- -- -- -- 38 39 -- -- -- -- -- --
312    /// 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
313    /// 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
314    /// 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
315    /// 70: -- -- -- -- -- -- -- --
316    /// ```
317    ///
318    /// [i2cdetect-linux]: https://man.archlinux.org/man/community/i2c-tools/i2cdetect.8.en
319    pub fn i2cdetect<W: ufmt::uWrite>(
320        &mut self,
321        w: &mut W,
322        direction: Direction,
323    ) -> Result<(), W::Error> {
324        use embedded_hal_v0::blocking::delay::DelayMs;
325        let mut delay = crate::delay::Delay::<CLOCK>::new();
326
327        w.write_str(
328            "\
329-    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\r\n\
33000:      ",
331        )?;
332
333        fn u4_to_hex(b: u8) -> char {
334            match b {
335                x if x < 0xa => (0x30 + x).into(),
336                x if x < 0x10 => (0x57 + x).into(),
337                _ => '?',
338            }
339        }
340
341        for address in 0x02..=0x77 {
342            let (ah, al) = (u4_to_hex(address >> 4), u4_to_hex(address & 0xf));
343
344            if address % 0x10 == 0 {
345                w.write_str("\r\n")?;
346                w.write_char(ah)?;
347                w.write_str("0:")?;
348            }
349
350            match self.ping_device(address, direction) {
351                Ok(true) => {
352                    w.write_char(' ')?;
353                    w.write_char(ah)?;
354                    w.write_char(al)?;
355                }
356                Ok(false) => {
357                    w.write_str(" --")?;
358                }
359                Err(e) => {
360                    w.write_str(" E")?;
361                    w.write_char(u4_to_hex(e as u8))?;
362                }
363            }
364
365            delay.delay_ms(10u16);
366        }
367
368        w.write_str("\r\n")?;
369
370        Ok(())
371    }
372}
373
374impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal_v0::blocking::i2c::Write
375    for I2c<H, I2C, SDA, SCL, CLOCK>
376{
377    type Error = Error;
378
379    fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
380        self.p.raw_start(address, Direction::Write)?;
381        self.p.raw_write(bytes)?;
382        self.p.raw_stop()?;
383        Ok(())
384    }
385}
386
387impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal_v0::blocking::i2c::Read
388    for I2c<H, I2C, SDA, SCL, CLOCK>
389{
390    type Error = Error;
391
392    fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
393        self.p.raw_start(address, Direction::Read)?;
394        self.p.raw_read(buffer, true)?;
395        self.p.raw_stop()?;
396        Ok(())
397    }
398}
399
400impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal_v0::blocking::i2c::WriteRead
401    for I2c<H, I2C, SDA, SCL, CLOCK>
402{
403    type Error = Error;
404
405    fn write_read(
406        &mut self,
407        address: u8,
408        bytes: &[u8],
409        buffer: &mut [u8],
410    ) -> Result<(), Self::Error> {
411        self.p.raw_start(address, Direction::Write)?;
412        self.p.raw_write(bytes)?;
413        self.p.raw_start(address, Direction::Read)?;
414        self.p.raw_read(buffer, true)?;
415        self.p.raw_stop()?;
416        Ok(())
417    }
418}
419
420impl<H, I2C: I2cOps<H, SDA, SCL>, SDA, SCL, CLOCK> embedded_hal::i2c::I2c<SevenBitAddress>
421    for I2c<H, I2C, SDA, SCL, CLOCK>
422{
423    fn transaction(
424        &mut self,
425        address: u8,
426        operations: &mut [embedded_hal::i2c::Operation<'_>],
427    ) -> Result<(), Self::Error> {
428        let mut previous_direction = Direction::Read;
429        let mut ops_iter = operations.iter_mut().enumerate().peekable();
430        while let Some((idx, operation)) = ops_iter.next() {
431            match operation {
432                embedded_hal::i2c::Operation::Read(buffer) => {
433                    if idx == 0 || previous_direction != Direction::Read {
434                        self.p.raw_start(address, Direction::Read)?;
435                    }
436
437                    let next_op_is_read = matches!(
438                        ops_iter.peek(),
439                        Some((_, embedded_hal::i2c::Operation::Read(_)))
440                    );
441
442                    self.p.raw_read(buffer, !next_op_is_read)?;
443                    previous_direction = Direction::Read;
444                }
445                embedded_hal::i2c::Operation::Write(bytes) => {
446                    if idx == 0 || previous_direction != Direction::Write {
447                        self.p.raw_start(address, Direction::Write)?;
448                    }
449                    self.p.raw_write(bytes)?;
450                    previous_direction = Direction::Write;
451                }
452            }
453        }
454        if operations.len() > 0 {
455            self.p.raw_stop()?;
456        }
457
458        Ok(())
459    }
460}
461
462#[macro_export]
463macro_rules! impl_i2c_twi {
464    (
465        hal: $HAL:ty,
466        peripheral: $I2C:ty,
467        sda: $sdapin:ty,
468        scl: $sclpin:ty,
469    ) => {
470        impl
471            $crate::i2c::I2cOps<
472                $HAL,
473                $crate::port::Pin<$crate::port::mode::Input, $sdapin>,
474                $crate::port::Pin<$crate::port::mode::Input, $sclpin>,
475            > for $I2C
476        {
477            #[inline]
478            fn raw_setup<CLOCK: $crate::clock::Clock>(&mut self, speed: u32) {
479                // Calculate TWBR register value
480                let twbr = ((CLOCK::FREQ / speed) - 16) / 2;
481                self.twbr.write(|w| unsafe { w.bits(twbr as u8) });
482
483                // Disable prescaler
484                self.twsr.write(|w| w.twps().prescaler_1());
485            }
486
487            #[inline]
488            fn raw_start(&mut self, address: u8, direction: Direction) -> Result<(), Error> {
489                // Write start condition
490                self.twcr
491                    .write(|w| w.twen().set_bit().twint().set_bit().twsta().set_bit());
492                // wait()
493                while self.twcr.read().twint().bit_is_clear() {}
494
495                // Validate status
496                match self.twsr.read().tws().bits() {
497                    $crate::i2c::twi_status::TW_START | $crate::i2c::twi_status::TW_REP_START => (),
498                    $crate::i2c::twi_status::TW_MT_ARB_LOST
499                    | $crate::i2c::twi_status::TW_MR_ARB_LOST => {
500                        return Err($crate::i2c::Error::ArbitrationLost);
501                    }
502                    $crate::i2c::twi_status::TW_BUS_ERROR => {
503                        return Err($crate::i2c::Error::BusError);
504                    }
505                    _ => {
506                        return Err($crate::i2c::Error::Unknown);
507                    }
508                }
509
510                // Send slave address
511                let dirbit = if direction == $crate::i2c::Direction::Read {
512                    1
513                } else {
514                    0
515                };
516                let rawaddr = (address << 1) | dirbit;
517                self.twdr.write(|w| unsafe { w.bits(rawaddr) });
518                // transact()
519                self.twcr.write(|w| w.twen().set_bit().twint().set_bit());
520                while self.twcr.read().twint().bit_is_clear() {}
521
522                // Check if the slave responded
523                match self.twsr.read().tws().bits() {
524                    $crate::i2c::twi_status::TW_MT_SLA_ACK
525                    | $crate::i2c::twi_status::TW_MR_SLA_ACK => (),
526                    $crate::i2c::twi_status::TW_MT_SLA_NACK
527                    | $crate::i2c::twi_status::TW_MR_SLA_NACK => {
528                        // Stop the transaction if it did not respond
529                        self.raw_stop()?;
530                        return Err($crate::i2c::Error::AddressNack);
531                    }
532                    $crate::i2c::twi_status::TW_MT_ARB_LOST
533                    | $crate::i2c::twi_status::TW_MR_ARB_LOST => {
534                        return Err($crate::i2c::Error::ArbitrationLost);
535                    }
536                    $crate::i2c::twi_status::TW_BUS_ERROR => {
537                        return Err($crate::i2c::Error::BusError);
538                    }
539                    _ => {
540                        return Err($crate::i2c::Error::Unknown);
541                    }
542                }
543
544                Ok(())
545            }
546
547            #[inline]
548            fn raw_write(&mut self, bytes: &[u8]) -> Result<(), Error> {
549                for byte in bytes {
550                    self.twdr.write(|w| unsafe { w.bits(*byte) });
551                    // transact()
552                    self.twcr.write(|w| w.twen().set_bit().twint().set_bit());
553                    while self.twcr.read().twint().bit_is_clear() {}
554
555                    match self.twsr.read().tws().bits() {
556                        $crate::i2c::twi_status::TW_MT_DATA_ACK => (),
557                        $crate::i2c::twi_status::TW_MT_DATA_NACK => {
558                            self.raw_stop()?;
559                            return Err($crate::i2c::Error::DataNack);
560                        }
561                        $crate::i2c::twi_status::TW_MT_ARB_LOST => {
562                            return Err($crate::i2c::Error::ArbitrationLost);
563                        }
564                        $crate::i2c::twi_status::TW_BUS_ERROR => {
565                            return Err($crate::i2c::Error::BusError);
566                        }
567                        _ => {
568                            return Err($crate::i2c::Error::Unknown);
569                        }
570                    }
571                }
572                Ok(())
573            }
574
575            #[inline]
576            fn raw_read(&mut self, buffer: &mut [u8], last_read: bool) -> Result<(), Error> {
577                let last = buffer.len() - 1;
578                for (i, byte) in buffer.iter_mut().enumerate() {
579                    if i != last || !last_read {
580                        self.twcr
581                            .write(|w| w.twint().set_bit().twen().set_bit().twea().set_bit());
582                        // wait()
583                        while self.twcr.read().twint().bit_is_clear() {}
584                    } else {
585                        self.twcr.write(|w| w.twint().set_bit().twen().set_bit());
586                        // wait()
587                        while self.twcr.read().twint().bit_is_clear() {}
588                    }
589
590                    match self.twsr.read().tws().bits() {
591                        $crate::i2c::twi_status::TW_MR_DATA_ACK
592                        | $crate::i2c::twi_status::TW_MR_DATA_NACK => (),
593                        $crate::i2c::twi_status::TW_MR_ARB_LOST => {
594                            return Err($crate::i2c::Error::ArbitrationLost);
595                        }
596                        $crate::i2c::twi_status::TW_BUS_ERROR => {
597                            return Err($crate::i2c::Error::BusError);
598                        }
599                        _ => {
600                            return Err($crate::i2c::Error::Unknown);
601                        }
602                    }
603
604                    *byte = self.twdr.read().bits();
605                }
606                Ok(())
607            }
608
609            #[inline]
610            fn raw_stop(&mut self) -> Result<(), Error> {
611                self.twcr
612                    .write(|w| w.twen().set_bit().twint().set_bit().twsto().set_bit());
613                Ok(())
614            }
615        }
616    };
617}