From 91fd567c8fa7c0cd71145e62ca298be87c1c60e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Roussel?= Date: Wed, 18 Jun 2014 15:13:05 +0200 Subject: [PATCH 1/3] Use custom assembly code instead of MSP GCC primitives for dINT()/eINT() and all other functions that enable or disable interrupts --- cpu/msp430-common/include/cpu.h | 20 ++++++++++++++------ cpu/msp430-common/msp430-main.c | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/cpu/msp430-common/include/cpu.h b/cpu/msp430-common/include/cpu.h index 8611bb2cd418..8a2a60680824 100644 --- a/cpu/msp430-common/include/cpu.h +++ b/cpu/msp430-common/include/cpu.h @@ -40,8 +40,8 @@ extern "C" { extern volatile int __inISR; extern char __isr_stack[MSP430_ISR_STACK_SIZE]; -//#define eINT() eint() -//#define dINT() dint() +/*#define eINT() eint() */ +/*#define dINT() dint() */ inline void __save_context_isr(void) { @@ -125,14 +125,22 @@ inline void __restore_context(unsigned int irqen) inline void eINT(void) { - // puts("+"); - eint(); + /* puts("+"); */ +/* eint(); // problem with MSPGCC intrinsics? */ + __asm__ __volatile__("bis %0, r2" : : "i"(GIE)); + __asm__ __volatile__("nop"); + /* this NOP is needed to handle a "delay slot" that all MSP430 MCUs + impose silently after messing with the GIE bit, DO NOT REMOVE IT! */ } inline void dINT(void) { - // puts("-"); - dint(); + /* puts("-"); */ +/* dint(); // problem with MSPGCC intrinsics? */ + __asm__ __volatile__("bic %0, r2" : : "i"(GIE)); + __asm__ __volatile__("nop"); + /* this NOP is needed to handle a "delay slot" that all MSP430 MCUs + impose silently after messing with the GIE bit, DO NOT REMOVE IT! */ } int inISR(void); diff --git a/cpu/msp430-common/msp430-main.c b/cpu/msp430-common/msp430-main.c index 81652658c3e2..50dcbd1985d6 100644 --- a/cpu/msp430-common/msp430-main.c +++ b/cpu/msp430-common/msp430-main.c @@ -160,6 +160,7 @@ splhigh_(void) int sr; asmv("mov r2, %0" : "=r"(sr)); asmv("bic %0, r2" : : "i"(GIE)); + asmv("nop"); return sr & GIE; /* Ignore other sr bits. */ } /*---------------------------------------------------------------------------*/ @@ -171,6 +172,7 @@ splx_(int sr) { /* If GIE was set, restore it. */ asmv("bis %0, r2" : : "r"(sr)); + asmv("nop"); } /*---------------------------------------------------------------------------*/ From 07b170595cdea4bbac1beca7ea2d6fa1c06e7f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Roussel?= Date: Thu, 19 Jun 2014 15:02:43 +0200 Subject: [PATCH 2/3] Ensure interrupts are enabled before going in low-power mode --- cpu/msp430-common/lpm_cpu.c | 49 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/cpu/msp430-common/lpm_cpu.c b/cpu/msp430-common/lpm_cpu.c index 8f3b66e657e6..96fa00e692b4 100644 --- a/cpu/msp430-common/lpm_cpu.c +++ b/cpu/msp430-common/lpm_cpu.c @@ -33,10 +33,10 @@ /* Initialise the MSP430 power-saving mechanisms. */ void lpm_init(void) { - // nothing to initialize on MSP430s: everything is done by fiddling - // with 4 bits of the status register (SR). + /* nothing to initialize on MSP430s: everything is done by fiddling + with 4 bits of the status register (SR). */ - // just ensure MCU is fully up and running at start + /* just ensure MCU is fully up and running at start */ lpm_awake(); } @@ -45,33 +45,44 @@ enum lpm_mode lpm_set(enum lpm_mode target) { enum lpm_mode last_mode = lpm_get(); + /* ensure that interrupts are enabled before going to sleep, + or we're bound to hang our MCU! */ + if (target != LPM_ON) { + if ((__read_status_register() & GIE) == 0) { + printf("WARNING: entering low-power mode with interrupts disabled!\n"); + printf(" Forcing GIE bit to 1!\n\n"); + __bis_status_register(GIE); + } + } + switch (target) { case LPM_ON: - // fully running MCU + /* fully running MCU */ __bic_status_register(CPUOFF | OSCOFF | SCG0 | SCG1); break; case LPM_IDLE: - // lightest mode => LPM0 mode of MSP430 + /* lightest mode => LPM0 mode of MSP430 */ __bic_status_register(OSCOFF | SCG0 | SCG1); - // only stops CPU block + /* only stops CPU block */ __bis_status_register(CPUOFF); break; case LPM_SLEEP: - // mid-level mode => LPM1 mode of MSP430 + /* mid-level mode => LPM1 mode of MSP430 */ __bic_status_register(OSCOFF | SCG1); - // stops CPU and master clock blocks + /* stops CPU and master clock blocks */ __bis_status_register(CPUOFF | SCG0); break; case LPM_POWERDOWN: - // deep-level mode => LPM3 mode of MSP430 + /* deep-level mode => LPM3 mode of MSP430 */ __bic_status_register(OSCOFF); - // stops all blocks except auxiliary clock (timers) + /* stops all blocks except auxiliary clock (timers) */ __bis_status_register(CPUOFF | SCG0 | SCG1); break; case LPM_OFF: - // MCU totally down (LPM4), only RESET or NMI can resume execution - __bis_status_register(CPUOFF | OSCOFF | SCG0 | SCG1); // all blocks off + /* MCU totally down (LPM4), only RESET or NMI can resume execution */ + __bis_status_register(CPUOFF | OSCOFF | SCG0 | SCG1); + /* all blocks off */ break; default: printf("ERROR: trying to set an invalid low-power mode!\n"); @@ -90,20 +101,20 @@ enum lpm_mode lpm_get(void) unsigned int current_sr = __read_status_register(); switch (current_sr & LPM_MASK_SR) { - case CPUOFF + OSCOFF + SCG0 + SCG1: // MSP430's LPM4 + case CPUOFF + OSCOFF + SCG0 + SCG1: /* MSP430's LPM4 */ current_mode = LPM_OFF; break; - case CPUOFF + SCG0 + SCG1: // MSP430's LPM3 - case CPUOFF + SCG1: // MSP430's LPM2 + case CPUOFF + SCG0 + SCG1: /* MSP430's LPM3 */ + case CPUOFF + SCG1: /* MSP430's LPM2 */ current_mode = LPM_POWERDOWN; break; - case CPUOFF + SCG0: // MSP430's LPM1 + case CPUOFF + SCG0: /* MSP430's LPM1 */ current_mode = LPM_SLEEP; break; - case CPUOFF: // MSP430's LPM1 + case CPUOFF: /* MSP430's LPM1 */ current_mode = LPM_IDLE; break; - case 0: // MSP430 active + case 0: /* MSP430 active */ current_mode = LPM_ON; break; } @@ -114,7 +125,7 @@ enum lpm_mode lpm_get(void) /* resume the MSP430 MCU */ inline void lpm_awake(void) { - // disable all power savings mechanisms + /* disable all power savings mechanisms */ __bic_status_register(CPUOFF | OSCOFF | SCG0 | SCG1); } From 892268d74b3ed2856320bcd39e172bdcebb504c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Roussel?= Date: Thu, 19 Jun 2014 15:03:48 +0200 Subject: [PATCH 3/3] Ensure only GIE bit is touched in splx_() --- cpu/msp430-common/lpm_cpu.c | 2 +- cpu/msp430-common/msp430-main.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cpu/msp430-common/lpm_cpu.c b/cpu/msp430-common/lpm_cpu.c index 96fa00e692b4..e7893bb0ac08 100644 --- a/cpu/msp430-common/lpm_cpu.c +++ b/cpu/msp430-common/lpm_cpu.c @@ -82,7 +82,7 @@ enum lpm_mode lpm_set(enum lpm_mode target) case LPM_OFF: /* MCU totally down (LPM4), only RESET or NMI can resume execution */ __bis_status_register(CPUOFF | OSCOFF | SCG0 | SCG1); - /* all blocks off */ + /* all blocks off */ break; default: printf("ERROR: trying to set an invalid low-power mode!\n"); diff --git a/cpu/msp430-common/msp430-main.c b/cpu/msp430-common/msp430-main.c index 50dcbd1985d6..6a908f2a4910 100644 --- a/cpu/msp430-common/msp430-main.c +++ b/cpu/msp430-common/msp430-main.c @@ -170,6 +170,7 @@ splhigh_(void) void splx_(int sr) { + sr &= GIE; /* If GIE was set, restore it. */ asmv("bis %0, r2" : : "r"(sr)); asmv("nop");