1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
//! Support for the Inter-Integrated Circuit (I2C) bus peripheral. Also supports SMBUS.
//! Provides APIs to configure, read, and write from
//! I2C, with blocking, nonblocking, and DMA functionality.

use cast::u16;
use core::ops::Deref;

use cortex_m::interrupt::free;

#[cfg(feature = "embedded-hal")]
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};

use crate::{
    clocks::Clocks,
    pac::{self, RCC},
    util::RccPeriph,
};

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(all(feature = "g0", not(any(feature = "g0b1", feature = "g0c1"))))] {
        use crate::pac::dma as dma_p;
    } else if #[cfg(feature = "f4")] {} else {
        use crate::pac::dma1 as dma_p;
    }
}

#[cfg(not(feature = "l552"))]
use crate::dma::{self, ChannelCfg, Dma, DmaChannel};

#[cfg(any(feature = "f3", feature = "l4"))]
use crate::dma::DmaInput;

// todo: Get rid of this macro.
macro_rules! busy_wait {
    ($regs:expr, $flag:ident) => {
        loop {
            let isr = $regs.isr.read();

            if isr.$flag().bit_is_set() {
                break;
            } else if isr.berr().bit_is_set() {
                $regs.icr.write(|w| w.berrcf().set_bit());
                return Err(Error::Bus);
            } else if isr.arlo().bit_is_set() {
                $regs.icr.write(|w| w.arlocf().set_bit());
                return Err(Error::Arbitration);
            } else if isr.nackf().bit_is_set() {
                $regs.icr.write(|w| w.stopcf().set_bit().nackcf().set_bit());

                // If a pending TXIS flag is set, write dummy data to TXDR
                if $regs.isr.read().txis().bit_is_set() {
                    $regs.txdr.write(|w| unsafe { w.txdata().bits(0) });
                }

                // If TXDR is not flagged as empty, write 1 to flush it
                if $regs.isr.read().txe().bit_is_clear() {
                    $regs.isr.write(|w| w.txe().set_bit());
                }

                return Err(Error::Nack);
            } else {
                // try again
            }
        }
    };
}

/// I2C error
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
    /// Bus error
    Bus,
    /// Arbitration loss
    Arbitration,
    /// NACK
    Nack,
    // Overrun, // slave mode only
    // Pec, // SMBUS mode only
    // Timeout, // SMBUS mode only
    // Alert, // SMBUS mode only
}

#[derive(Clone, Copy)]
#[repr(u8)]
/// Set master or slave mode. Sets the __ register, _ field.
pub enum I2cMode {
    /// In Master mode, the I2C interface initiates a data transfer and generates the clock signal. A
    /// serial data transfer always begins with a START condition and ends with a STOP condition.
    /// Both START and STOP conditions are generated in master mode by software.
    Master = 0,
    /// In Slave mode, the interface is capable of recognizing its own addresses (7 or 10-bit), and
    /// the general call address. The general call address detection can be enabled or disabled by
    /// software. The reserved SMBus addresses can also be enabled by software.
    Slave = 1,
}

#[derive(Clone, Copy)]
/// Set a preset I2C speed, based on RM tables: Examples of timings settings.
/// Sets 5 fields of the TIMINGR register.
pub enum I2cSpeed {
    /// Standard-mode: 10kHz.
    Standard10K,
    /// Standard-mode: 100kHz.
    Standard100K,
    /// Fast-mode: 400kHz.
    Fast400K,
    /// Fast-mode +: 1Mhz.
    FastPlus1M,
}

#[derive(Clone, Copy)]
#[repr(u8)]
/// Set the number of address bits to 7 or 10. Sets the CR2 register, ADD10 field.
pub enum AddressBits {
    B7 = 0,
    B10 = 1,
}

