BSP430  20141115
Board Support Package for MSP430 microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
Watchdogs, LPM, Interrupts, and All That

Table of Contents

Watchdog Support

BSP430 is implemented to support having the watchdog timer enabled from the moment the chip receives power.

Defining configBSP430_CORE_SUPPORT_WATCHDOG to a true value will cause BSP430_CORE_WATCHDOG_CLEAR() to reload the watchdog with a reset value each time it is executed. It will also cause BSP430_CORE_DELAY_CYCLES() to do so at least once every BSP430_CORE_WATCHDOG_MAX_DELAY_CYCLES MCLK ticks.

For convenience, the default value of configBSP430_CORE_SUPPORT_WATCHDOG is false, which causes BSP430_PLATFORM_BOOT_DISABLE_WATCHDOG to default to true, and the watchdog will be disabled as the first action taken by vBSP430platformInitialize_ni().

Where BSP430 provides a function that might execute for more than 30 milliseconds at 1 MHz, it will internally invoke BSP430_CORE_WATCHDOG_CLEAR() at least once every 30 milliseconds (potentially more frequently if so configured by BSP430_CORE_WATCHDOG_MAX_DELAY_CYCLES). Otherwise application code is responsible for clearing the watchdog.

There is no penalty for using BSP430_CORE_WATCHDOG_CLEAR() and BSP430_CORE_DELAY_CYCLES() when the watchdog is disabled.

BSP430 currently does not provide infrastructure abstracting the watchdog timer as an interval timer. You are, of course, free to use it in such a way so long as you do not enable configBSP430_CORE_SUPPORT_WATCHDOG.

Low Power Mode

As the intrinsics used to enter and leave low power mode are not entirely consistent across MSP430 toolchains, BSP430 provides several macros to assist with this.

BSP430_CORE_LPM_ENTER(lpm_bits) places the CPU into a low power mode as specified by lpm_bits. The bits are the same ones that are normally used in __bis_status_register() in MSPGCC, but BSP430 will mask them using BSP430_CORE_LPM_SR_MASK to ensure that other bits are not set. Use this macro when entering a low-power mode from a state where interrupts are currently enabled.

BSP430_CORE_LPM_ENTER_NI(lpm_bits) is similar but enables GIE prior to entering low-power mode, so that the CPU can be awoken by actions taken while processing an interrupt. Be aware that under normal circumstances interrupts will be enabled when this "call" completes (see configBSP430_CORE_LPM_EXIT_CLEAR_GIE for unusual circumstances).

BSP430_CORE_LPM_EXIT_FROM_ISR(lpm_bits) serves as an abstraction of __bic_status_tegister_on_exit() in MSPGCC, again filtering the bits for validity.

The flag BSP430_CORE_LPM_LPMXp5 is defined as a way of consistently representing a desire to enter the ultra-low-power LPMx.5 modes. The macros above do not examine this bit; see BSP430_PMM_ENTER_LPMXp5_NI() and the application LPM example for a demonstration of how to enter these modes on MCUs that support them.

Interrupts and Critical Sections

BSP430 provides several function macros that support interrupt management in a toolchain-independent manner. A core promise of BSP430 is that BSP430 it will preserve the application interrupt state over API calls unless specifically documented to do otherwise. In turn, the application is expected to not enable interrupts within an interrupt handler callback, though this can be done if the callback protects against reentrancy and ensures the interrupts are disabled again before returning.

Recall that on a power-up-clear ("PUC", i.e. any reset condition), the status register is reset, meaning that all interrupts are disabled when main() begins executing. If the application wishes to accept interrupts, it must explicitly enable them after configuration is complete.

The _ni "not interrupt-able" suffix

Several function and structure field names have a suffix _ni. This indicates that the function or field is intended to be called or manipulated in a context where interrupts are disabled. Cases where the _ni suffix is required include:

Functions that do not have the _ni suffix are either considered to be robust in the presence of interrupts, or will temporarily disable them in a critical section prior to restoring the incoming interrupt state before returning. In certain cases, structure fields with the _ni suffix may be atomically compared with NULL, but not manipulated; these cases are noted within the documentation for the field. Structure fields and variables that do not have the _ni suffix may be accessed without concern for interrupt being enabled or disabled.

