zynq7000_hal/
i2c.rs

1//! # I2C module
2use arbitrary_int::{u2, u3, u6};
3use embedded_hal::i2c::NoAcknowledgeSource;
4use zynq7000::{
5    i2c::{Control, I2C_0_BASE_ADDR, I2C_1_BASE_ADDR, InterruptStatus, MmioI2c, TransferSize},
6    slcr::reset::DualClockReset,
7};
8
9#[cfg(not(feature = "7z010-7z007s-clg225"))]
10use crate::gpio::mio::{
11    Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
12    Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
13};
14use crate::{
15    enable_amba_peripheral_clock,
16    gpio::{
17        IoPeriphPin,
18        mio::{
19            Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33,
20            Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, MioPin,
21            MuxConfig, Pin,
22        },
23    },
24    slcr::Slcr,
25    time::Hertz,
26};
27
28pub const I2C_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b010));
29pub const FIFO_DEPTH: usize = 16;
30/// Maximum read size in one read operation.
31pub const MAX_READ_SIZE: usize = 255;
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum I2cId {
35    I2c0 = 0,
36    I2c1 = 1,
37}
38
39pub trait PsI2c {
40    fn reg_block(&self) -> MmioI2c<'static>;
41    fn id(&self) -> Option<I2cId>;
42}
43
44impl PsI2c for MmioI2c<'static> {
45    #[inline]
46    fn reg_block(&self) -> MmioI2c<'static> {
47        unsafe { self.clone() }
48    }
49
50    #[inline]
51    fn id(&self) -> Option<I2cId> {
52        let base_addr = unsafe { self.ptr() } as usize;
53        if base_addr == I2C_0_BASE_ADDR {
54            return Some(I2cId::I2c0);
55        } else if base_addr == I2C_1_BASE_ADDR {
56            return Some(I2cId::I2c1);
57        }
58        None
59    }
60}
61
62pub trait SdaPin: MioPin {
63    const ID: I2cId;
64}
65
66pub trait SckPin: MioPin {
67    const ID: I2cId;
68}
69
70pub trait I2cPins {}
71
72macro_rules! i2c_pin_impls {
73    ($Id: path, $SckMio:ident, $SdaMio:ident) => {
74        impl SckPin for Pin<$SckMio> {
75            const ID: I2cId = $Id;
76        }
77
78        impl SdaPin for Pin<$SdaMio> {
79            const ID: I2cId = $Id;
80        }
81
82        impl I2cPins for (Pin<$SckMio>, Pin<$SdaMio>) {}
83    };
84}
85
86/*
87macro_rules! into_i2c {
88    ($($Mio:ident),+) => {
89        $(
90            impl <M: PinMode> MioPin<$Mio, M> {
91                /// Convert the pin into I2C pins by configuring the pin routing via the
92                /// MIO multiplexer bits. Also enables pull-ups for the pins.
93                pub fn into_i2c(self) -> MioPin<$Mio, IoPeriph> {
94                    // Enable pull-ups for the I2C pins.
95                    self.into_io_periph(I2C_MUX_CONF, Some(true))
96                }
97            }
98        )+
99    };
100}
101
102into_i2c!(
103    Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28,
104    Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53
105);
106#[cfg(not(feature = "7z010-7z007s-clg225"))]
107into_i2c!(
108    Mio18, Mio19, Mio22, Mio23, Mio26, Mio27, Mio42, Mio43, Mio46, Mio47, Mio50, Mio51, Mio16,
109    Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45
110);
111*/
112
113i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11);
114i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15);
115#[cfg(not(feature = "7z010-7z007s-clg225"))]
116i2c_pin_impls!(I2cId::I2c0, Mio18, Mio19);
117#[cfg(not(feature = "7z010-7z007s-clg225"))]
118i2c_pin_impls!(I2cId::I2c0, Mio22, Mio23);
119#[cfg(not(feature = "7z010-7z007s-clg225"))]
120i2c_pin_impls!(I2cId::I2c0, Mio26, Mio27);
121i2c_pin_impls!(I2cId::I2c0, Mio30, Mio31);
122i2c_pin_impls!(I2cId::I2c0, Mio34, Mio35);
123i2c_pin_impls!(I2cId::I2c0, Mio38, Mio39);
124#[cfg(not(feature = "7z010-7z007s-clg225"))]
125i2c_pin_impls!(I2cId::I2c0, Mio42, Mio43);
126#[cfg(not(feature = "7z010-7z007s-clg225"))]
127i2c_pin_impls!(I2cId::I2c0, Mio46, Mio47);
128#[cfg(not(feature = "7z010-7z007s-clg225"))]
129i2c_pin_impls!(I2cId::I2c0, Mio50, Mio51);
130
131i2c_pin_impls!(I2cId::I2c1, Mio12, Mio13);
132#[cfg(not(feature = "7z010-7z007s-clg225"))]
133i2c_pin_impls!(I2cId::I2c1, Mio16, Mio17);
134#[cfg(not(feature = "7z010-7z007s-clg225"))]
135i2c_pin_impls!(I2cId::I2c1, Mio20, Mio21);
136#[cfg(not(feature = "7z010-7z007s-clg225"))]
137i2c_pin_impls!(I2cId::I2c1, Mio24, Mio25);
138i2c_pin_impls!(I2cId::I2c1, Mio28, Mio29);
139i2c_pin_impls!(I2cId::I2c1, Mio32, Mio33);
140i2c_pin_impls!(I2cId::I2c1, Mio36, Mio37);
141#[cfg(not(feature = "7z010-7z007s-clg225"))]
142i2c_pin_impls!(I2cId::I2c1, Mio40, Mio41);
143#[cfg(not(feature = "7z010-7z007s-clg225"))]
144i2c_pin_impls!(I2cId::I2c1, Mio44, Mio45);
145i2c_pin_impls!(I2cId::I2c1, Mio48, Mio49);
146i2c_pin_impls!(I2cId::I2c1, Mio52, Mio53);
147
148#[derive(Debug, Clone, Copy)]
149pub enum I2cSpeed {
150    Normal100kHz,
151    HighSpeed400KHz,
152}
153
154impl I2cSpeed {
155    pub fn frequency_full_number(&self) -> Hertz {
156        Hertz::from_raw(match self {
157            I2cSpeed::Normal100kHz => 100_000,
158            I2cSpeed::HighSpeed400KHz => 400_000,
159        })
160    }
161
162    /// From Xilinx embeddedsw
163    /// If frequency 400KHz is selected, 384.6KHz should be set.
164    /// If frequency 100KHz is selected, 90KHz should be set.
165    /// This is due to a hardware limitation.
166    pub fn frequency_for_calculation(&self) -> Hertz {
167        Hertz::from_raw(match self {
168            I2cSpeed::Normal100kHz => 90_000,
169            I2cSpeed::HighSpeed400KHz => 384_600,
170        })
171    }
172}
173
174#[derive(Debug, thiserror::Error)]
175#[error("I2C speed not attainable")]
176pub struct I2cSpeedNotAttainable;
177
178#[derive(Debug, thiserror::Error)]
179pub enum I2cTxError {
180    #[error("arbitration lost")]
181    ArbitrationLoss,
182    #[error("transfer not acknowledged: {0}")]
183    Nack(NoAcknowledgeSource),
184    #[error("TX overflow")]
185    TxOverflow,
186    #[error("timeout of transfer")]
187    Timeout,
188}
189
190#[derive(Debug, thiserror::Error)]
191pub enum I2cRxError {
192    #[error("arbitration lost")]
193    ArbitrationLoss,
194    #[error("transfer not acknowledged")]
195    Nack(NoAcknowledgeSource),
196    #[error("RX underflow")]
197    RxUnderflow,
198    #[error("RX overflow")]
199    RxOverflow,
200    #[error("timeout of transfer")]
201    Timeout,
202    #[error("read data exceeds maximum allowed 255 bytes per transfer")]
203    ReadDataLenTooLarge,
204}
205
206#[derive(Debug, thiserror::Error)]
207pub enum I2cError {
208    #[error("arbitration lost")]
209    ArbitrationLoss,
210    #[error("transfer not acknowledged: {0}")]
211    Nack(NoAcknowledgeSource),
212    #[error("TX overflow")]
213    TxOverflow,
214    #[error("RX underflow")]
215    RxUnderflow,
216    #[error("RX overflow")]
217    RxOverflow,
218    #[error("timeout of transfer")]
219    Timeout,
220    #[error("read data exceeds maximum allowed 255 bytes per transfer")]
221    ReadDataLenTooLarge,
222}
223
224impl From<I2cRxError> for I2cError {
225    fn from(err: I2cRxError) -> Self {
226        match err {
227            I2cRxError::ArbitrationLoss => I2cError::ArbitrationLoss,
228            I2cRxError::Nack(nack) => I2cError::Nack(nack),
229            I2cRxError::RxUnderflow => I2cError::RxUnderflow,
230            I2cRxError::RxOverflow => I2cError::RxOverflow,
231            I2cRxError::Timeout => I2cError::Timeout,
232            I2cRxError::ReadDataLenTooLarge => I2cError::ReadDataLenTooLarge,
233        }
234    }
235}
236
237impl From<I2cTxError> for I2cError {
238    fn from(err: I2cTxError) -> Self {
239        match err {
240            I2cTxError::ArbitrationLoss => I2cError::ArbitrationLoss,
241            I2cTxError::Nack(nack) => I2cError::Nack(nack),
242            I2cTxError::TxOverflow => I2cError::TxOverflow,
243            I2cTxError::Timeout => I2cError::Timeout,
244        }
245    }
246}
247
248#[inline]
249pub fn calculate_i2c_speed(cpu_1x_clk: Hertz, clk_config: ClockConfig) -> Hertz {
250    cpu_1x_clk / (22 * (clk_config.div_a as u32 + 1) * (clk_config.div_b as u32 + 1))
251}
252
253pub fn calculate_divisors(
254    cpu_1x_clk: Hertz,
255    speed: I2cSpeed,
256) -> Result<ClockConfig, I2cSpeedNotAttainable> {
257    let target_speed = speed.frequency_for_calculation();
258    if cpu_1x_clk > 22 * 64 * 4 * target_speed {
259        return Err(I2cSpeedNotAttainable);
260    }
261    let mut smallest_deviation = u32::MAX;
262    let mut best_div_a = 1;
263    let mut best_div_b = 1;
264    for divisor_a in 1..=4 {
265        for divisor_b in 1..=64 {
266            let i2c_clock = cpu_1x_clk / (22 * divisor_a * divisor_b);
267            let deviation = (target_speed.raw() as i32 - i2c_clock.raw() as i32).unsigned_abs();
268            if deviation < smallest_deviation {
269                smallest_deviation = deviation;
270                best_div_a = divisor_a;
271                best_div_b = divisor_b;
272            }
273        }
274    }
275    Ok(ClockConfig::new(best_div_a as u8 - 1, best_div_b as u8 - 1))
276}
277
278#[derive(Debug, PartialEq, Eq, Clone, Copy)]
279pub struct ClockConfig {
280    div_a: u8,
281    div_b: u8,
282}
283
284impl ClockConfig {
285    pub fn new(div_a: u8, div_b: u8) -> Self {
286        Self { div_a, div_b }
287    }
288
289    pub fn div_a(&self) -> u8 {
290        self.div_a
291    }
292
293    pub fn div_b(&self) -> u8 {
294        self.div_b
295    }
296}
297
298#[derive(Debug, thiserror::Error)]
299#[error("invalid I2C ID")]
300pub struct InvalidPsI2cError;
301
302#[derive(Debug, thiserror::Error)]
303pub enum I2cConstructionError {
304    #[error("invalid I2C ID {0}")]
305    InvalidPsI2c(#[from] InvalidPsI2cError),
306    #[error("pin invalid for I2C ID")]
307    PinInvalidForI2cId,
308    #[error("invalid pin configuration for I2C")]
309    InvalidPinConf,
310}
311pub struct I2c {
312    regs: MmioI2c<'static>,
313}
314
315impl I2c {
316    pub fn new_with_mio<Sck: SckPin, Sda: SdaPin>(
317        i2c: impl PsI2c,
318        clk_cfg: ClockConfig,
319        i2c_pins: (Sck, Sda),
320    ) -> Result<Self, I2cConstructionError> {
321        if i2c.id().is_none() {
322            return Err(InvalidPsI2cError.into());
323        }
324        if Sck::ID != Sda::ID {
325            return Err(I2cConstructionError::PinInvalidForI2cId);
326        }
327        IoPeriphPin::new(i2c_pins.0, I2C_MUX_CONF, Some(true));
328        IoPeriphPin::new(i2c_pins.1, I2C_MUX_CONF, Some(true));
329        Ok(Self::new_generic(
330            i2c.id().unwrap(),
331            i2c.reg_block(),
332            clk_cfg,
333        ))
334    }
335
336    pub fn new_with_emio(i2c: impl PsI2c, clk_cfg: ClockConfig) -> Result<Self, InvalidPsI2cError> {
337        if i2c.id().is_none() {
338            return Err(InvalidPsI2cError);
339        }
340        Ok(Self::new_generic(
341            i2c.id().unwrap(),
342            i2c.reg_block(),
343            clk_cfg,
344        ))
345    }
346
347    pub fn new_generic(id: I2cId, mut regs: MmioI2c<'static>, clk_cfg: ClockConfig) -> Self {
348        let periph_sel = match id {
349            I2cId::I2c0 => crate::PeriphSelect::I2c0,
350            I2cId::I2c1 => crate::PeriphSelect::I2c1,
351        };
352        enable_amba_peripheral_clock(periph_sel);
353        //reset(id);
354        regs.write_cr(
355            Control::builder()
356                .with_div_a(u2::new(clk_cfg.div_a()))
357                .with_div_b(u6::new(clk_cfg.div_b()))
358                .with_clear_fifo(true)
359                .with_slv_mon(false)
360                .with_hold_bus(false)
361                .with_acken(false)
362                .with_addressing(true)
363                .with_mode(zynq7000::i2c::Mode::Master)
364                .with_dir(zynq7000::i2c::Direction::Transmitter)
365                .build(),
366        );
367        Self { regs }
368    }
369
370    /// Start the transfer by writing the I2C address.
371    #[inline]
372    fn start_transfer(&mut self, address: u8) {
373        self.regs
374            .write_addr(zynq7000::i2c::Address::new_with_raw_value(address as u32));
375    }
376
377    #[inline]
378    pub fn set_hold_bit(&mut self) {
379        self.regs.modify_cr(|mut cr| {
380            cr.set_hold_bus(true);
381            cr
382        });
383    }
384
385    #[inline]
386    pub fn clear_hold_bit(&mut self) {
387        self.regs.modify_cr(|mut cr| {
388            cr.set_hold_bus(false);
389            cr
390        });
391    }
392
393    pub fn write_transfer_blocking(
394        &mut self,
395        addr: u8,
396        data: &[u8],
397        generate_stop: bool,
398    ) -> Result<(), I2cTxError> {
399        self.regs.modify_cr(|mut cr| {
400            cr.set_acken(true);
401            cr.set_mode(zynq7000::i2c::Mode::Master);
402            cr.set_clear_fifo(true);
403            cr.set_dir(zynq7000::i2c::Direction::Transmitter);
404            if !generate_stop {
405                cr.set_hold_bus(true);
406            }
407            cr
408        });
409        let mut first_write_cycle = true;
410        let mut addr_set = false;
411        let mut written = 0;
412        // Clear the interrupt status register before using it to monitor the transfer.
413        self.regs.modify_isr(|isr| isr);
414        loop {
415            let bytes_to_write = core::cmp::min(
416                FIFO_DEPTH - self.regs.read_transfer_size().size() as usize,
417                data.len() - written,
418            );
419            (0..bytes_to_write).for_each(|_| {
420                self.regs
421                    .write_data(zynq7000::i2c::Fifo::new_with_raw_value(
422                        data[written] as u32,
423                    ));
424                written += 1;
425            });
426            if !addr_set {
427                self.start_transfer(addr);
428                addr_set = true;
429            }
430            let mut status = self.regs.read_sr();
431            // While the hardware is busy sending out data, we poll for errors.
432            while status.tx_busy() {
433                let isr = self.regs.read_isr();
434                self.check_and_handle_tx_errors(isr, first_write_cycle, bytes_to_write)?;
435                // Re-read for next check.
436                status = self.regs.read_sr();
437            }
438            first_write_cycle = false;
439            // Just need to poll to completion now.
440            if written == data.len() {
441                break;
442            }
443        }
444        // Poll to completion.
445        while !self.regs.read_isr().complete() {
446            let isr = self.regs.read_isr();
447            self.check_and_handle_tx_errors(isr, first_write_cycle, data.len())?;
448        }
449        if generate_stop {
450            self.clear_hold_bit();
451        }
452        Ok(())
453    }
454
455    fn check_and_handle_tx_errors(
456        &mut self,
457        isr: InterruptStatus,
458        first_write_cycle: bool,
459        first_chunk_len: usize,
460    ) -> Result<(), I2cTxError> {
461        if isr.tx_overflow() {
462            self.clean_up_after_transfer_or_on_error();
463            return Err(I2cTxError::TxOverflow);
464        }
465        if isr.arbitration_lost() {
466            self.clean_up_after_transfer_or_on_error();
467            return Err(I2cTxError::ArbitrationLoss);
468        }
469        if isr.nack() {
470            self.clean_up_after_transfer_or_on_error();
471            // I have no tested this yet, but if no data was sent yet, this is probably
472            // an address NACK.
473            if first_write_cycle
474                && self.regs.read_transfer_size().size() as usize + 1 == first_chunk_len
475            {
476                return Err(I2cTxError::Nack(NoAcknowledgeSource::Address));
477            } else {
478                return Err(I2cTxError::Nack(NoAcknowledgeSource::Data));
479            }
480        }
481        if isr.timeout() {
482            // Timeout / Stall condition.
483            self.clean_up_after_transfer_or_on_error();
484            return Err(I2cTxError::Timeout);
485        }
486        Ok(())
487    }
488
489    pub fn clean_up_after_transfer_or_on_error(&mut self) {
490        self.regs.modify_cr(|mut cr| {
491            cr.set_acken(false);
492            cr.set_clear_fifo(true);
493            cr
494        });
495    }
496
497    pub fn read_transfer_blocking(&mut self, addr: u8, data: &mut [u8]) -> Result<(), I2cRxError> {
498        self.regs.modify_cr(|mut cr| {
499            cr.set_acken(true);
500            cr.set_mode(zynq7000::i2c::Mode::Master);
501            cr.set_clear_fifo(true);
502            cr.set_dir(zynq7000::i2c::Direction::Receiver);
503            if data.len() > FIFO_DEPTH {
504                cr.set_hold_bus(true);
505            }
506            cr
507        });
508        let mut read = 0;
509        if data.len() > MAX_READ_SIZE {
510            return Err(I2cRxError::ReadDataLenTooLarge);
511        }
512        // Clear the interrupt status register before using it to monitor the transfer.
513        self.regs.modify_isr(|isr| isr);
514        self.regs
515            .write_transfer_size(TransferSize::new_with_raw_value(data.len() as u32));
516        self.start_transfer(addr);
517        loop {
518            let mut status = self.regs.read_sr();
519            loop {
520                let isr = self.regs.read_isr();
521                self.check_and_handle_rx_errors(read, isr)?;
522                if status.rx_valid() {
523                    break;
524                }
525                // Re-read for next check.
526                status = self.regs.read_sr();
527            }
528            // Data to be read.
529            while self.regs.read_sr().rx_valid() {
530                data[read] = self.regs.read_data().data();
531                read += 1;
532            }
533            // The outstading read size is smaller than the FIFO. Clear the HOLD register as
534            // specified in TRM p.649 polled read step 6.
535            if self.regs.read_transfer_size().size() as usize <= FIFO_DEPTH {
536                self.clear_hold_bit();
537            }
538            // Read everything, just need to poll to completion now.
539            if read == data.len() {
540                break;
541            }
542        }
543
544        // Poll to completion.
545        while !self.regs.read_isr().complete() {
546            let isr = self.regs.read_isr();
547            self.check_and_handle_rx_errors(read, isr)?
548        }
549        self.clear_hold_bit();
550        self.clean_up_after_transfer_or_on_error();
551        Ok(())
552    }
553
554    fn check_and_handle_rx_errors(
555        &mut self,
556        read_count: usize,
557        isr: InterruptStatus,
558    ) -> Result<(), I2cRxError> {
559        if isr.rx_overflow() {
560            self.clean_up_after_transfer_or_on_error();
561            return Err(I2cRxError::RxOverflow);
562        }
563        if isr.rx_underflow() {
564            self.clean_up_after_transfer_or_on_error();
565            return Err(I2cRxError::RxUnderflow);
566        }
567        if isr.nack() {
568            self.clean_up_after_transfer_or_on_error();
569            // I have no tested this yet, but if no data was sent yet, this is probably
570            // an address NACK.
571            if read_count == 0 {
572                return Err(I2cRxError::Nack(NoAcknowledgeSource::Address));
573            } else {
574                return Err(I2cRxError::Nack(NoAcknowledgeSource::Data));
575            }
576        }
577        if isr.timeout() {
578            // Timeout / Stall condition.
579            self.clean_up_after_transfer_or_on_error();
580            return Err(I2cRxError::Timeout);
581        }
582        Ok(())
583    }
584}
585
586impl embedded_hal::i2c::ErrorType for I2c {
587    type Error = I2cError;
588}
589
590impl embedded_hal::i2c::Error for I2cError {
591    fn kind(&self) -> embedded_hal::i2c::ErrorKind {
592        match self {
593            I2cError::ArbitrationLoss => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
594            I2cError::Nack(nack_kind) => embedded_hal::i2c::ErrorKind::NoAcknowledge(*nack_kind),
595            I2cError::RxOverflow => embedded_hal::i2c::ErrorKind::Overrun,
596            I2cError::TxOverflow => embedded_hal::i2c::ErrorKind::Other,
597            I2cError::RxUnderflow => embedded_hal::i2c::ErrorKind::Other,
598            I2cError::Timeout | I2cError::ReadDataLenTooLarge => {
599                embedded_hal::i2c::ErrorKind::Other
600            }
601        }
602    }
603}
604
605impl embedded_hal::i2c::I2c for I2c {
606    fn transaction(
607        &mut self,
608        address: u8,
609        operations: &mut [embedded_hal::i2c::Operation<'_>],
610    ) -> Result<(), Self::Error> {
611        for op in operations {
612            match op {
613                embedded_hal::i2c::Operation::Read(items) => {
614                    self.read_transfer_blocking(address, items)?
615                }
616                embedded_hal::i2c::Operation::Write(items) => {
617                    self.write_transfer_blocking(address, items, true)?
618                }
619            }
620        }
621        Ok(())
622    }
623
624    fn write_read(
625        &mut self,
626        address: u8,
627        write: &[u8],
628        read: &mut [u8],
629    ) -> Result<(), Self::Error> {
630        // I have never tested this, so I am not sure whether the master still generates a stop
631        // condition somehow.. which might break the trait contract.
632        self.write_transfer_blocking(address, write, false)?;
633        Ok(self.read_transfer_blocking(address, read)?)
634    }
635}
636
637/// Reset the SPI peripheral using the SLCR reset register for SPI.
638///
639/// Please note that this function will interfere with an already configured
640/// SPI instance.
641#[inline]
642pub fn reset(id: I2cId) {
643    let assert_reset = match id {
644        I2cId::I2c0 => DualClockReset::builder()
645            .with_periph1_cpu1x_rst(false)
646            .with_periph0_cpu1x_rst(true)
647            .build(),
648        I2cId::I2c1 => DualClockReset::builder()
649            .with_periph1_cpu1x_rst(true)
650            .with_periph0_cpu1x_rst(false)
651            .build(),
652    };
653    unsafe {
654        Slcr::with(|regs| {
655            regs.reset_ctrl().write_i2c(assert_reset);
656            // Keep it in reset for some cycles.. The TMR just mentions some small delay,
657            // no idea what is meant with that.
658            for _ in 0..3 {
659                cortex_ar::asm::nop();
660            }
661            regs.reset_ctrl().write_i2c(DualClockReset::DEFAULT);
662        });
663    }
664}
665
666#[cfg(test)]
667mod tests {
668    extern crate std;
669    use super::*;
670    use fugit::RateExtU32;
671    use std::println;
672
673    #[test]
674    fn example_test() {
675        let clk_cfg = calculate_divisors(111.MHz(), I2cSpeed::Normal100kHz).unwrap();
676        assert_eq!(clk_cfg.div_a(), 0);
677        assert_eq!(clk_cfg.div_b(), 55);
678        let speed = calculate_i2c_speed(111.MHz(), clk_cfg);
679        assert!(speed.raw() < 100_000);
680        assert!(speed.raw() > 85_000);
681    }
682
683    #[test]
684    fn example_test_2() {
685        let clk_cfg = calculate_divisors(111.MHz(), I2cSpeed::HighSpeed400KHz).unwrap();
686        assert_eq!(clk_cfg.div_a(), 0);
687        assert_eq!(clk_cfg.div_b(), 12);
688        let speed = calculate_i2c_speed(111.MHz(), clk_cfg);
689        assert!(speed.raw() < 400_000);
690        assert!(speed.raw() > 360_000);
691    }
692
693    #[test]
694    fn example_test_3() {
695        let clk_cfg = calculate_divisors(133.MHz(), I2cSpeed::Normal100kHz).unwrap();
696        assert_eq!(clk_cfg.div_a(), 1);
697        assert_eq!(clk_cfg.div_b(), 33);
698        let speed = calculate_i2c_speed(133.MHz(), clk_cfg);
699        assert!(speed.raw() < 100_000);
700        assert!(speed.raw() > 85_000);
701    }
702
703    #[test]
704    fn example_test_4() {
705        let clk_cfg = calculate_divisors(133.MHz(), I2cSpeed::HighSpeed400KHz).unwrap();
706        assert_eq!(clk_cfg.div_a(), 0);
707        assert_eq!(clk_cfg.div_b(), 15);
708        let speed = calculate_i2c_speed(133.MHz(), clk_cfg);
709        assert!(speed.raw() < 400_000);
710        assert!(speed.raw() > 360_000);
711    }
712}