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