Note
The _ni suffix should not be overused. See The _rh "resource held" suffix for an alternative that has less impact on responsiveness.
Warning
Failure to disable interrupts prior to invoking functions with the _ni suffix may result in non-deterministic behavior including application lockup.
The _ni suffix does not guarantee that the function will not enable interrupts internally if its operation requires waiting for some condition. It only guarantees that, if this happens, they will be disabled again when the function returns. Any function (with or without an _ni suffix) that could enable interrupts should clearly state this in its description using the @blocking and/or @consoleoutput attributes.
Note
Where both _rh and _ni apply the combined suffix _rh_ni should be used.

The _rh "resource held" suffix

The _rh suffix is used to indicate functions that manipulate a particular resource in a way that must be safe from simultaneous access, but is not sensitive to unrelated interrupts. Cases where the _rh suffix is required include:

The <bsp430/resource.h> infrastructure may be used to prevent of undesired concurrent access in many situations that involve resource held functions, even if accessed from an interrupt handler. When resources are used for a HAL structure (e.g. BSP430_SERIAL_ENABLE_RESOURCE) all fields in the structure should be manipulated only when the resource is held by the subsystem that is accessing it.

The documentation for functions that require resources should use @resource.

Note
Where both _rh and _ni apply the combined suffix _rh_ni should be used.

Unconditionally Enabling and Disabling Interrupts

The function macro BSP430_CORE_ENABLE_INTERRUPT() will invoke the toolchain intrinsic to enable interrupts by setting the GIE bit in the MSP430 status register.

The function macro BSP430_CORE_DISABLE_INTERRUPT() will invoke the toolchain intrinsic to disable interrupts by clearing the GIE bit in the MSP430 status register.

These function macros include any necessary workarounds for MCU design "features" and errata that can result in interrupts being executed in the following instruction, such as the documented need for a NOP instruction after a DINT, and similar need after EINT when erratum CPU42 affects the MCU.

Creating Critical Sections

Critical sections may be implemented by saving the current interrupt state, disabling interrupts, performing the critical operations, then restoring interrupt state. The recommended pattern for this is:

int rv;
/* ... */
/* non-critical code */
rv = 0; /* assume success */
do {
/* critical code */
if (something_went_wrong) {
rv = -1; /* error */
break;
}
/* more critical code */
} while (0);
if (0 != rv) {
/* handle failure from critical section */
}
/* non-critical code */

See the button example for an interesting application architecture that leaves interrupts disabled at all times that the MCU is active, simplifying the application logic by eliminating non-deterministic signals.

Resource Management

The bsp430/resource.h header provides data structures and functions that support safe access to shared resources when using functions with the _rh suffix.

Application Architecture

The choice of application architecture is up to the implementer; BSP430 is intended to support all but the most contorted architectures. Pure examples of two standard solutions that it should support are described in this section.

Interrupt-Driven

static int
callback (/* ... */)
{
/* ... */
return 0; /* Return without waking */
}
void main (/* ... */)
{
/* Initialization */
while (1) { /* Gratuitous loop in case of error */
}
}

Features of the interrupt-only architecture:

Super Loop

typedef unsigned int tEventSet;
volatile tEventSet events_ni;
/* ... */
static int
callback (/* ... */)
{
/* ... */
events_ni |= EVT_FLAG;
}
void main (void)
{
tEventSet events;
/* Initialization with interrupts disabled, including setting up callback */
/* Initialization with interrupts enabled. */
while (1) { /* Super Loop */
/* Record and reset current event set */
events = events_ni;
events_ni = 0;
if (! events) {
/* Sleep with interrupts enabled until events occur */
/* Interrupts enabled during sleep and normally enabled when wakeup.
* Restart at loop top to check events again */
continue;
}
/* Other preparation with interrupts disabled */
/* Process events */
}
}

Features of this architecture:

As a special case, the super loop architecture can be supported while retaining the strict priority of the interrupt-driven architecture by using configBSP430_CORE_LPM_EXIT_CLEAR_GIE to so that when BSP430_CORE_LPM_ENTER_NI() returns interrupts remain disabled. This architecture never leaves interrupts enabled while the CPU is active, but still allows event processing to be prioritized relative to other activity.

Copyright 2012-2014, Peter A. Bigot