stm32f7xx_hal/
i2c.rs

1//! Inter-Integrated Circuit (I2C) bus
2//! For now, only master mode is implemented
3
4// NB : this implementation started as a modified copy of https://github.com/stm32-rs/stm32f1xx-hal/blob/master/src/i2c.rs
5
6use crate::gpio::{self, Alternate, OpenDrain};
7use crate::hal::blocking::i2c::{Read, Write, WriteRead};
8use crate::pac::{DWT, I2C1, I2C2, I2C3};
9use crate::rcc::{BusClock, Clocks, Enable, RccBus, Reset};
10use fugit::HertzU32 as Hertz;
11use nb::Error::{Other, WouldBlock};
12use nb::{Error as NbError, Result as NbResult};
13
14use cast::u16;
15
16/// I2C error
17#[derive(Debug, Eq, PartialEq)]
18#[non_exhaustive]
19pub enum Error {
20    /// Bus error
21    Bus,
22    /// Arbitration loss
23    Arbitration,
24    /// No ack received
25    Acknowledge,
26    /// Overrun/underrun
27    Overrun,
28    /// Bus is busy
29    Busy,
30    // Pec, // SMBUS mode only
31    // Timeout, // SMBUS mode only
32    // Alert, // SMBUS mode only
33}
34
35/// SPI mode. The user should make sure that the requested frequency can be
36/// generated considering the buses clocks.
37#[derive(Debug, PartialEq)]
38pub enum Mode {
39    Standard { frequency: Hertz },
40    Fast { frequency: Hertz },
41    FastPlus { frequency: Hertz },
42    Custom { timing_r: u32 },
43}
44
45impl Mode {
46    pub fn standard(frequency: Hertz) -> Self {
47        Mode::Standard { frequency }
48    }
49
50    pub fn fast(frequency: Hertz) -> Self {
51        Mode::Fast { frequency }
52    }
53
54    pub fn fast_plus(frequency: Hertz) -> Self {
55        Mode::FastPlus { frequency }
56    }
57}
58
59/// Marker trait to define SCL pins for an I2C interface.
60pub trait PinScl<I2C> {}
61
62/// Marker trait to define SDA pins for an I2C interface.
63pub trait PinSda<I2C> {}
64
65impl PinScl<I2C1> for gpio::PB6<Alternate<4, OpenDrain>> {}
66impl PinScl<I2C1> for gpio::PB8<Alternate<4, OpenDrain>> {}
67impl PinScl<I2C2> for gpio::PB10<Alternate<4, OpenDrain>> {}
68impl PinScl<I2C2> for gpio::PF1<Alternate<4, OpenDrain>> {}
69impl PinScl<I2C2> for gpio::PH4<Alternate<4, OpenDrain>> {}
70impl PinScl<I2C3> for gpio::PA8<Alternate<4, OpenDrain>> {}
71impl PinScl<I2C3> for gpio::PH7<Alternate<4, OpenDrain>> {}
72
73impl PinSda<I2C1> for gpio::PB7<Alternate<4, OpenDrain>> {}
74impl PinSda<I2C1> for gpio::PB9<Alternate<4, OpenDrain>> {}
75impl PinSda<I2C2> for gpio::PB11<Alternate<4, OpenDrain>> {}
76impl PinSda<I2C2> for gpio::PF0<Alternate<4, OpenDrain>> {}
77impl PinSda<I2C2> for gpio::PH5<Alternate<4, OpenDrain>> {}
78impl PinSda<I2C3> for gpio::PC9<Alternate<4, OpenDrain>> {}
79impl PinSda<I2C3> for gpio::PH8<Alternate<4, OpenDrain>> {}
80
81/// I2C peripheral operating in master mode
82pub struct I2c<I2C, SCL, SDA> {
83    i2c: I2C,
84    pins: (SCL, SDA),
85    mode: Mode,
86    pclk: Hertz,
87}
88
89/// embedded-hal compatible blocking I2C implementation
90pub struct BlockingI2c<I2C, SCL, SDA> {
91    nb: I2c<I2C, SCL, SDA>,
92    data_timeout: u32,
93}
94
95impl<SCL, SDA> I2c<I2C1, SCL, SDA> {
96    /// Creates a generic I2C1 object.
97    pub fn i2c1(
98        i2c: I2C1,
99        pins: (SCL, SDA),
100        mode: Mode,
101        clocks: &Clocks,
102        apb: &mut <I2C1 as RccBus>::Bus,
103    ) -> Self
104    where
105        SCL: PinScl<I2C1>,
106        SDA: PinSda<I2C1>,
107    {
108        I2c::_i2c1(i2c, pins, mode, clocks, apb)
109    }
110}
111
112impl<SCL, SDA> BlockingI2c<I2C1, SCL, SDA> {
113    /// Creates a blocking I2C1 object using the embedded-hal `BlockingI2c` trait.
114    pub fn i2c1(
115        i2c: I2C1,
116        pins: (SCL, SDA),
117        mode: Mode,
118        clocks: &Clocks,
119        apb: &mut <I2C1 as RccBus>::Bus,
120        data_timeout_us: u32,
121    ) -> Self
122    where
123        SCL: PinScl<I2C1>,
124        SDA: PinSda<I2C1>,
125    {
126        BlockingI2c::_i2c1(i2c, pins, mode, clocks, apb, data_timeout_us)
127    }
128}
129
130impl<SCL, SDA> I2c<I2C2, SCL, SDA> {
131    /// Creates a generic I2C2 object.
132    pub fn i2c2(
133        i2c: I2C2,
134        pins: (SCL, SDA),
135        mode: Mode,
136        clocks: &Clocks,
137        apb: &mut <I2C2 as RccBus>::Bus,
138    ) -> Self
139    where
140        SCL: PinScl<I2C2>,
141        SDA: PinSda<I2C2>,
142    {
143        I2c::_i2c2(i2c, pins, mode, clocks, apb)
144    }
145}
146
147impl<SCL, SDA> BlockingI2c<I2C2, SCL, SDA> {
148    /// Creates a blocking I2C2 object using the embedded-hal `BlockingI2c` trait.
149    pub fn i2c2(
150        i2c: I2C2,
151        pins: (SCL, SDA),
152        mode: Mode,
153        clocks: &Clocks,
154        apb: &mut <I2C2 as RccBus>::Bus,
155        data_timeout_us: u32,
156    ) -> Self
157    where
158        SCL: PinScl<I2C2>,
159        SDA: PinSda<I2C2>,
160    {
161        BlockingI2c::_i2c2(i2c, pins, mode, clocks, apb, data_timeout_us)
162    }
163}
164
165impl<SCL, SDA> I2c<I2C3, SCL, SDA> {
166    /// Creates a generic I2C3 object.
167    pub fn i2c3(
168        i2c: I2C3,
169        pins: (SCL, SDA),
170        mode: Mode,
171        clocks: &Clocks,
172        apb: &mut <I2C3 as RccBus>::Bus,
173    ) -> Self
174    where
175        SCL: PinScl<I2C3>,
176        SDA: PinSda<I2C3>,
177    {
178        I2c::_i2c3(i2c, pins, mode, clocks, apb)
179    }
180}
181
182impl<SCL, SDA> BlockingI2c<I2C3, SCL, SDA> {
183    /// Creates a blocking I2C3 object using the embedded-hal `BlockingI2c` trait.
184    pub fn i2c3(
185        i2c: I2C3,
186        pins: (SCL, SDA),
187        mode: Mode,
188        clocks: &Clocks,
189        apb: &mut <I2C3 as RccBus>::Bus,
190        data_timeout_us: u32,
191    ) -> Self
192    where
193        SCL: PinScl<I2C3>,
194        SDA: PinSda<I2C3>,
195    {
196        BlockingI2c::_i2c3(i2c, pins, mode, clocks, apb, data_timeout_us)
197    }
198}
199
200/// Generates a blocking I2C instance from a universal I2C object
201fn blocking_i2c<I2C, SCL, SDA>(
202    i2c: I2c<I2C, SCL, SDA>,
203    clocks: &Clocks,
204    data_timeout_us: u32,
205) -> BlockingI2c<I2C, SCL, SDA> {
206    let sysclk_mhz = clocks.sysclk().to_MHz();
207    BlockingI2c {
208        nb: i2c,
209        data_timeout: data_timeout_us * sysclk_mhz,
210    }
211}
212
213// hddat and vddat are removed because SDADEL is always going to be 0 in this implementation so
214// condition is always met
215struct I2cSpec {
216    freq_max: u32,
217    sudat_min: u32,
218    _lscl_min: u32,
219    _hscl_min: u32,
220    trise_max: u32, // in ns
221    _tfall_max: u32,
222}
223
224#[derive(Debug)]
225struct I2cTiming {
226    presc: u8,
227    scldel: u8,
228    sdadel: u8,
229    sclh: u8,
230    scll: u8,
231}
232
233// everything is in nano seconds
234const I2C_STANDARD_MODE_SPEC: I2cSpec = I2cSpec {
235    freq_max: 102400,
236    sudat_min: 250,
237    _lscl_min: 4700,
238    _hscl_min: 4000,
239    trise_max: 640,
240    _tfall_max: 20,
241};
242const I2C_FAST_MODE_SPEC: I2cSpec = I2cSpec {
243    freq_max: 409600,
244    sudat_min: 100,
245    _lscl_min: 1300,
246    _hscl_min: 600,
247    trise_max: 250,
248    _tfall_max: 100,
249};
250
251const I2C_FAST_PLUS_MODE_SPEC: I2cSpec = I2cSpec {
252    freq_max: 1024000,
253    sudat_min: 50,
254    _lscl_min: 500,
255    _hscl_min: 260,
256    trise_max: 60,
257    _tfall_max: 100,
258};
259
260fn calculate_timing(
261    spec: I2cSpec,
262    i2c_freq: u32,
263    scl_freq: u32,
264    an_filter: bool,
265    dnf: u8,
266) -> I2cTiming {
267    // This dependency is not used when `cargo test`ing. More info:
268    // https://docs.rs/micromath/1.1.1/micromath/index.html#unused-import-warnings-when-linking-std
269    #[cfg(not(test))]
270    use micromath::F32Ext as _;
271
272    // frequency limit check
273    assert!(scl_freq <= spec.freq_max);
274    // T_sync or delay introduced in SCL
275    // generally it is 2-3 clock cycles
276    // t_sync + dnf delay
277    let t_dnf = (dnf) as f32 / i2c_freq as f32;
278    // if analog filter is enabled then it offer about 50 - 70 ns delay
279    let t_af: f32 = if an_filter {
280        40.0 / 1_000_000_000f32
281    } else {
282        0.0
283    };
284    // t_sync = 2 to 3 * i2cclk
285    let t_sync = 2.0 / (i2c_freq as f32);
286    // fall or rise time
287    let t_fall: f32 = 50f32 / 1_000_000_000f32;
288    let t_rise: f32 = 60f32 / 1_000_000_000f32;
289    let t_delay = t_fall + t_rise + 2.0 * (t_dnf + t_af + t_sync);
290    // formula is like F_i2cclk/F/F_scl_clk = (scl_h+scl_l+2)*(Presc + 1)
291    // consider scl_l+scl_h is 256 max. but in that case clock should always
292    // be 50% duty cycle. lets consider scl_l+scl_h to be 128. so that it can
293    // be changed later
294    // (scl_l+scl_h+2)(presc +1 ) ==> as scl_width*presc ==F_i2cclk/F/F_scl_clk
295    let product: f32 = (1.0 - t_delay * (scl_freq as f32)) * (i2c_freq / scl_freq) as f32;
296    let scl_l: u8;
297    let scl_h: u8;
298    let mut presc: u8;
299    // if ratio is > (scll+sclh)*presc. that frequancy is not possible to generate. so
300    // minimum frequancy possible is generated
301    if product > 8192_f32 {
302        // TODO: should we panic or use minimum allowed frequancy
303        scl_l = 0x7fu8;
304        scl_h = 0x7fu8;
305        presc = 0xfu8;
306    } else {
307        // smaller the minimum devition less difference between expected vs
308        // actual scl clock
309        let mut min_deviation = 16f32;
310        // TODO: use duty cycle and based on that use precstart
311        let presc_start = (product / 512.0).ceil() as u8;
312        presc = presc_start;
313        for tmp_presc in presc_start..17 {
314            let deviation = product % tmp_presc as f32;
315            if min_deviation > deviation {
316                min_deviation = deviation;
317                presc = tmp_presc as u8;
318            }
319        }
320        // now that we have optimal prescalar value. optimal scl_l and scl_h
321        // needs to be calculated
322        let scl_width = (product / presc as f32) as u16; // it will be always less than 256
323        scl_h = (scl_width / 2 - 1) as u8;
324        scl_l = (scl_width - scl_h as u16 - 1) as u8; // This is to get max precision
325        presc -= 1;
326    }
327    let scldel: u8 = (((spec.trise_max + spec.sudat_min) as f32 / 1_000_000_000.0)
328        / ((presc + 1) as f32 / i2c_freq as f32)
329        - 1.0)
330        .ceil() as u8;
331    I2cTiming {
332        presc,
333        scldel,
334        sdadel: 0,
335        sclh: scl_h,
336        scll: scl_l,
337    }
338}
339
340macro_rules! check_status_flag {
341    ($i2c:expr, $flag:ident, $status:ident) => {{
342        let isr = $i2c.isr.read();
343
344        if isr.berr().bit_is_set() {
345            $i2c.icr.write(|w| w.berrcf().set_bit());
346            Err(Other(Error::Bus))
347        } else if isr.arlo().bit_is_set() {
348            $i2c.icr.write(|w| w.arlocf().set_bit());
349            Err(Other(Error::Arbitration))
350        } else if isr.nackf().bit_is_set() {
351            $i2c.icr.write(|w| w.stopcf().set_bit().nackcf().set_bit());
352            Err(Other(Error::Acknowledge))
353        } else if isr.ovr().bit_is_set() {
354            $i2c.icr.write(|w| w.stopcf().set_bit().ovrcf().set_bit());
355            Err(Other(Error::Overrun))
356        } else if isr.$flag().$status() {
357            Ok(())
358        } else {
359            Err(WouldBlock)
360        }
361    }};
362}
363
364macro_rules! busy_wait {
365    ($nb_expr:expr, $exit_cond:expr) => {{
366        loop {
367            let res = $nb_expr;
368            if res != Err(WouldBlock) {
369                break res;
370            }
371            if $exit_cond {
372                break res;
373            }
374        }
375    }};
376}
377
378macro_rules! busy_wait_cycles {
379    ($nb_expr:expr, $cycles:expr) => {{
380        let started = DWT::cycle_count();
381        let cycles = $cycles;
382        busy_wait!($nb_expr, DWT::cycle_count().wrapping_sub(started) >= cycles)
383    }};
384}
385
386// Generate the same code for both I2Cs
387macro_rules! hal {
388    ($($I2CX:ident: ($i2cX:ident),)+) => {
389        $(
390            impl<SCL, SDA> I2c<$I2CX, SCL, SDA> {
391                /// Configures the I2C peripheral to work in master mode
392                fn $i2cX(
393                    i2c: $I2CX,
394                    pins: (SCL, SDA),
395                    mode: Mode,
396                    clocks: &Clocks,
397                    apb: &mut <I2C1 as RccBus>::Bus
398                ) -> Self {
399                    $I2CX::enable(apb);
400                    $I2CX::reset(apb);
401
402                    let pclk = <$I2CX>::clock(clocks);
403
404                    let mut i2c = I2c { i2c, pins, mode, pclk };
405                    i2c.init();
406                    i2c
407                }
408
409                /// Initializes I2C as master. Configures I2C_PRESC, I2C_SCLDEL,
410                /// I2C_SDAEL, I2C_SCLH, I2C_SCLL
411                ///
412                /// For now, only standard mode is implemented
413                fn init(&mut self) {
414                    // NOTE : operations are in float for better precision,
415                    // STM32F7 usually have FPU and this runs only at
416                    // initialization so the footprint of such heavy calculation
417                    // occurs only once
418                    // Disable I2C during configuration
419                    self.i2c.cr1.write(|w| w.pe().disabled());
420
421                    let an_filter:bool = self.i2c.cr1.read().anfoff().is_enabled();
422                    let dnf = self.i2c.cr1.read().dnf().bits();
423
424                    let i2c_timingr: I2cTiming =  match self.mode {
425                        Mode::Standard{ frequency } => calculate_timing(I2C_STANDARD_MODE_SPEC, self.pclk.raw(), frequency.raw(), an_filter, dnf ),
426                        Mode::Fast{ frequency } => calculate_timing(I2C_FAST_MODE_SPEC, self.pclk.raw(), frequency.raw(), an_filter, dnf),
427                        Mode::FastPlus{ frequency } => calculate_timing(I2C_FAST_PLUS_MODE_SPEC, self.pclk.raw(), frequency.raw(), an_filter, dnf ),
428                        Mode::Custom{ timing_r } => {
429                            I2cTiming{
430                                presc:  ((timing_r & 0xf000_0000) >> 28 ) as u8,
431                                scldel: ((timing_r & 0x00f0_0000) >> 20 ) as u8 ,
432                                sdadel: ((timing_r & 0x000f_0000) >> 16 ) as u8,
433                                sclh:   ((timing_r & 0x0000_ff00) >> 8 ) as u8,
434                                scll:   ((timing_r & 0x0000_00ff) >> 0 ) as u8,
435                            }
436                        }
437                    };
438                    self.i2c.timingr.write(|w|
439                        w.presc()
440                            .bits(i2c_timingr.presc)
441                            .scll()
442                            .bits(i2c_timingr.scll)
443                            .sclh()
444                            .bits(i2c_timingr.sclh)
445                            .sdadel()
446                            .bits(i2c_timingr.sdadel)
447                            .scldel()
448                            .bits(i2c_timingr.scldel)
449                    );
450
451                    self.i2c.cr1.modify(|_, w| w.pe().enabled());
452                }
453
454                /// Perform an I2C software reset
455                #[allow(dead_code)]
456                fn reset(&mut self) {
457                    self.i2c.cr1.write(|w| w.pe().disabled());
458                    // wait for disabled
459                    while self.i2c.cr1.read().pe().is_enabled() {}
460
461                    // Re-enable
462                    self.i2c.cr1.write(|w| w.pe().enabled());
463                }
464
465                /// Set (7-bit) slave address, bus direction (write or read),
466                /// generate START condition and set address.
467                ///
468                /// The user has to specify the number `n_bytes` of bytes to
469                /// read. The peripheral automatically waits for the bus to be
470                /// free before sending the START and address
471                ///
472                /// Data transfers of more than 255 bytes are not yet
473                /// supported, 10-bit slave address are not yet supported
474                fn start(&self, addr: u8, n_bytes: u8, read: bool, auto_stop: bool) {
475                    self.i2c.cr2.write(|mut w| {
476                        // Setup data
477                        w = w.sadd()
478                            .bits(u16(addr << 1 | 0))
479                            .add10().clear_bit()
480                            .nbytes()
481                            .bits(n_bytes as u8)
482                            .start()
483                            .set_bit();
484
485                        // Setup transfer direction
486                        w = match read {
487                            true => w.rd_wrn().read(),
488                            false => w.rd_wrn().write()
489                        };
490
491                        // setup auto-stop
492                        match auto_stop {
493                            true => w.autoend().automatic(),
494                            false => w.autoend().software(),
495                        }
496                    });
497                }
498
499                /// Releases the I2C peripheral and associated pins
500                pub fn free(self) -> ($I2CX, (SCL, SDA)) {
501                    (self.i2c, self.pins)
502                }
503            }
504
505            impl<SCL, SDA> BlockingI2c<$I2CX, SCL, SDA> {
506                fn $i2cX(
507                    i2c: $I2CX,
508                    pins: (SCL, SDA),
509                    mode: Mode,
510                    clocks: &Clocks,
511                    apb: &mut <$I2CX as RccBus>::Bus,
512                    data_timeout_us: u32
513                ) -> Self {
514                    blocking_i2c(I2c::$i2cX(i2c, pins, mode, clocks, apb),
515                        clocks, data_timeout_us)
516                }
517
518                /// Wait for a byte to be read and return it (ie for RXNE flag
519                /// to be set)
520                fn wait_byte_read(&self) -> NbResult<u8, Error> {
521                    // Wait until we have received something
522                    busy_wait_cycles!(
523                        check_status_flag!(self.nb.i2c, rxne, is_not_empty),
524                        self.data_timeout
525                    )?;
526
527                    Ok(self.nb.i2c.rxdr.read().rxdata().bits())
528                }
529
530                /// Wait the write data register to be empty  (ie for TXIS flag
531                /// to be set) and write the byte to it
532                fn wait_byte_write(&self, byte: u8) -> NbResult<(), Error> {
533                    // Wait until we are allowed to send data
534                    // (START has been ACKed or last byte when through)
535                    busy_wait_cycles!(
536                        check_status_flag!(self.nb.i2c, txis, is_empty),
537                        self.data_timeout
538                    )?;
539
540                    // Put byte on the wire
541                    self.nb.i2c.txdr.write(|w| w.txdata().bits(byte));
542
543                    Ok(())
544                }
545
546                /// Wait for any previous address sequence to end automatically.
547                fn wait_start(&self) {
548                    while self.nb.i2c.cr2.read().start().bit_is_set() {};
549                }
550            }
551
552            impl<SCL, SDA> Write for BlockingI2c<$I2CX, SCL, SDA> {
553                type Error = NbError<Error>;
554
555                /// Write bytes to I2C. Currently, `bytes.len()` must be less or
556                /// equal than 255
557                fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
558                    // TODO support transfers of more than 255 bytes
559                    assert!(bytes.len() < 256 && bytes.len() > 0);
560
561                    // Wait for any previous address sequence to end
562                    // automatically. This could be up to 50% of a bus
563                    // cycle (ie. up to 0.5/freq)
564                    self.wait_start();
565
566                    // Set START and prepare to send `bytes`. The
567                    // START bit can be set even if the bus is BUSY or
568                    // I2C is in slave mode.
569                    self.nb.start(addr, bytes.len() as u8, false, true);
570
571                    for byte in bytes {
572                        self.wait_byte_write(*byte)?;
573                    }
574                    // automatic STOP
575
576                    Ok(())
577                }
578            }
579
580            impl<SCL, SDA> Read for BlockingI2c<$I2CX, SCL, SDA> {
581                type Error = NbError<Error>;
582
583                /// Reads enough bytes from slave with `address` to fill `buffer`
584                fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
585                    // TODO support transfers of more than 255 bytes
586                    assert!(buffer.len() < 256 && buffer.len() > 0);
587
588                    // Wait for any previous address sequence to end
589                    // automatically. This could be up to 50% of a bus
590                    // cycle (ie. up to 0.5/freq)
591                    self.wait_start();
592
593                    // Set START and prepare to receive bytes into
594                    // `buffer`. The START bit can be set even if the bus
595                    // is BUSY or I2C is in slave mode.
596                    self.nb.start(addr, buffer.len() as u8, true, true);
597
598                    for byte in buffer {
599                        *byte = self.wait_byte_read()?;
600                    }
601
602                    // automatic STOP
603
604                    Ok(())
605                }
606            }
607
608            impl<SCL, SDA> WriteRead for BlockingI2c<$I2CX, SCL, SDA> {
609                type Error = NbError<Error>;
610
611                fn write_read(
612                    &mut self,
613                    addr: u8,
614                    bytes: &[u8],
615                    buffer: &mut [u8],
616                ) -> Result<(), Self::Error> {
617                    // TODO support transfers of more than 255 bytes
618                    assert!(bytes.len() < 256 && bytes.len() > 0);
619                    assert!(buffer.len() < 256 && buffer.len() > 0);
620
621                    // Start and make sure we don't send STOP after the write
622                    self.wait_start();
623                    self.nb.start(addr, bytes.len() as u8, false, false);
624
625                    for byte in bytes {
626                        self.wait_byte_write(*byte)?;
627                    }
628
629                    // Wait until the write finishes before beginning to read.
630                    // busy_wait2!(self.nb.i2c, tc, is_complete);
631                    busy_wait_cycles!(
632                        check_status_flag!(self.nb.i2c, tc, is_complete),
633                        self.data_timeout
634                    )?;
635
636                    // reSTART and prepare to receive bytes into `buffer`
637                    self.nb.start(addr, buffer.len() as u8, true, true);
638
639                    for byte in buffer {
640                        *byte = self.wait_byte_read()?;
641                    }
642                    // automatic STOP
643
644                    Ok(())
645                }
646            }
647        )+
648    }
649}
650
651hal! {
652    I2C1: (_i2c1),
653    I2C2: (_i2c2),
654    I2C3: (_i2c3),
655}