@@ -663,6 +663,237 @@ macro_rules! impl_port_traditional {
663663 } ;
664664}
665665
666+ #[ macro_export]
667+ macro_rules! impl_port_xmega {
668+ (
669+ enum Ports {
670+ $( $PortName: ident: ( $Port: ty) , ) +
671+ }
672+
673+ $( #[ $pins_attr: meta] ) *
674+ pub struct Pins {
675+ $( $pin: ident: $Pin: ident = ( $PinPort: ty, $PinPortName: ident, $pin_num: expr, $pin_pinctrl_reg: ident) , ) +
676+ }
677+ ) => {
678+ /// Type-alias for a pin type which can represent any concrete pin.
679+ ///
680+ /// Sometimes it is easier to handle pins if they are all of the same type. By default,
681+ /// each pin gets its own distinct type in `avr-hal`, but by
682+ /// [downgrading][avr_hal_generic::port::Pin#downgrading], you can cast them into this
683+ /// "dynamic" type. Do note, however, that using this dynamic type has a runtime cost.
684+ pub type Pin <MODE , PIN = Dynamic > = $crate:: port:: Pin <MODE , PIN >;
685+
686+ $( #[ $pins_attr] ) *
687+ pub struct Pins {
688+ $( pub $pin: Pin <
689+ mode:: Input <mode:: Floating >,
690+ $Pin,
691+ >, ) +
692+ }
693+
694+ impl Pins {
695+ pub fn new(
696+ $( _: $Port, ) +
697+ ) -> Self {
698+ Self {
699+ $( $pin: $crate:: port:: Pin :: new(
700+ $Pin { _private: ( ) , }
701+ ) , ) +
702+ }
703+ }
704+ }
705+
706+ #[ repr( u8 ) ]
707+ pub enum DynamicPort {
708+ $( $PortName, ) +
709+ }
710+
711+ pub struct Dynamic {
712+ port: DynamicPort ,
713+ // We'll store the mask instead of the pin number because this allows much less code to
714+ // be generated for the trait method implementations.
715+ //
716+ // (TODO verify this statement quantitatively? This implementation detail was
717+ // copied from impl_port_traditional, but it makes some things more complicated,
718+ // like accessing PINxCTRL to configure pull-up.
719+ mask: u8 ,
720+ }
721+
722+ impl Dynamic {
723+ fn new( port: DynamicPort , pin_num: u8 ) -> Self {
724+ Self {
725+ port,
726+ mask: 1 << pin_num,
727+ }
728+ }
729+ }
730+
731+ impl $crate:: port:: PinOps for Dynamic {
732+ type Dynamic = Self ;
733+
734+ #[ inline]
735+ fn into_dynamic( self ) -> Self :: Dynamic {
736+ self
737+ }
738+
739+ #[ inline]
740+ unsafe fn out_set( & mut self ) {
741+ match self . port {
742+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . outset. write( |w| {
743+ w. bits( self . mask)
744+ } ) , ) +
745+ }
746+ }
747+
748+ #[ inline]
749+ unsafe fn out_clear( & mut self ) {
750+ match self . port {
751+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . outclr. write( |w| {
752+ w. bits( self . mask)
753+ } ) , ) +
754+ }
755+ }
756+
757+ #[ inline]
758+ unsafe fn out_toggle( & mut self ) {
759+ match self . port {
760+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . outtgl. write( |w| {
761+ w. bits( self . mask)
762+ } ) , ) +
763+ }
764+ }
765+
766+ #[ inline]
767+ unsafe fn out_get( & self ) -> bool {
768+ match self . port {
769+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . out. read( ) . bits( )
770+ & self . mask != 0 , ) +
771+ }
772+ }
773+
774+ #[ inline]
775+ unsafe fn in_get( & self ) -> bool {
776+ match self . port {
777+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . in_. read( ) . bits( )
778+ & self . mask != 0 , ) +
779+ }
780+ }
781+
782+ #[ inline]
783+ unsafe fn make_output( & mut self ) {
784+ match self . port {
785+ $( DynamicPort :: $PortName => ( * <$Port>:: ptr( ) ) . dirset. write( |w| {
786+ w. bits( self . mask)
787+ } ) , ) +
788+ }
789+ }
790+
791+ #[ inline]
792+ unsafe fn make_input( & mut self , pull_up: bool ) {
793+ match self . port {
794+ $( DynamicPort :: $PortName => {
795+ if pull_up {
796+ match self . mask {
797+ 0x01 => ( * <$Port>:: ptr( ) ) . pin0ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
798+ 0x02 => ( * <$Port>:: ptr( ) ) . pin1ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
799+ 0x04 => ( * <$Port>:: ptr( ) ) . pin2ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
800+ 0x08 => ( * <$Port>:: ptr( ) ) . pin3ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
801+ 0x10 => ( * <$Port>:: ptr( ) ) . pin4ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
802+ 0x20 => ( * <$Port>:: ptr( ) ) . pin5ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
803+ 0x40 => ( * <$Port>:: ptr( ) ) . pin6ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
804+ 0x80 => ( * <$Port>:: ptr( ) ) . pin7ctrl. modify( |_, w| w. pullupen( ) . set_bit( ) ) ,
805+ // TODO exhaustive match with an enum?
806+ //_ => unreachable!()
807+ _ => { }
808+ }
809+ } else {
810+ match self . mask {
811+ 0x01 => ( * <$Port>:: ptr( ) ) . pin0ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
812+ 0x02 => ( * <$Port>:: ptr( ) ) . pin1ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
813+ 0x04 => ( * <$Port>:: ptr( ) ) . pin2ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
814+ 0x08 => ( * <$Port>:: ptr( ) ) . pin3ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
815+ 0x10 => ( * <$Port>:: ptr( ) ) . pin4ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
816+ 0x20 => ( * <$Port>:: ptr( ) ) . pin5ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
817+ 0x40 => ( * <$Port>:: ptr( ) ) . pin6ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
818+ 0x80 => ( * <$Port>:: ptr( ) ) . pin7ctrl. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ,
819+ // TODO exhaustive match with an enum?
820+ //_ => unreachable!()
821+ _ => { }
822+ }
823+ }
824+ ( * <$Port>:: ptr( ) ) . dirclr. write( |w| {
825+ w. bits( self . mask)
826+ } ) ;
827+ } ) +
828+ }
829+ }
830+ }
831+
832+ $(
833+ pub struct $Pin {
834+ _private: ( )
835+ }
836+
837+ impl $crate:: port:: PinOps for $Pin {
838+ type Dynamic = Dynamic ;
839+
840+ #[ inline]
841+ fn into_dynamic( self ) -> Self :: Dynamic {
842+ Dynamic :: new( DynamicPort :: $PinPortName, $pin_num)
843+ }
844+
845+ #[ inline]
846+ unsafe fn out_set( & mut self ) {
847+ ( * <$PinPort>:: ptr( ) ) . outset. write( |w| {
848+ w. bits( 1 << $pin_num)
849+ } ) ;
850+ }
851+
852+ #[ inline]
853+ unsafe fn out_clear( & mut self ) {
854+ ( * <$PinPort>:: ptr( ) ) . outclr. write( |w| {
855+ w. bits( 1 << $pin_num)
856+ } ) ;
857+ }
858+
859+ #[ inline]
860+ unsafe fn out_toggle( & mut self ) {
861+ ( * <$PinPort>:: ptr( ) ) . outtgl. write( |w| w. bits( 1 << $pin_num) ) ;
862+ }
863+
864+ #[ inline]
865+ unsafe fn out_get( & self ) -> bool {
866+ ( * <$PinPort>:: ptr( ) ) . out. read( ) . bits( ) & ( 1 << $pin_num) != 0
867+ }
868+
869+ #[ inline]
870+ unsafe fn in_get( & self ) -> bool {
871+ ( * <$PinPort>:: ptr( ) ) . in_. read( ) . bits( ) & ( 1 << $pin_num) != 0
872+ }
873+
874+ #[ inline]
875+ unsafe fn make_output( & mut self ) {
876+ ( * <$PinPort>:: ptr( ) ) . dirset. write( |w| {
877+ w. bits( 1 << $pin_num)
878+ } ) ;
879+ }
880+
881+ #[ inline]
882+ unsafe fn make_input( & mut self , pull_up: bool ) {
883+ if pull_up {
884+ ( * <$PinPort>:: ptr( ) ) . $pin_pinctrl_reg. modify( |_, w| w. pullupen( ) . set_bit( ) ) ;
885+ } else {
886+ ( * <$PinPort>:: ptr( ) ) . $pin_pinctrl_reg. modify( |_, w| w. pullupen( ) . clear_bit( ) ) ;
887+ }
888+ ( * <$PinPort>:: ptr( ) ) . dirclr. write( |w| {
889+ w. bits( 1 << $pin_num)
890+ } ) ;
891+ }
892+ }
893+ ) +
894+ } ;
895+ }
896+
666897#[ macro_export]
667898macro_rules! renamed_pins {
668899 (
0 commit comments