vorago_shared_hal/i2c/
mod.rs

1pub mod regs;
2
3use crate::{
4    PeripheralSelect, enable_peripheral_clock, sealed::Sealed,
5    sysconfig::reset_peripheral_for_cycles, time::Hertz,
6};
7use arbitrary_int::{u4, u10, u11, u20};
8use core::marker::PhantomData;
9use embedded_hal::i2c::{self, Operation, SevenBitAddress, TenBitAddress};
10use regs::ClockTimeoutLimit;
11pub use regs::{Bank, I2cSpeed, RxFifoFullMode, TxFifoEmptyMode};
12
13#[cfg(feature = "vor1x")]
14use va108xx as pac;
15#[cfg(feature = "vor4x")]
16use va416xx as pac;
17
18//==================================================================================================
19// Defintions
20//==================================================================================================
21
22const CLK_100K: Hertz = Hertz::from_raw(100_000);
23const CLK_400K: Hertz = Hertz::from_raw(400_000);
24const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000);
25
26#[derive(Debug, PartialEq, Eq, thiserror::Error)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28#[error("clock too slow for fast I2C mode")]
29pub struct ClockTooSlowForFastI2cError;
30
31#[derive(Debug, PartialEq, Eq, thiserror::Error)]
32#[error("invalid timing parameters")]
33pub struct InvalidTimingParamsError;
34
35#[derive(Debug, PartialEq, Eq, thiserror::Error)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub enum Error {
38    #[error("arbitration lost")]
39    ArbitrationLost,
40    #[error("nack address")]
41    NackAddr,
42    /// Data not acknowledged in write operation
43    #[error("data not acknowledged in write operation")]
44    NackData,
45    /// Not enough data received in read operation
46    #[error("insufficient data received")]
47    InsufficientDataReceived,
48    /// Number of bytes in transfer too large (larger than 0x7fe)
49    #[error("data too large (larger than 0x7fe)")]
50    DataTooLarge,
51    #[error("clock timeout, SCL was low for {0} clock cycles")]
52    ClockTimeout(u20),
53}
54
55#[derive(Debug, PartialEq, Eq, thiserror::Error)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57pub enum InitError {
58    /// Wrong address used in constructor
59    #[error("wrong address mode")]
60    WrongAddrMode,
61    /// APB1 clock is too slow for fast I2C mode.
62    #[error("clock too slow for fast I2C mode: {0}")]
63    ClockTooSlow(#[from] ClockTooSlowForFastI2cError),
64}
65
66impl embedded_hal::i2c::Error for Error {
67    fn kind(&self) -> embedded_hal::i2c::ErrorKind {
68        match self {
69            Error::ArbitrationLost => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
70            Error::NackAddr => {
71                embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Address)
72            }
73            Error::NackData => {
74                embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data)
75            }
76            Error::DataTooLarge | Error::InsufficientDataReceived | Error::ClockTimeout(_) => {
77                embedded_hal::i2c::ErrorKind::Other
78            }
79        }
80    }
81}
82
83#[derive(Debug, PartialEq, Copy, Clone)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub enum I2cCommand {
86    Start = 0b01,
87    Stop = 0b10,
88    StartWithStop = 0b11,
89    Cancel = 0b100,
90}
91
92#[derive(Debug, PartialEq, Eq, Copy, Clone)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub enum I2cAddress {
95    Regular(u8),
96    TenBit(u16),
97}
98
99impl I2cAddress {
100    pub fn ten_bit_addr(&self) -> bool {
101        match self {
102            I2cAddress::Regular(_) => false,
103            I2cAddress::TenBit(_) => true,
104        }
105    }
106    pub fn raw(&self) -> u16 {
107        match self {
108            I2cAddress::Regular(addr) => *addr as u16,
109            I2cAddress::TenBit(addr) => *addr,
110        }
111    }
112}
113
114/// Common trait implemented by all PAC peripheral access structures. The register block
115/// format is the same for all SPI blocks.
116pub trait I2cInstance: Sealed {
117    const ID: Bank;
118    const PERIPH_SEL: PeripheralSelect;
119}
120
121#[cfg(feature = "vor1x")]
122pub type I2c0 = pac::I2ca;
123#[cfg(feature = "vor4x")]
124pub type I2c0 = pac::I2c0;
125
126impl I2cInstance for I2c0 {
127    const ID: Bank = Bank::I2c0;
128    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0;
129}
130impl Sealed for I2c0 {}
131
132#[cfg(feature = "vor1x")]
133pub type I2c1 = pac::I2cb;
134#[cfg(feature = "vor4x")]
135pub type I2c1 = pac::I2c1;
136
137impl I2cInstance for I2c1 {
138    const ID: Bank = Bank::I2c1;
139    const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1;
140}
141impl Sealed for I2c1 {}
142
143//==================================================================================================
144// Config
145//==================================================================================================
146
147fn calc_clk_div_generic(
148    ref_clk: Hertz,
149    speed_mode: I2cSpeed,
150) -> Result<u8, ClockTooSlowForFastI2cError> {
151    if speed_mode == I2cSpeed::Regular100khz {
152        Ok(((ref_clk.raw() / CLK_100K.raw() / 20) - 1) as u8)
153    } else {
154        if ref_clk.raw() < MIN_CLK_400K.raw() {
155            return Err(ClockTooSlowForFastI2cError);
156        }
157        Ok(((ref_clk.raw() / CLK_400K.raw() / 25) - 1) as u8)
158    }
159}
160
161#[cfg(feature = "vor4x")]
162fn calc_clk_div(
163    clks: &crate::clock::Clocks,
164    speed_mode: I2cSpeed,
165) -> Result<u8, ClockTooSlowForFastI2cError> {
166    calc_clk_div_generic(clks.apb1(), speed_mode)
167}
168
169#[cfg(feature = "vor1x")]
170fn calc_clk_div(sys_clk: Hertz, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2cError> {
171    calc_clk_div_generic(sys_clk, speed_mode)
172}
173
174#[derive(Debug, PartialEq, Eq, Clone, Copy)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
176pub struct TimingConfig {
177    pub t_rise: u4,
178    pub t_fall: u4,
179    pub t_high: u4,
180    pub t_low: u4,
181    pub tsu_stop: u4,
182    pub tsu_start: u4,
183    pub thd_start: u4,
184    pub t_buf: u4,
185}
186
187/// Default configuration are the register reset value which are used by default.
188impl Default for TimingConfig {
189    fn default() -> Self {
190        TimingConfig {
191            t_rise: u4::new(0b0010),
192            t_fall: u4::new(0b0001),
193            t_high: u4::new(0b1000),
194            t_low: u4::new(0b1001),
195            tsu_stop: u4::new(0b1000),
196            tsu_start: u4::new(0b1010),
197            thd_start: u4::new(0b1000),
198            t_buf: u4::new(0b1010),
199        }
200    }
201}
202
203#[cfg_attr(feature = "defmt", derive(defmt::Format))]
204pub struct MasterConfig {
205    pub tx_empty_mode: TxFifoEmptyMode,
206    pub rx_full_mode: RxFifoFullMode,
207    /// Enable the analog delay glitch filter
208    pub alg_filt: bool,
209    /// Enable the digital glitch filter
210    pub dlg_filt: bool,
211    pub timing_config: Option<TimingConfig>,
212    /// See [I2cMaster::set_clock_low_timeout] documentation.
213    pub timeout: Option<u20>,
214    // Loopback mode
215    // lbm: bool,
216}
217
218impl Default for MasterConfig {
219    fn default() -> Self {
220        MasterConfig {
221            tx_empty_mode: TxFifoEmptyMode::Stall,
222            rx_full_mode: RxFifoFullMode::Stall,
223            alg_filt: false,
224            dlg_filt: false,
225            timeout: None,
226            timing_config: None,
227        }
228    }
229}
230
231impl Sealed for MasterConfig {}
232
233#[derive(Debug, PartialEq, Eq)]
234enum WriteCompletionCondition {
235    Idle,
236    Waiting,
237}
238
239struct TimeoutGuard {
240    clk_timeout_enabled: bool,
241    regs: regs::MmioI2c<'static>,
242}
243
244impl TimeoutGuard {
245    fn new(regs: &regs::MmioI2c<'static>) -> Self {
246        let clk_timeout_enabled = regs.read_clk_timeout_limit().value().value() > 0;
247        let mut guard = TimeoutGuard {
248            clk_timeout_enabled,
249            regs: unsafe { regs.clone() },
250        };
251        if clk_timeout_enabled {
252            // Clear any interrupts which might be pending.
253            guard.regs.write_irq_clear(
254                regs::InterruptClear::builder()
255                    .with_clock_timeout(true)
256                    .with_tx_overflow(false)
257                    .with_rx_overflow(false)
258                    .build(),
259            );
260            guard.regs.modify_irq_enb(|mut value| {
261                value.set_clock_timeout(true);
262                value
263            });
264        }
265        guard
266    }
267
268    fn timeout_enabled(&self) -> bool {
269        self.clk_timeout_enabled
270    }
271}
272
273impl Drop for TimeoutGuard {
274    fn drop(&mut self) {
275        if self.clk_timeout_enabled {
276            self.regs.modify_irq_enb(|mut value| {
277                value.set_clock_timeout(false);
278                value
279            });
280        }
281    }
282}
283//==================================================================================================
284// I2C Master
285//==================================================================================================
286
287pub struct I2cMaster<Addr = SevenBitAddress> {
288    id: Bank,
289    regs: regs::MmioI2c<'static>,
290    addr: PhantomData<Addr>,
291}
292
293impl<Addr> I2cMaster<Addr> {
294    pub fn new<I2c: I2cInstance>(
295        _i2c: I2c,
296        #[cfg(feature = "vor1x")] sysclk: Hertz,
297        #[cfg(feature = "vor4x")] clks: &crate::clock::Clocks,
298        cfg: MasterConfig,
299        speed_mode: I2cSpeed,
300    ) -> Result<Self, ClockTooSlowForFastI2cError> {
301        reset_peripheral_for_cycles(I2c::PERIPH_SEL, 2);
302        enable_peripheral_clock(I2c::PERIPH_SEL);
303        let mut regs = regs::I2c::new_mmio(I2c::ID);
304        #[cfg(feature = "vor1x")]
305        let clk_div = calc_clk_div(sysclk, speed_mode)?;
306        #[cfg(feature = "vor4x")]
307        let clk_div = calc_clk_div(clks, speed_mode)?;
308        regs.write_clkscale(
309            regs::ClockScale::builder()
310                .with_div(clk_div)
311                .with_fastmode(speed_mode)
312                .build(),
313        );
314        regs.modify_control(|mut value| {
315            value.set_tx_fifo_empty_mode(cfg.tx_empty_mode);
316            value.set_rx_fifo_full_mode(cfg.rx_full_mode);
317            value.set_analog_filter(cfg.alg_filt);
318            value.set_digital_filter(cfg.dlg_filt);
319            value
320        });
321
322        if let Some(ref timing_cfg) = cfg.timing_config {
323            regs.modify_control(|mut value| {
324                value.set_enable_timing_config(true);
325                value
326            });
327            regs.write_timing_config(
328                regs::TimingConfig::builder()
329                    .with_t_rise(timing_cfg.t_rise)
330                    .with_t_fall(timing_cfg.t_fall)
331                    .with_t_high(timing_cfg.t_high)
332                    .with_t_low(timing_cfg.t_low)
333                    .with_tsu_stop(timing_cfg.tsu_stop)
334                    .with_tsu_start(timing_cfg.tsu_start)
335                    .with_thd_start(timing_cfg.thd_start)
336                    .with_t_buf(timing_cfg.t_buf)
337                    .build(),
338            );
339        }
340        regs.write_fifo_clear(
341            regs::FifoClear::builder()
342                .with_tx_fifo(true)
343                .with_rx_fifo(true)
344                .build(),
345        );
346        if let Some(timeout) = cfg.timeout {
347            regs.write_clk_timeout_limit(ClockTimeoutLimit::new(timeout));
348        }
349        let mut i2c_master = I2cMaster {
350            addr: PhantomData,
351            id: I2c::ID,
352            regs,
353        };
354        i2c_master.enable();
355        Ok(i2c_master)
356    }
357
358    pub const fn id(&self) -> Bank {
359        self.id
360    }
361
362    #[inline]
363    pub fn perid(&self) -> u32 {
364        self.regs.read_perid()
365    }
366
367    /// Configures the clock scale for a given speed mode setting
368    pub fn set_clk_scale(
369        &mut self,
370        #[cfg(feature = "vor1x")] sys_clk: Hertz,
371        #[cfg(feature = "vor4x")] clks: &crate::clock::Clocks,
372        speed_mode: I2cSpeed,
373    ) -> Result<(), ClockTooSlowForFastI2cError> {
374        self.disable();
375        #[cfg(feature = "vor1x")]
376        let clk_div = calc_clk_div(sys_clk, speed_mode)?;
377        #[cfg(feature = "vor4x")]
378        let clk_div = calc_clk_div(clks, speed_mode)?;
379        self.regs.write_clkscale(
380            regs::ClockScale::builder()
381                .with_div(clk_div)
382                .with_fastmode(speed_mode)
383                .build(),
384        );
385        self.enable();
386        Ok(())
387    }
388
389    #[inline]
390    pub fn cancel_transfer(&mut self) {
391        self.regs.write_cmd(
392            regs::Command::builder()
393                .with_start(false)
394                .with_stop(false)
395                .with_cancel(true)
396                .build(),
397        );
398    }
399
400    #[inline]
401    pub fn clear_tx_fifo(&mut self) {
402        self.regs.write_fifo_clear(
403            regs::FifoClear::builder()
404                .with_tx_fifo(true)
405                .with_rx_fifo(false)
406                .build(),
407        );
408    }
409
410    #[inline]
411    pub fn clear_rx_fifo(&mut self) {
412        self.regs.write_fifo_clear(
413            regs::FifoClear::builder()
414                .with_tx_fifo(false)
415                .with_rx_fifo(true)
416                .build(),
417        );
418    }
419
420    /// Configure a timeout limit on the amount of time the I2C clock is seen to be low.
421    /// The timeout is specified as I2C clock cycles.
422    ///
423    /// If the timeout is enabled, the blocking transaction handlers provided by the [I2cMaster]
424    /// will poll the interrupt status register to check for timeouts. This can be used to avoid
425    /// hang-ups of the I2C bus.
426    #[inline]
427    pub fn set_clock_low_timeout(&mut self, clock_cycles: u20) {
428        self.regs
429            .write_clk_timeout_limit(ClockTimeoutLimit::new(clock_cycles));
430    }
431
432    #[inline]
433    pub fn disable_clock_low_timeout(&mut self) {
434        self.regs
435            .write_clk_timeout_limit(ClockTimeoutLimit::new(u20::new(0)));
436    }
437
438    #[inline]
439    pub fn enable(&mut self) {
440        self.regs.modify_control(|mut value| {
441            value.set_enable(true);
442            value
443        });
444    }
445
446    #[inline]
447    pub fn disable(&mut self) {
448        self.regs.modify_control(|mut value| {
449            value.set_enable(false);
450            value
451        });
452    }
453
454    #[inline(always)]
455    fn write_fifo_unchecked(&mut self, word: u8) {
456        self.regs.write_data(regs::Data::new(word));
457    }
458
459    #[inline(always)]
460    fn read_fifo_unchecked(&self) -> u8 {
461        self.regs.read_data().data()
462    }
463
464    #[inline]
465    pub fn read_status(&mut self) -> regs::Status {
466        self.regs.read_status()
467    }
468
469    #[inline]
470    pub fn write_command(&mut self, cmd: I2cCommand) {
471        self.regs
472            .write_cmd(regs::Command::new_with_raw_value(cmd as u32));
473    }
474
475    #[inline]
476    pub fn write_address(&mut self, addr: I2cAddress, dir: regs::Direction) {
477        self.regs.write_address(
478            regs::Address::builder()
479                .with_direction(dir)
480                .with_address(u10::new(addr.raw()))
481                .with_a10_mode(addr.ten_bit_addr())
482                .build(),
483        );
484    }
485
486    fn error_handler_write(&mut self, init_cmd: I2cCommand) {
487        if init_cmd == I2cCommand::Start {
488            self.write_command(I2cCommand::Stop);
489        }
490        // The other case is start with stop where, so a CANCEL command should not be necessary
491        // because the hardware takes care of it.
492        self.clear_tx_fifo();
493    }
494
495    /// Blocking write transaction on the I2C bus.
496    pub fn write_blocking(&mut self, addr: I2cAddress, output: &[u8]) -> Result<(), Error> {
497        self.write_blocking_generic(
498            I2cCommand::StartWithStop,
499            addr,
500            output,
501            WriteCompletionCondition::Idle,
502        )
503    }
504
505    /// Blocking read transaction on the I2C bus.
506    pub fn read_blocking(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> {
507        let len = buffer.len();
508        if len > 0x7fe {
509            return Err(Error::DataTooLarge);
510        }
511        // Clear the receive FIFO
512        self.clear_rx_fifo();
513
514        let timeout_guard = TimeoutGuard::new(&self.regs);
515
516        // Load number of words
517        self.regs
518            .write_words(regs::Words::new(u11::new(len as u16)));
519        // Load address
520        self.write_address(addr, regs::Direction::Receive);
521
522        let mut buf_iter = buffer.iter_mut();
523        let mut read_bytes = 0;
524        // Start receive transfer
525        self.write_command(I2cCommand::StartWithStop);
526        loop {
527            let status = self.read_status();
528            if status.arb_lost() {
529                self.clear_rx_fifo();
530                return Err(Error::ArbitrationLost);
531            }
532            if status.nack_addr() {
533                self.clear_rx_fifo();
534                return Err(Error::NackAddr);
535            }
536            if status.idle() {
537                if read_bytes != len {
538                    return Err(Error::InsufficientDataReceived);
539                }
540                return Ok(());
541            }
542            if timeout_guard.timeout_enabled() && self.regs.read_irq_status().clock_timeout() {
543                return Err(Error::ClockTimeout(
544                    self.regs.read_clk_timeout_limit().value(),
545                ));
546            }
547            if status.rx_not_empty() {
548                if let Some(next_byte) = buf_iter.next() {
549                    *next_byte = self.read_fifo_unchecked();
550                }
551                read_bytes += 1;
552            }
553        }
554    }
555
556    fn write_blocking_generic(
557        &mut self,
558        init_cmd: I2cCommand,
559        addr: I2cAddress,
560        output: &[u8],
561        end_condition: WriteCompletionCondition,
562    ) -> Result<(), Error> {
563        let len = output.len();
564        if len > 0x7fe {
565            return Err(Error::DataTooLarge);
566        }
567        // Clear the send FIFO
568        self.clear_tx_fifo();
569
570        let timeout_guard = TimeoutGuard::new(&self.regs);
571
572        // Load number of words
573        self.regs
574            .write_words(regs::Words::new(u11::new(len as u16)));
575        let mut bytes = output.iter();
576        // FIFO has a depth of 16. We load slightly above the trigger level
577        // but not all of it because the transaction might fail immediately
578        const FILL_DEPTH: usize = 12;
579
580        let mut current_index = core::cmp::min(FILL_DEPTH, len);
581        // load the FIFO
582        for _ in 0..current_index {
583            self.write_fifo_unchecked(*bytes.next().unwrap());
584        }
585        self.write_address(addr, regs::Direction::Send);
586        self.write_command(init_cmd);
587        loop {
588            let status = self.regs.read_status();
589            if status.arb_lost() {
590                self.error_handler_write(init_cmd);
591                return Err(Error::ArbitrationLost);
592            }
593            if status.nack_addr() {
594                self.error_handler_write(init_cmd);
595                return Err(Error::NackAddr);
596            }
597            if status.nack_data() {
598                self.error_handler_write(init_cmd);
599                return Err(Error::NackData);
600            }
601            match end_condition {
602                WriteCompletionCondition::Idle => {
603                    if status.idle() {
604                        return Ok(());
605                    }
606                }
607
608                WriteCompletionCondition::Waiting => {
609                    if status.waiting() {
610                        return Ok(());
611                    }
612                }
613            }
614            if timeout_guard.timeout_enabled() && self.regs.read_irq_status().clock_timeout() {
615                return Err(Error::ClockTimeout(
616                    self.regs.read_clk_timeout_limit().value(),
617                ));
618            }
619            if status.tx_not_full() && current_index < len {
620                self.write_fifo_unchecked(output[current_index]);
621                current_index += 1;
622            }
623        }
624    }
625
626    /// Blocking write-read transaction on the I2C bus.
627    pub fn write_read_blocking(
628        &mut self,
629        address: I2cAddress,
630        write: &[u8],
631        read: &mut [u8],
632    ) -> Result<(), Error> {
633        self.write_blocking_generic(
634            I2cCommand::Start,
635            address,
636            write,
637            WriteCompletionCondition::Waiting,
638        )?;
639        self.read_blocking(address, read)
640    }
641}
642
643//======================================================================================
644// Embedded HAL I2C implementations
645//======================================================================================
646
647impl embedded_hal::i2c::ErrorType for I2cMaster<SevenBitAddress> {
648    type Error = Error;
649}
650
651impl embedded_hal::i2c::I2c for I2cMaster<SevenBitAddress> {
652    fn transaction(
653        &mut self,
654        address: SevenBitAddress,
655        operations: &mut [Operation<'_>],
656    ) -> Result<(), Self::Error> {
657        for operation in operations {
658            match operation {
659                Operation::Read(buf) => self.read_blocking(I2cAddress::Regular(address), buf)?,
660                Operation::Write(buf) => self.write_blocking(I2cAddress::Regular(address), buf)?,
661            }
662        }
663        Ok(())
664    }
665
666    fn write_read(
667        &mut self,
668        address: u8,
669        write: &[u8],
670        read: &mut [u8],
671    ) -> Result<(), Self::Error> {
672        let addr = I2cAddress::Regular(address);
673        self.write_read_blocking(addr, write, read)
674    }
675}
676
677impl embedded_hal::i2c::ErrorType for I2cMaster<TenBitAddress> {
678    type Error = Error;
679}
680
681impl embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<TenBitAddress> {
682    fn transaction(
683        &mut self,
684        address: TenBitAddress,
685        operations: &mut [Operation<'_>],
686    ) -> Result<(), Self::Error> {
687        for operation in operations {
688            match operation {
689                Operation::Read(buf) => self.read_blocking(I2cAddress::TenBit(address), buf)?,
690                Operation::Write(buf) => self.write_blocking(I2cAddress::TenBit(address), buf)?,
691            }
692        }
693        Ok(())
694    }
695
696    fn write_read(
697        &mut self,
698        address: TenBitAddress,
699        write: &[u8],
700        read: &mut [u8],
701    ) -> Result<(), Self::Error> {
702        let addr = I2cAddress::TenBit(address);
703        self.write_read_blocking(addr, write, read)
704    }
705}