@@ -18,8 +18,8 @@ use crate::target::TWIM1;
1818
1919use crate :: {
2020 gpio:: { Floating , Input , Pin } ,
21- slice_in_ram_or,
22- target_constants:: EASY_DMA_SIZE ,
21+ slice_in_ram , slice_in_ram_or,
22+ target_constants:: { EASY_DMA_SIZE , FORCE_COPY_BUFFER_SIZE } ,
2323} ;
2424
2525pub use twim0:: frequency:: FREQUENCY_A as Frequency ;
@@ -133,7 +133,7 @@ where
133133 while self . 0 . events_lasttx . read ( ) . bits ( ) == 0 { }
134134 self . 0 . events_lasttx . write ( |w| w) ; // reset event
135135
136- // Stop read operation
136+ // Stop write operation
137137 self . 0 . tasks_stop . write ( |w|
138138 // `1` is a valid value to write to task registers.
139139 unsafe { w. bits ( 1 ) } ) ;
@@ -229,7 +229,8 @@ where
229229 /// Write data to an I2C slave, then read data from the slave without
230230 /// triggering a stop condition between the two
231231 ///
232- /// The buffer must have a length of at most 255 bytes.
232+ /// The buffers must have a length of at most 255 bytes on the nRF52832
233+ /// and at most 65535 bytes on the nRF52840.
233234 pub fn write_then_read (
234235 & mut self ,
235236 address : u8 ,
@@ -333,6 +334,122 @@ where
333334 Ok ( ( ) )
334335 }
335336
337+ /// Copy data into RAM and write to an I2C slave, then read data from the slave without
338+ /// triggering a stop condition between the two
339+ ///
340+ /// The read buffer must have a length of at most 255 bytes on the nRF52832
341+ /// and at most 65535 bytes on the nRF52840.
342+ pub fn copy_write_then_read (
343+ & mut self ,
344+ address : u8 ,
345+ tx_buffer : & [ u8 ] ,
346+ rx_buffer : & mut [ u8 ] ,
347+ ) -> Result < ( ) , Error > {
348+ if rx_buffer. len ( ) > EASY_DMA_SIZE {
349+ return Err ( Error :: RxBufferTooLong ) ;
350+ }
351+
352+ // Conservative compiler fence to prevent optimizations that do not
353+ // take in to account actions by DMA. The fence has been placed here,
354+ // before any DMA action has started
355+ compiler_fence ( SeqCst ) ;
356+
357+ self . 0
358+ . address
359+ . write ( |w| unsafe { w. address ( ) . bits ( address) } ) ;
360+
361+ // Set up the DMA read
362+ self . 0 . rxd . ptr . write ( |w|
363+ // We're giving the register a pointer to the stack. Since we're
364+ // waiting for the I2C transaction to end before this stack pointer
365+ // becomes invalid, there's nothing wrong here.
366+ //
367+ // The PTR field is a full 32 bits wide and accepts the full range
368+ // of values.
369+ unsafe { w. ptr ( ) . bits ( rx_buffer. as_mut_ptr ( ) as u32 ) } ) ;
370+ self . 0 . rxd . maxcnt . write ( |w|
371+ // We're giving it the length of the buffer, so no danger of
372+ // accessing invalid memory. We have verified that the length of the
373+ // buffer fits in an `u8`, so the cast to the type of maxcnt
374+ // is also fine.
375+ //
376+ // Note that that nrf52840 maxcnt is a wider
377+ // type than a u8, so we use a `_` cast rather than a `u8` cast.
378+ // The MAXCNT field is thus at least 8 bits wide and accepts the
379+ // full range of values that fit in a `u8`.
380+ unsafe { w. maxcnt ( ) . bits ( rx_buffer. len ( ) as _ ) } ) ;
381+
382+ // Chunk write data
383+ let wr_buffer = & mut [ 0 ; FORCE_COPY_BUFFER_SIZE ] [ ..] ;
384+ for chunk in tx_buffer. chunks ( FORCE_COPY_BUFFER_SIZE ) {
385+ // Copy chunk into RAM
386+ wr_buffer[ ..chunk. len ( ) ] . copy_from_slice ( chunk) ;
387+
388+ // Set up the DMA write
389+ self . 0 . txd . ptr . write ( |w|
390+ // We're giving the register a pointer to the stack. Since we're
391+ // waiting for the I2C transaction to end before this stack pointer
392+ // becomes invalid, there's nothing wrong here.
393+ //
394+ // The PTR field is a full 32 bits wide and accepts the full range
395+ // of values.
396+ unsafe { w. ptr ( ) . bits ( wr_buffer. as_ptr ( ) as u32 ) } ) ;
397+
398+ self . 0 . txd . maxcnt . write ( |w|
399+ // We're giving it the length of the buffer, so no danger of
400+ // accessing invalid memory. We have verified that the length of the
401+ // buffer fits in an `u8`, so the cast to `u8` is also fine.
402+ //
403+ // The MAXCNT field is 8 bits wide and accepts the full range of
404+ // values.
405+ unsafe { w. maxcnt ( ) . bits ( wr_buffer. len ( ) as _ ) } ) ;
406+
407+ // Start write operation
408+ self . 0 . tasks_starttx . write ( |w|
409+ // `1` is a valid value to write to task registers.
410+ unsafe { w. bits ( 1 ) } ) ;
411+
412+ // Wait until write operation is about to end
413+ while self . 0 . events_lasttx . read ( ) . bits ( ) == 0 { }
414+ self . 0 . events_lasttx . write ( |w| w) ; // reset event
415+
416+ // Check for bad writes
417+ if self . 0 . txd . amount . read ( ) . bits ( ) != wr_buffer. len ( ) as u32 {
418+ return Err ( Error :: Transmit ) ;
419+ }
420+ }
421+
422+ // Start read operation
423+ self . 0 . tasks_startrx . write ( |w|
424+ // `1` is a valid value to write to task registers.
425+ unsafe { w. bits ( 1 ) } ) ;
426+
427+ // Wait until read operation is about to end
428+ while self . 0 . events_lastrx . read ( ) . bits ( ) == 0 { }
429+ self . 0 . events_lastrx . write ( |w| w) ; // reset event
430+
431+ // Stop read operation
432+ self . 0 . tasks_stop . write ( |w|
433+ // `1` is a valid value to write to task registers.
434+ unsafe { w. bits ( 1 ) } ) ;
435+
436+ // Wait until total operation has ended
437+ while self . 0 . events_stopped . read ( ) . bits ( ) == 0 { }
438+ self . 0 . events_stopped . write ( |w| w) ; // reset event
439+
440+ // Conservative compiler fence to prevent optimizations that do not
441+ // take in to account actions by DMA. The fence has been placed here,
442+ // after all possible DMA actions have completed
443+ compiler_fence ( SeqCst ) ;
444+
445+ // Check for bad reads
446+ if self . 0 . rxd . amount . read ( ) . bits ( ) != rx_buffer. len ( ) as u32 {
447+ return Err ( Error :: Receive ) ;
448+ }
449+
450+ Ok ( ( ) )
451+ }
452+
336453 /// Return the raw interface to the underlying TWIM peripheral
337454 pub fn free ( self ) -> T {
338455 self . 0
@@ -348,7 +465,16 @@ where
348465 type Error = Error ;
349466
350467 fn write < ' w > ( & mut self , addr : u8 , bytes : & ' w [ u8 ] ) -> Result < ( ) , Error > {
351- self . write ( addr, bytes)
468+ if slice_in_ram ( bytes) {
469+ self . write ( addr, bytes)
470+ } else {
471+ let buf = & mut [ 0 ; FORCE_COPY_BUFFER_SIZE ] [ ..] ;
472+ for chunk in bytes. chunks ( FORCE_COPY_BUFFER_SIZE ) {
473+ buf[ ..chunk. len ( ) ] . copy_from_slice ( chunk) ;
474+ self . write ( addr, & buf[ ..chunk. len ( ) ] ) ?;
475+ }
476+ Ok ( ( ) )
477+ }
352478 }
353479}
354480
@@ -375,11 +501,15 @@ where
375501 bytes : & ' w [ u8 ] ,
376502 buffer : & ' w mut [ u8 ] ,
377503 ) -> Result < ( ) , Error > {
378- self . write_then_read ( addr, bytes, buffer)
504+ if slice_in_ram ( bytes) {
505+ self . write_then_read ( addr, bytes, buffer)
506+ } else {
507+ self . copy_write_then_read ( addr, bytes, buffer)
508+ }
379509 }
380510}
381511
382- /// The pins used by the TWIN peripheral
512+ /// The pins used by the TWIM peripheral
383513///
384514/// Currently, only P0 pins are supported.
385515pub struct Pins {
0 commit comments