@@ -7,6 +7,7 @@ use core::task::Poll;
77
88use embassy_hal_internal:: { Peri , PeripheralType } ;
99use embassy_sync:: waitqueue:: AtomicWaker ;
10+ use embassy_time:: { Duration , Instant } ;
1011use pac:: i2c;
1112
1213use crate :: gpio:: AnyPin ;
@@ -44,6 +45,8 @@ pub enum Error {
4445 /// Target i2c address is reserved
4546 #[ deprecated = "embassy_rp no longer prevents accesses to reserved addresses." ]
4647 AddressReserved ( u16 ) ,
48+ /// Operation timed out
49+ Timeout ,
4750}
4851
4952/// I2C Config error
@@ -74,13 +77,16 @@ pub struct Config {
7477 /// Using external pullup resistors is recommended for I2C. If you do
7578 /// have external pullups you should not enable this.
7679 pub scl_pullup : bool ,
80+ /// Timeout for I2C operations.
81+ pub timeout : Duration ,
7782}
7883impl Default for Config {
7984 fn default ( ) -> Self {
8085 Self {
8186 frequency : 100_000 ,
8287 sda_pullup : true ,
8388 scl_pullup : true ,
89+ timeout : Duration :: from_millis ( 1000 ) ,
8490 }
8591 }
8692}
@@ -91,6 +97,7 @@ pub const FIFO_SIZE: u8 = 16;
9197#[ derive( Debug ) ]
9298pub struct I2c < ' d , T : Instance , M : Mode > {
9399 phantom : PhantomData < ( & ' d mut T , M ) > ,
100+ timeout : Duration ,
94101}
95102
96103impl < ' d , T : Instance > I2c < ' d , T , Blocking > {
@@ -105,6 +112,35 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> {
105112 }
106113}
107114
115+ impl < ' d , T : Instance > I2c < ' d , T , Blocking > {
116+ fn timeout ( & self ) -> Timeout {
117+ Timeout :: new ( self . timeout )
118+ }
119+ }
120+
121+ #[ derive( Copy , Clone ) ]
122+ struct Timeout {
123+ deadline : Instant ,
124+ }
125+
126+ impl Timeout {
127+ #[ inline]
128+ fn new ( duration : Duration ) -> Self {
129+ Self {
130+ deadline : Instant :: now ( ) + duration,
131+ }
132+ }
133+
134+ #[ inline]
135+ fn check ( self ) -> Result < ( ) , Error > {
136+ if Instant :: now ( ) > self . deadline {
137+ return Err ( Error :: Timeout ) ;
138+ }
139+
140+ Ok ( ( ) )
141+ }
142+ }
143+
108144impl < ' d , T : Instance > I2c < ' d , T , Async > {
109145 /// Create a new driver instance in async mode.
110146 pub fn new_async (
@@ -330,7 +366,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
330366 /// Read from address into buffer asynchronously.
331367 pub async fn read_async ( & mut self , addr : impl Into < u16 > , buffer : & mut [ u8 ] ) -> Result < ( ) , Error > {
332368 Self :: setup ( addr. into ( ) ) ?;
333- self . read_async_internal ( buffer, true , true ) . await
369+ match embassy_time:: with_timeout ( self . timeout , self . read_async_internal ( buffer, true , true ) ) . await {
370+ Ok ( result) => result,
371+ Err ( _) => Err ( Error :: Timeout ) ,
372+ }
334373 }
335374
336375 /// Write to address from buffer asynchronously.
@@ -340,7 +379,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
340379 bytes : impl IntoIterator < Item = u8 > ,
341380 ) -> Result < ( ) , Error > {
342381 Self :: setup ( addr. into ( ) ) ?;
343- self . write_async_internal ( bytes, true ) . await
382+ match embassy_time:: with_timeout ( self . timeout , self . write_async_internal ( bytes, true ) ) . await {
383+ Ok ( result) => result,
384+ Err ( _) => Err ( Error :: Timeout ) ,
385+ }
344386 }
345387
346388 /// Write to address from bytes and read from address into buffer asynchronously.
@@ -351,8 +393,18 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
351393 buffer : & mut [ u8 ] ,
352394 ) -> Result < ( ) , Error > {
353395 Self :: setup ( addr. into ( ) ) ?;
354- self . write_async_internal ( bytes, false ) . await ?;
355- self . read_async_internal ( buffer, true , true ) . await
396+
397+ // Apply timeout to the write operation
398+ match embassy_time:: with_timeout ( self . timeout , self . write_async_internal ( bytes, false ) ) . await {
399+ Ok ( result) => result?,
400+ Err ( _) => return Err ( Error :: Timeout ) ,
401+ } ;
402+
403+ // Apply timeout to the read operation
404+ match embassy_time:: with_timeout ( self . timeout , self . read_async_internal ( buffer, true , true ) ) . await {
405+ Ok ( result) => result,
406+ Err ( _) => Err ( Error :: Timeout ) ,
407+ }
356408 }
357409}
358410
@@ -399,7 +451,10 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
399451 set_up_i2c_pin ( & scl, config. scl_pullup ) ;
400452 set_up_i2c_pin ( & sda, config. sda_pullup ) ;
401453
402- let mut me = Self { phantom : PhantomData } ;
454+ let mut me = Self {
455+ phantom : PhantomData ,
456+ timeout : config. timeout ,
457+ } ;
403458
404459 if let Err ( e) = me. set_config_inner ( & config) {
405460 panic ! ( "Error configuring i2c: {:?}" , e) ;
@@ -529,6 +584,8 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
529584 }
530585
531586 fn read_blocking_internal ( & mut self , read : & mut [ u8 ] , restart : bool , send_stop : bool ) -> Result < ( ) , Error > {
587+ let timeout = Timeout :: new ( self . timeout ) ;
588+
532589 if read. is_empty ( ) {
533590 return Err ( Error :: InvalidReadBufferLength ) ;
534591 }
@@ -540,7 +597,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
540597 let last = i == lastindex;
541598
542599 // wait until there is space in the FIFO to write the next byte
543- while Self :: tx_fifo_full ( ) { }
600+ while Self :: tx_fifo_full ( ) {
601+ timeout. check ( ) ?;
602+ }
544603
545604 p. ic_data_cmd ( ) . write ( |w| {
546605 w. set_restart ( restart && first) ;
@@ -550,6 +609,7 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
550609 } ) ;
551610
552611 while Self :: rx_fifo_len ( ) == 0 {
612+ timeout. check ( ) ?;
553613 self . read_and_clear_abort_reason ( ) ?;
554614 }
555615
@@ -560,6 +620,8 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
560620 }
561621
562622 fn write_blocking_internal ( & mut self , write : & [ u8 ] , send_stop : bool ) -> Result < ( ) , Error > {
623+ let timeout = Timeout :: new ( self . timeout ) ;
624+
563625 if write. is_empty ( ) {
564626 return Err ( Error :: InvalidWriteBufferLength ) ;
565627 }
@@ -578,15 +640,19 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
578640 // internal shift register has completed. For this to function
579641 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
580642 // TX_EMPTY_CTRL flag was set in i2c_init.
581- while !p. ic_raw_intr_stat ( ) . read ( ) . tx_empty ( ) { }
643+ while !p. ic_raw_intr_stat ( ) . read ( ) . tx_empty ( ) {
644+ timeout. check ( ) ?;
645+ }
582646
583647 let abort_reason = self . read_and_clear_abort_reason ( ) ;
584648
585649 if abort_reason. is_err ( ) || ( send_stop && last) {
586650 // If the transaction was aborted or if it completed
587651 // successfully wait until the STOP condition has occurred.
588652
589- while !p. ic_raw_intr_stat ( ) . read ( ) . stop_det ( ) { }
653+ while !p. ic_raw_intr_stat ( ) . read ( ) . stop_det ( ) {
654+ timeout. check ( ) ?;
655+ }
590656
591657 p. ic_clr_stop_det ( ) . read ( ) . clr_stop_det ( ) ;
592658 }
@@ -658,14 +724,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for
658724 address : u8 ,
659725 operations : & mut [ embedded_hal_02:: blocking:: i2c:: Operation < ' _ > ] ,
660726 ) -> Result < ( ) , Self :: Error > {
727+ let timeout = Timeout :: new ( self . timeout ) ;
728+
661729 Self :: setup ( address. into ( ) ) ?;
662730 for i in 0 ..operations. len ( ) {
663731 let last = i == operations. len ( ) - 1 ;
664732 match & mut operations[ i] {
665733 embedded_hal_02:: blocking:: i2c:: Operation :: Read ( buf) => {
734+ timeout. check ( ) ?;
666735 self . read_blocking_internal ( buf, false , last) ?
667736 }
668- embedded_hal_02:: blocking:: i2c:: Operation :: Write ( buf) => self . write_blocking_internal ( buf, last) ?,
737+ embedded_hal_02:: blocking:: i2c:: Operation :: Write ( buf) => {
738+ timeout. check ( ) ?;
739+ self . write_blocking_internal ( buf, last) ?
740+ }
669741 }
670742 }
671743 Ok ( ( ) )
@@ -686,6 +758,7 @@ impl embedded_hal_1::i2c::Error for Error {
686758 Self :: AddressOutOfRange ( _) => embedded_hal_1:: i2c:: ErrorKind :: Other ,
687759 #[ allow( deprecated) ]
688760 Self :: AddressReserved ( _) => embedded_hal_1:: i2c:: ErrorKind :: Other ,
761+ Self :: Timeout => embedded_hal_1:: i2c:: ErrorKind :: Other ,
689762 }
690763 }
691764}
@@ -712,12 +785,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
712785 address : u8 ,
713786 operations : & mut [ embedded_hal_1:: i2c:: Operation < ' _ > ] ,
714787 ) -> Result < ( ) , Self :: Error > {
788+ let timeout = Timeout :: new ( self . timeout ) ;
789+
715790 Self :: setup ( address. into ( ) ) ?;
716791 for i in 0 ..operations. len ( ) {
717792 let last = i == operations. len ( ) - 1 ;
718793 match & mut operations[ i] {
719- embedded_hal_1:: i2c:: Operation :: Read ( buf) => self . read_blocking_internal ( buf, false , last) ?,
720- embedded_hal_1:: i2c:: Operation :: Write ( buf) => self . write_blocking_internal ( buf, last) ?,
794+ embedded_hal_1:: i2c:: Operation :: Read ( buf) => {
795+ timeout. check ( ) ?;
796+ self . read_blocking_internal ( buf, false , last) ?
797+ }
798+ embedded_hal_1:: i2c:: Operation :: Write ( buf) => {
799+ timeout. check ( ) ?;
800+ self . write_blocking_internal ( buf, last) ?
801+ }
721802 }
722803 }
723804 Ok ( ( ) )
@@ -753,21 +834,30 @@ where
753834 if !operations. is_empty ( ) {
754835 Self :: setup ( addr) ?;
755836 }
756- let mut iterator = operations. iter_mut ( ) ;
757837
758- while let Some ( op) = iterator. next ( ) {
759- let last = iterator. len ( ) == 0 ;
838+ // Apply timeout to the whole transaction
839+ match embassy_time:: with_timeout ( self . timeout , async {
840+ let mut iterator = operations. iter_mut ( ) ;
760841
761- match op {
762- Operation :: Read ( buffer) => {
763- self . read_async_internal ( buffer, false , last) . await ?;
764- }
765- Operation :: Write ( buffer) => {
766- self . write_async_internal ( buffer. iter ( ) . cloned ( ) , last) . await ?;
842+ while let Some ( op) = iterator. next ( ) {
843+ let last = iterator. len ( ) == 0 ;
844+
845+ match op {
846+ Operation :: Read ( buffer) => {
847+ self . read_async_internal ( buffer, false , last) . await ?;
848+ }
849+ Operation :: Write ( buffer) => {
850+ self . write_async_internal ( buffer. iter ( ) . cloned ( ) , last) . await ?;
851+ }
767852 }
768853 }
854+ Ok ( ( ) )
855+ } )
856+ . await
857+ {
858+ Ok ( result) => result,
859+ Err ( _) => Err ( Error :: Timeout ) ,
769860 }
770- Ok ( ( ) )
771861 }
772862}
773863
0 commit comments