#[derive(Clone, Copy, PartialEq)]
/// Set the number of address bits to 7 or 10. Sets the CR1 register, ANFOFF and DNF fields.
pub enum NoiseFilter {
    /// Analog noise filter enabled.
    Analog,
    /// Digital filter enabled and filtering capability ( filters spikes with a length of)
    /// up to (value) t_I2CCLK
    Digital(u8),
    /// Analog and digital filters disabled.
    Disabled,
}

/// Configuration data for the I2C peripheral.
#[derive(Clone)]
pub struct I2cConfig {
    /// Select master or slave mode. Defaults to Master.
    pub mode: I2cMode,
    /// Select between one of 4 preset speeds. If you'd like to use custom
    /// speed settings, use the PAC directly, with I2C disabled, after the
    /// peripheral clocks are enabled by `new()`. Defaults to Standard mode, 100kHz.
    pub speed: I2cSpeed,
    /// Allows setting 7 or 10-bit addresses. Defaults to 7.
    pub address_bits: AddressBits,
    /// Select the analog noise filter, a digital filter, or no filter. Deafults to analog.
    pub noise_filter: NoiseFilter,
    /// Support for SMBUS, including hardware PEC, and alert pin. Defaults to false.
    pub smbus: bool,
    /// Optionally disable clock stretching. Defaults to false (stretching allowed).
    /// Only relevant in slave mode.
    pub nostretch: bool,
}

impl Default for I2cConfig {
    fn default() -> Self {
        Self {
            mode: I2cMode::Master,
            speed: I2cSpeed::Standard100K,
            address_bits: AddressBits::B7,
            noise_filter: NoiseFilter::Analog,
            smbus: false,
            nostretch: false,
        }
    }
}

/// Represents an Inter-Integrated Circuit (I2C) peripheral.
pub struct I2c<R> {
    pub regs: R,
    pub cfg: I2cConfig,
}

