@@ -184,6 +184,12 @@ impl I2cAddress {
184184
185185 Ok ( ( ) )
186186 }
187+
188+ fn bytes ( self ) -> usize {
189+ match self {
190+ I2cAddress :: SevenBit ( _) => 1 ,
191+ }
192+ }
187193}
188194
189195impl From < u8 > for I2cAddress {
@@ -1976,12 +1982,14 @@ impl Driver<'_> {
19761982 /// - `bytes` is the data two be sent.
19771983 /// - `start` indicates whether the operation should start by a START condition and sending the
19781984 /// address.
1985+ /// - `stop` indicates whether the operation will end with a STOP condition.
19791986 /// - `cmd_iterator` is an iterator over the command registers.
19801987 fn setup_write < ' a , I > (
19811988 & self ,
19821989 addr : I2cAddress ,
19831990 bytes : & [ u8 ] ,
19841991 start : bool ,
1992+ stop : bool ,
19851993 cmd_iterator : & mut I ,
19861994 ) -> Result < ( ) , Error >
19871995 where
@@ -2005,60 +2013,32 @@ impl Driver<'_> {
20052013 let write_len = if start { bytes. len ( ) + 1 } else { bytes. len ( ) } ;
20062014 // don't issue write if there is no data to write
20072015 if write_len > 0 {
2008- if cfg ! ( any( esp32, esp32s2) ) {
2009- // try to place END at the same index
2010- if write_len < 2 {
2011- add_cmd (
2012- cmd_iterator,
2013- Command :: Write {
2014- ack_exp : Ack :: Ack ,
2015- ack_check_en : true ,
2016- length : write_len as u8 ,
2017- } ,
2018- ) ?;
2019- } else if start {
2020- add_cmd (
2021- cmd_iterator,
2022- Command :: Write {
2023- ack_exp : Ack :: Ack ,
2024- ack_check_en : true ,
2025- length : ( write_len as u8 ) - 1 ,
2026- } ,
2027- ) ?;
2028- add_cmd (
2029- cmd_iterator,
2030- Command :: Write {
2031- ack_exp : Ack :: Ack ,
2032- ack_check_en : true ,
2033- length : 1 ,
2034- } ,
2035- ) ?;
2036- } else {
2037- add_cmd (
2038- cmd_iterator,
2039- Command :: Write {
2040- ack_exp : Ack :: Ack ,
2041- ack_check_en : true ,
2042- length : ( write_len as u8 ) - 2 ,
2043- } ,
2044- ) ?;
2045- add_cmd (
2046- cmd_iterator,
2047- Command :: Write {
2048- ack_exp : Ack :: Ack ,
2049- ack_check_en : true ,
2050- length : 1 ,
2051- } ,
2052- ) ?;
2053- add_cmd (
2054- cmd_iterator,
2055- Command :: Write {
2056- ack_exp : Ack :: Ack ,
2057- ack_check_en : true ,
2058- length : 1 ,
2059- } ,
2060- ) ?;
2061- }
2016+ // ESP32 can't alter the position of END, so we need to split the chunk always into
2017+ // 3-command sequences. Chunking makes sure not to place a 1-byte
2018+ // command at the end, which would cause an arithmetic underflow.
2019+ // The sequences we can generate are:
2020+ // - START-WRITE-STOP
2021+ // - START-WRITE-END-WRITE-STOP
2022+ // - START-WRITE-END-(WRITE-WRITE-END)*-WRITE-STOP sequence.
2023+ if cfg ! ( esp32) && !( start || stop) {
2024+ // Chunks that do not have a START or STOP command need to be split into multiple
2025+ // commands.
2026+ add_cmd (
2027+ cmd_iterator,
2028+ Command :: Write {
2029+ ack_exp : Ack :: Ack ,
2030+ ack_check_en : true ,
2031+ length : ( write_len as u8 ) - 1 ,
2032+ } ,
2033+ ) ?;
2034+ add_cmd (
2035+ cmd_iterator,
2036+ Command :: Write {
2037+ ack_exp : Ack :: Ack ,
2038+ ack_check_en : true ,
2039+ length : 1 ,
2040+ } ,
2041+ ) ?;
20622042 } else {
20632043 add_cmd (
20642044 cmd_iterator,
@@ -2091,6 +2071,7 @@ impl Driver<'_> {
20912071 /// - `buffer` is the buffer to store the read data.
20922072 /// - `start` indicates whether the operation should start by a START condition and sending the
20932073 /// address.
2074+ /// - `stop` indicates whether the operation will end with a STOP condition.
20942075 /// - `will_continue` indicates whether there is another read operation following this one and
20952076 /// we should not nack the last byte.
20962077 /// - `cmd_iterator` is an iterator over the command registers.
@@ -2099,6 +2080,7 @@ impl Driver<'_> {
20992080 addr : I2cAddress ,
21002081 buffer : & mut [ u8 ] ,
21012082 start : bool ,
2083+ stop : bool ,
21022084 will_continue : bool ,
21032085 cmd_iterator : & mut I ,
21042086 ) -> Result < ( ) , Error >
@@ -2119,7 +2101,7 @@ impl Driver<'_> {
21192101
21202102 if start {
21212103 add_cmd ( cmd_iterator, Command :: Start ) ?;
2122- // WRITE command
2104+ // WRITE 7-bit address
21232105 add_cmd (
21242106 cmd_iterator,
21252107 Command :: Write {
@@ -2131,60 +2113,32 @@ impl Driver<'_> {
21312113 }
21322114
21332115 if initial_len > 0 {
2134- if cfg ! ( any( esp32, esp32s2) ) {
2135- // try to place END at the same index
2136- if initial_len < 2 || start {
2137- add_cmd (
2138- cmd_iterator,
2139- Command :: Read {
2140- ack_value : Ack :: Ack ,
2141- length : initial_len as u8 ,
2142- } ,
2143- ) ?;
2144- } else if !will_continue {
2145- add_cmd (
2146- cmd_iterator,
2147- Command :: Read {
2148- ack_value : Ack :: Ack ,
2149- length : ( initial_len as u8 ) - 1 ,
2150- } ,
2151- ) ?;
2152- add_cmd (
2153- cmd_iterator,
2154- Command :: Read {
2155- ack_value : Ack :: Ack ,
2156- length : 1 ,
2157- } ,
2158- ) ?;
2159- } else {
2160- add_cmd (
2161- cmd_iterator,
2162- Command :: Read {
2163- ack_value : Ack :: Ack ,
2164- length : ( initial_len as u8 ) - 2 ,
2165- } ,
2166- ) ?;
2167- add_cmd (
2168- cmd_iterator,
2169- Command :: Read {
2170- ack_value : Ack :: Ack ,
2171- length : 1 ,
2172- } ,
2173- ) ?;
2174- add_cmd (
2175- cmd_iterator,
2176- Command :: Read {
2177- ack_value : Ack :: Ack ,
2178- length : 1 ,
2179- } ,
2180- ) ?;
2116+ let extra_commands = if cfg ! ( esp32) {
2117+ match ( start, will_continue) {
2118+ // No chunking (START-WRITE-READ-STOP) or first chunk (START-WRITE-READ-END)
2119+ ( true , _) => 0 ,
2120+ // Middle chunk - (READ-READ-READ-END)
2121+ ( false , true ) => 2 ,
2122+ // Last chunk - (READ-READ-STOP-END)
2123+ ( false , false ) => 1 - stop as u8 ,
21812124 }
21822125 } else {
2126+ 0
2127+ } ;
2128+
2129+ add_cmd (
2130+ cmd_iterator,
2131+ Command :: Read {
2132+ ack_value : Ack :: Ack ,
2133+ length : initial_len as u8 - extra_commands,
2134+ } ,
2135+ ) ?;
2136+ for _ in 0 ..extra_commands {
21832137 add_cmd (
21842138 cmd_iterator,
21852139 Command :: Read {
21862140 ack_value : Ack :: Ack ,
2187- length : initial_len as u8 ,
2141+ length : 1 ,
21882142 } ,
21892143 ) ?;
21902144 }
@@ -2437,24 +2391,28 @@ impl Driver<'_> {
24372391 fn start_write_operation (
24382392 & self ,
24392393 address : I2cAddress ,
2440- bytes : & [ u8 ] ,
2394+ buffer : & [ u8 ] ,
24412395 start : bool ,
24422396 stop : bool ,
24432397 deadline : Deadline ,
24442398 ) -> Result < Option < Instant > , Error > {
24452399 let cmd_iterator = & mut self . regs ( ) . comd_iter ( ) ;
24462400
2447- self . setup_write ( address, bytes , start, cmd_iterator) ?;
2401+ self . setup_write ( address, buffer , start, stop , cmd_iterator) ?;
24482402
24492403 if stop {
24502404 add_cmd ( cmd_iterator, Command :: Stop ) ?;
2451- } else {
2405+ }
2406+ if !( start && stop) {
2407+ // Multi-chunk write, terminate with END. ESP32 TRM suggests a write should work with
2408+ // only a STOP at the end, but STOP does not seem to generate a TX_COMPLETE interrupt
2409+ // without END.
24522410 add_cmd ( cmd_iterator, Command :: End ) ?;
24532411 }
2412+
24542413 self . start_transmission ( ) ;
2455- let deadline = deadline. start ( bytes. len ( ) + start as usize ) ;
24562414
2457- Ok ( deadline)
2415+ Ok ( deadline. start ( buffer . len ( ) + address . bytes ( ) ) )
24582416 }
24592417
24602418 /// Executes an I2C read operation.
@@ -2482,17 +2440,19 @@ impl Driver<'_> {
24822440
24832441 let cmd_iterator = & mut self . regs ( ) . comd_iter ( ) ;
24842442
2485- self . setup_read ( address, buffer, start, will_continue, cmd_iterator) ?;
2443+ self . setup_read ( address, buffer, start, stop , will_continue, cmd_iterator) ?;
24862444
24872445 if stop {
24882446 add_cmd ( cmd_iterator, Command :: Stop ) ?;
2489- } else {
2447+ }
2448+ if !( start && stop) {
2449+ // Multi-chunk read, terminate with END. On ESP32, assume same limitation as writes.
24902450 add_cmd ( cmd_iterator, Command :: End ) ?;
24912451 }
2452+
24922453 self . start_transmission ( ) ;
2493- let deadline = deadline. start ( buffer. len ( ) + start as usize ) ;
24942454
2495- Ok ( deadline)
2455+ Ok ( deadline. start ( buffer . len ( ) + address . bytes ( ) ) )
24962456 }
24972457
24982458 /// Executes an I2C write operation.
0 commit comments