Dynamic LED Blink Rate Control Using Hardware Timers on MSPM0G3507

Project Initialization and SysConfig Setup

Duplicate the empty DriverLib template located in the MSPM0 SDK directory (examples/nortos/LP_MSPM0G3507/driverlib) and rename the copy to match the application. Open the corresponding Keil MDK project file and perform an initial build to resolve all source dependencies and clear any missing file indicators. Launch SysConfig from the IDE toolbar to begin hardware abstraction layer generation.

Peripheral Configuration

Configure the status indicator GPIO first. Set the initial output state to high to guarantee the LED remains off during microcontrolller reset. To the user input button, assign the target pin (e.g., PA18) as a digital input and enable the internal pull-down resistor. Activate GPIO interrupts and configure the trigger condition to rising edge to capture button press events accurately.

Add a general-purpose timer instance to the configuration. Select BUSCLK as the clock source, apply a clock divider of 8, and set the prescaler to 200. Switch the timer mode to periodic down-counting and define a target period of 50 ms. Enable the zero-match interrupt and configure the timer to start automatically upon initialization. Save the configuration to generate the initialization headers and source files, then return to the IDE.

Firmware Implementation

The application relies on two interrupt service routines: one for the timer zero-match event to toggle the LED, and another for the GPIO pin to adjust the timer reload value dynamically. The main thread handles system initialization and enters a low-power wait state.

#include "ti_msp_dl_config.h"

volatile uint32_t g_reload_value = 999; // Initial period (~50ms)

int main(void)
{
    SYSCFG_DL_init();

    NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
    NVIC_EnableIRQ(GPIOA_INT_IRQN);

    DL_Timer_setLoadValue(TIMER_0_INST, g_reload_value);
    DL_TimerG_startCounter(TIMER_0_INST);

    while (1) {
        __WFI(); // Halt CPU until interrupt occurs
    }
}

void TIMER_0_INST_IRQHandler(void)
{
    uint32_t irq_status = DL_TimerA_getPendingInterrupt(TIMER_0_INST);

    if (irq_status == DL_TIMER_IIDX_ZERO) {
        DL_GPIO_togglePins(LEDS_PORT, LEDS_LED_1_PIN);
        DL_TimerA_clearInterruptStatus(TIMER_0_INST, DL_TIMER_IIDX_ZERO);
    }
}

void GROUP1_IRQHandler(void)
{
    uint32_t gpio_irq = DL_GPIO_getPendingInterrupt(GPIOA);

    if (gpio_irq == KEYS_KEY_S1_IIDX) {
        // Initial debounce delay
        for (volatile uint32_t d = 0; d < 80000; d++);

        DL_TimerG_stopCounter(TIMER_0_INST);

        // Step the period up by 4750 ticks, reset to baseline if max reached
        if (g_reload_value >= 19999) {
            g_reload_value = 999;
        } else {
            g_reload_value += 4750;
        }

        DL_Timer_setLoadValue(TIMER_0_INST, g_reload_value);
        DL_TimerG_startCounter(TIMER_0_INST);

        // Post-adjustment debounce and wait for pin release
        for (volatile uint32_t d = 0; d < 80000; d++);
        while (DL_GPIO_readPins(KEYS_PORT, KEYS_KEY_S1_PIN) == 0);

        DL_GPIO_clearInterruptStatus(GPIOA, KEYS_KEY_S1_PIN);
    }
}

Debugging and Execution

Open the build configuration and verify that the debug interface is set to CMSIS-DAP. Compile the project and flash the binary to the target board. Once the debug session starts, the LED will toggle at the baseline frequency. Pressing the configured button will halt the timer, update the load register with the new step value, and restart the counter, resulting in a visibly slower blink rate. Subsequent presses will continue to increase the period until the threshold is met, at which point the frequency resets to the initial value.

Tags: MSPM0G3507 Embedded Systems ARM Cortex-M0+ Timer Configuration GPIO Interrupts

Posted on Tue, 12 May 2026 21:18:23 +0000 by neorunner