@@ -378,6 +378,15 @@ impl EntryInterruptEnable {
378378/// `#[interrupt] fn DefaultHandler(..` can be used to override the default interrupt handler. When
379379/// not overridden `DefaultHandler` defaults to an infinite loop.
380380///
381+ /// `#[interrupt(wake_cpu)]` additionally returns the CPU to active mode after the interrupt
382+ /// returns. This cannot be done by naively writing to the status register, as the status register
383+ /// contents are pushed to the stack before an interrupt begins and this value is loaded back into
384+ /// the status register after an interrupt completes, effectively making any changes to the status
385+ /// register within an interrupt temporary.
386+ /// Using the `wake_cpu` variant incurs a delay of two instructions (6 cycles) before the interrupt
387+ /// handler begins.
388+ /// The following status register bits are cleared: SCG1, SCG0, OSC_OFF and CPU_OFF.
389+ ///
381390/// # Properties
382391///
383392/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer
@@ -417,11 +426,21 @@ impl EntryInterruptEnable {
417426pub fn interrupt ( args : TokenStream , input : TokenStream ) -> TokenStream {
418427 let f: ItemFn = syn:: parse ( input) . expect ( "`#[interrupt]` must be applied to a function" ) ;
419428
420- if !args. is_empty ( ) {
421- return parse:: Error :: new ( Span :: call_site ( ) , "this attribute accepts no arguments" )
429+ let maybe_arg = parse_macro_input:: parse :: < Option < Ident > > ( args. clone ( ) ) ;
430+
431+ let wake_cpu = match maybe_arg {
432+ Ok ( None ) => false ,
433+ Ok ( Some ( ident) ) if ident == "wake_cpu" => true ,
434+ Ok ( Some ( _) ) => {
435+ return parse:: Error :: new (
436+ Span :: call_site ( ) ,
437+ "this attribute accepts only 'wake_cpu' as an argument" ,
438+ )
422439 . to_compile_error ( )
423- . into ( ) ;
424- }
440+ . into ( )
441+ }
442+ Err ( e) => return e. into_compile_error ( ) . into ( ) ,
443+ } ;
425444
426445 let fspan = f. sig . span ( ) ;
427446 let ident = f. sig . ident ;
@@ -491,21 +510,46 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
491510 let output = f. sig . output ;
492511 let hash = random_ident ( ) ;
493512 let ident = ident. to_string ( ) ;
494- quote ! (
495- #[ export_name = #ident]
496- #( #attrs) *
497- #unsafety extern "msp430-interrupt" fn #hash( ) {
498- #check
499-
500- #[ inline( always) ]
501- #unsafety fn #hash<' a>( #fn_param) #output {
502- #( #vars) *
503- #( #stmts) *
513+ if wake_cpu {
514+ quote ! (
515+ #[ export_name = #ident]
516+ #( #attrs) *
517+ #[ unsafe ( naked) ]
518+ unsafe extern "msp430-interrupt" fn #hash( ) {
519+ #[ inline( always) ]
520+ #unsafety extern "msp430-interrupt" fn #hash<' a>( #fn_param) #output {
521+ #check
522+ #( #vars) *
523+ #( #stmts) *
524+ }
525+ {
526+ // Clear SCG1, SCG0, OSC_OFF, CPU_OFF in saved copy of SR register on stack
527+ const MASK : u8 = ( 1 <<7 ) + ( 1 <<6 ) + ( 1 <<5 ) + ( 1 <<4 ) ;
528+ core:: arch:: naked_asm!(
529+ "bic.b #{mask}, 0(r1)" ,
530+ "jmp {inner}" ,
531+ inner = sym #hash,
532+ mask = const MASK
533+ ) ;
534+ }
504535 }
505- { #hash( #fn_arg) }
506- }
507- )
508- . into ( )
536+ )
537+ } else {
538+ quote ! (
539+ #[ export_name = #ident]
540+ #( #attrs) *
541+ #unsafety extern "msp430-interrupt" fn #hash( ) {
542+ #check
543+
544+ #[ inline( always) ]
545+ #unsafety fn #hash<' a>( #fn_param) #output {
546+ #( #vars) *
547+ #( #stmts) *
548+ }
549+ { #hash( #fn_arg) }
550+ }
551+ )
552+ } . into ( )
509553 } else {
510554 parse:: Error :: new (
511555 fspan,
0 commit comments