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