11use core:: ops:: Deref ;
22
33use crate :: gpio;
4- use crate :: i2c :: { Error , NoAcknowledgeSource } ;
4+
55use crate :: pac:: fmpi2c1 as i2c1;
66use crate :: pac:: { self , rcc, RCC } ;
77use crate :: rcc:: { BusClock , Clocks , Enable , Reset } ;
88use fugit:: { HertzU32 as Hertz , RateExtU32 } ;
99use micromath:: F32Ext ;
1010
11+ #[ path = "i2c/common.rs" ]
12+ mod common;
13+ pub use common:: { Address , Error , NoAcknowledgeSource } ;
14+ use common:: { Hal02Operation , Hal1Operation } ;
15+
1116// Old names
1217pub use I2c as FmpI2c ;
1318pub use Mode as FmpMode ;
1419
20+ #[ path = "i2c/hal_02.rs" ]
1521mod hal_02;
22+ #[ path = "i2c/hal_1.rs" ]
1623mod hal_1;
1724
1825type I2cSel = rcc:: dckcfgr2:: FMPI2C1SEL ;
@@ -403,6 +410,83 @@ impl<I2C: Instance> I2c<I2C> {
403410 Ok ( ( ) )
404411 }
405412
413+ /// Sends START and Address for writing
414+ #[ inline( always) ]
415+ fn prepare_write ( & self , addr : Address , datalen : usize ) -> Result < ( ) , Error > {
416+ // Set up current slave address for writing and disable autoending
417+ self . i2c . cr2 ( ) . modify ( |_, w| {
418+ match addr {
419+ Address :: Seven ( addr) => {
420+ w. add10 ( ) . clear_bit ( ) ;
421+ w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
422+ }
423+ Address :: Ten ( addr) => {
424+ w. add10 ( ) . set_bit ( ) ;
425+ w. sadd ( ) . set ( addr) ;
426+ }
427+ }
428+ w. nbytes ( ) . set ( datalen as u8 ) ;
429+ w. rd_wrn ( ) . clear_bit ( ) ;
430+ w. autoend ( ) . clear_bit ( )
431+ } ) ;
432+
433+ // Send a START condition
434+ self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
435+
436+ // Wait until address was sent
437+ while {
438+ let isr = self . i2c . isr ( ) . read ( ) ;
439+ self . check_and_clear_error_flags ( & isr)
440+ . map_err ( Error :: nack_addr) ?;
441+ isr. txis ( ) . bit_is_clear ( ) && isr. tc ( ) . bit_is_clear ( )
442+ } { }
443+
444+ Ok ( ( ) )
445+ }
446+
447+ /// Sends START and Address for reading
448+ fn prepare_read (
449+ & self ,
450+ addr : Address ,
451+ buflen : usize ,
452+ first_transaction : bool ,
453+ ) -> Result < ( ) , Error > {
454+ // Set up current address for reading
455+ self . i2c . cr2 ( ) . modify ( |_, w| {
456+ match addr {
457+ Address :: Seven ( addr) => {
458+ w. add10 ( ) . clear_bit ( ) ;
459+ w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
460+ }
461+ Address :: Ten ( addr) => {
462+ w. add10 ( ) . set_bit ( ) ;
463+ w. head10r ( ) . bit ( !first_transaction) ;
464+ w. sadd ( ) . set ( addr) ;
465+ }
466+ }
467+ w. nbytes ( ) . set ( buflen as u8 ) ;
468+ w. rd_wrn ( ) . set_bit ( )
469+ } ) ;
470+
471+ // Send a START condition
472+ self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
473+
474+ // Send the autoend after setting the start to get a restart
475+ self . i2c . cr2 ( ) . modify ( |_, w| w. autoend ( ) . set_bit ( ) ) ;
476+
477+ Ok ( ( ) )
478+ }
479+
480+ fn write_bytes ( & mut self , bytes : impl Iterator < Item = u8 > ) -> Result < ( ) , Error > {
481+ // Send bytes
482+ for c in bytes {
483+ self . send_byte ( c) ?;
484+ }
485+
486+ // Fallthrough is success
487+ Ok ( ( ) )
488+ }
489+
406490 fn send_byte ( & self , byte : u8 ) -> Result < ( ) , Error > {
407491 // Wait until we're ready for sending
408492 while {
@@ -432,72 +516,38 @@ impl<I2C: Instance> I2c<I2C> {
432516 Ok ( value)
433517 }
434518
435- pub fn read ( & mut self , addr : u8 , buffer : & mut [ u8 ] ) -> Result < ( ) , Error > {
436- // Set up current address for reading
437- self . i2c . cr2 ( ) . modify ( |_, w| {
438- w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
439- w. nbytes ( ) . set ( buffer. len ( ) as u8 ) ;
440- w. rd_wrn ( ) . set_bit ( )
441- } ) ;
442-
443- // Send a START condition
444- self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
445-
446- // Send the autoend after setting the start to get a restart
447- self . i2c . cr2 ( ) . modify ( |_, w| w. autoend ( ) . set_bit ( ) ) ;
448-
449- // Now read in all bytes
450- for c in buffer. iter_mut ( ) {
519+ fn read_bytes ( & mut self , buffer : & mut [ u8 ] ) -> Result < ( ) , Error > {
520+ // Receive bytes into buffer
521+ for c in buffer {
451522 * c = self . recv_byte ( ) ?;
452523 }
453524
454- self . end_transaction ( )
525+ Ok ( ( ) )
455526 }
456527
457- pub fn write ( & mut self , addr : u8 , bytes : & [ u8 ] ) -> Result < ( ) , Error > {
458- // Set up current slave address for writing and enable autoending
459- self . i2c . cr2 ( ) . modify ( |_, w| {
460- w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
461- w. nbytes ( ) . set ( bytes. len ( ) as u8 ) ;
462- w. rd_wrn ( ) . clear_bit ( ) ;
463- w. autoend ( ) . set_bit ( )
464- } ) ;
465-
466- // Send a START condition
467- self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
468-
469- // Send out all individual bytes
470- for c in bytes {
471- self . send_byte ( * c) ?;
472- }
528+ pub fn read ( & mut self , addr : impl Into < Address > , buffer : & mut [ u8 ] ) -> Result < ( ) , Error > {
529+ self . prepare_read ( addr. into ( ) , buffer. len ( ) , true ) ?;
530+ self . read_bytes ( buffer) ?;
473531
474532 self . end_transaction ( )
475533 }
476534
477- pub fn write_read ( & mut self , addr : u8 , bytes : & [ u8 ] , buffer : & mut [ u8 ] ) -> Result < ( ) , Error > {
478- // Set up current slave address for writing and disable autoending
479- self . i2c . cr2 ( ) . modify ( |_, w| {
480- w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
481- w. nbytes ( ) . set ( bytes. len ( ) as u8 ) ;
482- w. rd_wrn ( ) . clear_bit ( ) ;
483- w. autoend ( ) . clear_bit ( )
484- } ) ;
535+ pub fn write ( & mut self , addr : impl Into < Address > , bytes : & [ u8 ] ) -> Result < ( ) , Error > {
536+ self . prepare_write ( addr. into ( ) , bytes. len ( ) ) ?;
537+ self . write_bytes ( bytes. iter ( ) . cloned ( ) ) ?;
485538
486- // Send a START condition
487- self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
488-
489- // Wait until the transmit buffer is empty and there hasn't been any error condition
490- while {
491- let isr = self . i2c . isr ( ) . read ( ) ;
492- self . check_and_clear_error_flags ( & isr)
493- . map_err ( Error :: nack_addr) ?;
494- isr. txis ( ) . bit_is_clear ( ) && isr. tc ( ) . bit_is_clear ( )
495- } { }
539+ self . end_transaction ( )
540+ }
496541
497- // Send out all individual bytes
498- for c in bytes {
499- self . send_byte ( * c) ?;
500- }
542+ pub fn write_read (
543+ & mut self ,
544+ addr : impl Into < Address > ,
545+ bytes : & [ u8 ] ,
546+ buffer : & mut [ u8 ] ,
547+ ) -> Result < ( ) , Error > {
548+ let addr = addr. into ( ) ;
549+ self . prepare_write ( addr, bytes. len ( ) ) ?;
550+ self . write_bytes ( bytes. iter ( ) . cloned ( ) ) ?;
501551
502552 // Wait until data was sent
503553 while {
@@ -507,24 +557,122 @@ impl<I2C: Instance> I2c<I2C> {
507557 isr. tc ( ) . bit_is_clear ( )
508558 } { }
509559
510- // Set up current address for reading
511- self . i2c . cr2 ( ) . modify ( |_, w| {
512- w. sadd ( ) . set ( u16:: from ( addr) << 1 ) ;
513- w. nbytes ( ) . set ( buffer. len ( ) as u8 ) ;
514- w. rd_wrn ( ) . set_bit ( )
515- } ) ;
560+ self . read ( addr, buffer)
561+ }
516562
517- // Send another START condition
518- self . i2c . cr2 ( ) . modify ( |_, w| w. start ( ) . set_bit ( ) ) ;
563+ pub fn transaction < ' a > (
564+ & mut self ,
565+ addr : impl Into < Address > ,
566+ mut ops : impl Iterator < Item = Hal1Operation < ' a > > ,
567+ ) -> Result < ( ) , Error > {
568+ let addr = addr. into ( ) ;
569+ if let Some ( mut prev_op) = ops. next ( ) {
570+ // 1. Generate Start for operation
571+ match & prev_op {
572+ Hal1Operation :: Read ( buf) => self . prepare_read ( addr, buf. len ( ) , true ) ?,
573+ Hal1Operation :: Write ( data) => self . prepare_write ( addr, data. len ( ) ) ?,
574+ } ;
575+
576+ for op in ops {
577+ // 2. Execute previous operations.
578+ match & mut prev_op {
579+ Hal1Operation :: Read ( rb) => self . read_bytes ( rb) ?,
580+ Hal1Operation :: Write ( wb) => self . write_bytes ( wb. iter ( ) . cloned ( ) ) ?,
581+ } ;
582+ // 3. If operation changes type we must generate new start
583+ match ( & prev_op, & op) {
584+ ( Hal1Operation :: Read ( _) , Hal1Operation :: Write ( data) ) => {
585+ self . prepare_write ( addr, data. len ( ) ) ?
586+ }
587+ ( Hal1Operation :: Write ( _) , Hal1Operation :: Read ( buf) ) => {
588+ self . prepare_read ( addr, buf. len ( ) , false ) ?
589+ }
590+ _ => { } // No changes if operation have not changed
591+ }
519592
520- // Send the autoend after setting the start to get a restart
521- self . i2c . cr2 ( ) . modify ( |_ , w| w . autoend ( ) . set_bit ( ) ) ;
593+ prev_op = op ;
594+ }
522595
523- // Now read in all bytes
524- for c in buffer. iter_mut ( ) {
525- * c = self . recv_byte ( ) ?;
596+ // 4. Now, prev_op is last command use methods variations that will generate stop
597+ match prev_op {
598+ Hal1Operation :: Read ( rb) => self . read_bytes ( rb) ?,
599+ Hal1Operation :: Write ( wb) => self . write_bytes ( wb. iter ( ) . cloned ( ) ) ?,
600+ } ;
601+
602+ self . end_transaction ( ) ?;
526603 }
527604
528- self . end_transaction ( )
605+ // Fallthrough is success
606+ Ok ( ( ) )
607+ }
608+
609+ pub fn transaction_slice (
610+ & mut self ,
611+ addr : impl Into < Address > ,
612+ ops_slice : & mut [ Hal1Operation < ' _ > ] ,
613+ ) -> Result < ( ) , Error > {
614+ let addr = addr. into ( ) ;
615+ transaction_impl ! ( self , addr, ops_slice, Hal1Operation ) ;
616+ // Fallthrough is success
617+ Ok ( ( ) )
618+ }
619+
620+ fn transaction_slice_hal_02 (
621+ & mut self ,
622+ addr : impl Into < Address > ,
623+ ops_slice : & mut [ Hal02Operation < ' _ > ] ,
624+ ) -> Result < ( ) , Error > {
625+ let addr = addr. into ( ) ;
626+ transaction_impl ! ( self , addr, ops_slice, Hal02Operation ) ;
627+ // Fallthrough is success
628+ Ok ( ( ) )
529629 }
530630}
631+
632+ macro_rules! transaction_impl {
633+ ( $self: ident, $addr: ident, $ops_slice: ident, $Operation: ident) => {
634+ let i2c = $self;
635+ let addr = $addr;
636+ let mut ops = $ops_slice. iter_mut( ) ;
637+
638+ if let Some ( mut prev_op) = ops. next( ) {
639+ // 1. Generate Start for operation
640+ match & prev_op {
641+ $Operation:: Read ( buf) => i2c. prepare_read( addr, buf. len( ) , true ) ?,
642+ $Operation:: Write ( data) => i2c. prepare_write( addr, data. len( ) ) ?,
643+ } ;
644+
645+ for op in ops {
646+ // 2. Execute previous operations.
647+ match & mut prev_op {
648+ $Operation:: Read ( rb) => i2c. read_bytes( rb) ?,
649+ $Operation:: Write ( wb) => i2c. write_bytes( wb. iter( ) . cloned( ) ) ?,
650+ } ;
651+ // 3. If operation changes type we must generate new start
652+ match ( & prev_op, & op) {
653+ ( $Operation:: Read ( _) , $Operation:: Write ( data) ) => {
654+ i2c. prepare_write( addr, data. len( ) ) ?
655+ }
656+ ( $Operation:: Write ( _) , $Operation:: Read ( buf) ) => {
657+ i2c. prepare_read( addr, buf. len( ) , false ) ?
658+ }
659+ _ => { } // No changes if operation have not changed
660+ }
661+
662+ prev_op = op;
663+ }
664+
665+ // 4. Now, prev_op is last command use methods variations that will generate stop
666+ match prev_op {
667+ $Operation:: Read ( rb) => i2c. read_bytes( rb) ?,
668+ $Operation:: Write ( wb) => i2c. write_bytes( wb. iter( ) . cloned( ) ) ?,
669+ } ;
670+
671+ i2c. end_transaction( ) ?;
672+ }
673+ } ;
674+ }
675+ use transaction_impl;
676+
677+ // Note: implementation is from f0xx-hal
678+ // TODO: check error handling. See https://github.com/stm32-rs/stm32f0xx-hal/pull/95/files
0 commit comments