@@ -669,3 +669,116 @@ impl SCB {
669
669
}
670
670
}
671
671
}
672
+
673
+ /// System handlers, exceptions with configurable priority
674
+ #[ allow( non_camel_case_types) ]
675
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
676
+ pub enum SystemHandler {
677
+ // NonMaskableInt, // priority is fixed
678
+ // HardFault, // priority is fixed
679
+ /// Memory management interrupt (not present on Cortex-M0 variants)
680
+ #[ cfg( not( armv6m) ) ]
681
+ MemoryManagement ,
682
+
683
+ /// Bus fault interrupt (not present on Cortex-M0 variants)
684
+ #[ cfg( not( armv6m) ) ]
685
+ BusFault ,
686
+
687
+ /// Usage fault interrupt (not present on Cortex-M0 variants)
688
+ #[ cfg( not( armv6m) ) ]
689
+ UsageFault ,
690
+
691
+ /// Secure fault interrupt (only on ARMv8-M)
692
+ #[ cfg( any( armv8m, target_arch = "x86_64" ) ) ]
693
+ SecureFault ,
694
+
695
+ /// SV call interrupt
696
+ SVCall ,
697
+
698
+ // #[cfg(not(armv6m))]
699
+ // DebugMonitor, // unclear whether this has configurable priority
700
+ /// Pend SV interrupt
701
+ PendSV ,
702
+
703
+ /// System Tick interrupt
704
+ SysTick ,
705
+
706
+ // Make this enum extensible
707
+ #[ doc( hidden) ]
708
+ __DO_NOT_MATCH_AGAINST_THIS_VARIANT__,
709
+ }
710
+
711
+ impl SystemHandler {
712
+ fn index ( & self ) -> u8 {
713
+ match * self {
714
+ #[ cfg( not( armv6m) ) ]
715
+ SystemHandler :: MemoryManagement => 4 ,
716
+ #[ cfg( not( armv6m) ) ]
717
+ SystemHandler :: BusFault => 5 ,
718
+ #[ cfg( not( armv6m) ) ]
719
+ SystemHandler :: UsageFault => 6 ,
720
+ #[ cfg( any( armv8m, target_arch = "x86_64" ) ) ]
721
+ SystemHandler :: SecureFault => 7 ,
722
+ SystemHandler :: SVCall => 11 ,
723
+ SystemHandler :: PendSV => 14 ,
724
+ SystemHandler :: SysTick => 15 ,
725
+ SystemHandler :: __DO_NOT_MATCH_AGAINST_THIS_VARIANT__ => unreachable ! ( ) ,
726
+ }
727
+ }
728
+ }
729
+
730
+ impl SCB {
731
+ /// Returns the hardware priority of `system_handler`
732
+ ///
733
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
734
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
735
+ pub fn get_priority ( system_handler : SystemHandler ) -> u8 {
736
+ let index = system_handler. index ( ) ;
737
+
738
+ #[ cfg( not( armv6m) ) ]
739
+ {
740
+ // NOTE(unsafe) atomic read with no side effects
741
+ unsafe { ( * Self :: ptr ( ) ) . shpr [ usize:: from ( index - 4 ) ] . read ( ) }
742
+ }
743
+
744
+ #[ cfg( armv6m) ]
745
+ {
746
+ // NOTE(unsafe) atomic read with no side effects
747
+ let shpr = unsafe { ( * Self :: ptr ( ) ) . shpr [ usize:: from ( ( index - 8 ) / 4 ) ] . read ( ) } ;
748
+ let prio = ( shpr >> ( index % 4 ) ) & 0x000000ff ;
749
+ prio as u8
750
+ }
751
+ }
752
+
753
+ /// Sets the hardware priority of `system_handler` to `prio`
754
+ ///
755
+ /// *NOTE*: Hardware priority does not exactly match logical priority levels. See
756
+ /// [`NVIC.get_priority`](struct.NVIC.html#method.get_priority) for more details.
757
+ ///
758
+ /// On ARMv6-M, updating a system handler priority requires a read-modify-write operation. On
759
+ /// ARMv7-M, the operation is performed in a single, atomic write operation.
760
+ ///
761
+ /// # Unsafety
762
+ ///
763
+ /// Changing priority levels can break priority-based critical sections (see
764
+ /// [`register::basepri`](../register/basepri/index.html)) and compromise memory safety.
765
+ pub unsafe fn set_priority ( & mut self , system_handler : SystemHandler , prio : u8 ) {
766
+ let index = system_handler. index ( ) ;
767
+
768
+ #[ cfg( not( armv6m) ) ]
769
+ {
770
+ self . shpr [ usize:: from ( index - 4 ) ] . write ( prio)
771
+ }
772
+
773
+ #[ cfg( armv6m) ]
774
+ {
775
+ self . shpr [ usize:: from ( ( index - 8 ) / 4 ) ] . modify ( |value| {
776
+ let shift = index % 4 ;
777
+ let mask = 0x000000ff << shift;
778
+ let prio = u32:: from ( prio) << shift;
779
+
780
+ ( value & !mask) | prio
781
+ } ) ;
782
+ }
783
+ }
784
+ }
0 commit comments