Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Embedded Testing on the FRDM-MCXA153

What this project is

A beginner-focused, reproducible workflow for testing embedded C, built around the NXP FRDM-MCXA153. The goal is to move the reader from a standard of "it works" (it compiled and the LED blinked) to a standard of "it is verified": not just to show which buttons to press in Unity, Ceedling and CMock, but to change how students reason about software correctness in embedded systems, where the hardware is slow to reach, hard to observe and easy to blame.

The guide is written for undergraduates who know C and pointers, have seen memory-mapped I/O, and have never written a test harness or a mock. Every command is reproducible on Ubuntu Bash, and everything the chapters show (compiler errors, test output, register values, flash logs) comes from an actual run.

Concretely, it teaches how to separate a decision from a hardware action, how to put a seam between your code and the vendor SDK, how to mock that seam so a driver can be unit-tested on a laptop with no board attached, and how to carry the same source file, once written, onto real hardware, verifying it twice without changing it once (dual-targeting).

Chapters

Chapter Title What it covers
1 Why We Test What "it works" means, the V-model, module design, and why a sloppy design or a sloppy test both fail silently
2 Unit Testing with Unity & Ceedling Installing the toolchain and building a real Unity/Ceedling harness that catches a planted bug
3 Mocking and Hardware Abstraction The hardware wall, the seam, CMock, and unit-testing a driver that never touches a register on the host
4 Dual-Targeting: Build and Flash The real HAL implementations, connecting the board, and flashing host-tested code to run for real
5 Code the Hardware Calls An interrupt handler tested on the host: an ISR is a function, time is a parameter, and where this guide's testing deliberately stops

Layout