impl<R> I2c<R>
where
    R: Deref<Target = pac::i2c1::RegisterBlock> + RccPeriph,
{
    /// Initialize a I2C peripheral, including configuration register writes, and enabling and resetting
    /// its RCC peripheral clock. `freq` is in Hz.
    pub fn new(regs: R, cfg: I2cConfig, clocks: &Clocks) -> Self {
        free(|_| {
            let rcc = unsafe { &(*RCC::ptr()) };
            R::en_reset(rcc);
        });

        // Make sure the I2C unit is disabled so we can configure it
        regs.cr1.modify(|_, w| w.pe().clear_bit());

        // todo: Slave currently nonfunctional!
        // todo: Check out the RM recipes for slave transmitter and receiver.

        // RM: I2C timings:
        // The timings must be configured in order to guarantee a correct data hold and setup time,
        // used in master and slave modes. This is done by programming the PRESC[3:0],
        // SCLDEL[3:0] and SDADEL[3:0] bits in the I2C_TIMINGR register.
        // ... Additionally, in master mode, the SCL clock high and low levels must be configured by
        // programming the PRESC[3:0], SCLH[7:0] and SCLL[7:0] bits in the I2C_TIMINGR register

        // For these speed and frequency variables, we use the RM's conventions.
        let t_i2cclk = clocks.apb1();

        // assert!(t_i2cclk < (t_low - f_f) / 4);
        // assert!(t_i2cclk < t_high);

        // Set the prescaler using RM tables as a guide;
        // L552 RM, Tables 324 - 326: Examples of timings settings.
        // Note that the table only includes I2C clock multiples of 4Mhz (well, multiples of 8Mhz).
        // In this case, we'll use the integer floor rounding to handle in-between
        // values.

        // We use this constant in several calculations.
        let presc_const = match cfg.speed {
            I2cSpeed::Standard10K => 4_000_000,
            I2cSpeed::Standard100K => 4_000_000,
            I2cSpeed::Fast400K => 8_000_000,
            // Note: The 16Mhz example uses F+ / 16. The other 2 examples
            // use 8e6.
            I2cSpeed::FastPlus1M => 8_000_000,
        };

        // This is (offset by 1) which we set as the prescaler.
        let mut presc_val = t_i2cclk / presc_const;

        // The tables don't show faster I2C input clocks than 48Mhz, but it often will be.
        // For example, an 80Mhz APB clock will peg prescaler at its maximum value.
        // Let's just set it to this max. (Maybe we should use fast mode etc if this is so?)
        if presc_val > 16 {
            presc_val = 16;
        }

        // Hit the target freq by setting up t_scll (Period of SCL low)
        // to be half the whole period. These constants
        // are from the tables.
        let freq = match cfg.speed {
            I2cSpeed::Standard10K => 10_000,
            I2cSpeed::Standard100K => 100_000,
            I2cSpeed::Fast400K => 400_000,
            I2cSpeed::FastPlus1M => 1_000_000,
        };

        // Set SCLL (SCL low time) to be half the duty period
        // associated with the target frequency.
        // todo: QC this is right if you peg presc_val at 16.
        let scll_val;
        if presc_val == 16 {
            // IF we peg presc, we need to modify out calculation of scll (??)
            scll_val = (t_i2cclk / presc_val) / (2 * freq);
        } else {
            scll_val = presc_const / (2 * freq);
        }

        // SCLH is smaller than SCLH. For standard mode it's close, although
        // in the example tables, 20% different for 100Khz, and 2% different for
        // 10K. THis may be due to delays
        // involved. The ratio is different for Fast-mode and Fast-mode+.
        // todo: Come back to this. How should we set this?
        let sclh_val = match cfg.speed {
            I2cSpeed::Standard10K => scll_val - 4,
            I2cSpeed::Standard100K => scll_val - 4,
            I2cSpeed::Fast400K => scll_val * 4 / 10,
            I2cSpeed::FastPlus1M => scll_val / 2,
        };

        // Timing prescaler. This field is used to prescale I2CCLK in order to generate the clock period tPRESC used for
        // data setup and hold counters (refer to I2C timings on page 1495) and for SCL high and low
        // level counters (refer to I2C master initialization on page 1510).
        // Sets TIMINGR reg, PRESC field.

        let presc = presc_val - 1;

        // SCL low period (master mode)
        // This field is used to generate the SCL low period in master mode.
        // tSCLL = (SCLL+1) x tPRESC
        // Note: SCLL is also used to generate tBUF and tSU:STA timings.
        // Sets TIMINGR reg, SCLL field.
        let scll = scll_val - 1;

        // SCL high period (master mode)
        // This field is used to generate the SCL high period in master mode.
        // tSCLH = (SCLH+1) x tPRESC
        // Note: SCLH is also used to generate tSU:STO and tHD:STA timing
        // Set the clock prescaler value. Sets TIMINGR reg, SCLH field.
        let sclh = sclh_val - 1;

        // todo: Can't find the sdadel and scldel pattern
        // Data hold time
        // This field is used to generate the delay tSDADEL between SCL falling edge and SDA edge. In
        // master mode and in slave mode with NOSTRETCH = 0, the SCL line is stretched low during
        // tSDADEL.
        // tSDADEL= SDADEL x tPRESC
        // Note: SDADEL is used to generate tHD:DAT timing
        // Sets TIMINGR reg, SDADEL field.
        let sdadel = match cfg.speed {
            I2cSpeed::Standard10K => 0x2,
            I2cSpeed::Standard100K => 0x2,
            I2cSpeed::Fast400K => 0x3,
            I2cSpeed::FastPlus1M => 0x0,
        };

        // Data setup time
        // This field is used to generate a delay tSCLDEL between SDA edge and SCL rising edge. In
        // master mode and in slave mode with NOSTRETCH = 0, the SCL line is stretched low during
        // tSCLDEL.
        // tSCLDEL = (SCLDEL+1) x tPRESC
        // Note: tSCLDEL is used to generate tSU:DAT timing
        // Sets TIMINGR reg, SCLDEL field.
        let scldel = match cfg.speed {
            I2cSpeed::Standard10K => 0x4,
            I2cSpeed::Standard100K => 0x4,
            I2cSpeed::Fast400K => 0x3,
            I2cSpeed::FastPlus1M => 0x1,
        };

        // The fields for PRESC, SCLDEL, and SDADEL are 4-bits; don't overflow.
        // The other TIMINGR fields we set are 8-bits, so won't overflow with u8.
        assert!(presc <= 15);
        assert!(scldel <= 15);
        assert!(sdadel <= 15);

        assert!(scll <= 255);
        assert!(sclh <= 255);

        regs.timingr.write(|w| unsafe {
            w.presc().bits(presc as u8);
            w.scldel().bits(scldel as u8);
            w.sdadel().bits(sdadel as u8);
            w.sclh().bits(sclh as u8);
            w.scll().bits(scll as u8)
        });

        // Before enabling the I2C peripheral by setting the PE bit in I2C_CR1 register, the user must
        // configure the noise filters, if needed. By default, an analog noise filter is present on the SDA
        // and SCL inputs. This analog filter is compliant with the I2C specification which requires the
        // suppression of spikes with a pulse width up to 50 ns in Fast-mode and Fast-mode Plus. The
        // user can disable this analog filter by setting the ANFOFF bit, and/or select a digital filter by
        // configuring the DNF[3:0] bit in the I2C_CR1 register.
        // When the digital filter is enabled, the level of the SCL or the SDA line is internally changed
        // only if it remains stable for more than DNF x I2CCLK periods. This allows spikes with a
        // programmable length of 1 to 15 I2CCLK periods to be suppressed.
        let (anf_bit, dnf_bits) = match cfg.noise_filter {
            NoiseFilter::Analog => (false, 0),
            NoiseFilter::Digital(filtering_len) => {
                assert!(filtering_len <= 0b1111);
                (true, filtering_len)
            }
            NoiseFilter::Disabled => (true, 0),
        };

        regs.cr1.modify(|_, w| unsafe {
            w.anfoff().bit(anf_bit);
            w.dnf().bits(dnf_bits)
        });

        if let I2cMode::Slave = cfg.mode {
            regs.cr1.modify(|_, w| w.nostretch().bit(cfg.nostretch));
        }

        let mut result = Self { regs, cfg };

        if result.cfg.smbus {
            result.enable_smbus();
        }

        // Enable the peripheral
        result.regs.cr1.write(|w| w.pe().set_bit());

        result
    }

    /// Enable SMBus support. See L44 RM, section 37.4.11: SMBus initialization
    pub fn enable_smbus(&mut self) {
        // todo: Roll this into an init setting or I2cConfig struct etc.
        // PEC calculation is enabled by setting the PECEN bit in the I2C_CR1 register. Then the PEC
        // transfer is managed with the help of a hardware byte counter: NBYTES[7:0] in the I2C_CR2
        // register. The PECEN bit must be configured before enabling the I2C.

        // The PEC transfer is managed with the hardware byte counter, so the SBC bit must be set
        // when interfacing the SMBus in slave mode. The PEC is transferred after NBYTES-1 data
        // have been transferred when the PECBYTE bit is set and the RELOAD bit is cleared. If
        // RELOAD is set, PECBYTE has no effect.
        // Caution: Changing the PECEN configuration is not allowed when the I2C is enabled.

        let originally_enabled = self.regs.cr1.read().pe().bit_is_set();
        if originally_enabled {
            self.regs.cr1.modify(|_, w| w.pe().clear_bit());
            while self.regs.cr1.read().pe().bit_is_set() {}
        }

        self.regs.cr1.modify(|_, w| w.pecen().set_bit());

        // todo: Timeout detection?

        // todo: HWCFGR Missing from PAC
        // self.regs.hwcfgr.modify(|_, w| w.smbus().set_bit());

        if originally_enabled {
            self.regs.cr1.modify(|_, w| w.pe().set_bit());
        }
    }

    /// Read multiple words to a buffer. Can return an error due to Bus, Arbitration, or NACK.
    pub fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> {
        // Wait for any previous address sequence to end
        // automatically. This could be up to 50% of a bus
        // cycle (ie. up to 0.5/freq)
        while self.regs.cr2.read().start().bit_is_set() {}

        // Set START and prepare to receive bytes into
        // `buffer`. The START bit can be set even if the bus
        // is BUSY or I2C is in slave mode.
        self.set_cr2_read(addr, bytes.len() as u8);

        for byte in bytes {
            // Wait until we have received something
            busy_wait!(self.regs, rxne);

            *byte = self.regs.rxdr.read().rxdata().bits();
        }

        Ok(())
    }

    /// Write an array of words. Can return an error due to Bus, Arbitration, or NACK.
    pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
        // Wait for any previous address sequence to end
        // automatically. This could be up to 50% of a bus
        // cycle (ie. up to 0.5/freq)
        while self.regs.cr2.read().start().bit_is_set() {}

        self.set_cr2_write(addr, bytes.len() as u8, true);

        for byte in bytes {
            // Wait until we are allowed to send data
            // (START has been ACKed or last byte when
            // through)
            busy_wait!(self.regs, txis); // TXDR register is empty

            // Put byte on the wire
            self.regs.txdr.write(|w| unsafe { w.txdata().bits(*byte) });
        }

        Ok(())
    }

    /// Write and read an array of words. Can return an error due to Bus, Arbitration, or NACK.
    pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
        // Wait for any previous address sequence to end
        // automatically. This could be up to 50% of a bus
        // cycle (ie. up to 0.5/freq)
        while self.regs.cr2.read().start().bit_is_set() {}

        self.set_cr2_write(addr, bytes.len() as u8, false);

        for byte in bytes {
            // Wait until we are allowed to send data
            // (START has been ACKed or last byte went through)

            busy_wait!(self.regs, txis); // TXDR register is empty

            // Put byte on the wire
            self.regs.txdr.write(|w| unsafe { w.txdata().bits(*byte) });
        }

        // Wait until the write finishes before beginning to read.
        busy_wait!(self.regs, tc); // transfer is complete

        // reSTART and prepare to receive bytes into `buffer`

        self.set_cr2_read(addr, buffer.len() as u8);

        for byte in buffer {
            // Wait until we have received something
            busy_wait!(self.regs, rxne);

            *byte = self.regs.rxdr.read().rxdata().bits();
        }

        Ok(())
    }

    /// Helper function to prevent repetition between `write`, `write_read`, and `write_dma`.
    fn set_cr2_write(&mut self, addr: u8, len: u8, autoend: bool) {
        // L44 RM: "Master communication initialization (address phase)
        // In order to initiate the communication, the user must program the following parameters for
        // the addressed slave in the I2C_CR2 register:
        self.regs.cr2.write(|w| {
            unsafe {
                // Addressing mode (7-bit or 10-bit): ADD10
                w.add10().bit(self.cfg.address_bits as u8 != 0);
                // Slave address to be sent: SADD[9:0]
                // SADD0: "This bit is don’t care"
                // SADD[7:1]: "These bits should be written with the 7-bit slave address to be sent"
                w.sadd().bits(u16(addr << 1));
                // Transfer direction: RD_WRN
                w.rd_wrn().clear_bit(); // write
                                        // The number of bytes to be transferred: NBYTES[7:0]. If the number of bytes is equal to
                                        // or greater than 255 bytes, NBYTES[7:0] must initially be filled with 0xFF.
                w.nbytes().bits(len);
                w.autoend().bit(autoend); // software end mode
                                          // The user must then set the START bit in I2C_CR2 register. Changing all the above bits is
                                          // not allowed when START bit is set.
                                          // When the SMBus master wants to transmit the PEC, the PECBYTE bit must be set and the
                                          // number of bytes must be programmed in the NBYTES[7:0] field, before setting the START
                                          // bit. In this case the total number of TXIS interrupts is NBYTES-1. So if the PECBYTE bit is
                                          // set when NBYTES=0x1, the content of the I2C_PECR register is automatically transmitted.
                                          // If the SMBus master wants to send a STOP condition after the PEC, automatic end mode
                                          // must be selected (AUTOEND=1). In this case, the STOP condition automatically follows the
                                          // PEC transmission.
                w.pecbyte().bit(self.cfg.smbus);
                w.start().set_bit()
            }
        });
        // Note on start bit (RM):
        // If the I2C is already in master mode with AUTOEND = 0, setting this bit generates a
        // Repeated Start condition when RELOAD=0, after the end of the NBYTES transfer.
        // Otherwise setting this bit generates a START condition once the bus is free.
        // (This is why we don't set autoend on the write portion of a write_read.)
    }

    /// Helper function to prevent repetition between `read`, `write_read`, and `read_dma`.
    fn set_cr2_read(&mut self, addr: u8, len: u8) {
        self.regs.cr2.write(|w| {
            unsafe {
                w.add10().bit(self.cfg.address_bits as u8 != 0);
                w.sadd().bits(u16(addr << 1));
                w.rd_wrn().set_bit(); // read
                w.nbytes().bits(len);
                w.autoend().set_bit(); // automatic end mode
                                       // When the SMBus master wants to receive the PEC followed by a STOP at the end of the
                                       // transfer, automatic end mode can be selected (AUTOEND=1). The PECBYTE bit must be
                                       // set and the slave address must be programmed, before setting the START bit. In this case,
                                       // after NBYTES-1 data have been received, the next received byte is automatically checked
                                       // versus the I2C_PECR register content. A NACK response is given to the PEC byte, followed
                                       // by a STOP condition.
                w.pecbyte().bit(self.cfg.smbus);
                w.start().set_bit()
            }
        });
    }

    #[cfg(not(feature = "g0"))]
    /// Read data, using DMA. See L44 RM, 37.4.16: "Transmission using DMA"
    /// Note that the `channel` argument is only used on F3 and L4.
    /// For a single write, set `autoend` to `true`. For a write_read and other use cases,
    /// set it to `false`.
    #[cfg(not(feature = "l552"))]
    pub unsafe fn write_dma<D>(
        &mut self,
        addr: u8,
        buf: &[u8],
        autoend: bool,
        channel: DmaChannel,
        channel_cfg: ChannelCfg,
        dma: &mut Dma<D>,
    ) where
        D: Deref<Target = dma_p::RegisterBlock>,
    {
        while self.regs.cr2.read().start().bit_is_set() {}

        let (ptr, len) = (buf.as_ptr(), buf.len());

        #[cfg(any(feature = "f3", feature = "l4"))]
        let channel = R::write_chan();
        #[cfg(feature = "l4")]
        R::write_sel(dma);

        // DMA (Direct Memory Access) can be enabled for transmission by setting the TXDMAEN bit
        // in the I2C_CR1 register. Data is loaded from an SRAM area configured using the DMA
        // peripheral (see Section 11: Direct memory access controller (DMA) on page 295) to the
        // I2C_TXDR register whenever the TXIS bit is set.
        self.regs.cr1.modify(|_, w| w.txdmaen().set_bit());
        while self.regs.cr1.read().txdmaen().bit_is_clear() {}

        // Only the data are transferred with DMA.
        // • In master mode: the initialization, the slave address, direction, number of bytes and
        // START bit are programmed by software (the transmitted slave address cannot be
        // transferred with DMA). When all data are transferred using DMA, the DMA must be
        // initialized before setting the START bit. The end of transfer is managed with the
        // NBYTES counter. Refer to Master transmitter on page 1151.
        // (The steps above are handled in the write this function performs.)
        self.set_cr2_write(addr, len as u8, autoend);

        // • In slave mode:
        // – With NOSTRETCH=0, when all data are transferred using DMA, the DMA must be
        // initialized before the address match event, or in ADDR interrupt subroutine, before
        // clearing ADDR.
        // – With NOSTRETCH=1, the DMA must be initialized before the address match
        // event.

        // • For instances supporting SMBus: the PEC transfer is managed with NBYTES counter.
        // Refer to SMBus Slave transmitter on page 1165 and SMBus Master transmitter on
        // page 1169.
        // Note: If DMA is used for transmission, the TXIE bit does not need to be enabled

        #[cfg(feature = "h7")]
        let num_data = len as u32;
        #[cfg(not(feature = "h7"))]
        let num_data = len as u16;

        dma.cfg_channel(
            channel,
            &self.regs.txdr as *const _ as u32,
            ptr as u32,
            num_data,
            dma::Direction::ReadFromMem,
            dma::DataSize::S8,
            dma::DataSize::S8,
            channel_cfg,
        );
    }

    /// Read data, using DMA. See L44 RM, 37.4.16: "Reception using DMA"
    /// Note that the `channel` argument is only used on F3 and L4.
    #[cfg(not(feature = "l552"))]
    pub unsafe fn read_dma<D>(
        &mut self,
        addr: u8,
        buf: &mut [u8],
        channel: DmaChannel,
        channel_cfg: ChannelCfg,
        dma: &mut Dma<D>,
    ) where
        D: Deref<Target = dma_p::RegisterBlock>,
    {
        let (ptr, len) = (buf.as_mut_ptr(), buf.len());

        #[cfg(any(feature = "f3", feature = "l4"))]
        let channel = R::read_chan();
        #[cfg(feature = "l4")]
        R::read_sel(dma);

        // DMA (Direct Memory Access) can be enabled for reception by setting the RXDMAEN bit in
        // the I2C_CR1 register. Data is loaded from the I2C_RXDR register to an SRAM area
        // configured using the DMA peripheral (refer to Section 11: Direct memory access controller
        // (DMA) on page 295) whenever the RXNE bit is set. Only the data (including PEC) are
        // transferred with DMA.
        self.regs.cr1.modify(|_, w| w.rxdmaen().set_bit());
        while self.regs.cr1.read().rxdmaen().bit_is_clear() {}

        // • In master mode, the initialization, the slave address, direction, number of bytes and
        // START bit are programmed by software. When all data are transferred using DMA, the
        // DMA must be initialized before setting the START bit. The end of transfer is managed
        // with the NBYTES counter.
        self.set_cr2_read(addr, len as u8);

        // • In slave mode with NOSTRETCH=0, when all data are transferred using DMA, the
        // DMA must be initialized before the address match event, or in the ADDR interrupt
        // subroutine, before clearing the ADDR flag.
        // • If SMBus is supported (see Section 37.3: I2C implementation): the PEC transfer is
        // managed with the NBYTES counter. Refer to SMBus Slave receiver on page 1167 and
        // SMBus Master receiver on page 1171.
        // Note: If DMA is used for reception, the RXIE bit does not need to be enabled

        #[cfg(feature = "h7")]
        let num_data = len as u32;
        #[cfg(not(feature = "h7"))]
        let num_data = len as u16;

        dma.cfg_channel(
            channel,
            &self.regs.rxdr as *const _ as u32,
            ptr as u32,
            num_data,
            dma::Direction::ReadFromPeriph,
            dma::DataSize::S8,
            dma::DataSize::S8,
            channel_cfg,
        );
    }

    // /// Write, and read data, using DMA. This is the primary read api.
    // /// See L44 RM, 37.4.16: "Reception using DMA"
    // /// Note that the `channel` argument is only used on F3 and L4.
    // // todo: WIP. Is this the way to do it?
    // #[cfg(not(feature = "l552"))]
    // pub unsafe fn write_read_dma<D>(
    //     &mut self,
    //     addr: u8,
    //     buf_write: &[u8],
    //     buf_read: &mut [u8],
    //     channel_write: DmaChannel,
    //     channel_read: DmaChannel,
    //     channel_cfg_write: ChannelCfg,
    //     channel_cfg_read: ChannelCfg,
    //     dma: &mut Dma<D>,
    // ) where
    //     D: Deref<Target = dma_p::RegisterBlock>,
    // {
    //     // todo: This might not work as you expect. Maybe remove it?

    //     while self.regs.cr2.read().start().bit_is_set() {}

    //     let (ptr_write, len_write) = (buf_write.as_ptr(), buf_write.len());
    //     let (ptr_read, len_read) = (buf_read.as_mut_ptr(), buf_read.len());

    //     self.regs.cr1.modify(|_, w| w.txdmaen().set_bit());
    //     while self.regs.cr1.read().txdmaen().bit_is_clear() {}
    //     self.regs.cr1.modify(|_, w| w.rxdmaen().set_bit());
    //     while self.regs.cr1.read().rxdmaen().bit_is_clear() {}
       
    //     let periph_addr_write = &self.regs.txdr as *const _ as u32;
    //     let periph_addr_read = &self.regs.rxdr as *const _ as u32;

    //     #[cfg(feature = "h7")]
    //     let num_data_write = len_write as u32;
    //     #[cfg(not(feature = "h7"))]
    //     let num_data_write = len_write as u16;

    //     #[cfg(feature = "h7")]
    //     let num_data_read = len_read as u32;
    //     #[cfg(not(feature = "h7"))]
    //     let num_data_read = len_read as u16;

    //     #[cfg(any(feature = "f3", feature = "l4"))]
    //     let channel_write = R::write_chan();
    //     #[cfg(feature = "l4")]
    //     R::write_sel(dma);

    //     self.set_cr2_write(addr, len_write as u8, false);

    //     dma.cfg_channel(
    //         channel_write,
    //         periph_addr_write,
    //         ptr_write as u32,
    //         num_data_write,
    //         dma::Direction::ReadFromMem,
    //         dma::DataSize::S8,
    //         dma::DataSize::S8,
    //         channel_cfg_write,
    //     );

    //     #[cfg(any(feature = "f3", feature = "l4"))]
    //     let channel_read = R::read_chan();
    //     #[cfg(feature = "l4")]
    //     R::read_sel(dma);

    //     self.set_cr2_read(addr, len_read as u8);

    //     dma.cfg_channel(
    //         channel_read,
    //         periph_addr_read,
    //         ptr_read as u32,
    //         num_data_read,
    //         dma::Direction::ReadFromPeriph,
    //         dma::DataSize::S8,
    //         dma::DataSize::S8,
    //         channel_cfg_read,
    //     );
    // }
}

#[cfg(feature = "embedded-hal")]
// #[cfg_attr(docsrs, doc(cfg(feature = "embedded-hal")))]
impl<R> Write for I2c<R>
where
    R: Deref<Target = pac::i2c1::RegisterBlock> + RccPeriph,
{
    type Error = Error;

    fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
        I2c::write(self, addr, bytes)
    }
}

#[cfg(feature = "embedded-hal")]
// #[cfg_attr(docsrs, doc(cfg(feature = "embedded-hal")))]
impl<R> Read for I2c<R>
where
    R: Deref<Target = pac::i2c1::RegisterBlock> + RccPeriph,
{
    type Error = Error;

    fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> {
        I2c::read(self, addr, bytes)
    }
}

#[cfg(feature = "embedded-hal")]
// #[cfg_attr(docsrs, doc(cfg(feature = "embedded-hal")))]
impl<R> WriteRead for I2c<R>
where
    R: Deref<Target = pac::i2c1::RegisterBlock> + RccPeriph,
{
    type Error = Error;

    fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
        I2c::write_read(self, addr, bytes, buffer)
    }
}