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    /// Used with [`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    /// Listens 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 SDA
549    /// indefinitely. Forces the slave to release the bus by sending 9 clock pulses.
550    fn clear_bus_blocking(&self, reset_fsm: bool) {
551        let mut future = ClearBusFuture::new(*self, reset_fsm);
552        let start = Instant::now();
553        while future.poll_completion().is_pending() {
554            if start.elapsed() > CLEAR_BUS_TIMEOUT_MS {
555                break;
556            }
557        }
558    }
559
560    async fn clear_bus(&self) {
561        let clear_bus = ClearBusFuture::new(*self, true);
562        let start = Instant::now();
563
564        embassy_futures::select::select(clear_bus, async {
565            while start.elapsed() < CLEAR_BUS_TIMEOUT_MS {
566                embassy_futures::yield_now().await;
567            }
568        })
569        .await;
570    }
571
572    pub(super) fn force_scl_low(&self, low: bool) {
573        cfg_select! {
574            i2c_master_has_pd_en => self.set_scl_pd(low),
575            _ => self.force_pin_low(low, self.config.scl_pin.pin_number(), &self.info.scl_output),
576        }
577    }
578
579    pub(super) fn force_sda_low(&self, low: bool) {
580        cfg_select! {
581            i2c_master_has_pd_en => self.set_sda_pd(low),
582            _ => self.force_pin_low(low, self.config.sda_pin.pin_number(), &self.info.sda_output),
583        }
584    }
585
586    /// Restores force_out to open-drain mode for both lines.
587    #[cfg(i2c_master_has_pd_en)]
588    fn restore_force_out(&self) {
589        self.regs().ctr().modify(|_, w| {
590            w.scl_force_out().open_drain();
591            w.sda_force_out().open_drain()
592        });
593        self.update_registers();
594    }
595
596    #[cfg(not(i2c_master_has_pd_en))]
597    fn force_pin_low(
598        &self,
599        low: bool,
600        pin_number: Option<u8>,
601        output_signal: &crate::gpio::OutputSignal,
602    ) {
603        use crate::gpio::AnyPin;
604        let Some(n) = pin_number else { return };
605        let pin = unsafe { AnyPin::steal(n) };
606        if low {
607            pin.set_output_high(false);
608            output_signal.disconnect_from(&pin);
609        } else {
610            output_signal.connect_to(&pin);
611        }
612    }
613
614    /// Sets or clears `scl_pd_en`. Switches `scl_force_out` to direct-output while
615    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
616    /// bits clear.
617    #[cfg(i2c_master_has_pd_en)]
618    fn set_scl_pd(&self, low: bool) {
619        if low {
620            self.regs()
621                .ctr()
622                .modify(|_, w| w.scl_force_out().direct_output());
623        }
624        self.regs()
625            .scl_sp_conf()
626            .modify(|_, w| w.scl_pd_en().bit(low));
627        if !low {
628            let sp = self.regs().scl_sp_conf().read();
629            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
630                self.restore_force_out();
631                return;
632            }
633        }
634        self.update_registers();
635    }
636
637    /// Sets or clears `sda_pd_en`. Switches `sda_force_out` to direct-output while
638    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
639    /// bits clear.
640    #[cfg(i2c_master_has_pd_en)]
641    fn set_sda_pd(&self, low: bool) {
642        if low {
643            self.regs()
644                .ctr()
645                .modify(|_, w| w.sda_force_out().direct_output());
646        }
647        self.regs()
648            .scl_sp_conf()
649            .modify(|_, w| w.sda_pd_en().bit(low));
650        if !low {
651            let sp = self.regs().scl_sp_conf().read();
652            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
653                self.restore_force_out();
654                return;
655            }
656        }
657        self.update_registers();
658    }
659
660    /// Resets the I2C peripheral's command registers.
661    fn reset_command_list(&self) {
662        for cmd in self.regs().comd_iter() {
663            cmd.reset();
664        }
665    }
666
667    /// Configures the I2C peripheral for a write operation.
668    /// - `addr` is the address of the slave device.
669    /// - `bytes` is the data to be sent
670    /// - `start` indicates whether the operation should start by a START condition and sending the
671    ///   address.
672    /// - `stop` indicates whether the operation will end with a STOP condition.
673    /// - `cmd_iterator` is an iterator over the command registers.
674    fn setup_write<'a, I>(
675        &self,
676        addr: I2cAddress,
677        bytes: &[u8],
678        start: bool,
679        stop: bool,
680        cmd_iterator: &mut I,
681    ) -> Result<(), Error>
682    where
683        I: Iterator<Item = &'a COMD>,
684    {
685        // If start is true we need to send the address, too, which takes up a data
686        // byte.
687        let max_len = if start {
688            I2C_CHUNK_SIZE
689        } else {
690            I2C_CHUNK_SIZE + 1
691        };
692        if bytes.len() > max_len {
693            return Err(Error::FifoExceeded);
694        }
695
696        if start {
697            add_cmd(cmd_iterator, Command::Start)?;
698        }
699
700        let write_len = if start { bytes.len() + 1 } else { bytes.len() };
701        // don't issue write if there is no data to write
702        if write_len > 0 {
703            // ESP32 can't alter the position of END, so we need to split the chunk always into
704            // 3-command sequences. Chunking makes sure not to place a 1-byte
705            // command at the end, which would cause an arithmetic underflow.
706            // The sequences we can generate are:
707            // - START-WRITE-STOP
708            // - START-WRITE-END-WRITE-STOP
709            // - START-WRITE-END-(WRITE-WRITE-END)*-WRITE-STOP sequence.
710            if cfg!(i2c_master_version = "1") && !(start || stop) {
711                // Chunks that do not have a START or STOP command need to be split into multiple
712                // commands.
713                add_cmd(
714                    cmd_iterator,
715                    Command::Write {
716                        ack_exp: Ack::Ack,
717                        ack_check_en: true,
718                        length: (write_len as u8) - 1,
719                    },
720                )?;
721                add_cmd(
722                    cmd_iterator,
723                    Command::Write {
724                        ack_exp: Ack::Ack,
725                        ack_check_en: true,
726                        length: 1,
727                    },
728                )?;
729            } else {
730                add_cmd(
731                    cmd_iterator,
732                    Command::Write {
733                        ack_exp: Ack::Ack,
734                        ack_check_en: true,
735                        length: write_len as u8,
736                    },
737                )?;
738            }
739        }
740
741        if start {
742            // Load address and R/W bit into FIFO
743            match addr {
744                I2cAddress::SevenBit(addr) => {
745                    self.write_fifo((addr << 1) | OperationType::Write as u8);
746                }
747            }
748        }
749        for b in bytes {
750            self.write_fifo(*b);
751        }
752
753        Ok(())
754    }
755
756    /// Configures the I2C peripheral for a read operation.
757    /// - `addr` is the address of the slave device.
758    /// - `buffer` is the buffer to store the read data.
759    /// - `start` indicates whether the operation should start by a START condition and sending the
760    ///   address.
761    /// - `stop` indicates whether the operation will end with a STOP condition.
762    /// - `will_continue` indicates whether there is another read operation following this one and
763    ///   the last byte must not be nacked.
764    /// - `cmd_iterator` is an iterator over the command registers.
765    fn setup_read<'a, I>(
766        &self,
767        addr: I2cAddress,
768        buffer: &mut [u8],
769        start: bool,
770        stop: bool,
771        will_continue: bool,
772        cmd_iterator: &mut I,
773    ) -> Result<(), Error>
774    where
775        I: Iterator<Item = &'a COMD>,
776    {
777        if buffer.is_empty() {
778            return Err(Error::ZeroLengthInvalid);
779        }
780        let (max_len, initial_len) = if will_continue {
781            (I2C_CHUNK_SIZE + 1, buffer.len())
782        } else {
783            (I2C_CHUNK_SIZE, buffer.len() - 1)
784        };
785        if buffer.len() > max_len {
786            return Err(Error::FifoExceeded);
787        }
788
789        if start {
790            add_cmd(cmd_iterator, Command::Start)?;
791            // WRITE 7-bit address
792            add_cmd(
793                cmd_iterator,
794                Command::Write {
795                    ack_exp: Ack::Ack,
796                    ack_check_en: true,
797                    length: 1,
798                },
799            )?;
800        }
801
802        if initial_len > 0 {
803            let extra_commands = if cfg!(i2c_master_version = "1") {
804                match (start, will_continue) {
805                    // No chunking (START-WRITE-READ-STOP) or first chunk (START-WRITE-READ-END)
806                    (true, _) => 0,
807                    // Middle chunk - (READ-READ-READ-END)
808                    (false, true) => 2,
809                    // Last chunk - (READ-READ-STOP-END)
810                    (false, false) => 1 - stop as u8,
811                }
812            } else {
813                0
814            };
815
816            add_cmd(
817                cmd_iterator,
818                Command::Read {
819                    ack_value: Ack::Ack,
820                    length: initial_len as u8 - extra_commands,
821                },
822            )?;
823            for _ in 0..extra_commands {
824                add_cmd(
825                    cmd_iterator,
826                    Command::Read {
827                        ack_value: Ack::Ack,
828                        length: 1,
829                    },
830                )?;
831            }
832        }
833
834        if !will_continue {
835            // this is the last read so we need to nack the last byte
836            // READ w/o ACK
837            add_cmd(
838                cmd_iterator,
839                Command::Read {
840                    ack_value: Ack::Nack,
841                    length: 1,
842                },
843            )?;
844        }
845
846        self.update_registers();
847
848        if start {
849            // Load address and R/W bit into FIFO
850            match addr {
851                I2cAddress::SevenBit(addr) => {
852                    self.write_fifo((addr << 1) | OperationType::Read as u8);
853                }
854            }
855        }
856        Ok(())
857    }
858
859    /// Reads from RX FIFO into the given buffer.
860    fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> {
861        if self.regs().sr().read().rxfifo_cnt().bits() < buffer.len() as u8 {
862            return Err(Error::ExecutionIncomplete);
863        }
864
865        // Read bytes from FIFO
866        for byte in buffer.iter_mut() {
867            *byte = self.read_fifo();
868        }
869
870        // The RX FIFO should be empty now. If it is not, it means we queued up reading
871        // more data than we read, which is an error.
872        debug_assert!(self.regs().sr().read().rxfifo_cnt().bits() == 0);
873
874        Ok(())
875    }
876
877    /// Clears all pending interrupts for the I2C peripheral.
878    fn clear_all_interrupts(&self) {
879        self.regs()
880            .int_clr()
881            .write(|w| unsafe { w.bits(property!("i2c_master.ll_intr_mask")) });
882    }
883
884    async fn wait_for_completion(&self, deadline: Option<Instant>) -> Result<(), Error> {
885        I2cFuture::new(Event::TxComplete | Event::EndDetect, *self, deadline).await?;
886        self.check_all_commands_done(deadline).await
887    }
888
889    /// Waits for the completion of an I2C transaction.
890    fn wait_for_completion_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
891        let mut future =
892            I2cFuture::new_blocking(Event::TxComplete | Event::EndDetect, *self, deadline);
893        loop {
894            if let Poll::Ready(result) = future.poll_completion() {
895                result?;
896                return self.check_all_commands_done_blocking(deadline);
897            }
898        }
899    }
900
901    fn all_commands_done(&self, deadline: Option<Instant>) -> Result<bool, Error> {
902        // NOTE: on esp32 executing the end command generates the end_detect interrupt
903        //       but does not seem to clear the done bit! So we don't check the done
904        //       status of an end command
905        let now = if deadline.is_some() {
906            Instant::now()
907        } else {
908            Instant::EPOCH
909        };
910
911        self.check_errors()?;
912
913        for cmd_reg in self.regs().comd_iter() {
914            let cmd = cmd_reg.read();
915
916            // if there is a valid command which is not END, check if it's marked as done
917            if cmd.bits() != 0x0 && !cmd.opcode().is_end() && !cmd.command_done().bit_is_set() {
918                // Let's retry
919                if let Some(deadline) = deadline
920                    && now > deadline
921                {
922                    return Err(Error::ExecutionIncomplete);
923                }
924
925                return Ok(false);
926            }
927
928            // once we hit END or STOP we can break the loop
929            if cmd.opcode().is_end() {
930                break;
931            }
932            if cmd.opcode().is_stop() {
933                #[cfg(i2c_master_version = "1")]
934                // wait for STOP - apparently on ESP32 we otherwise miss the ACK error for an
935                // empty write
936                if self.regs().sr().read().scl_state_last() == 6 {
937                    self.check_errors()?;
938                } else {
939                    continue;
940                }
941                break;
942            }
943        }
944        Ok(true)
945    }
946
947    /// Returns whether all I2C commands have completed execution.
948    fn check_all_commands_done_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
949        // loop until commands are actually done
950        while !self.all_commands_done(deadline)? {}
951        self.check_errors()?;
952
953        Ok(())
954    }
955
956    /// Returns whether all I2C commands have completed execution.
957    async fn check_all_commands_done(&self, deadline: Option<Instant>) -> Result<(), Error> {
958        // loop until commands are actually done
959        while !self.all_commands_done(deadline)? {
960            embassy_futures::yield_now().await;
961        }
962        self.check_errors()?;
963
964        Ok(())
965    }
966
967    /// Checks for I2C transmission errors and handles them.
968    ///
969    /// Inspects specific I2C-related interrupts to detect errors during
970    /// communication, such as timeouts, failed acknowledgments, or arbitration loss.
971    /// If an error is detected, resets the I2C peripheral to clear the error condition
972    /// and returns an appropriate error.
973    fn check_errors(&self) -> Result<(), Error> {
974        let r = self.regs().int_raw().read();
975
976        // Handle error cases
977        if r.nack().bit_is_set() {
978            return Err(Error::AcknowledgeCheckFailed(estimate_ack_failed_reason(
979                self.regs(),
980            )));
981        }
982        if r.arbitration_lost().bit_is_set() {
983            return Err(Error::ArbitrationLost);
984        }
985
986        #[cfg(not(i2c_master_version = "1"))]
987        if r.trans_complete().bit_is_set() && self.regs().sr().read().resp_rec().bit_is_clear() {
988            return Err(Error::AcknowledgeCheckFailed(
989                AcknowledgeCheckFailedReason::Data,
990            ));
991        }
992
993        #[cfg(i2c_master_has_fsm_timeouts)]
994        {
995            if r.scl_st_to().bit_is_set() {
996                return Err(Error::Timeout);
997            }
998            if r.scl_main_st_to().bit_is_set() {
999                return Err(Error::Timeout);
1000            }
1001        }
1002        if r.time_out().bit_is_set() {
1003            return Err(Error::Timeout);
1004        }
1005
1006        Ok(())
1007    }
1008
1009    /// Updates the configuration of the I2C peripheral.
1010    ///
1011    /// Ensures that configuration values, such as clock settings, SDA/SCL filtering,
1012    /// timeouts, and other operational parameters configured in other methods, are
1013    /// propagated to the I2C hardware. This step synchronizes the software-configured
1014    /// settings with the peripheral's internal registers.
1015    fn update_registers(&self) {
1016        // Ensure that the configuration of the peripheral is correctly propagated
1017        // (only necessary for C2, C3, C6, H2 and S3 variant)
1018        #[cfg(i2c_master_has_conf_update)]
1019        self.regs().ctr().modify(|_, w| w.conf_upgate().set_bit());
1020    }
1021
1022    fn set_frequency(&self, config: &Config) -> Result<(), ConfigError> {
1023        version::set_frequency(self, config)
1024    }
1025
1026    fn reset_fifo(&self) {
1027        version::reset_fifo(self);
1028    }
1029
1030    fn read_fifo(&self) -> u8 {
1031        version::read_fifo(self.regs())
1032    }
1033
1034    fn write_fifo(&self, data: u8) {
1035        version::write_fifo(self.regs(), data);
1036    }
1037
1038    /// Starts an I2C transmission.
1039    fn start_transmission(&self) {
1040        // Start transmission
1041        self.regs().ctr().modify(|_, w| w.trans_start().set_bit());
1042    }
1043
1044    fn start_write_operation(
1045        &self,
1046        address: I2cAddress,
1047        buffer: &[u8],
1048        start: bool,
1049        stop: bool,
1050        deadline: Deadline,
1051    ) -> Result<Option<Instant>, Error> {
1052        let cmd_iterator = &mut self.regs().comd_iter();
1053
1054        self.setup_write(address, buffer, start, stop, cmd_iterator)?;
1055
1056        if stop {
1057            add_cmd(cmd_iterator, Command::Stop)?;
1058        }
1059        if !(start && stop) {
1060            // Multi-chunk write, terminate with END. ESP32 TRM suggests a write should work with
1061            // only a STOP at the end, but STOP does not seem to generate a TX_COMPLETE interrupt
1062            // without END.
1063            add_cmd(cmd_iterator, Command::End)?;
1064        }
1065
1066        self.start_transmission();
1067
1068        Ok(deadline.start(buffer.len() + address.bytes()))
1069    }
1070
1071    /// Executes an I2C read operation.
1072    /// - `addr` is the address of the slave device.
1073    /// - `buffer` is the buffer to store the read data.
1074    /// - `start` indicates whether the operation should start by a START condition and sending the
1075    ///   address.
1076    /// - `stop` indicates whether the operation should end with a STOP condition.
1077    /// - `will_continue` indicates whether there is another read operation following this one and
1078    ///   the last byte must not be nacked.
1079    /// - `cmd_iterator` is an iterator over the command registers.
1080    fn start_read_operation(
1081        &self,
1082        address: I2cAddress,
1083        buffer: &mut [u8],
1084        start: bool,
1085        will_continue: bool,
1086        stop: bool,
1087        deadline: Deadline,
1088    ) -> Result<Option<Instant>, Error> {
1089        // We don't support single I2C reads larger than the FIFO. This should be
1090        // enforced by `VariableChunkIterMut` used in `Driver::read` and
1091        // `Driver::read_async`.
1092        debug_assert!(buffer.len() <= I2C_FIFO_SIZE);
1093
1094        let cmd_iterator = &mut self.regs().comd_iter();
1095
1096        self.setup_read(address, buffer, start, stop, will_continue, cmd_iterator)?;
1097
1098        if stop {
1099            add_cmd(cmd_iterator, Command::Stop)?;
1100        }
1101        if !(start && stop) {
1102            // Multi-chunk read, terminate with END. On ESP32, assume same limitation as writes.
1103            add_cmd(cmd_iterator, Command::End)?;
1104        }
1105
1106        self.start_transmission();
1107
1108        Ok(deadline.start(buffer.len() + address.bytes()))
1109    }
1110
1111    /// Executes an I2C write operation.
1112    /// - `addr` is the address of the slave device.
1113    /// - `bytes` is the data to be sent
1114    /// - `start` indicates whether the operation should start by a START condition and sending the
1115    ///   address.
1116    /// - `stop` indicates whether the operation should end with a STOP condition.
1117    /// - `cmd_iterator` is an iterator over the command registers.
1118    fn write_operation_blocking(
1119        &self,
1120        address: I2cAddress,
1121        bytes: &[u8],
1122        start: bool,
1123        stop: bool,
1124        deadline: Deadline,
1125    ) -> Result<(), Error> {
1126        address.validate()?;
1127
1128        self.reset_before_transmission();
1129
1130        // Short circuit for zero length writes without start or end as that would be an
1131        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
1132        if bytes.is_empty() && !start && !stop {
1133            return Ok(());
1134        }
1135
1136        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
1137        self.wait_for_completion_blocking(deadline)?;
1138
1139        Ok(())
1140    }
1141
1142    /// Executes an I2C read operation.
1143    /// - `addr` is the address of the slave device.
1144    /// - `buffer` is the buffer to store the read data.
1145    /// - `start` indicates whether the operation should start by a START condition and sending the
1146    ///   address.
1147    /// - `stop` indicates whether the operation should end with a STOP condition.
1148    /// - `will_continue` indicates whether there is another read operation following this one and
1149    ///   the last byte must not be nacked.
1150    /// - `cmd_iterator` is an iterator over the command registers.
1151    fn read_operation_blocking(
1152        &self,
1153        address: I2cAddress,
1154        buffer: &mut [u8],
1155        start: bool,
1156        stop: bool,
1157        will_continue: bool,
1158        deadline: Deadline,
1159    ) -> Result<(), Error> {
1160        address.validate()?;
1161        self.reset_before_transmission();
1162
1163        // Short circuit for zero length reads as that would be an invalid operation
1164        // read lengths in the TRM (at least for ESP32-S3) are 1-255
1165        if buffer.is_empty() {
1166            return Ok(());
1167        }
1168
1169        let deadline =
1170            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
1171        self.wait_for_completion_blocking(deadline)?;
1172        self.read_all_from_fifo(buffer)?;
1173
1174        Ok(())
1175    }
1176
1177    /// Executes an async I2C write operation.
1178    /// - `addr` is the address of the slave device.
1179    /// - `bytes` is the data to be sent
1180    /// - `start` indicates whether the operation should start by a START condition and sending the
1181    ///   address.
1182    /// - `stop` indicates whether the operation should end with a STOP condition.
1183    /// - `cmd_iterator` is an iterator over the command registers.
1184    async fn write_operation(
1185        &self,
1186        address: I2cAddress,
1187        bytes: &[u8],
1188        start: bool,
1189        stop: bool,
1190        deadline: Deadline,
1191    ) -> Result<(), Error> {
1192        address.validate()?;
1193        self.reset_before_transmission();
1194
1195        // Short circuit for zero length writes without start or end as that would be an
1196        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
1197        if bytes.is_empty() && !start && !stop {
1198            return Ok(());
1199        }
1200
1201        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
1202        self.wait_for_completion(deadline).await?;
1203
1204        Ok(())
1205    }
1206
1207    /// Executes an async I2C read operation.
1208    /// - `addr` is the address of the slave device.
1209    /// - `buffer` is the buffer to store the read data.
1210    /// - `start` indicates whether the operation should start by a START condition and sending the
1211    ///   address.
1212    /// - `stop` indicates whether the operation should end with a STOP condition.
1213    /// - `will_continue` indicates whether there is another read operation following this one and
1214    ///   the last byte must not be nacked.
1215    /// - `cmd_iterator` is an iterator over the command registers.
1216    async fn read_operation(
1217        &self,
1218        address: I2cAddress,
1219        buffer: &mut [u8],
1220        start: bool,
1221        stop: bool,
1222        will_continue: bool,
1223        deadline: Deadline,
1224    ) -> Result<(), Error> {
1225        address.validate()?;
1226        self.reset_before_transmission();
1227
1228        // Short circuit for zero length reads as that would be an invalid operation
1229        // read lengths in the TRM (at least for ESP32-S3) are 1-255
1230        if buffer.is_empty() {
1231            return Ok(());
1232        }
1233
1234        let deadline =
1235            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
1236        self.wait_for_completion(deadline).await?;
1237        self.read_all_from_fifo(buffer)?;
1238
1239        Ok(())
1240    }
1241
1242    fn read_blocking(
1243        &self,
1244        address: I2cAddress,
1245        buffer: &mut [u8],
1246        start: bool,
1247        stop: bool,
1248        will_continue: bool,
1249        deadline: Deadline,
1250    ) -> Result<(), Error> {
1251        let chunk_count = VariableChunkIterMut::new(buffer).count();
1252        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
1253            self.read_operation_blocking(
1254                address,
1255                chunk,
1256                start && idx == 0,
1257                stop && idx == chunk_count - 1,
1258                will_continue || idx < chunk_count - 1,
1259                deadline,
1260            )?;
1261        }
1262
1263        Ok(())
1264    }
1265
1266    fn write_blocking(
1267        &self,
1268        address: I2cAddress,
1269        buffer: &[u8],
1270        start: bool,
1271        stop: bool,
1272        deadline: Deadline,
1273    ) -> Result<(), Error> {
1274        if buffer.is_empty() {
1275            return self.write_operation_blocking(address, &[], start, stop, deadline);
1276        }
1277
1278        let chunk_count = VariableChunkIter::new(buffer).count();
1279        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
1280            self.write_operation_blocking(
1281                address,
1282                chunk,
1283                start && idx == 0,
1284                stop && idx == chunk_count - 1,
1285                deadline,
1286            )?;
1287        }
1288
1289        Ok(())
1290    }
1291
1292    async fn read(
1293        &self,
1294        address: I2cAddress,
1295        buffer: &mut [u8],
1296        start: bool,
1297        stop: bool,
1298        will_continue: bool,
1299        deadline: Deadline,
1300    ) -> Result<(), Error> {
1301        let chunk_count = VariableChunkIterMut::new(buffer).count();
1302        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
1303            self.read_operation(
1304                address,
1305                chunk,
1306                start && idx == 0,
1307                stop && idx == chunk_count - 1,
1308                will_continue || idx < chunk_count - 1,
1309                deadline,
1310            )
1311            .await?;
1312        }
1313
1314        Ok(())
1315    }
1316
1317    async fn write(
1318        &self,
1319        address: I2cAddress,
1320        buffer: &[u8],
1321        start: bool,
1322        stop: bool,
1323        deadline: Deadline,
1324    ) -> Result<(), Error> {
1325        if buffer.is_empty() {
1326            return self
1327                .write_operation(address, &[], start, stop, deadline)
1328                .await;
1329        }
1330
1331        let chunk_count = VariableChunkIter::new(buffer).count();
1332        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
1333            self.write_operation(
1334                address,
1335                chunk,
1336                start && idx == 0,
1337                stop && idx == chunk_count - 1,
1338                deadline,
1339            )
1340            .await?;
1341        }
1342
1343        Ok(())
1344    }
1345
1346    pub(super) fn transaction_impl<'a>(
1347        &self,
1348        address: I2cAddress,
1349        operations: impl Iterator<Item = Operation<'a>>,
1350    ) -> Result<(), Error> {
1351        address.validate()?;
1352        self.ensure_idle_blocking();
1353
1354        let mut deadline = Deadline::None;
1355
1356        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
1357            deadline = Deadline::Fixed(Instant::now() + timeout);
1358        }
1359
1360        let mut last_op: Option<OpKind> = None;
1361        // filter out 0 length read operations
1362        let mut op_iter = operations
1363            .filter(|op| op.is_write() || !op.is_empty())
1364            .peekable();
1365
1366        while let Some(op) = op_iter.next() {
1367            let next_op = op_iter.peek().map(|v| v.kind());
1368            let kind = op.kind();
1369            match op {
1370                Operation::Write(buffer) => {
1371                    // execute a write operation:
1372                    // - issue START/RSTART if op is different from previous
1373                    // - issue STOP if op is the last one
1374                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1375                        deadline = Deadline::PerByte(timeout);
1376                    }
1377                    self.write_blocking(
1378                        address,
1379                        buffer,
1380                        !matches!(last_op, Some(OpKind::Write)),
1381                        next_op.is_none(),
1382                        deadline,
1383                    )?;
1384                }
1385                Operation::Read(buffer) => {
1386                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1387                        deadline = Deadline::PerByte(timeout);
1388                    }
1389                    // execute a read operation:
1390                    // - issue START/RSTART if op is different from previous
1391                    // - issue STOP if op is the last one
1392                    // - will_continue is true if there is another read operation next
1393                    self.read_blocking(
1394                        address,
1395                        buffer,
1396                        !matches!(last_op, Some(OpKind::Read)),
1397                        next_op.is_none(),
1398                        matches!(next_op, Some(OpKind::Read)),
1399                        deadline,
1400                    )?;
1401                }
1402            }
1403
1404            last_op = Some(kind);
1405        }
1406
1407        Ok(())
1408    }
1409
1410    pub(super) async fn transaction_impl_async<'a>(
1411        &self,
1412        address: I2cAddress,
1413        operations: impl Iterator<Item = Operation<'a>>,
1414    ) -> Result<(), Error> {
1415        address.validate()?;
1416        self.ensure_idle().await;
1417
1418        let mut deadline = Deadline::None;
1419
1420        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
1421            deadline = Deadline::Fixed(Instant::now() + timeout);
1422        }
1423
1424        let mut last_op: Option<OpKind> = None;
1425        // filter out 0 length read operations
1426        let mut op_iter = operations
1427            .filter(|op| op.is_write() || !op.is_empty())
1428            .peekable();
1429
1430        while let Some(op) = op_iter.next() {
1431            let next_op = op_iter.peek().map(|v| v.kind());
1432            let kind = op.kind();
1433            match op {
1434                Operation::Write(buffer) => {
1435                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1436                        deadline = Deadline::PerByte(timeout);
1437                    }
1438                    // execute a write operation:
1439                    // - issue START/RSTART if op is different from previous
1440                    // - issue STOP if op is the last one
1441                    self.write(
1442                        address,
1443                        buffer,
1444                        !matches!(last_op, Some(OpKind::Write)),
1445                        next_op.is_none(),
1446                        deadline,
1447                    )
1448                    .await?;
1449                }
1450                Operation::Read(buffer) => {
1451                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1452                        deadline = Deadline::PerByte(timeout);
1453                    }
1454                    // execute a read operation:
1455                    // - issue START/RSTART if op is different from previous
1456                    // - issue STOP if op is the last one
1457                    // - will_continue is true if there is another read operation next
1458                    self.read(
1459                        address,
1460                        buffer,
1461                        !matches!(last_op, Some(OpKind::Read)),
1462                        next_op.is_none(),
1463                        matches!(next_op, Some(OpKind::Read)),
1464                        deadline,
1465                    )
1466                    .await?;
1467                }
1468            }
1469
1470            last_op = Some(kind);
1471        }
1472
1473        Ok(())
1474    }
1475}
1476
1477/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
1478/// sized smaller than 2
1479struct VariableChunkIterMut<'a, T> {
1480    buffer: &'a mut [T],
1481}
1482
1483impl<'a, T> VariableChunkIterMut<'a, T> {
1484    fn new(buffer: &'a mut [T]) -> Self {
1485        Self { buffer }
1486    }
1487}
1488
1489impl<'a, T> Iterator for VariableChunkIterMut<'a, T> {
1490    type Item = &'a mut [T];
1491
1492    fn next(&mut self) -> Option<Self::Item> {
1493        if self.buffer.is_empty() {
1494            return None;
1495        }
1496
1497        let s = calculate_chunk_size(self.buffer.len());
1498        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at_mut(s);
1499        self.buffer = remaining;
1500        Some(chunk)
1501    }
1502}
1503
1504/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
1505/// sized smaller than 2
1506struct VariableChunkIter<'a, T> {
1507    buffer: &'a [T],
1508}
1509
1510impl<'a, T> VariableChunkIter<'a, T> {
1511    fn new(buffer: &'a [T]) -> Self {
1512        Self { buffer }
1513    }
1514}
1515
1516impl<'a, T> Iterator for VariableChunkIter<'a, T> {
1517    type Item = &'a [T];
1518
1519    fn next(&mut self) -> Option<Self::Item> {
1520        if self.buffer.is_empty() {
1521            return None;
1522        }
1523
1524        let s = calculate_chunk_size(self.buffer.len());
1525        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at(s);
1526        self.buffer = remaining;
1527        Some(chunk)
1528    }
1529}
1530
1531fn calculate_chunk_size(remaining: usize) -> usize {
1532    if remaining <= I2C_CHUNK_SIZE {
1533        remaining
1534    } else if remaining > I2C_CHUNK_SIZE + 2 {
1535        I2C_CHUNK_SIZE
1536    } else {
1537        I2C_CHUNK_SIZE - 2
1538    }
1539}
1540
1541#[cfg(i2c_master_has_hw_bus_clear)]
1542mod bus_clear {
1543    use esp_rom_sys::rom::ets_delay_us;
1544
1545    use super::*;
1546
1547    #[must_use = "futures do nothing unless you `.await` or poll them"]
1548    pub struct ClearBusFuture<'a> {
1549        driver: Driver<'a>,
1550    }
1551
1552    impl<'a> ClearBusFuture<'a> {
1553        // Number of SCL pulses to clear the bus
1554        const BUS_CLEAR_BITS: u8 = 9;
1555        const DELAY_US: u32 = 5; // 5us -> 100kHz
1556
1557        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
1558            // If we have a HW implementation, reset FSM to make sure it's not trying to transmit
1559            // while we clear the bus.
1560            if reset_fsm {
1561                // Resetting the FSM may still generate a short SCL pulse, but I don't know how to
1562                // work around it - just waiting doesn't solve anything if the hardware is running.
1563                driver.do_fsm_reset();
1564            }
1565
1566            let mut this = Self { driver };
1567
1568            // Prevent SCL from going low immediately after FSM reset/previous operation has set
1569            // it high
1570            ets_delay_us(Self::DELAY_US);
1571
1572            this.configure(Self::BUS_CLEAR_BITS);
1573            this
1574        }
1575
1576        fn configure(&mut self, bits: u8) {
1577            self.driver.regs().scl_sp_conf().modify(|_, w| {
1578                unsafe { w.scl_rst_slv_num().bits(bits) };
1579                w.scl_rst_slv_en().bit(bits > 0)
1580            });
1581            self.driver.update_registers();
1582        }
1583
1584        fn is_done(&self) -> bool {
1585            self.driver
1586                .regs()
1587                .scl_sp_conf()
1588                .read()
1589                .scl_rst_slv_en()
1590                .bit_is_clear()
1591        }
1592
1593        pub fn poll_completion(&mut self) -> Poll<()> {
1594            if self.is_done() {
1595                Poll::Ready(())
1596            } else {
1597                Poll::Pending
1598            }
1599        }
1600    }
1601
1602    impl Drop for ClearBusFuture<'_> {
1603        fn drop(&mut self) {
1604            use crate::gpio::AnyPin;
1605            if !self.is_done() {
1606                self.configure(0);
1607            }
1608
1609            // Generate a stop condition
1610            let sda = self
1611                .driver
1612                .config
1613                .sda_pin
1614                .pin_number()
1615                .map(|n| unsafe { AnyPin::steal(n) });
1616            let scl = self
1617                .driver
1618                .config
1619                .scl_pin
1620                .pin_number()
1621                .map(|n| unsafe { AnyPin::steal(n) });
1622
1623            if let (Some(sda), Some(scl)) = (sda, scl) {
1624                // Prevent short SCL pulse right after HW clearing completes
1625                ets_delay_us(Self::DELAY_US);
1626
1627                sda.set_output_high(true);
1628                scl.set_output_high(false);
1629
1630                self.driver.info.scl_output.disconnect_from(&scl);
1631                self.driver.info.sda_output.disconnect_from(&sda);
1632
1633                // Set SDA low - whatever state it was in, we need a low -> high transition.
1634                sda.set_output_high(false);
1635                ets_delay_us(Self::DELAY_US);
1636
1637                // Set SCL high to prepare for STOP condition
1638                scl.set_output_high(true);
1639                ets_delay_us(Self::DELAY_US);
1640
1641                // STOP
1642                sda.set_output_high(true);
1643                ets_delay_us(Self::DELAY_US);
1644
1645                self.driver.info.sda_output.connect_to(&sda);
1646                self.driver.info.scl_output.connect_to(&scl);
1647            }
1648
1649            // We don't care about errors during bus clearing
1650            self.driver.clear_all_interrupts();
1651        }
1652    }
1653}
1654
1655#[cfg(not(i2c_master_has_hw_bus_clear))]
1656mod bus_clear {
1657    use super::*;
1658    use crate::gpio::AnyPin;
1659
1660    /// State of the bus clearing operation.
1661    ///
1662    /// Pins are changed on the start of the state, and a wait is scheduled
1663    /// for the end of the state. At the end of the wait, the state is
1664    /// updated to the next state.
1665    enum State {
1666        Idle,
1667        SendStop,
1668
1669        // Number of SCL pulses left to send, and the last SCL level.
1670        //
1671        // Our job is to send 9 high->low SCL transitions, followed by a STOP condition.
1672        SendClock(u8, bool),
1673    }
1674
1675    #[must_use = "futures do nothing unless you `.await` or poll them"]
1676    pub struct ClearBusFuture<'a> {
1677        driver: Driver<'a>,
1678        wait: Instant,
1679        state: State,
1680        reset_fsm: bool,
1681        pins: Option<(AnyPin<'static>, AnyPin<'static>)>,
1682    }
1683
1684    impl<'a> ClearBusFuture<'a> {
1685        // Number of SCL pulses to clear the bus (max 8 data bits sent by the device, + NACK)
1686        const BUS_CLEAR_BITS: u8 = 9;
1687        // use standard 100kHz data rate
1688        const SCL_DELAY: Duration = Duration::from_micros(5);
1689
1690        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
1691            let sda = driver
1692                .config
1693                .sda_pin
1694                .pin_number()
1695                .map(|n| unsafe { AnyPin::steal(n) });
1696            let scl = driver
1697                .config
1698                .scl_pin
1699                .pin_number()
1700                .map(|n| unsafe { AnyPin::steal(n) });
1701
1702            let (Some(sda), Some(scl)) = (sda, scl) else {
1703                // If we don't have the pins, we can't clear the bus.
1704                if reset_fsm {
1705                    driver.do_fsm_reset();
1706                }
1707                return Self {
1708                    driver,
1709                    wait: Instant::now(),
1710                    state: State::Idle,
1711                    reset_fsm: false,
1712                    pins: None,
1713                };
1714            };
1715
1716            sda.set_output_high(true);
1717            scl.set_output_high(false);
1718
1719            driver.info.scl_output.disconnect_from(&scl);
1720            driver.info.sda_output.disconnect_from(&sda);
1721
1722            // Starting from (9, false), becase:
1723            // - we start with SCL low
1724            // - a complete SCL cycle consists of a high period and a low period
1725            // - we decrement the remaining counter at the beginning of a cycle, which gives us 9
1726            //   complete SCL cycles.
1727            let state = State::SendClock(Self::BUS_CLEAR_BITS, false);
1728
1729            Self {
1730                driver,
1731                wait: Instant::now() + Self::SCL_DELAY,
1732                state,
1733                reset_fsm,
1734                pins: Some((sda, scl)),
1735            }
1736        }
1737    }
1738
1739    impl ClearBusFuture<'_> {
1740        pub fn poll_completion(&mut self) -> Poll<()> {
1741            let now = Instant::now();
1742
1743            match self.state {
1744                State::Idle => {
1745                    if let Some((sda, _scl)) = self.pins.as_ref() {
1746                        // Pins are disconnected from the peripheral, we can't use `bus_busy`.
1747                        if !sda.is_input_high() {
1748                            return Poll::Pending;
1749                        }
1750                    }
1751                    return Poll::Ready(());
1752                }
1753                _ if now < self.wait => {
1754                    // Still waiting for the end of the SCL pulse
1755                    return Poll::Pending;
1756                }
1757                State::SendStop => {
1758                    if let Some((sda, _scl)) = self.pins.as_ref() {
1759                        sda.set_output_high(true); // STOP, SDA low -> high while SCL is HIGH
1760                    }
1761                    self.state = State::Idle;
1762                    return Poll::Pending;
1763                }
1764                State::SendClock(0, false) => {
1765                    if let Some((sda, scl)) = self.pins.as_ref() {
1766                        // Set up for STOP condition
1767                        sda.set_output_high(false);
1768                        scl.set_output_high(true);
1769                    }
1770                    self.state = State::SendStop;
1771                }
1772                State::SendClock(n, false) => {
1773                    if let Some((sda, scl)) = self.pins.as_ref() {
1774                        scl.set_output_high(true);
1775                        if sda.is_input_high() {
1776                            sda.set_output_high(false);
1777                            // The device has released SDA, we can move on to generating a STOP
1778                            // condition
1779                            self.wait = Instant::now() + Self::SCL_DELAY;
1780                            self.state = State::SendStop;
1781                            return Poll::Pending;
1782                        }
1783                    }
1784                    self.state = State::SendClock(n - 1, true);
1785                }
1786                State::SendClock(n, true) => {
1787                    if let Some((_sda, scl)) = self.pins.as_ref() {
1788                        scl.set_output_high(false);
1789                    }
1790                    self.state = State::SendClock(n, false);
1791                }
1792            }
1793            self.wait = Instant::now() + Self::SCL_DELAY;
1794
1795            Poll::Pending
1796        }
1797    }
1798
1799    impl Drop for ClearBusFuture<'_> {
1800        fn drop(&mut self) {
1801            if let Some((sda, scl)) = self.pins.take() {
1802                // Make sure _we_ release the bus.
1803                scl.set_output_high(true);
1804                sda.set_output_high(true);
1805
1806                // If we don't have a HW implementation, reset the peripheral after clearing the
1807                // bus, but before we reconnect the pins in Drop. This should prevent glitches.
1808                if self.reset_fsm {
1809                    self.driver.do_fsm_reset();
1810                }
1811
1812                self.driver.info.sda_output.connect_to(&sda);
1813                self.driver.info.scl_output.connect_to(&scl);
1814
1815                // We don't care about errors during bus clearing. There shouldn't be any,
1816                // anyway.
1817                self.driver.clear_all_interrupts();
1818            }
1819        }
1820    }
1821}
1822
1823use bus_clear::ClearBusFuture;
1824
1825impl Future for ClearBusFuture<'_> {
1826    type Output = ();
1827
1828    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
1829        let pending = self.poll_completion();
1830        if pending.is_pending() {
1831            ctx.waker().wake_by_ref();
1832        }
1833        pending
1834    }
1835}
1836
1837/// Peripheral state for an I2C instance.
1838#[doc(hidden)]
1839#[non_exhaustive]
1840pub struct State {
1841    /// Waker for the asynchronous operations.
1842    pub waker: AtomicWaker,
1843}
1844
1845/// A peripheral singleton compatible with the I2C master driver.
1846pub trait Instance: crate::private::Sealed + any::Degrade {
1847    #[doc(hidden)]
1848    /// Returns the peripheral data and state describing this instance.
1849    fn parts(&self) -> (&Info, &State);
1850
1851    /// Returns the peripheral data describing this instance.
1852    #[doc(hidden)]
1853    #[inline(always)]
1854    fn info(&self) -> &Info {
1855        self.parts().0
1856    }
1857
1858    /// Returns the peripheral state for this instance.
1859    #[doc(hidden)]
1860    #[inline(always)]
1861    fn state(&self) -> &State {
1862        self.parts().1
1863    }
1864}
1865
1866/// Adds a command to the I2C command sequence.
1867///
1868/// The first command after a FSM reset must be a START, otherwise
1869/// the hardware will hang with no timeouts.
1870fn add_cmd<'a, I>(cmd_iterator: &mut I, command: Command) -> Result<(), Error>
1871where
1872    I: Iterator<Item = &'a COMD>,
1873{
1874    let cmd = cmd_iterator.next().ok_or(Error::CommandNumberExceeded)?;
1875
1876    cmd.write(|w| match command {
1877        Command::Start => w.opcode().rstart(),
1878        Command::Stop => w.opcode().stop(),
1879        Command::End => w.opcode().end(),
1880        Command::Write {
1881            ack_exp,
1882            ack_check_en,
1883            length,
1884        } => unsafe {
1885            w.opcode().write();
1886            w.ack_exp().bit(ack_exp == Ack::Nack);
1887            w.ack_check_en().bit(ack_check_en);
1888            w.byte_num().bits(length);
1889            w
1890        },
1891        Command::Read { ack_value, length } => unsafe {
1892            w.opcode().read();
1893            w.ack_value().bit(ack_value == Ack::Nack);
1894            w.byte_num().bits(length);
1895            w
1896        },
1897    });
1898
1899    Ok(())
1900}
1901
1902// Estimate the reason for an acknowledge check failure on a best effort basis.
1903// When in doubt it's better to return `Unknown` than to return a wrong reason.
1904fn estimate_ack_failed_reason(_register_block: &RegisterBlock) -> AcknowledgeCheckFailedReason {
1905    cfg_select! {
1906        i2c_master_can_estimate_nack_reason => {
1907            // this is based on observations rather than documented behavior
1908            if _register_block.fifo_st().read().txfifo_raddr().bits() <= 1 {
1909                AcknowledgeCheckFailedReason::Address
1910            } else {
1911                AcknowledgeCheckFailedReason::Data
1912            }
1913        }
1914        _ => AcknowledgeCheckFailedReason::Unknown,
1915    }
1916}
1917
1918for_each_i2c_master!(
1919    ($id:literal, $inst:ident, $peri:ident, $scl:ident, $sda:ident) => {
1920        impl Instance for crate::peripherals::$inst<'_> {
1921            fn parts(&self) -> (&Info, &State) {
1922                #[handler]
1923                #[ram]
1924                pub(super) fn irq_handler() {
1925                    async_handler(&PERIPHERAL, &STATE);
1926                }
1927
1928                static STATE: State = State {
1929                    waker: AtomicWaker::new(),
1930                };
1931
1932                static PERIPHERAL: Info = Info {
1933                    #[cfg(soc_has_i2c1)]
1934                    id: $id,
1935                    register_block: crate::peripherals::$inst::ptr(),
1936                    peripheral: crate::system::Peripheral::$peri,
1937                    async_handler: irq_handler,
1938                    scl_output: OutputSignal::$scl,
1939                    scl_input: InputSignal::$scl,
1940                    sda_output: OutputSignal::$sda,
1941                    sda_input: InputSignal::$sda,
1942                    clock_instance: paste::paste! { crate::soc::clocks::I2cInstance::[<I2c $id>] },
1943                };
1944                (&PERIPHERAL, &STATE)
1945            }
1946        }
1947    };
1948);
1949
1950crate::any_peripheral! {
1951    /// Any I2C peripheral.
1952    pub peripheral AnyI2c<'d> {
1953        #[cfg(i2c_master_i2c0)]
1954        I2c0(crate::peripherals::I2C0<'d>),
1955        #[cfg(i2c_master_i2c1)]
1956        I2c1(crate::peripherals::I2C1<'d>),
1957    }
1958}
1959
1960impl Instance for AnyI2c<'_> {
1961    fn parts(&self) -> (&Info, &State) {
1962        any::delegate!(self, i2c => { i2c.parts() })
1963    }
1964}
1965
1966impl AnyI2c<'_> {
1967    fn bind_peri_interrupt(&self, handler: InterruptHandler) {
1968        any::delegate!(self, i2c => { i2c.bind_peri_interrupt(handler) })
1969    }
1970
1971    pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
1972        any::delegate!(self, i2c => { i2c.disable_peri_interrupt_on_all_cores() })
1973    }
1974
1975    pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
1976        self.disable_peri_interrupt_on_all_cores();
1977
1978        self.info().enable_listen(EnumSet::all(), false);
1979        self.info().clear_interrupts(EnumSet::all());
1980
1981        self.bind_peri_interrupt(handler);
1982    }
1983}