@@ -378,6 +378,15 @@ impl EntryInterruptEnable {
378
378
/// `#[interrupt] fn DefaultHandler(..` can be used to override the default interrupt handler. When
379
379
/// not overridden `DefaultHandler` defaults to an infinite loop.
380
380
///
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
+ ///
381
390
/// # Properties
382
391
///
383
392
/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer
@@ -417,11 +426,21 @@ impl EntryInterruptEnable {
417
426
pub fn interrupt ( args : TokenStream , input : TokenStream ) -> TokenStream {
418
427
let f: ItemFn = syn:: parse ( input) . expect ( "`#[interrupt]` must be applied to a function" ) ;
419
428
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
+ )
422
439
. to_compile_error ( )
423
- . into ( ) ;
424
- }
440
+ . into ( )
441
+ }
442
+ Err ( e) => return e. into_compile_error ( ) . into ( ) ,
443
+ } ;
425
444
426
445
let fspan = f. sig . span ( ) ;
427
446
let ident = f. sig . ident ;
@@ -491,21 +510,46 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
491
510
let output = f. sig . output ;
492
511
let hash = random_ident ( ) ;
493
512
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
+ }
504
535
}
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 ( )
509
553
} else {
510
554
parse:: Error :: new (
511
555
fspan,
0 commit comments