docs/               the five chapters above, plus docs/asset/ (screenshots Chapter 2 embeds)
examples/<name>/     one Ceedling project per example, shipped and ready to run
scripts/*.sh         five scripts; see below
Project Chapter Host test result
examples/overtemp_alarm 2 passes: 13
examples/led_driver 3 §3.2, the wall fails on purpose; has EXPECTED_TO_FAIL. Before Chapter 4 it stops on PERI_ADC.h: No such file or directory. After Chapter 4, source scripts/target_env.sh and uncomment the SDK include lines in its project.yml to reproduce Obstacle 1's #error "Unknown Arm architecture profile"
examples/led_driver/experiments 3 §3.2 Obstacles 2 and 3 not a Ceedling project; built directly with gcc
examples/led_driver_seam 3 §3.4-§3.6, 4 §4.1, 4 §4.4 passes: 3
examples/alarm_update 3 §3.7 passes: 2
examples/button 5 passes: 7

scripts/run_tests.sh runs ceedling test:all in every project folder (every folder with a project.yml) and skips any folder that has an EXPECTED_TO_FAIL marker, led_driver being the only one. The other four scripts belong to Chapter 4's board workflow: setup_target_toolchain.sh (one-time target toolchain setup), connect_board.sh (udev rule and probe check, native Ubuntu and WSL2), create_target_project.sh (exports a freestanding target project from the SDK), and target_env.sh (sourced, not run, to set the Chapter 4 shell environment).

Requirements

Hardware

Item Needed for Notes
A laptop or PC (x86_64) running Ubuntu 24.04 every chapter Native Ubuntu or WSL2 Ubuntu 24.04 on Windows; all commands are Bash. Chapters 1, 2, 3 and 5 need nothing else: the host tests run on the laptop alone
NXP FRDM-MCXA153 board Chapter 4 MCXA153 MCU (Arm Cortex-M33). The on-board MCU-Link debug probe (port J15) does the flashing and debugging, so no separate probe is needed
USB-C cable that carries data Chapter 4 Connects J15 to the laptop. A charge-only cable will not enumerate
On WSL2 only: usbipd-win on the Windows side Chapter 4 §4.3 Hands the USB port over to WSL2; scripts/connect_board.sh prints the exact commands

Software

Host testing (Chapter 2 §2.2 installs these, in this order):

Tool Role How it is installed
build-essential (gcc, make) compiles and runs the tests on the host sudo apt install -y build-essential
Ruby 3.x with ruby-dev Ceedling runs on it sudo apt install -y ruby ruby-dev
Ceedling (bundles Unity and CMock) build/test manager; Unity is the test framework, CMock the mock generator sudo gem install ceedling. The guide's transcripts were made with Ceedling 1.1.8, Unity 2.7.2 and CMock 2.7.2

Target build and flash (Chapter 4 §4.2 and scripts/):

Tool Role How it is installed
MCUXpresso Installer NXP's installer for everything below Downloaded from NXP; tick MCUXpresso SDK Developer and LinkServer
Arm GNU Toolchain (arm-none-eabi-gcc, arm-none-eabi-gdb) cross-compiles for the Cortex-M33 and debugs it via the Installer, under ~/.mcuxpressotools
west, cmake, ninja, git, Python fetches and builds the SDK-based target project via the Installer (west lives in its Python venv)
LinkServer talks to the MCU-Link probe: flash, gdbserver via the Installer, under /usr/local/LinkServer_*
MCUXpresso SDK, v26.06.00-LTS, board frdmmcxa153 vendor drivers, startup code and CMake files scripts/setup_target_toolchain.sh fetches it with west into ~/mcuxsdk

scripts/target_env.sh (sourced, not run) puts all of the target tools on PATH and sets ARMGCC_DIR for a Chapter 4 shell.

How to run

Install Ceedling as described in Chapter 2 §2.2, then, for any example:

cd examples/<name>
ceedling test:all

or run every project at once from the repository root:

scripts/run_tests.sh

Building and flashing the target requires the physical FRDM-MCXA153 board and the SDK workspace set up in Chapter 4; there is no host-only substitute for that part.

Path convention

Commands in the chapters build projects under ~/embedded-testing/exercises/<name>, because you are building them as you follow along. The finished version of each one is shipped in this repository under examples/<name>, so you can compare against it or run a chapter's tests without typing the chapter first.

Hardware facts used

Verified against schematic SPF-90829_A1 and the MCXA153 reference manual:

  • RGB LED, common-anode, active-low: red P3_12, green P3_13, blue P3_0, all on GPIO3.
  • GPIO3 base 0x40105000; PSOR (set) 0x44, PCOR (clear) 0x48, PDDR (direction) 0x54.
  • SW3 (user button) is P1_7 on GPIO1, active-low, pulled up. Chapter 4 reads it as a level, Chapter 5 as an edge.

Board documentation is NXP's UM12012, linked from the FRDM-MCXA153 product page: https://www.nxp.com/webapp/Download?colCode=UM12012.

Scope

It is a guide to one workflow, host-first unit testing with a thin hardware abstraction, taken far enough that a reader can apply it to their own driver, not a survey of embedded testing.

In scope: the test hierarchy from Chapter 1 and why "it compiled and the LED blinked" is not verification; host unit tests with Unity and Ceedling; separating decisions (pure logic, tested directly) from actions (thin hardware calls, mocked only when the call itself needs checking); hardware abstraction and the seam; CMock; dual-targeting, with the same source file built for the host and for the board; interrupt wiring tested on the host, with the ISR reduced to a shell.

Out of scope: RTOS and race conditions, memory-leak analysis, frameworks other than Unity/CMock/Ceedling, DMA, NVIC arbitration, Docker-based reproducibility, TDD theory beyond working fluency, and emulators (QEMU/Renode get a callout in §4.9 and no more).

References

  • Grenning, James W. Test-Driven Development for Embedded C. Pragmatic Bookshelf, 2011.
  • Feathers, Michael. Working Effectively with Legacy Code. Prentice Hall, 2004. (Coined the term "seam", which Grenning applied to embedded C.)

License

MIT. See LICENSE.

About

Beginner's guide to host-based unit testing for embedded C — Unity, Ceedling, CMock, and dual-targeting on the NXP FRDM-MCXA153.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages