1#[cfg(not(lp_io_has_gpio_matrix))]
6use crate::gpio::{LpPin, lp_io::LpFunction};
7#[cfg(not(esp32p4))]
8use crate::peripherals::LPWR;
9use crate::{
10 i2c::lp_i2c::{Error, LpI2c},
11 pac::lp_i2c0::RegisterBlock,
12 peripherals::LP_PERI,
13 time::Rate,
14};
15
16const LP_I2C_FILTER_CYC_NUM_DEF: u8 = 7;
17
18const FIFO_SIZE: usize = property!("lp_i2c_master.fifo_size");
20
21const COMMAND_SLOTS: usize = 8;
23
24#[cfg(not(lp_io_has_gpio_matrix))]
25for_each_lp_function! {
26 (LP_I2C_SDA, $gpio:ident, $af:ident) => {
27 impl super::Sda for crate::peripherals::$gpio<'_> {
28 fn connect_sda(&self) {
29 configure_pad(self, LpFunction::$af);
30 }
31 }
32 };
33 (LP_I2C_SCL, $gpio:ident, $af:ident) => {
34 impl super::Scl for crate::peripherals::$gpio<'_> {
35 fn connect_scl(&self) {
36 configure_pad(self, LpFunction::$af);
37 }
38 }
39 };
40}
41
42enum OperationType {
43 Write = 0,
44 Read = 1,
45}
46
47#[derive(Eq, PartialEq, Copy, Clone)]
48enum Ack {
49 Ack,
50 Nack,
51}
52
53#[derive(Clone, Copy)]
54enum Command {
55 Start,
56 Stop,
57 End,
58 Write {
59 ack_exp: Ack,
61 ack_check_en: bool,
64 length: u8,
67 },
68 Read {
69 ack_value: Ack,
72 length: u8,
75 },
76}
77
78impl From<Command> for u16 {
79 fn from(c: Command) -> u16 {
80 let opcode: u16 = match c {
81 Command::Start => 6,
82 Command::Write { .. } => 1,
83 Command::Stop => 2,
84 Command::Read { .. } => 3,
85 Command::End => 4,
86 };
87
88 let length = match c {
89 Command::Start | Command::Stop | Command::End => 0,
90 Command::Write { length: l, .. } | Command::Read { length: l, .. } => l,
91 };
92
93 let ack_exp = match c {
94 Command::Start | Command::Stop | Command::End | Command::Read { .. } => Ack::Nack,
95 Command::Write { ack_exp: exp, .. } => exp,
96 };
97
98 let ack_check_en = match c {
99 Command::Start | Command::Stop | Command::End | Command::Read { .. } => false,
100 Command::Write {
101 ack_check_en: en, ..
102 } => en,
103 };
104
105 let ack_value = match c {
106 Command::Start | Command::Stop | Command::End | Command::Write { .. } => Ack::Nack,
107 Command::Read { ack_value: ack, .. } => ack,
108 };
109
110 let mut cmd: u16 = length.into();
111
112 if ack_check_en {
113 cmd |= 1 << 8;
114 }
115
116 if ack_exp == Ack::Nack {
117 cmd |= 1 << 9;
118 }
119
120 if ack_value == Ack::Nack {
121 cmd |= 1 << 10;
122 }
123
124 cmd |= opcode << 11;
125
126 cmd
127 }
128}
129
130#[cfg(not(lp_io_has_gpio_matrix))]
143fn configure_pad(pin: &impl LpPin, function: LpFunction) {
144 cfg_select! {
145 esp32c6 => {
146 use crate::peripherals::{LP_IO as LP_GPIO, LP_IO as LP_IO_MUX};
147 }
148 esp32c5 => {
149 use crate::peripherals::{LP_GPIO, LP_IO_MUX};
150 }
151 }
152
153 let ionum = pin.lp_number() as usize;
154
155 cfg_select! {
159 esp32c6 => {
160 LP_GPIO::regs()
161 .out_data_w1ts()
162 .write(|w| unsafe { w.out_data_w1ts().bits(1 << ionum) });
163 }
164 esp32c5 => {
165 LP_GPIO::regs()
166 .out_w1ts()
167 .write(|w| unsafe { w.out_w1ts().bits(1 << ionum) });
168 }
169 }
170
171 LP_GPIO::regs()
173 .pin(ionum)
174 .modify(|_, w| w.pad_driver().set_bit());
175
176 LP_GPIO::regs()
179 .out_enable_w1ts()
180 .write(|w| unsafe { w.enable_w1ts().bits(1 << ionum) });
181
182 LP_IO_MUX::regs().gpio(ionum).modify(|_, w| {
183 w.fun_wpd().clear_bit();
185 w.fun_wpu().set_bit()
187 });
188
189 crate::gpio::lp_io::low_level::set_config(ionum as u8, true, true, function);
190}
191
192impl<'d> LpI2c<'d> {
193 fn regs(&self) -> &RegisterBlock {
194 self.i2c.register_block()
195 }
196
197 pub(super) fn init(&mut self) {
198 self.i2c
200 .register_block()
201 .clk_conf()
202 .modify(|_, w| w.sclk_active().set_bit());
203
204 self.enable(true);
206 self.reset();
207 }
208
209 pub(super) fn configure(&mut self, config: &Config) -> Result<(), ConfigError> {
210 self.select_lp_fast_clock();
211
212 self.i2c.register_block().ctr().write(|w| unsafe {
214 w.bits(0);
216 #[cfg(not(esp32p4))]
218 {
219 w.sda_force_out().set_bit();
220 w.scl_force_out().set_bit();
221 }
222 w.clk_en().set_bit()
224 });
225
226 self.i2c
228 .register_block()
229 .fifo_conf()
230 .modify(|_, w| w.nonfifo_en().clear_bit());
231
232 self.i2c.register_block().ctr().modify(|_, w| {
233 w.tx_lsb_first().clear_bit();
234 w.rx_lsb_first().clear_bit()
235 });
236
237 self.reset_fifo();
238
239 self.select_lp_fast_clock();
240
241 let source_clk = 16_000_000;
245 let bus_freq = config.frequency.as_hz();
246
247 let clkm_div: u32 = source_clk / (bus_freq * 1024) + 1;
248 let sclk_freq: u32 = source_clk / clkm_div;
249 let half_cycle: u32 = sclk_freq / bus_freq / 2;
250
251 let scl_low = half_cycle;
253 let scl_wait_high = if bus_freq >= 80 * 1000 {
258 half_cycle / 2 - 2
259 } else {
260 half_cycle / 4
261 };
262 let scl_high = half_cycle - scl_wait_high;
263 let sda_hold = half_cycle / 4;
264 let sda_sample = half_cycle / 2; let setup = half_cycle;
266 let hold = half_cycle;
267 let tout = (4 * 8 - (5 * half_cycle).leading_zeros()) + 2;
270
271 let scl_low_period = scl_low - 1;
279 let scl_high_period = scl_high;
280 let scl_wait_high_period = scl_wait_high;
281 let sda_hold_time = sda_hold - 1;
283 let sda_sample_time = sda_sample - 1;
284 let scl_rstart_setup_time = setup - 1;
286 let scl_stop_setup_time = setup - 1;
287 let scl_start_hold_time = hold - 1;
289 let scl_stop_hold_time = hold - 1;
290 let time_out_value = tout;
291 let time_out_en = true;
292
293 unsafe {
295 self.i2c.register_block().clk_conf().modify(|_, w| {
296 w.sclk_sel().clear_bit();
297 w.sclk_div_num().bits((clkm_div - 1) as u8)
298 });
299
300 self.i2c
302 .register_block()
303 .scl_low_period()
304 .write(|w| w.scl_low_period().bits(scl_low_period as u16));
305
306 self.i2c.register_block().scl_high_period().write(|w| {
307 w.scl_high_period().bits(scl_high_period as u16);
308 w.scl_wait_high_period().bits(scl_wait_high_period as u8)
309 });
310 self.i2c
312 .register_block()
313 .sda_hold()
314 .write(|w| w.time().bits(sda_hold_time as u16));
315 self.i2c
316 .register_block()
317 .sda_sample()
318 .write(|w| w.time().bits(sda_sample_time as u16));
319
320 self.i2c
322 .register_block()
323 .scl_rstart_setup()
324 .write(|w| w.time().bits(scl_rstart_setup_time as u16));
325 self.i2c
326 .register_block()
327 .scl_stop_setup()
328 .write(|w| w.time().bits(scl_stop_setup_time as u16));
329
330 self.i2c
332 .register_block()
333 .scl_start_hold()
334 .write(|w| w.time().bits(scl_start_hold_time as u16));
335 self.i2c
336 .register_block()
337 .scl_stop_hold()
338 .write(|w| w.time().bits(scl_stop_hold_time as u16));
339
340 self.i2c.register_block().to().write(|w| {
341 w.time_out_en().bit(time_out_en);
342 w.time_out_value().bits(time_out_value.try_into().unwrap())
343 });
344 }
345
346 self.i2c
350 .register_block()
351 .filter_cfg()
352 .modify(|_, w| unsafe { w.sda_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) });
353 self.i2c
354 .register_block()
355 .filter_cfg()
356 .modify(|_, w| unsafe { w.scl_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) });
357
358 self.i2c
359 .register_block()
360 .filter_cfg()
361 .modify(|_, w| w.sda_filter_en().set_bit());
362 self.i2c
363 .register_block()
364 .filter_cfg()
365 .modify(|_, w| w.scl_filter_en().set_bit());
366
367 self.i2c
369 .register_block()
370 .ctr()
371 .modify(|_, w| w.rx_full_ack_level().set_bit());
372
373 self.lp_i2c_update();
375
376 Ok(())
377 }
378
379 pub(super) fn write_bytes(
380 &mut self,
381 address: u8,
382 register: u8,
383 data: &[u8],
384 ) -> Result<(), Error> {
385 self.start_transaction();
386
387 let mut slot = 0;
388 self.write_cmd(&mut slot, Command::Start);
389
390 self.write_fifo((address << 1) | OperationType::Write as u8);
391 self.write_cmd(
392 &mut slot,
393 Command::Write {
394 ack_exp: Ack::Ack,
395 ack_check_en: true,
396 length: 1,
397 },
398 );
399
400 let payload_len = data.len() + 1;
402 let payload = |index: usize| {
403 if index == 0 {
404 register
405 } else {
406 data[index - 1]
407 }
408 };
409
410 let mut fifo_free = FIFO_SIZE - 1;
412 let mut sent = 0;
413
414 while sent < payload_len {
415 let chunk = (payload_len - sent).min(fifo_free);
416 for index in sent..sent + chunk {
417 self.write_fifo(payload(index));
418 }
419 sent += chunk;
420
421 self.write_cmd(
422 &mut slot,
423 Command::Write {
424 ack_exp: Ack::Ack,
425 ack_check_en: true,
426 length: chunk as u8,
427 },
428 );
429 self.write_cmd(
432 &mut slot,
433 if sent == payload_len {
434 Command::Stop
435 } else {
436 Command::End
437 },
438 );
439
440 self.execute()?;
441
442 slot = 0;
443 fifo_free = FIFO_SIZE;
444 }
445
446 Ok(())
447 }
448
449 pub(super) fn read_bytes(
450 &mut self,
451 address: u8,
452 register: u8,
453 data: &mut [u8],
454 ) -> Result<(), Error> {
455 if data.is_empty() {
456 return Ok(());
457 }
458
459 self.start_transaction();
460
461 let mut slot = 0;
462
463 self.write_cmd(&mut slot, Command::Start);
465 self.write_fifo((address << 1) | OperationType::Write as u8);
466 self.write_fifo(register);
467 self.write_cmd(
468 &mut slot,
469 Command::Write {
470 ack_exp: Ack::Ack,
471 ack_check_en: true,
472 length: 2,
473 },
474 );
475
476 self.write_cmd(&mut slot, Command::Start);
478 self.write_fifo((address << 1) | OperationType::Read as u8);
479 self.write_cmd(
480 &mut slot,
481 Command::Write {
482 ack_exp: Ack::Ack,
483 ack_check_en: true,
484 length: 1,
485 },
486 );
487
488 let mut received = 0;
489
490 while received < data.len() {
491 let chunk = (data.len() - received).min(FIFO_SIZE);
492
493 if received + chunk == data.len() {
494 if chunk > 1 {
496 self.write_cmd(
497 &mut slot,
498 Command::Read {
499 ack_value: Ack::Ack,
500 length: (chunk - 1) as u8,
501 },
502 );
503 }
504 self.write_cmd(
505 &mut slot,
506 Command::Read {
507 ack_value: Ack::Nack,
508 length: 1,
509 },
510 );
511 self.write_cmd(&mut slot, Command::Stop);
512 } else {
513 self.write_cmd(
514 &mut slot,
515 Command::Read {
516 ack_value: Ack::Ack,
517 length: chunk as u8,
518 },
519 );
520 self.write_cmd(&mut slot, Command::End);
521 }
522
523 self.execute()?;
524
525 for byte in data[received..received + chunk].iter_mut() {
526 *byte = self.read_fifo();
527 }
528 received += chunk;
529
530 slot = 0;
531 }
532
533 Ok(())
534 }
535
536 fn start_transaction(&self) {
538 if self.regs().sr().read().bus_busy().bit_is_set() {
540 self.regs().ctr().modify(|_, w| w.fsm_rst().set_bit());
541 }
542
543 self.reset_fifo();
544 self.clear_interrupts();
545 }
546
547 fn execute(&self) -> Result<(), Error> {
549 self.lp_i2c_update();
550 self.regs().ctr().modify(|_, w| w.trans_start().set_bit());
551
552 let result = loop {
553 let interrupts = self.regs().int_raw().read();
554
555 if interrupts.nack().bit_is_set() {
556 break Err(Error::AckCheckFailed);
557 } else if interrupts.arbitration_lost().bit_is_set() {
558 break Err(Error::ArbitrationLost);
559 } else if interrupts.time_out().bit_is_set() {
560 break Err(Error::TimeOut);
561 } else if interrupts.trans_complete().bit_is_set()
562 || interrupts.end_detect().bit_is_set()
563 {
564 break Ok(());
565 }
566 };
567
568 self.clear_interrupts();
569
570 result
571 }
572
573 fn clear_interrupts(&self) {
574 self.regs().int_clr().write(|w| {
575 w.nack().clear_bit_by_one();
576 w.arbitration_lost().clear_bit_by_one();
577 w.time_out().clear_bit_by_one();
578 w.trans_complete().clear_bit_by_one();
579 w.end_detect().clear_bit_by_one()
580 });
581 }
582
583 fn write_cmd(&self, slot: &mut usize, command: Command) {
584 debug_assert!(*slot < COMMAND_SLOTS);
585
586 self.regs()
587 .comd(*slot)
588 .write(|w| unsafe { w.command().bits(command.into()) });
589
590 *slot += 1;
591 }
592
593 fn write_fifo(&self, data: u8) {
594 self.regs()
595 .data()
596 .write(|w| unsafe { w.fifo_rdata().bits(data) });
597 }
598
599 fn read_fifo(&self) -> u8 {
600 self.regs().data().read().fifo_rdata().bits()
601 }
602
603 fn lp_i2c_update(&self) {
605 self.i2c
606 .register_block()
607 .ctr()
608 .modify(|_, w| w.conf_upgate().set_bit());
609 }
610
611 fn reset_fifo(&self) {
613 let fifo_conf = self.i2c.register_block().fifo_conf();
614
615 fifo_conf.modify(|_, w| w.tx_fifo_rst().set_bit());
616 fifo_conf.modify(|_, w| w.tx_fifo_rst().clear_bit());
617 fifo_conf.modify(|_, w| w.rx_fifo_rst().set_bit());
618 fifo_conf.modify(|_, w| w.rx_fifo_rst().clear_bit());
619 }
620
621 fn select_lp_fast_clock(&mut self) {
622 cfg_select! {
624 esp32p4 => {
625 LP_PERI::regs()
626 .core_clk_sel()
627 .modify(|_, w| unsafe { w.lp_i2c_clk_sel().bits(0) });
628 }
629 _ => {
630 LPWR::regs()
631 .lpperi()
632 .modify(|_, w| w.lp_i2c_clk_sel().clear_bit());
633 }
634 }
635 }
636
637 pub(super) fn enable(&mut self, enable: bool) {
638 let clk_en = LP_PERI::regs().clk_en();
639 cfg_select! {
640 esp32p4 => clk_en.modify(|_, w| w.ck_en_lp_i2c().bit(enable)),
641 _ => clk_en.modify(|_, w| w.lp_ext_i2c_ck_en().bit(enable)),
642 };
643 }
644 pub(super) fn disable(&mut self) {
645 self.reset();
646 self.enable(false);
647 }
648
649 pub(super) fn reset(&mut self) {
650 let reset_en = LP_PERI::regs().reset_en();
651 cfg_select! {
652 esp32p4 => {
653 reset_en.modify(|_, w| w.rst_en_lp_i2c().set_bit());
654 reset_en.modify(|_, w| w.rst_en_lp_i2c().clear_bit());
655 }
656 _ => {
657 reset_en.modify(|_, w| w.lp_ext_i2c_reset_en().set_bit());
658 reset_en.modify(|_, w| w.lp_ext_i2c_reset_en().clear_bit());
659 }
660 }
661 }
662}
663
664#[derive(Debug, Clone, Copy, PartialEq)]
666#[cfg_attr(feature = "defmt", derive(defmt::Format))]
667#[non_exhaustive]
668pub enum ConfigError {}
669
670#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, procmacros::BuilderLite)]
672#[cfg_attr(feature = "defmt", derive(defmt::Format))]
673#[non_exhaustive]
674pub struct Config {
675 frequency: Rate,
677}
678
679impl Default for Config {
680 fn default() -> Self {
681 Self {
682 frequency: Rate::from_khz(100),
683 }
684 }
685}