Skip to main content

esp_hal/i2c/master/low_level/
mod.rs

1use super::*;
2use crate::{rtc_cntl::WakeLock, soc::clocks::ClockTree};
3
4#[cfg_attr(i2c_master_version = "1", path = "v1.rs")]
5#[cfg_attr(i2c_master_version = "2", path = "v2.rs")]
6#[cfg_attr(
7    any(i2c_master_version = "3", i2c_master_version = "4"),
8    path = "v3.rs"
9)]
10mod version;
11
12#[must_use = "futures do nothing unless you `.await` or poll them"]
13pub(super) struct I2cFuture<'a> {
14    events: EnumSet<Event>,
15    driver: Driver<'a>,
16    deadline: Option<Instant>,
17    /// True if the Future has been polled to completion.
18    finished: bool,
19    _wake_lock: WakeLock,
20}
21
22impl<'a> I2cFuture<'a> {
23    pub fn new(events: EnumSet<Event>, driver: Driver<'a>, deadline: Option<Instant>) -> Self {
24        driver.regs().int_ena().modify(|_, w| {
25            for event in events {
26                match event {
27                    Event::EndDetect => w.end_detect().set_bit(),
28                    Event::TxComplete => w.trans_complete().set_bit(),
29                    #[cfg(i2c_master_has_tx_fifo_watermark)]
30                    Event::TxFifoWatermark => w.txfifo_wm().set_bit(),
31                };
32            }
33
34            w.arbitration_lost().set_bit();
35            w.time_out().set_bit();
36            w.nack().set_bit();
37            #[cfg(i2c_master_has_fsm_timeouts)]
38            {
39                w.scl_main_st_to().set_bit();
40                w.scl_st_to().set_bit();
41            }
42
43            w
44        });
45
46        Self::new_blocking(events, driver, deadline)
47    }
48
49    pub fn new_blocking(
50        events: EnumSet<Event>,
51        driver: Driver<'a>,
52        deadline: Option<Instant>,
53    ) -> Self {
54        Self {
55            events,
56            driver,
57            deadline,
58            finished: false,
59            _wake_lock: WakeLock::new(),
60        }
61    }
62
63    fn is_done(&self) -> bool {
64        !self.driver.info.interrupts().is_disjoint(self.events)
65    }
66
67    fn poll_completion(&mut self) -> Poll<Result<(), Error>> {
68        // Grab the current time before doing anything. This will ensure that a long
69        // interruption still allows the peripheral sufficient time to complete the
70        // operation (i.e. it ensures that the deadline is "at least", not "at most").
71        let now = if self.deadline.is_some() {
72            Instant::now()
73        } else {
74            Instant::EPOCH
75        };
76        let error = self.driver.check_errors();
77
78        let result = if self.is_done() {
79            // Even though we are done, we have to check for NACK and arbitration loss.
80            let result = if error == Err(Error::Timeout) {
81                // We are both done, and timed out. Likely the transaction has completed, but we
82                // checked too late?
83                Ok(())
84            } else {
85                error
86            };
87            Poll::Ready(result)
88        } else if error.is_err() {
89            Poll::Ready(error)
90        } else if let Some(deadline) = self.deadline
91            && now > deadline
92        {
93            // If the deadline is reached, we return an error.
94            Poll::Ready(Err(Error::Timeout))
95        } else {
96            Poll::Pending
97        };
98
99        if result.is_ready() {
100            self.finished = true;
101        }
102
103        result
104    }
105}
106
107impl core::future::Future for I2cFuture<'_> {
108    type Output = Result<(), Error>;
109
110    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
111        self.driver.state.waker.register(ctx.waker());
112
113        let result = self.poll_completion();
114
115        if result.is_pending() && self.deadline.is_some() {
116            ctx.waker().wake_by_ref();
117        }
118
119        result
120    }
121}
122
123impl Drop for I2cFuture<'_> {
124    fn drop(&mut self) {
125        if !self.finished {
126            let result = self.poll_completion();
127            if result.is_pending() || result == Poll::Ready(Err(Error::Timeout)) {
128                self.driver.reset_fsm(true);
129            }
130        }
131    }
132}
133
134#[ram]
135pub(super) fn async_handler(info: &Info, state: &State) {
136    // Disable all interrupts. The I2C Future will check events based on the
137    // interrupt status bits.
138    info.regs().int_ena().write(|w| unsafe { w.bits(0) });
139
140    state.waker.wake();
141}
142
143/// Sets the filter with a supplied threshold in clock cycles for which a
144/// pulse must be present to pass the filter
145fn set_filter(
146    register_block: &RegisterBlock,
147    sda_threshold: Option<u8>,
148    scl_threshold: Option<u8>,
149) {
150    cfg_select! {
151        i2c_master_separate_filter_config_registers => {
152            register_block.sda_filter_cfg().modify(|_, w| {
153                if let Some(threshold) = sda_threshold {
154                    unsafe { w.sda_filter_thres().bits(threshold) };
155                }
156                w.sda_filter_en().bit(sda_threshold.is_some())
157            });
158            register_block.scl_filter_cfg().modify(|_, w| {
159                if let Some(threshold) = scl_threshold {
160                    unsafe { w.scl_filter_thres().bits(threshold) };
161                }
162                w.scl_filter_en().bit(scl_threshold.is_some())
163            });
164        }
165        _ => {
166            register_block.filter_cfg().modify(|_, w| {
167                if let Some(threshold) = sda_threshold {
168                    unsafe { w.sda_filter_thres().bits(threshold) };
169                }
170                if let Some(threshold) = scl_threshold {
171                    unsafe { w.scl_filter_thres().bits(threshold) };
172                }
173                w.sda_filter_en().bit(sda_threshold.is_some());
174                w.scl_filter_en().bit(scl_threshold.is_some())
175            });
176        }
177    }
178}
179
180#[expect(clippy::too_many_arguments)]
181#[allow(unused)]
182/// Configures the timing parameters for the I2C peripheral.
183///
184/// Clock source selection is handled separately via the clock tree.
185fn configure_clock(
186    info: &Info,
187    scl_low_period: u32,
188    scl_high_period: u32,
189    scl_wait_high_period: u32,
190    sda_hold_time: u32,
191    sda_sample_time: u32,
192    scl_rstart_setup_time: u32,
193    scl_stop_setup_time: u32,
194    scl_start_hold_time: u32,
195    scl_stop_hold_time: u32,
196    timeout: Option<u32>,
197) -> Result<(), ConfigError> {
198    unsafe {
199        // scl period
200        info.regs()
201            .scl_low_period()
202            .write(|w| w.scl_low_period().bits(scl_low_period as u16));
203
204        #[cfg(not(i2c_master_version = "1"))]
205        let scl_wait_high_period = scl_wait_high_period
206            .try_into()
207            .map_err(|_| ConfigError::FrequencyOutOfRange)?;
208
209        info.regs().scl_high_period().write(|w| {
210            #[cfg(not(i2c_master_version = "1"))] // ESP32 does not have a wait_high field
211            w.scl_wait_high_period().bits(scl_wait_high_period);
212            w.scl_high_period().bits(scl_high_period as u16)
213        });
214
215        // sda sample
216        info.regs()
217            .sda_hold()
218            .write(|w| w.time().bits(sda_hold_time as u16));
219        info.regs()
220            .sda_sample()
221            .write(|w| w.time().bits(sda_sample_time as u16));
222
223        // setup
224        info.regs()
225            .scl_rstart_setup()
226            .write(|w| w.time().bits(scl_rstart_setup_time as u16));
227        info.regs()
228            .scl_stop_setup()
229            .write(|w| w.time().bits(scl_stop_setup_time as u16));
230
231        // hold
232        info.regs()
233            .scl_start_hold()
234            .write(|w| w.time().bits(scl_start_hold_time as u16));
235        info.regs()
236            .scl_stop_hold()
237            .write(|w| w.time().bits(scl_stop_hold_time as u16));
238
239        cfg_select! {
240            i2c_master_has_bus_timeout_enable => {
241                info.regs().to().write(|w| {
242                    w.time_out_en().bit(timeout.is_some());
243                    w.time_out_value().bits(timeout.unwrap_or(1) as _)
244                });
245            }
246            _ => {
247                info.regs()
248                    .to()
249                    .write(|w| w.time_out().bits(timeout.unwrap_or(1)));
250            }
251        }
252    }
253    Ok(())
254}
255
256/// Peripheral data describing a particular I2C instance.
257#[doc(hidden)]
258#[derive(Debug)]
259#[non_exhaustive]
260#[allow(private_interfaces, reason = "Unstable details")]
261pub struct Info {
262    /// Numeric instance id (0 = I2C0, 1 = I2C1, ...)
263    #[cfg(soc_has_i2c1)]
264    pub id: u8,
265
266    /// Pointer to the register block for this I2C instance.
267    ///
268    /// Use [Self::register_block] to access the register block.
269    pub register_block: *const RegisterBlock,
270
271    /// System peripheral marker.
272    pub peripheral: crate::system::Peripheral,
273
274    /// Interrupt handler for the asynchronous operations of this I2C instance.
275    pub async_handler: InterruptHandler,
276
277    /// SCL output signal.
278    pub scl_output: OutputSignal,
279
280    /// SCL input signal.
281    pub scl_input: InputSignal,
282
283    /// SDA output signal.
284    pub sda_output: OutputSignal,
285
286    /// SDA input signal.
287    pub sda_input: InputSignal,
288
289    /// I2C clock group instance.
290    pub clock_instance: crate::soc::clocks::I2cInstance,
291}
292
293impl Info {
294    /// Returns the register block for this I2C instance.
295    pub fn regs(&self) -> &RegisterBlock {
296        unsafe { &*self.register_block }
297    }
298
299    /// Listen for the given interrupts
300    pub(super) fn enable_listen(&self, interrupts: EnumSet<Event>, enable: bool) {
301        let reg_block = self.regs();
302
303        reg_block.int_ena().modify(|_, w| {
304            for interrupt in interrupts {
305                match interrupt {
306                    Event::EndDetect => w.end_detect().bit(enable),
307                    Event::TxComplete => w.trans_complete().bit(enable),
308                    #[cfg(i2c_master_has_tx_fifo_watermark)]
309                    Event::TxFifoWatermark => w.txfifo_wm().bit(enable),
310                };
311            }
312            w
313        });
314    }
315
316    pub(super) fn interrupts(&self) -> EnumSet<Event> {
317        let mut res = EnumSet::new();
318        let reg_block = self.regs();
319
320        let ints = reg_block.int_raw().read();
321
322        if ints.end_detect().bit_is_set() {
323            res.insert(Event::EndDetect);
324        }
325        if ints.trans_complete().bit_is_set() {
326            res.insert(Event::TxComplete);
327        }
328        #[cfg(i2c_master_has_tx_fifo_watermark)]
329        if ints.txfifo_wm().bit_is_set() {
330            res.insert(Event::TxFifoWatermark);
331        }
332
333        res
334    }
335
336    pub(super) fn clear_interrupts(&self, interrupts: EnumSet<Event>) {
337        let reg_block = self.regs();
338
339        reg_block.int_clr().write(|w| {
340            for interrupt in interrupts {
341                match interrupt {
342                    Event::EndDetect => w.end_detect().clear_bit_by_one(),
343                    Event::TxComplete => w.trans_complete().clear_bit_by_one(),
344                    #[cfg(i2c_master_has_tx_fifo_watermark)]
345                    Event::TxFifoWatermark => w.txfifo_wm().clear_bit_by_one(),
346                };
347            }
348            w
349        });
350    }
351}
352
353impl PartialEq for Info {
354    fn eq(&self, other: &Self) -> bool {
355        core::ptr::eq(self.register_block, other.register_block)
356    }
357}
358
359unsafe impl Sync for Info {}
360
361pub(super) struct I2cClockGuard {
362    clock: crate::clock::ll::I2cInstance,
363}
364
365impl I2cClockGuard {
366    pub(super) fn new(i2c: AnyI2c<'_>) -> Self {
367        let clock = i2c.info().clock_instance;
368        ClockTree::with(|clocks| clock.request_function_clock(clocks));
369        Self { clock }
370    }
371}
372
373impl Drop for I2cClockGuard {
374    fn drop(&mut self) {
375        ClockTree::with(|clocks| self.clock.release_function_clock(clocks));
376    }
377}
378
379#[derive(Clone, Copy)]
380enum Deadline {
381    None,
382    Fixed(Instant),
383    PerByte(Duration),
384}
385
386impl Deadline {
387    fn start(self, data_len: usize) -> Option<Instant> {
388        match self {
389            Deadline::None => None,
390            Deadline::Fixed(deadline) => Some(deadline),
391            Deadline::PerByte(duration) => Some(Instant::now() + duration * data_len as u32),
392        }
393    }
394}
395
396#[allow(dead_code)] // Some versions don't need `state`
397#[derive(Clone, Copy)]
398pub(super) struct Driver<'a> {
399    pub(super) info: &'a Info,
400    pub(super) state: &'a State,
401    pub(super) config: &'a DriverConfig,
402}
403
404impl Driver<'_> {
405    fn regs(&self) -> &RegisterBlock {
406        self.info.regs()
407    }
408
409    pub(super) fn connect_pin(
410        pin: crate::gpio::interconnect::OutputSignal<'_>,
411        input: InputSignal,
412        output: OutputSignal,
413        guard: &mut PinGuard,
414    ) {
415        // avoid the pin going low during configuration
416        pin.set_output_high(true);
417
418        pin.apply_output_config(
419            &OutputConfig::default()
420                .with_drive_mode(DriveMode::OpenDrain)
421                .with_pull(Pull::Up),
422        );
423        pin.set_output_enable(true);
424        pin.set_input_enable(true);
425
426        input.connect_to(&pin);
427
428        *guard = interconnect::OutputSignal::connect_with_guard(pin, output);
429    }
430
431    fn init_master(&self, config: &Config) {
432        self.regs().ctr().write(|w| {
433            // Set I2C controller to master mode
434            w.ms_mode().set_bit();
435            w.sda_force_out().open_drain();
436            w.scl_force_out().open_drain();
437            // Use Most Significant Bit first for sending and receiving data
438            w.tx_lsb_first().clear_bit();
439            w.rx_lsb_first().clear_bit();
440
441            w.sample_scl_level()
442                .bit(config.scl_sample_level == Level::Low);
443
444            #[cfg(i2c_master_has_arbitration_en)]
445            w.arbitration_en().bit(config.bus_arbitration);
446
447            #[cfg(i2c_master_version = "2")]
448            w.ref_always_on().set_bit();
449
450            // Ensure that clock is enabled
451            w.clk_en().set_bit()
452        });
453    }
454
455    /// Configures the I2C peripheral with the specified frequency, clocks, and
456    /// optional timeout.
457    pub(super) fn setup(&self, config: &Config) -> Result<(), ConfigError> {
458        self.init_master(config);
459
460        // Configure filter
461        // FIXME if we ever change this we need to adapt `set_frequency` for ESP32
462        set_filter(self.regs(), Some(7), Some(7));
463
464        // Configure frequency
465        self.set_frequency(config)?;
466
467        // Configure additional timeouts
468        #[cfg(i2c_master_has_fsm_timeouts)]
469        {
470            self.regs()
471                .scl_st_time_out()
472                .write(|w| unsafe { w.scl_st_to().bits(config.scl_st_timeout.value()) });
473            self.regs()
474                .scl_main_st_time_out()
475                .write(|w| unsafe { w.scl_main_st_to().bits(config.scl_main_st_timeout.value()) });
476        }
477
478        self.update_registers();
479
480        Ok(())
481    }
482
483    fn do_fsm_reset(&self) {
484        cfg_select! {
485            i2c_master_has_reliable_fsm_reset => {
486                // Device has a working FSM reset mechanism
487                self.regs().ctr().modify(|_, w| w.fsm_rst().set_bit());
488            }
489            _ => {
490                // Even though C2 and C3 have a FSM reset bit, esp-idf does not
491                // define I2C_LL_SUPPORT_HW_FSM_RST for them, so include them in the fallback impl.
492
493                crate::system::PeripheralClockControl::reset(self.info.peripheral);
494
495                // Restore configuration. This operation has succeeded once, so we can
496                // assume that the config is valid and we can ignore the result.
497                self.setup(&self.config.config).ok();
498            }
499        }
500    }
501
502    /// Resets the I2C controller (FIFO + FSM + command list)
503    // This function implements esp-idf's `s_i2c_hw_fsm_reset`
504    // https://github.com/espressif/esp-idf/blob/27d68f57e6bdd3842cd263585c2c352698a9eda2/components/esp_driver_i2c/i2c_master.c#L115
505    //
506    // Make sure you don't call this function in the middle of a transaction. If the
507    // first command in the command list is not a START, the hardware will hang
508    // with no timeouts.
509    pub(super) fn reset_fsm(&self, clear_bus: bool) {
510        if clear_bus {
511            self.clear_bus_blocking(true);
512        } else {
513            self.do_fsm_reset();
514        }
515    }
516
517    fn bus_busy(&self) -> bool {
518        self.regs().sr().read().bus_busy().bit_is_set()
519    }
520
521    fn ensure_idle_blocking(&self) {
522        if self.bus_busy() {
523            // If the bus is busy, we need to clear it.
524            self.clear_bus_blocking(false);
525        }
526    }
527
528    async fn ensure_idle(&self) {
529        if self.bus_busy() {
530            // If the bus is busy, we need to clear it.
531            self.clear_bus().await;
532        }
533    }
534
535    fn reset_before_transmission(&self) {
536        // Clear all I2C interrupts
537        self.clear_all_interrupts();
538
539        // Reset fifo
540        self.reset_fifo();
541
542        // Reset the command list
543        self.reset_command_list();
544    }
545
546    /// Implements s_i2c_master_clear_bus
547    ///
548    /// If a transaction ended incorrectly for some reason, the slave may drive
549    /// SDA indefinitely. This function forces the slave to release the
550    /// bus by sending 9 clock pulses.
551    fn clear_bus_blocking(&self, reset_fsm: bool) {
552        let mut future = ClearBusFuture::new(*self, reset_fsm);
553        let start = Instant::now();
554        while future.poll_completion().is_pending() {
555            if start.elapsed() > CLEAR_BUS_TIMEOUT_MS {
556                break;
557            }
558        }
559    }
560
561    async fn clear_bus(&self) {
562        let clear_bus = ClearBusFuture::new(*self, true);
563        let start = Instant::now();
564
565        embassy_futures::select::select(clear_bus, async {
566            while start.elapsed() < CLEAR_BUS_TIMEOUT_MS {
567                embassy_futures::yield_now().await;
568            }
569        })
570        .await;
571    }
572
573    pub(super) fn force_scl_low(&self, low: bool) {
574        cfg_select! {
575            i2c_master_has_pd_en => self.set_scl_pd(low),
576            _ => self.force_pin_low(low, self.config.scl_pin.pin_number(), &self.info.scl_output),
577        }
578    }
579
580    pub(super) fn force_sda_low(&self, low: bool) {
581        cfg_select! {
582            i2c_master_has_pd_en => self.set_sda_pd(low),
583            _ => self.force_pin_low(low, self.config.sda_pin.pin_number(), &self.info.sda_output),
584        }
585    }
586
587    /// Restores force_out to open-drain mode for both lines.
588    #[cfg(i2c_master_has_pd_en)]
589    fn restore_force_out(&self) {
590        self.regs().ctr().modify(|_, w| {
591            w.scl_force_out().open_drain();
592            w.sda_force_out().open_drain()
593        });
594        self.update_registers();
595    }
596
597    #[cfg(not(i2c_master_has_pd_en))]
598    fn force_pin_low(
599        &self,
600        low: bool,
601        pin_number: Option<u8>,
602        output_signal: &crate::gpio::OutputSignal,
603    ) {
604        use crate::gpio::AnyPin;
605        let Some(n) = pin_number else { return };
606        let pin = unsafe { AnyPin::steal(n) };
607        if low {
608            pin.set_output_high(false);
609            output_signal.disconnect_from(&pin);
610        } else {
611            output_signal.connect_to(&pin);
612        }
613    }
614
615    /// Sets or clears `scl_pd_en`. Switches `scl_force_out` to direct-output while
616    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
617    /// bits clear.
618    #[cfg(i2c_master_has_pd_en)]
619    fn set_scl_pd(&self, low: bool) {
620        if low {
621            self.regs()
622                .ctr()
623                .modify(|_, w| w.scl_force_out().direct_output());
624        }
625        self.regs()
626            .scl_sp_conf()
627            .modify(|_, w| w.scl_pd_en().bit(low));
628        if !low {
629            let sp = self.regs().scl_sp_conf().read();
630            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
631                self.restore_force_out();
632                return;
633            }
634        }
635        self.update_registers();
636    }
637
638    /// Sets or clears `sda_pd_en`. Switches `sda_force_out` to direct-output while
639    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
640    /// bits clear.
641    #[cfg(i2c_master_has_pd_en)]
642    fn set_sda_pd(&self, low: bool) {
643        if low {
644            self.regs()
645                .ctr()
646                .modify(|_, w| w.sda_force_out().direct_output());
647        }
648        self.regs()
649            .scl_sp_conf()
650            .modify(|_, w| w.sda_pd_en().bit(low));
651        if !low {
652            let sp = self.regs().scl_sp_conf().read();
653            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
654                self.restore_force_out();
655                return;
656            }
657        }
658        self.update_registers();
659    }
660
661    /// Resets the I2C peripheral's command registers.
662    fn reset_command_list(&self) {
663        for cmd in self.regs().comd_iter() {
664            cmd.reset();
665        }
666    }
667
668    /// Configures the I2C peripheral for a write operation.
669    /// - `addr` is the address of the slave device.
670    /// - `bytes` is the data two be sent.
671    /// - `start` indicates whether the operation should start by a START condition and sending the
672    ///   address.
673    /// - `stop` indicates whether the operation will end with a STOP condition.
674    /// - `cmd_iterator` is an iterator over the command registers.
675    fn setup_write<'a, I>(
676        &self,
677        addr: I2cAddress,
678        bytes: &[u8],
679        start: bool,
680        stop: bool,
681        cmd_iterator: &mut I,
682    ) -> Result<(), Error>
683    where
684        I: Iterator<Item = &'a COMD>,
685    {
686        // If start is true we need to send the address, too, which takes up a data
687        // byte.
688        let max_len = if start {
689            I2C_CHUNK_SIZE
690        } else {
691            I2C_CHUNK_SIZE + 1
692        };
693        if bytes.len() > max_len {
694            return Err(Error::FifoExceeded);
695        }
696
697        if start {
698            add_cmd(cmd_iterator, Command::Start)?;
699        }
700
701        let write_len = if start { bytes.len() + 1 } else { bytes.len() };
702        // don't issue write if there is no data to write
703        if write_len > 0 {
704            // ESP32 can't alter the position of END, so we need to split the chunk always into
705            // 3-command sequences. Chunking makes sure not to place a 1-byte
706            // command at the end, which would cause an arithmetic underflow.
707            // The sequences we can generate are:
708            // - START-WRITE-STOP
709            // - START-WRITE-END-WRITE-STOP
710            // - START-WRITE-END-(WRITE-WRITE-END)*-WRITE-STOP sequence.
711            if cfg!(i2c_master_version = "1") && !(start || stop) {
712                // Chunks that do not have a START or STOP command need to be split into multiple
713                // commands.
714                add_cmd(
715                    cmd_iterator,
716                    Command::Write {
717                        ack_exp: Ack::Ack,
718                        ack_check_en: true,
719                        length: (write_len as u8) - 1,
720                    },
721                )?;
722                add_cmd(
723                    cmd_iterator,
724                    Command::Write {
725                        ack_exp: Ack::Ack,
726                        ack_check_en: true,
727                        length: 1,
728                    },
729                )?;
730            } else {
731                add_cmd(
732                    cmd_iterator,
733                    Command::Write {
734                        ack_exp: Ack::Ack,
735                        ack_check_en: true,
736                        length: write_len as u8,
737                    },
738                )?;
739            }
740        }
741
742        if start {
743            // Load address and R/W bit into FIFO
744            match addr {
745                I2cAddress::SevenBit(addr) => {
746                    self.write_fifo((addr << 1) | OperationType::Write as u8);
747                }
748            }
749        }
750        for b in bytes {
751            self.write_fifo(*b);
752        }
753
754        Ok(())
755    }
756
757    /// Configures the I2C peripheral for a read operation.
758    /// - `addr` is the address of the slave device.
759    /// - `buffer` is the buffer to store the read data.
760    /// - `start` indicates whether the operation should start by a START condition and sending the
761    ///   address.
762    /// - `stop` indicates whether the operation will end with a STOP condition.
763    /// - `will_continue` indicates whether there is another read operation following this one and
764    ///   we should not nack the last byte.
765    /// - `cmd_iterator` is an iterator over the command registers.
766    fn setup_read<'a, I>(
767        &self,
768        addr: I2cAddress,
769        buffer: &mut [u8],
770        start: bool,
771        stop: bool,
772        will_continue: bool,
773        cmd_iterator: &mut I,
774    ) -> Result<(), Error>
775    where
776        I: Iterator<Item = &'a COMD>,
777    {
778        if buffer.is_empty() {
779            return Err(Error::ZeroLengthInvalid);
780        }
781        let (max_len, initial_len) = if will_continue {
782            (I2C_CHUNK_SIZE + 1, buffer.len())
783        } else {
784            (I2C_CHUNK_SIZE, buffer.len() - 1)
785        };
786        if buffer.len() > max_len {
787            return Err(Error::FifoExceeded);
788        }
789
790        if start {
791            add_cmd(cmd_iterator, Command::Start)?;
792            // WRITE 7-bit address
793            add_cmd(
794                cmd_iterator,
795                Command::Write {
796                    ack_exp: Ack::Ack,
797                    ack_check_en: true,
798                    length: 1,
799                },
800            )?;
801        }
802
803        if initial_len > 0 {
804            let extra_commands = if cfg!(i2c_master_version = "1") {
805                match (start, will_continue) {
806                    // No chunking (START-WRITE-READ-STOP) or first chunk (START-WRITE-READ-END)
807                    (true, _) => 0,
808                    // Middle chunk - (READ-READ-READ-END)
809                    (false, true) => 2,
810                    // Last chunk - (READ-READ-STOP-END)
811                    (false, false) => 1 - stop as u8,
812                }
813            } else {
814                0
815            };
816
817            add_cmd(
818                cmd_iterator,
819                Command::Read {
820                    ack_value: Ack::Ack,
821                    length: initial_len as u8 - extra_commands,
822                },
823            )?;
824            for _ in 0..extra_commands {
825                add_cmd(
826                    cmd_iterator,
827                    Command::Read {
828                        ack_value: Ack::Ack,
829                        length: 1,
830                    },
831                )?;
832            }
833        }
834
835        if !will_continue {
836            // this is the last read so we need to nack the last byte
837            // READ w/o ACK
838            add_cmd(
839                cmd_iterator,
840                Command::Read {
841                    ack_value: Ack::Nack,
842                    length: 1,
843                },
844            )?;
845        }
846
847        self.update_registers();
848
849        if start {
850            // Load address and R/W bit into FIFO
851            match addr {
852                I2cAddress::SevenBit(addr) => {
853                    self.write_fifo((addr << 1) | OperationType::Read as u8);
854                }
855            }
856        }
857        Ok(())
858    }
859
860    /// Reads from RX FIFO into the given buffer.
861    fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> {
862        if self.regs().sr().read().rxfifo_cnt().bits() < buffer.len() as u8 {
863            return Err(Error::ExecutionIncomplete);
864        }
865
866        // Read bytes from FIFO
867        for byte in buffer.iter_mut() {
868            *byte = self.read_fifo();
869        }
870
871        // The RX FIFO should be empty now. If it is not, it means we queued up reading
872        // more data than we read, which is an error.
873        debug_assert!(self.regs().sr().read().rxfifo_cnt().bits() == 0);
874
875        Ok(())
876    }
877
878    /// Clears all pending interrupts for the I2C peripheral.
879    fn clear_all_interrupts(&self) {
880        self.regs()
881            .int_clr()
882            .write(|w| unsafe { w.bits(property!("i2c_master.ll_intr_mask")) });
883    }
884
885    async fn wait_for_completion(&self, deadline: Option<Instant>) -> Result<(), Error> {
886        I2cFuture::new(Event::TxComplete | Event::EndDetect, *self, deadline).await?;
887        self.check_all_commands_done(deadline).await
888    }
889
890    /// Waits for the completion of an I2C transaction.
891    fn wait_for_completion_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
892        let mut future =
893            I2cFuture::new_blocking(Event::TxComplete | Event::EndDetect, *self, deadline);
894        loop {
895            if let Poll::Ready(result) = future.poll_completion() {
896                result?;
897                return self.check_all_commands_done_blocking(deadline);
898            }
899        }
900    }
901
902    fn all_commands_done(&self, deadline: Option<Instant>) -> Result<bool, Error> {
903        // NOTE: on esp32 executing the end command generates the end_detect interrupt
904        //       but does not seem to clear the done bit! So we don't check the done
905        //       status of an end command
906        let now = if deadline.is_some() {
907            Instant::now()
908        } else {
909            Instant::EPOCH
910        };
911
912        self.check_errors()?;
913
914        for cmd_reg in self.regs().comd_iter() {
915            let cmd = cmd_reg.read();
916
917            // if there is a valid command which is not END, check if it's marked as done
918            if cmd.bits() != 0x0 && !cmd.opcode().is_end() && !cmd.command_done().bit_is_set() {
919                // Let's retry
920                if let Some(deadline) = deadline
921                    && now > deadline
922                {
923                    return Err(Error::ExecutionIncomplete);
924                }
925
926                return Ok(false);
927            }
928
929            // once we hit END or STOP we can break the loop
930            if cmd.opcode().is_end() {
931                break;
932            }
933            if cmd.opcode().is_stop() {
934                #[cfg(i2c_master_version = "1")]
935                // wait for STOP - apparently on ESP32 we otherwise miss the ACK error for an
936                // empty write
937                if self.regs().sr().read().scl_state_last() == 6 {
938                    self.check_errors()?;
939                } else {
940                    continue;
941                }
942                break;
943            }
944        }
945        Ok(true)
946    }
947
948    /// Checks whether all I2C commands have completed execution.
949    fn check_all_commands_done_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
950        // loop until commands are actually done
951        while !self.all_commands_done(deadline)? {}
952        self.check_errors()?;
953
954        Ok(())
955    }
956
957    /// Checks whether all I2C commands have completed execution.
958    async fn check_all_commands_done(&self, deadline: Option<Instant>) -> Result<(), Error> {
959        // loop until commands are actually done
960        while !self.all_commands_done(deadline)? {
961            embassy_futures::yield_now().await;
962        }
963        self.check_errors()?;
964
965        Ok(())
966    }
967
968    /// Checks for I2C transmission errors and handles them.
969    ///
970    /// This function inspects specific I2C-related interrupts to detect errors
971    /// during communication, such as timeouts, failed acknowledgments, or
972    /// arbitration loss. If an error is detected, the function handles it
973    /// by resetting the I2C peripheral to clear the error condition and then
974    /// returns an appropriate error.
975    fn check_errors(&self) -> Result<(), Error> {
976        let r = self.regs().int_raw().read();
977
978        // Handle error cases
979        if r.nack().bit_is_set() {
980            return Err(Error::AcknowledgeCheckFailed(estimate_ack_failed_reason(
981                self.regs(),
982            )));
983        }
984        if r.arbitration_lost().bit_is_set() {
985            return Err(Error::ArbitrationLost);
986        }
987
988        #[cfg(not(i2c_master_version = "1"))]
989        if r.trans_complete().bit_is_set() && self.regs().sr().read().resp_rec().bit_is_clear() {
990            return Err(Error::AcknowledgeCheckFailed(
991                AcknowledgeCheckFailedReason::Data,
992            ));
993        }
994
995        #[cfg(i2c_master_has_fsm_timeouts)]
996        {
997            if r.scl_st_to().bit_is_set() {
998                return Err(Error::Timeout);
999            }
1000            if r.scl_main_st_to().bit_is_set() {
1001                return Err(Error::Timeout);
1002            }
1003        }
1004        if r.time_out().bit_is_set() {
1005            return Err(Error::Timeout);
1006        }
1007
1008        Ok(())
1009    }
1010
1011    /// Updates the configuration of the I2C peripheral.
1012    ///
1013    /// This function ensures that the configuration values, such as clock
1014    /// settings, SDA/SCL filtering, timeouts, and other operational
1015    /// parameters, which are configured in other functions, are properly
1016    /// propagated to the I2C hardware. This step is necessary to synchronize
1017    /// the software-configured settings with the peripheral's internal
1018    /// registers, ensuring that the hardware behaves according to the
1019    /// current configuration.
1020    fn update_registers(&self) {
1021        // Ensure that the configuration of the peripheral is correctly propagated
1022        // (only necessary for C2, C3, C6, H2 and S3 variant)
1023        #[cfg(i2c_master_has_conf_update)]
1024        self.regs().ctr().modify(|_, w| w.conf_upgate().set_bit());
1025    }
1026
1027    fn set_frequency(&self, config: &Config) -> Result<(), ConfigError> {
1028        version::set_frequency(self, config)
1029    }
1030
1031    fn reset_fifo(&self) {
1032        version::reset_fifo(self);
1033    }
1034
1035    fn read_fifo(&self) -> u8 {
1036        version::read_fifo(self.regs())
1037    }
1038
1039    fn write_fifo(&self, data: u8) {
1040        version::write_fifo(self.regs(), data);
1041    }
1042
1043    /// Starts an I2C transmission.
1044    fn start_transmission(&self) {
1045        // Start transmission
1046        self.regs().ctr().modify(|_, w| w.trans_start().set_bit());
1047    }
1048
1049    fn start_write_operation(
1050        &self,
1051        address: I2cAddress,
1052        buffer: &[u8],
1053        start: bool,
1054        stop: bool,
1055        deadline: Deadline,
1056    ) -> Result<Option<Instant>, Error> {
1057        let cmd_iterator = &mut self.regs().comd_iter();
1058
1059        self.setup_write(address, buffer, start, stop, cmd_iterator)?;
1060
1061        if stop {
1062            add_cmd(cmd_iterator, Command::Stop)?;
1063        }
1064        if !(start && stop) {
1065            // Multi-chunk write, terminate with END. ESP32 TRM suggests a write should work with
1066            // only a STOP at the end, but STOP does not seem to generate a TX_COMPLETE interrupt
1067            // without END.
1068            add_cmd(cmd_iterator, Command::End)?;
1069        }
1070
1071        self.start_transmission();
1072
1073        Ok(deadline.start(buffer.len() + address.bytes()))
1074    }
1075
1076    /// Executes an I2C read operation.
1077    /// - `addr` is the address of the slave device.
1078    /// - `buffer` is the buffer to store the read data.
1079    /// - `start` indicates whether the operation should start by a START condition and sending the
1080    ///   address.
1081    /// - `stop` indicates whether the operation should end with a STOP condition.
1082    /// - `will_continue` indicates whether there is another read operation following this one and
1083    ///   we should not nack the last byte.
1084    /// - `cmd_iterator` is an iterator over the command registers.
1085    fn start_read_operation(
1086        &self,
1087        address: I2cAddress,
1088        buffer: &mut [u8],
1089        start: bool,
1090        will_continue: bool,
1091        stop: bool,
1092        deadline: Deadline,
1093    ) -> Result<Option<Instant>, Error> {
1094        // We don't support single I2C reads larger than the FIFO. This should be
1095        // enforced by `VariableChunkIterMut` used in `Driver::read` and
1096        // `Driver::read_async`.
1097        debug_assert!(buffer.len() <= I2C_FIFO_SIZE);
1098
1099        let cmd_iterator = &mut self.regs().comd_iter();
1100
1101        self.setup_read(address, buffer, start, stop, will_continue, cmd_iterator)?;
1102
1103        if stop {
1104            add_cmd(cmd_iterator, Command::Stop)?;
1105        }
1106        if !(start && stop) {
1107            // Multi-chunk read, terminate with END. On ESP32, assume same limitation as writes.
1108            add_cmd(cmd_iterator, Command::End)?;
1109        }
1110
1111        self.start_transmission();
1112
1113        Ok(deadline.start(buffer.len() + address.bytes()))
1114    }
1115
1116    /// Executes an I2C write operation.
1117    /// - `addr` is the address of the slave device.
1118    /// - `bytes` is the data two be sent.
1119    /// - `start` indicates whether the operation should start by a START condition and sending the
1120    ///   address.
1121    /// - `stop` indicates whether the operation should end with a STOP condition.
1122    /// - `cmd_iterator` is an iterator over the command registers.
1123    fn write_operation_blocking(
1124        &self,
1125        address: I2cAddress,
1126        bytes: &[u8],
1127        start: bool,
1128        stop: bool,
1129        deadline: Deadline,
1130    ) -> Result<(), Error> {
1131        address.validate()?;
1132
1133        self.reset_before_transmission();
1134
1135        // Short circuit for zero length writes without start or end as that would be an
1136        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
1137        if bytes.is_empty() && !start && !stop {
1138            return Ok(());
1139        }
1140
1141        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
1142        self.wait_for_completion_blocking(deadline)?;
1143
1144        Ok(())
1145    }
1146
1147    /// Executes an I2C read operation.
1148    /// - `addr` is the address of the slave device.
1149    /// - `buffer` is the buffer to store the read data.
1150    /// - `start` indicates whether the operation should start by a START condition and sending the
1151    ///   address.
1152    /// - `stop` indicates whether the operation should end with a STOP condition.
1153    /// - `will_continue` indicates whether there is another read operation following this one and
1154    ///   we should not nack the last byte.
1155    /// - `cmd_iterator` is an iterator over the command registers.
1156    fn read_operation_blocking(
1157        &self,
1158        address: I2cAddress,
1159        buffer: &mut [u8],
1160        start: bool,
1161        stop: bool,
1162        will_continue: bool,
1163        deadline: Deadline,
1164    ) -> Result<(), Error> {
1165        address.validate()?;
1166        self.reset_before_transmission();
1167
1168        // Short circuit for zero length reads as that would be an invalid operation
1169        // read lengths in the TRM (at least for ESP32-S3) are 1-255
1170        if buffer.is_empty() {
1171            return Ok(());
1172        }
1173
1174        let deadline =
1175            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
1176        self.wait_for_completion_blocking(deadline)?;
1177        self.read_all_from_fifo(buffer)?;
1178
1179        Ok(())
1180    }
1181
1182    /// Executes an async I2C write operation.
1183    /// - `addr` is the address of the slave device.
1184    /// - `bytes` is the data two be sent.
1185    /// - `start` indicates whether the operation should start by a START condition and sending the
1186    ///   address.
1187    /// - `stop` indicates whether the operation should end with a STOP condition.
1188    /// - `cmd_iterator` is an iterator over the command registers.
1189    async fn write_operation(
1190        &self,
1191        address: I2cAddress,
1192        bytes: &[u8],
1193        start: bool,
1194        stop: bool,
1195        deadline: Deadline,
1196    ) -> Result<(), Error> {
1197        address.validate()?;
1198        self.reset_before_transmission();
1199
1200        // Short circuit for zero length writes without start or end as that would be an
1201        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
1202        if bytes.is_empty() && !start && !stop {
1203            return Ok(());
1204        }
1205
1206        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
1207        self.wait_for_completion(deadline).await?;
1208
1209        Ok(())
1210    }
1211
1212    /// Executes an async I2C read operation.
1213    /// - `addr` is the address of the slave device.
1214    /// - `buffer` is the buffer to store the read data.
1215    /// - `start` indicates whether the operation should start by a START condition and sending the
1216    ///   address.
1217    /// - `stop` indicates whether the operation should end with a STOP condition.
1218    /// - `will_continue` indicates whether there is another read operation following this one and
1219    ///   we should not nack the last byte.
1220    /// - `cmd_iterator` is an iterator over the command registers.
1221    async fn read_operation(
1222        &self,
1223        address: I2cAddress,
1224        buffer: &mut [u8],
1225        start: bool,
1226        stop: bool,
1227        will_continue: bool,
1228        deadline: Deadline,
1229    ) -> Result<(), Error> {
1230        address.validate()?;
1231        self.reset_before_transmission();
1232
1233        // Short circuit for zero length reads as that would be an invalid operation
1234        // read lengths in the TRM (at least for ESP32-S3) are 1-255
1235        if buffer.is_empty() {
1236            return Ok(());
1237        }
1238
1239        let deadline =
1240            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
1241        self.wait_for_completion(deadline).await?;
1242        self.read_all_from_fifo(buffer)?;
1243
1244        Ok(())
1245    }
1246
1247    fn read_blocking(
1248        &self,
1249        address: I2cAddress,
1250        buffer: &mut [u8],
1251        start: bool,
1252        stop: bool,
1253        will_continue: bool,
1254        deadline: Deadline,
1255    ) -> Result<(), Error> {
1256        let chunk_count = VariableChunkIterMut::new(buffer).count();
1257        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
1258            self.read_operation_blocking(
1259                address,
1260                chunk,
1261                start && idx == 0,
1262                stop && idx == chunk_count - 1,
1263                will_continue || idx < chunk_count - 1,
1264                deadline,
1265            )?;
1266        }
1267
1268        Ok(())
1269    }
1270
1271    fn write_blocking(
1272        &self,
1273        address: I2cAddress,
1274        buffer: &[u8],
1275        start: bool,
1276        stop: bool,
1277        deadline: Deadline,
1278    ) -> Result<(), Error> {
1279        if buffer.is_empty() {
1280            return self.write_operation_blocking(address, &[], start, stop, deadline);
1281        }
1282
1283        let chunk_count = VariableChunkIter::new(buffer).count();
1284        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
1285            self.write_operation_blocking(
1286                address,
1287                chunk,
1288                start && idx == 0,
1289                stop && idx == chunk_count - 1,
1290                deadline,
1291            )?;
1292        }
1293
1294        Ok(())
1295    }
1296
1297    async fn read(
1298        &self,
1299        address: I2cAddress,
1300        buffer: &mut [u8],
1301        start: bool,
1302        stop: bool,
1303        will_continue: bool,
1304        deadline: Deadline,
1305    ) -> Result<(), Error> {
1306        let chunk_count = VariableChunkIterMut::new(buffer).count();
1307        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
1308            self.read_operation(
1309                address,
1310                chunk,
1311                start && idx == 0,
1312                stop && idx == chunk_count - 1,
1313                will_continue || idx < chunk_count - 1,
1314                deadline,
1315            )
1316            .await?;
1317        }
1318
1319        Ok(())
1320    }
1321
1322    async fn write(
1323        &self,
1324        address: I2cAddress,
1325        buffer: &[u8],
1326        start: bool,
1327        stop: bool,
1328        deadline: Deadline,
1329    ) -> Result<(), Error> {
1330        if buffer.is_empty() {
1331            return self
1332                .write_operation(address, &[], start, stop, deadline)
1333                .await;
1334        }
1335
1336        let chunk_count = VariableChunkIter::new(buffer).count();
1337        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
1338            self.write_operation(
1339                address,
1340                chunk,
1341                start && idx == 0,
1342                stop && idx == chunk_count - 1,
1343                deadline,
1344            )
1345            .await?;
1346        }
1347
1348        Ok(())
1349    }
1350
1351    pub(super) fn transaction_impl<'a>(
1352        &self,
1353        address: I2cAddress,
1354        operations: impl Iterator<Item = Operation<'a>>,
1355    ) -> Result<(), Error> {
1356        address.validate()?;
1357        self.ensure_idle_blocking();
1358
1359        let mut deadline = Deadline::None;
1360
1361        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
1362            deadline = Deadline::Fixed(Instant::now() + timeout);
1363        }
1364
1365        let mut last_op: Option<OpKind> = None;
1366        // filter out 0 length read operations
1367        let mut op_iter = operations
1368            .filter(|op| op.is_write() || !op.is_empty())
1369            .peekable();
1370
1371        while let Some(op) = op_iter.next() {
1372            let next_op = op_iter.peek().map(|v| v.kind());
1373            let kind = op.kind();
1374            match op {
1375                Operation::Write(buffer) => {
1376                    // execute a write operation:
1377                    // - issue START/RSTART if op is different from previous
1378                    // - issue STOP if op is the last one
1379                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1380                        deadline = Deadline::PerByte(timeout);
1381                    }
1382                    self.write_blocking(
1383                        address,
1384                        buffer,
1385                        !matches!(last_op, Some(OpKind::Write)),
1386                        next_op.is_none(),
1387                        deadline,
1388                    )?;
1389                }
1390                Operation::Read(buffer) => {
1391                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1392                        deadline = Deadline::PerByte(timeout);
1393                    }
1394                    // execute a read operation:
1395                    // - issue START/RSTART if op is different from previous
1396                    // - issue STOP if op is the last one
1397                    // - will_continue is true if there is another read operation next
1398                    self.read_blocking(
1399                        address,
1400                        buffer,
1401                        !matches!(last_op, Some(OpKind::Read)),
1402                        next_op.is_none(),
1403                        matches!(next_op, Some(OpKind::Read)),
1404                        deadline,
1405                    )?;
1406                }
1407            }
1408
1409            last_op = Some(kind);
1410        }
1411
1412        Ok(())
1413    }
1414
1415    pub(super) async fn transaction_impl_async<'a>(
1416        &self,
1417        address: I2cAddress,
1418        operations: impl Iterator<Item = Operation<'a>>,
1419    ) -> Result<(), Error> {
1420        address.validate()?;
1421        self.ensure_idle().await;
1422
1423        let mut deadline = Deadline::None;
1424
1425        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
1426            deadline = Deadline::Fixed(Instant::now() + timeout);
1427        }
1428
1429        let mut last_op: Option<OpKind> = None;
1430        // filter out 0 length read operations
1431        let mut op_iter = operations
1432            .filter(|op| op.is_write() || !op.is_empty())
1433            .peekable();
1434
1435        while let Some(op) = op_iter.next() {
1436            let next_op = op_iter.peek().map(|v| v.kind());
1437            let kind = op.kind();
1438            match op {
1439                Operation::Write(buffer) => {
1440                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1441                        deadline = Deadline::PerByte(timeout);
1442                    }
1443                    // execute a write operation:
1444                    // - issue START/RSTART if op is different from previous
1445                    // - issue STOP if op is the last one
1446                    self.write(
1447                        address,
1448                        buffer,
1449                        !matches!(last_op, Some(OpKind::Write)),
1450                        next_op.is_none(),
1451                        deadline,
1452                    )
1453                    .await?;
1454                }
1455                Operation::Read(buffer) => {
1456                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1457                        deadline = Deadline::PerByte(timeout);
1458                    }
1459                    // execute a read operation:
1460                    // - issue START/RSTART if op is different from previous
1461                    // - issue STOP if op is the last one
1462                    // - will_continue is true if there is another read operation next
1463                    self.read(
1464                        address,
1465                        buffer,
1466                        !matches!(last_op, Some(OpKind::Read)),
1467                        next_op.is_none(),
1468                        matches!(next_op, Some(OpKind::Read)),
1469                        deadline,
1470                    )
1471                    .await?;
1472                }
1473            }
1474
1475            last_op = Some(kind);
1476        }
1477
1478        Ok(())
1479    }
1480}
1481
1482/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
1483/// sized smaller than 2
1484struct VariableChunkIterMut<'a, T> {
1485    buffer: &'a mut [T],
1486}
1487
1488impl<'a, T> VariableChunkIterMut<'a, T> {
1489    fn new(buffer: &'a mut [T]) -> Self {
1490        Self { buffer }
1491    }
1492}
1493
1494impl<'a, T> Iterator for VariableChunkIterMut<'a, T> {
1495    type Item = &'a mut [T];
1496
1497    fn next(&mut self) -> Option<Self::Item> {
1498        if self.buffer.is_empty() {
1499            return None;
1500        }
1501
1502        let s = calculate_chunk_size(self.buffer.len());
1503        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at_mut(s);
1504        self.buffer = remaining;
1505        Some(chunk)
1506    }
1507}
1508
1509/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
1510/// sized smaller than 2
1511struct VariableChunkIter<'a, T> {
1512    buffer: &'a [T],
1513}
1514
1515impl<'a, T> VariableChunkIter<'a, T> {
1516    fn new(buffer: &'a [T]) -> Self {
1517        Self { buffer }
1518    }
1519}
1520
1521impl<'a, T> Iterator for VariableChunkIter<'a, T> {
1522    type Item = &'a [T];
1523
1524    fn next(&mut self) -> Option<Self::Item> {
1525        if self.buffer.is_empty() {
1526            return None;
1527        }
1528
1529        let s = calculate_chunk_size(self.buffer.len());
1530        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at(s);
1531        self.buffer = remaining;
1532        Some(chunk)
1533    }
1534}
1535
1536fn calculate_chunk_size(remaining: usize) -> usize {
1537    if remaining <= I2C_CHUNK_SIZE {
1538        remaining
1539    } else if remaining > I2C_CHUNK_SIZE + 2 {
1540        I2C_CHUNK_SIZE
1541    } else {
1542        I2C_CHUNK_SIZE - 2
1543    }
1544}
1545
1546#[cfg(i2c_master_has_hw_bus_clear)]
1547mod bus_clear {
1548    use esp_rom_sys::rom::ets_delay_us;
1549
1550    use super::*;
1551
1552    #[must_use = "futures do nothing unless you `.await` or poll them"]
1553    pub struct ClearBusFuture<'a> {
1554        driver: Driver<'a>,
1555    }
1556
1557    impl<'a> ClearBusFuture<'a> {
1558        // Number of SCL pulses to clear the bus
1559        const BUS_CLEAR_BITS: u8 = 9;
1560        const DELAY_US: u32 = 5; // 5us -> 100kHz
1561
1562        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
1563            // If we have a HW implementation, reset FSM to make sure it's not trying to transmit
1564            // while we clear the bus.
1565            if reset_fsm {
1566                // Resetting the FSM may still generate a short SCL pulse, but I don't know how to
1567                // work around it - just waiting doesn't solve anything if the hardware is running.
1568                driver.do_fsm_reset();
1569            }
1570
1571            let mut this = Self { driver };
1572
1573            // Prevent SCL from going low immediately after FSM reset/previous operation has set
1574            // it high
1575            ets_delay_us(Self::DELAY_US);
1576
1577            this.configure(Self::BUS_CLEAR_BITS);
1578            this
1579        }
1580
1581        fn configure(&mut self, bits: u8) {
1582            self.driver.regs().scl_sp_conf().modify(|_, w| {
1583                unsafe { w.scl_rst_slv_num().bits(bits) };
1584                w.scl_rst_slv_en().bit(bits > 0)
1585            });
1586            self.driver.update_registers();
1587        }
1588
1589        fn is_done(&self) -> bool {
1590            self.driver
1591                .regs()
1592                .scl_sp_conf()
1593                .read()
1594                .scl_rst_slv_en()
1595                .bit_is_clear()
1596        }
1597
1598        pub fn poll_completion(&mut self) -> Poll<()> {
1599            if self.is_done() {
1600                Poll::Ready(())
1601            } else {
1602                Poll::Pending
1603            }
1604        }
1605    }
1606
1607    impl Drop for ClearBusFuture<'_> {
1608        fn drop(&mut self) {
1609            use crate::gpio::AnyPin;
1610            if !self.is_done() {
1611                self.configure(0);
1612            }
1613
1614            // Generate a stop condition
1615            let sda = self
1616                .driver
1617                .config
1618                .sda_pin
1619                .pin_number()
1620                .map(|n| unsafe { AnyPin::steal(n) });
1621            let scl = self
1622                .driver
1623                .config
1624                .scl_pin
1625                .pin_number()
1626                .map(|n| unsafe { AnyPin::steal(n) });
1627
1628            if let (Some(sda), Some(scl)) = (sda, scl) {
1629                // Prevent short SCL pulse right after HW clearing completes
1630                ets_delay_us(Self::DELAY_US);
1631
1632                sda.set_output_high(true);
1633                scl.set_output_high(false);
1634
1635                self.driver.info.scl_output.disconnect_from(&scl);
1636                self.driver.info.sda_output.disconnect_from(&sda);
1637
1638                // Set SDA low - whatever state it was in, we need a low -> high transition.
1639                sda.set_output_high(false);
1640                ets_delay_us(Self::DELAY_US);
1641
1642                // Set SCL high to prepare for STOP condition
1643                scl.set_output_high(true);
1644                ets_delay_us(Self::DELAY_US);
1645
1646                // STOP
1647                sda.set_output_high(true);
1648                ets_delay_us(Self::DELAY_US);
1649
1650                self.driver.info.sda_output.connect_to(&sda);
1651                self.driver.info.scl_output.connect_to(&scl);
1652            }
1653
1654            // We don't care about errors during bus clearing
1655            self.driver.clear_all_interrupts();
1656        }
1657    }
1658}
1659
1660#[cfg(not(i2c_master_has_hw_bus_clear))]
1661mod bus_clear {
1662    use super::*;
1663    use crate::gpio::AnyPin;
1664
1665    /// State of the bus clearing operation.
1666    ///
1667    /// Pins are changed on the start of the state, and a wait is scheduled
1668    /// for the end of the state. At the end of the wait, the state is
1669    /// updated to the next state.
1670    enum State {
1671        Idle,
1672        SendStop,
1673
1674        // Number of SCL pulses left to send, and the last SCL level.
1675        //
1676        // Our job is to send 9 high->low SCL transitions, followed by a STOP condition.
1677        SendClock(u8, bool),
1678    }
1679
1680    #[must_use = "futures do nothing unless you `.await` or poll them"]
1681    pub struct ClearBusFuture<'a> {
1682        driver: Driver<'a>,
1683        wait: Instant,
1684        state: State,
1685        reset_fsm: bool,
1686        pins: Option<(AnyPin<'static>, AnyPin<'static>)>,
1687    }
1688
1689    impl<'a> ClearBusFuture<'a> {
1690        // Number of SCL pulses to clear the bus (max 8 data bits sent by the device, + NACK)
1691        const BUS_CLEAR_BITS: u8 = 9;
1692        // use standard 100kHz data rate
1693        const SCL_DELAY: Duration = Duration::from_micros(5);
1694
1695        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
1696            let sda = driver
1697                .config
1698                .sda_pin
1699                .pin_number()
1700                .map(|n| unsafe { AnyPin::steal(n) });
1701            let scl = driver
1702                .config
1703                .scl_pin
1704                .pin_number()
1705                .map(|n| unsafe { AnyPin::steal(n) });
1706
1707            let (Some(sda), Some(scl)) = (sda, scl) else {
1708                // If we don't have the pins, we can't clear the bus.
1709                if reset_fsm {
1710                    driver.do_fsm_reset();
1711                }
1712                return Self {
1713                    driver,
1714                    wait: Instant::now(),
1715                    state: State::Idle,
1716                    reset_fsm: false,
1717                    pins: None,
1718                };
1719            };
1720
1721            sda.set_output_high(true);
1722            scl.set_output_high(false);
1723
1724            driver.info.scl_output.disconnect_from(&scl);
1725            driver.info.sda_output.disconnect_from(&sda);
1726
1727            // Starting from (9, false), becase:
1728            // - we start with SCL low
1729            // - a complete SCL cycle consists of a high period and a low period
1730            // - we decrement the remaining counter at the beginning of a cycle, which gives us 9
1731            //   complete SCL cycles.
1732            let state = State::SendClock(Self::BUS_CLEAR_BITS, false);
1733
1734            Self {
1735                driver,
1736                wait: Instant::now() + Self::SCL_DELAY,
1737                state,
1738                reset_fsm,
1739                pins: Some((sda, scl)),
1740            }
1741        }
1742    }
1743
1744    impl ClearBusFuture<'_> {
1745        pub fn poll_completion(&mut self) -> Poll<()> {
1746            let now = Instant::now();
1747
1748            match self.state {
1749                State::Idle => {
1750                    if let Some((sda, _scl)) = self.pins.as_ref() {
1751                        // Pins are disconnected from the peripheral, we can't use `bus_busy`.
1752                        if !sda.is_input_high() {
1753                            return Poll::Pending;
1754                        }
1755                    }
1756                    return Poll::Ready(());
1757                }
1758                _ if now < self.wait => {
1759                    // Still waiting for the end of the SCL pulse
1760                    return Poll::Pending;
1761                }
1762                State::SendStop => {
1763                    if let Some((sda, _scl)) = self.pins.as_ref() {
1764                        sda.set_output_high(true); // STOP, SDA low -> high while SCL is HIGH
1765                    }
1766                    self.state = State::Idle;
1767                    return Poll::Pending;
1768                }
1769                State::SendClock(0, false) => {
1770                    if let Some((sda, scl)) = self.pins.as_ref() {
1771                        // Set up for STOP condition
1772                        sda.set_output_high(false);
1773                        scl.set_output_high(true);
1774                    }
1775                    self.state = State::SendStop;
1776                }
1777                State::SendClock(n, false) => {
1778                    if let Some((sda, scl)) = self.pins.as_ref() {
1779                        scl.set_output_high(true);
1780                        if sda.is_input_high() {
1781                            sda.set_output_high(false);
1782                            // The device has released SDA, we can move on to generating a STOP
1783                            // condition
1784                            self.wait = Instant::now() + Self::SCL_DELAY;
1785                            self.state = State::SendStop;
1786                            return Poll::Pending;
1787                        }
1788                    }
1789                    self.state = State::SendClock(n - 1, true);
1790                }
1791                State::SendClock(n, true) => {
1792                    if let Some((_sda, scl)) = self.pins.as_ref() {
1793                        scl.set_output_high(false);
1794                    }
1795                    self.state = State::SendClock(n, false);
1796                }
1797            }
1798            self.wait = Instant::now() + Self::SCL_DELAY;
1799
1800            Poll::Pending
1801        }
1802    }
1803
1804    impl Drop for ClearBusFuture<'_> {
1805        fn drop(&mut self) {
1806            if let Some((sda, scl)) = self.pins.take() {
1807                // Make sure _we_ release the bus.
1808                scl.set_output_high(true);
1809                sda.set_output_high(true);
1810
1811                // If we don't have a HW implementation, reset the peripheral after clearing the
1812                // bus, but before we reconnect the pins in Drop. This should prevent glitches.
1813                if self.reset_fsm {
1814                    self.driver.do_fsm_reset();
1815                }
1816
1817                self.driver.info.sda_output.connect_to(&sda);
1818                self.driver.info.scl_output.connect_to(&scl);
1819
1820                // We don't care about errors during bus clearing. There shouldn't be any,
1821                // anyway.
1822                self.driver.clear_all_interrupts();
1823            }
1824        }
1825    }
1826}
1827
1828use bus_clear::ClearBusFuture;
1829
1830impl Future for ClearBusFuture<'_> {
1831    type Output = ();
1832
1833    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1834        let pending = self.poll_completion();
1835        if pending.is_pending() {
1836            ctx.waker().wake_by_ref();
1837        }
1838        pending
1839    }
1840}
1841
1842/// Peripheral state for an I2C instance.
1843#[doc(hidden)]
1844#[non_exhaustive]
1845pub struct State {
1846    /// Waker for the asynchronous operations.
1847    pub waker: AtomicWaker,
1848}
1849
1850/// A peripheral singleton compatible with the I2C master driver.
1851pub trait Instance: crate::private::Sealed + any::Degrade {
1852    #[doc(hidden)]
1853    /// Returns the peripheral data and state describing this instance.
1854    fn parts(&self) -> (&Info, &State);
1855
1856    /// Returns the peripheral data describing this instance.
1857    #[doc(hidden)]
1858    #[inline(always)]
1859    fn info(&self) -> &Info {
1860        self.parts().0
1861    }
1862
1863    /// Returns the peripheral state for this instance.
1864    #[doc(hidden)]
1865    #[inline(always)]
1866    fn state(&self) -> &State {
1867        self.parts().1
1868    }
1869}
1870
1871/// Adds a command to the I2C command sequence.
1872///
1873/// Make sure the first command after a FSM reset is a START, otherwise
1874/// the hardware will hang with no timeouts.
1875fn add_cmd<'a, I>(cmd_iterator: &mut I, command: Command) -> Result<(), Error>
1876where
1877    I: Iterator<Item = &'a COMD>,
1878{
1879    let cmd = cmd_iterator.next().ok_or(Error::CommandNumberExceeded)?;
1880
1881    cmd.write(|w| match command {
1882        Command::Start => w.opcode().rstart(),
1883        Command::Stop => w.opcode().stop(),
1884        Command::End => w.opcode().end(),
1885        Command::Write {
1886            ack_exp,
1887            ack_check_en,
1888            length,
1889        } => unsafe {
1890            w.opcode().write();
1891            w.ack_exp().bit(ack_exp == Ack::Nack);
1892            w.ack_check_en().bit(ack_check_en);
1893            w.byte_num().bits(length);
1894            w
1895        },
1896        Command::Read { ack_value, length } => unsafe {
1897            w.opcode().read();
1898            w.ack_value().bit(ack_value == Ack::Nack);
1899            w.byte_num().bits(length);
1900            w
1901        },
1902    });
1903
1904    Ok(())
1905}
1906
1907// Estimate the reason for an acknowledge check failure on a best effort basis.
1908// When in doubt it's better to return `Unknown` than to return a wrong reason.
1909fn estimate_ack_failed_reason(_register_block: &RegisterBlock) -> AcknowledgeCheckFailedReason {
1910    cfg_select! {
1911        i2c_master_can_estimate_nack_reason => {
1912            // this is based on observations rather than documented behavior
1913            if _register_block.fifo_st().read().txfifo_raddr().bits() <= 1 {
1914                AcknowledgeCheckFailedReason::Address
1915            } else {
1916                AcknowledgeCheckFailedReason::Data
1917            }
1918        }
1919        _ => AcknowledgeCheckFailedReason::Unknown,
1920    }
1921}
1922
1923for_each_i2c_master!(
1924    ($id:literal, $inst:ident, $peri:ident, $scl:ident, $sda:ident) => {
1925        impl Instance for crate::peripherals::$inst<'_> {
1926            fn parts(&self) -> (&Info, &State) {
1927                #[handler]
1928                #[ram]
1929                pub(super) fn irq_handler() {
1930                    async_handler(&PERIPHERAL, &STATE);
1931                }
1932
1933                static STATE: State = State {
1934                    waker: AtomicWaker::new(),
1935                };
1936
1937                static PERIPHERAL: Info = Info {
1938                    #[cfg(soc_has_i2c1)]
1939                    id: $id,
1940                    register_block: crate::peripherals::$inst::ptr(),
1941                    peripheral: crate::system::Peripheral::$peri,
1942                    async_handler: irq_handler,
1943                    scl_output: OutputSignal::$scl,
1944                    scl_input: InputSignal::$scl,
1945                    sda_output: OutputSignal::$sda,
1946                    sda_input: InputSignal::$sda,
1947                    clock_instance: paste::paste! { crate::soc::clocks::I2cInstance::[<I2c $id>] },
1948                };
1949                (&PERIPHERAL, &STATE)
1950            }
1951        }
1952    };
1953);
1954
1955crate::any_peripheral! {
1956    /// Any I2C peripheral.
1957    pub peripheral AnyI2c<'d> {
1958        #[cfg(i2c_master_i2c0)]
1959        I2c0(crate::peripherals::I2C0<'d>),
1960        #[cfg(i2c_master_i2c1)]
1961        I2c1(crate::peripherals::I2C1<'d>),
1962    }
1963}
1964
1965impl Instance for AnyI2c<'_> {
1966    fn parts(&self) -> (&Info, &State) {
1967        any::delegate!(self, i2c => { i2c.parts() })
1968    }
1969}
1970
1971impl AnyI2c<'_> {
1972    fn bind_peri_interrupt(&self, handler: InterruptHandler) {
1973        any::delegate!(self, i2c => { i2c.bind_peri_interrupt(handler) })
1974    }
1975
1976    pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
1977        any::delegate!(self, i2c => { i2c.disable_peri_interrupt_on_all_cores() })
1978    }
1979
1980    pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
1981        self.disable_peri_interrupt_on_all_cores();
1982
1983        self.info().enable_listen(EnumSet::all(), false);
1984        self.info().clear_interrupts(EnumSet::all());
1985
1986        self.bind_peri_interrupt(handler);
1987    }
1988}