Skip to content

Lab 0: Stopwatch

In this lab, you will:

  • Set up your development environment using Code Composer Studio (CCS)
  • Explore the TM4C1294XL LaunchPad and BOOSTXL-EDUMKII BoosterPack hardware
  • Import and run a starter stopwatch project to verify your environment setup
  • Learn how to write modular embedded programs using C/C++ and TI’s driver libraries

To complete each lab in this course, you must:

  1. Submit your source code for the lab
  2. Demonstrate your project in operation to one of the course staff (TA or tutor)
  3. Receive a sign-off after successful demonstration

You will be graded based on the completion of the required steps and correct functionality.
Late submissions will receive a 20% penalty unless otherwise specified by your instructor.

StepDescriptionMax PointsScore
1Compile and flash the starter stopwatch example (verify environment)10
2Extend the stopwatch to display HH:MM:SS:MS format20
3Implement physical buttons S1 → Play/Pause and S2 → Reset35
4Add on-screen buttons with feedback and state text (Running / Stopped)15
5Source Code — Organization, readability, and modular structure20
Total100

By the end of this lab, you will have accomplished:

  • Install software: Code Composer Studio (CCS) and Free-RTOS
  • Set up a CCS project for the EK‑TM4C1294XL + BoosterPack
  • Output to the 128×128 LCD display
  • Configure general purpose timers and interrupts
  • Read and debounce user buttons
  • Understand how to import libraries
  • Using hardware timers for precise time measurement.
  • Managing non‑blocking tasks with elapsedMillis utilities.
  • Handling button debouncing and event callbacks.
  • Creating simple GUIs using GRLIB primitives.
  • Synchronizing display updates with real‑time processes.

Before starting this lab, make sure you have the following:

  • TI EK-TM4C1294XL LaunchPad Development Kit
  • BOOSTXL-EDUMKII BoosterPack
  • Micro-USB cable for programming and power
  • Lab 0 Template: Download ZIP

Implement a stopwatch with hours, minutes, seconds, and milliseconds, using the S1 button for Play/Pause and S2 for Reset. The application must also show two on‑screen buttons that react to physical button interactions, as well as a text label indicating the current state: Running or Stopped.

In this lab exercise, you will use a modular C/C++ approach to design a stopwatch running on the TM4C1294XL LaunchPad with the BOOSTXL‑EDUMKII LCD.
The system measures elapsed time using hardware timers and updates the display at a fixed refresh rate.

The application demonstrates:

  • Use of timers for precise millisecond tracking.
  • Integration of physical button input with graphical feedback.
  • Modular code structure using custom libraries (button.h, timerLib.h, elapsedTime.h).
  • Real‑time display management with TI GRLIB.

You are provided with a simplified starter example that demonstrates how to:

  • Initialize the system clock and LCD display.
  • Configure a periodic hardware timer using the Timer class and elapsedTime Class.
  • Use the Button class to detect press and release events for S1.
  • Draw on‑screen UI elements such as rectangles and text using GRLIB.

In the provided code:

  • S1 toggles between Play and Pause.
  • A single on‑screen button labeled PLAY/PAUSE changes color when pressed.
  • The display shows the word STOPWATCH and a time counter (in seconds) at the center.
  • The background is cleared and redrawn periodically at 20 ms button scan and 50 ms display refresh intervals.

Every embedded program should start by disabling global interrupts and enabling the Floating-Point Unit (FPU). The FPU improves performance when using floating-point arithmetic, which is often needed for signal processing, filters, or calculations involving time.

IntMasterDisable();
FPUEnable();
FPULazyStackingEnable();

Afterward, it is crucial to configure the system clock, as all peripherals (timers, ADC, UART, etc.) depend on it to operate correctly:

gSystemClock = SysCtlClockFreqSet(
SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480,
120000000);

This setup uses the 25 MHz external crystal and the PLL (Phase-Locked Loop) to generate a 120 MHz system clock.


If the program uses the LCD, the display must be initialized through the graphics context tContext. This block configures the SPI interface and prepares the screen for drawing.

tContext sContext;
initializeDisplay(sContext);

The display is connected through SPI2, and this helper function configures the GRLIB driver and clears the screen:

static void initializeDisplay(tContext &context)
{
Crystalfontz128x128_Init();
Crystalfontz128x128_SetOrientation(LCD_ORIENTATION_UP);
GrContextInit(&context, &g_sCrystalfontz128x128);
GrContextFontSet(&context, &g_sFontFixed6x8);
tRectangle full = {0, 0, 127, 127};
GrContextForegroundSet(&context, ClrBlack);
GrRectFill(&context, &full);
}

Any task that needs to be executed periodically—like reading a sensor, blinking an LED, or updating the display—requires a timer. In this project, Timer0 is used as the reference for the elapsedMillis objects:

Timer timer;
configureTimer(timer);
elapsedMillis buttonTick(timer);
elapsedMillis displayTick(timer);
elapsedMillis stopwatchTick(timer);

Each elapsedMillis instance keeps track of elapsed time independently, allowing you to execute tasks at precise intervals without using delays.

The timer configuration function:

static void configureTimer(Timer &timer)
{
timer.begin(gSystemClock, TIMER0_BASE);
}

This initializes Timer0 as a system time base synchronized with the configured system clock.


Each hardware button (S1, S2, or others) must be configured using the Button class before it can be used. The button library handles debouncing and state detection automatically.

static void setupButtons()
{
btnPlayPause.begin();
btnPlayPause.setTickIntervalMs(BUTTON_TICK_MS);
btnPlayPause.setDebounceMs(30);
}

After setup, interrupts can be re-enabled:

IntMasterEnable();

The main loop (while(true)) is where all recurring tasks are executed in non-blocking intervals. Each task checks its elapsed time counter and executes only when its timer expires.

This pattern ensures that the program remains responsive without delays.


It’s recommended to separate the LCD drawing logic into functions for readability and maintainability:

Draws the stopwatch title and current time.

static void drawStopwatchScreen(tContext &context, uint32_t currentSec, bool running)
{
tRectangle rectFull = {0, 0, 127, 127};
GrContextForegroundSet(&context, ClrBlack);
GrRectFill(&context, &rectFull);
GrContextForegroundSet(&context, ClrCyan);
GrStringDrawCentered(&context, "STOPWATCH", -1, 64, 15, false);
char str[10];
snprintf(str, sizeof(str), "%02u s", currentSec);
GrContextForegroundSet(&context, running ? ClrYellow : ClrOlive);
GrStringDrawCentered(&context, str, -1, 64, 50, false);
}

Handles rendering of buttons with color changes when pressed.

static void drawButton(tContext &context, const MyButton &btn)
{
uint16_t bgColor = btn.pressed ? ClrBlack : ClrGray;
uint16_t textColor = btn.pressed ? ClrWhite : ClrBlack;
tRectangle rect = {btn.x, btn.y, btn.x + btn.w - 1, btn.y + btn.h - 1};
GrContextForegroundSet(&context, bgColor);
GrRectFill(&context, &rect);
GrContextForegroundSet(&context, ClrBlack);
GrRectDraw(&context, &rect);
GrContextForegroundSet(&context, textColor);
GrStringDrawCentered(&context, btn.label, -1,
btn.x + btn.w / 2, btn.y + btn.h / 2, false);
}

You must extend this implementation to complete the full stopwatch behavior:

  1. Add a second button (S2)
    ‑ Use Button btnReset(S2);
    ‑ When pressed, set the stopwatch time back to zero.

  2. Expand the time format
    ‑ Display the time as HH:MM:SS:MS.
    ‑ Convert milliseconds using division and modulo operations.

  3. Display the system state
    ‑ Show a label Running or Stopped depending on the value of gRunning.

  4. Add a second on‑screen button for Reset
    ‑ Create a new MyButton struct instance for Reset.
    ‑ The button should visually change when S2 is pressed.

  5. Improve display logic
    ‑ Limit updates to roughly 60 Hz (~16 ms between redraws).
    ‑ Only refresh when time, button state, or mode changes.

  6. Ensure debouncing and callbacks
    ‑ Use btnPlayPause.setDebounceMs(30) and similar for the Reset button.
    ‑ Implement callback functions onPlayPauseClick(), onResetClick(), etc.


  • The stopwatch starts in the Stopped state at 00:00:00:000.
  • Pressing S1 toggles between Running and Stopped.
  • Pressing S2 resets the timer to zero.
  • The text label reflects the current state.
  • The on‑screen buttons change color briefly when their physical counterparts are pressed.

Stopwatch example screen
Example of the stopwatch interface with on‑screen buttons and state indicator

Your final stopwatch application must:

  • Display the time in HH:MM:SS:MS format.
  • Show Running or Stopped based on the system state.
  • Respond visually and functionally to both S1 and S2 presses.
  • Maintain smooth updates and clean modular code.

Exporting project:

  1. Ensure project named ece3849_lab0_<username>.
  2. Right‑click the project → Export...GeneralArchive File.
  3. Choose the output path and filename equal to the project name (ece3849_lab0_<username>.zip).
  4. Upload .zip to Canvas.