GitHub

Fox Red Labs / Builds / Edge AI

Time a tiny AI model that counts people in a room

Four room-occupancy networks, 636 to 33k weights, run as plain C on the MSPM0 G3507; every answer is checked and timed in clock cycles.

MediumNo wiring1 evening

Parts and steps

You need

Set up your computer once: 1 step. Done already? Start at step 2.
  1. Install the tools once, all free.TERMINAL

    Get CCStudio 21.0.1 from TI's CCStudio download page (1.9 GB download, 8.1 GB installed, free myTI login). It brings TI Arm Clang 5.1.1.LTS. Get the MSPM0 SDK 2.11.00.07 from TI's MSPM0 SDK download page (0.4 GB download, 2.2 GB installed). Get UniFlash 9.6.0 from TI's UniFlash page (0.3 GB download, 1.9 GB installed). Get xPack OpenOCD 0.12.0 from its GitHub release page (2 MB; the file xpack-openocd-0.12.0-7-darwin-x64.tar.gz on an Intel Mac, xpack-openocd-0.12.0-7-darwin-arm64.tar.gz on Apple Silicon), as the macOS x64 archive, and unpack it in your home folder. The generated pin and clock setup the build needs is already in the repository, so SysConfig is not needed for this page.

    You should see: /Applications/ti/ccs2101/ccs/tools/compiler/ti-cgt-armllvm_5.1.1.LTS/bin/tiarmclang --version prints 5.1.1, and the folders mspm0_sdk_2_11_00_07 and uniflash_9.6.0 are under /Applications/ti.

  1. Plug the LaunchPad in with a micro-USB data cable and read its XDS110 serial number.BENCH

    No wiring is needed.

    /Applications/ti/ccs2101/ccs/ccs_base/common/uscif/xds110/xdsdfu -e

    You should see: Serial Num: followed by your probe's serial number .

  2. Put your serial number where the bench board's is written.TERMINAL

    Two tracked files name <probe serial>. The probe check in sdk-common/flash.sh refuses to run unless that probe is on the USB bus. The two Value= lines of the connection file sdk-common/MSPM0G3507_<probe serial>.ccxml select the probe by serial number. Replace YOURSERIAL in both commands with the number from step 2 (<probe serial> below is the bench board's, the text the commands search for). Do not rename the file: flash.sh opens it by that name.

    Replace <probe serial> before you run this.

    sed -i '' 's/Serial Num: \*<probe serial>/Serial Num: *YOURSERIAL/' mspm0g3507/mcu-bench/sdk-common/flash.sh sed -i '' 's/Value="<probe serial>"/Value="YOURSERIAL"/g' mspm0g3507/mcu-bench/sdk-common/MSPM0G3507_<probe serial>.ccxml

    You should see: grep -n YOURSERIAL on those two files shows the changed lines, with your real number in place of the word. The filename MSPM0G3507_<probe serial>.ccxml is unchanged.

  3. Build the program that runs all four models on the board's 20 stored test windows, with the models compiled at -O3.TERMINAL

    The program is compiled by TI Arm Clang 5.1.1 at -O2. The model code is the prebuilt archives, built earlier by TI Arm Clang 4.0.4.LTS. It runs at 80 MHz, using the pin and clock setup of TI's sysctl_mclk_syspll example.

    mspm0g3507/mcu-bench/edgeai-sdk/occupancy/build.sh O3

    You should see: The last lines are the linker map's FLASH and SRAM rows: 0x1dbb0 bytes of flash used, which is 121,776 or 119 kB, and 0x334c of RAM, which is 12.8 kB. build-O3/occupancy.out exists. Use Os instead of O3 to link the smaller, slower -Os libraries, at 95.3 kB of flash.

  4. Flash the image and let it run.TERMINAL

    UniFlash's default erase for this chip is "Erase MAIN memory only", so the board's boot configuration area is not touched.

    mspm0g3507/mcu-bench/sdk-common/flash.sh mspm0g3507/mcu-bench/edgeai-sdk/occupancy/build-O3/occupancy.out

    You should see: UniFlash loads and then verifies: Program verification successful for the occupancy.out path. The program starts running.

  5. Wait for the whole run, then read the results table the program leaves in RAM.TERMINAL

    It is 35 words at 0x202020bc, the symbol occ in build-O3/occupancy.map. The read script halts the core after the wait; connecting OpenOCD restarts the program, so the wait must cover the whole run. OCD is the folder you unpacked OpenOCD into; OCD_CFG is the tracked connection file the digit build uses for this same board; PROBE is your serial. This command line is assembled from the saved run's scripts. It was not copied from a log; see the recovery line.

    export PROBE=YOURSERIAL export OCD=$HOME/xpack-openocd-0.12.0-7 export OCD_CFG=$PWD/ports/bitnetmcu/openocd-mspm0.cfg python3 mspm0g3507/mcu-bench/sdk-common/readwords.py 0x202020bc 35 70000

    You should see: Three or four lines starting 0x202020bc: followed by a list of 35 numbers, the first being 213909505, which is 0x0CC00001: the program finished.

  6. Read the numbers.TERMINAL

    There are three header words: done flag, clock in Hz, and timer read cost in cycles. Each model then has eight words, in the order of the 636, 1,748, 8.5k and 33k-weight models. They are mismatches and windows with the right class. Then come the smallest and largest of the best-of-5 cycle counts, for the network alone, for the float-to-int8 input step, and for both together. Divide the cycles of the last pair by 80,000,000 for seconds.

    You should see: Header 213909505, 80000000, 8. Every model reads 0, 20: no mismatches, 20 of 20. The fastest complete answer, input step plus network, is 320k cycles or 4.00 ms, 723,842 or 9.05 ms, 2,821,806 or 35.27 ms, and 10.4M cycles or 129.40 ms. The input step alone is about 100k cycles, or 1.25 ms, for every model.

Or hand it to a coding assistant

Paste this in a terminal. It hands off to an AI assistant.

git clone --depth 1 --filter=blob:none https://github.com/Fox-Red-Labs/fox-red-labs.git && cd fox-red-labs ./start.sh mspm0g3507 small-ai-model --assistant claude

It runs the steps above and reports what it saw.

Not Claude Code? Copy this prompt instead.
Clone https://github.com/Fox-Red-Labs/fox-red-labs and read mspm0g3507/AGENTS.md first. Then run Run a small AI model on the chip on my LP-MSPM0G3507, following docs/builds/small-ai-model.md. Tell me when to plug in a board and what you saw at each step.

If something goes wrong

At step 1build.sh has the SDK and compiler paths written in its first lines (SDK= and CC=); edit them if yours live elsewhere.
Nothing is listedThe cable is charge-only; swap it. With several boards plugged in, unplug the others.
You skip this the flash stops at Probe <probe serial> missing; that is the check working. The error text keeps the old number (Probe <probe serial> missing) even after the changeSo compare the probe your message should name with step 2.
A path is wrong the script stops at the first compiler call and names the missing file. The SDK's own makefiles point at folders that do not existWhich this script avoids by not using them.
The script stops at Probe ... missingThe serial number in step 3 does not match a probe on the USB bus; compare it with the step 2 output.
More troubleshooting
The first number is not 213909505 the program had not finishedOr OpenOCD restarted it: raise the wait. A short wait caught the restarted run in its first milliseconds on this bench. The 30k-weight model at -Os needs about 30 s, and reads with 45 and 70 s waits worked. The default connection file in ocd.sh is the one in the Zephyr project folder, and the saved run used it. ports/bitnetmcu/openocd-mspm0.cfg has the same three lines. That pairing with this read script was not run as written here.
A model's first number is not 0 or the second is below 20An answer differed from the stored one. Reflash, and check you built the same library flavour you are reading. The -Os build is slower: 4.68, 10.87, 39.94 and 199.45 ms.

Every fix for this board: the FAQ.

What to build next

Every build. The code for all of them is in the GitHub repository.

Evidence and limitsRoom-occupancy models of 636 to 33k weights, timed on 12 boards; 4.0 to 129 ms on the G3507. Ran on 1 board. Results, sources, timing and limits.

Expected result: All four models answer 20 of 20 stored test windows correctly on the board, in 4.00 ms for 636 weights to 129.40 ms for 33k weights per answer at -O3 and 80 MHz.

What this shows

  • A room-occupancy network runs on a Cortex-M0+ with no FPU and no AI hardware, as plain C, and gives the same class and the same four output values as the quantized model run in onnxruntime. This holds on all 20 stored windows.
  • Answer time grows with model size: 11,328 to 610,560 multiply-adds took 4.00 to 129.40 ms, about 16 to 20 cycles per multiply-add for the network alone at -O3.
  • All four models, with their stored test windows, fit one 118.9 kB image in 128 kB of flash and 12.8 kB of RAM.
What this does not establish, and limits

What this does not establish

  • Anything about live sensing. The windows are stored in the image; no light, sound, CO2 or motion sensor is read.
  • That the model is accurate in your room. The models score 85.4 to 90.9% on a held-out part of one room's four days of data. Balanced accuracy is 60.5 to 74.7%. They tell empty from occupied on 98.6 to 100% of windows but struggle to tell 2 people from 3. With whole days held out, the 8.5k-weight model scored 87.7% overall but 40.2% balanced: 159 of 170 three-person windows came out as empty.
  • That bigger is better: the 8.5k-weight model beat the 33k-weight one on accuracy.
  • Stack use, or current. Neither was measured for these programs.

Limits to keep in mind

  • No build steps are given here: Build steps for these models are not published, so the page lists the results only. The numbers come from runs on the boards named in the grid.
  • The timings are the fastest of five runs on the best of 20 windows, the table's min. They come from one board and one run of the program.
  • Quantizing the float input costs about 100k cycles (1.25 ms) every time, which is 30% of the smallest model's total; feeding int8 directly saves it.
  • TI's own Neural Network Compiler produced code 6 to 14% slower than this plain C at -Os on the three smaller models and 20% faster on the largest. This page does not run it.
  • This G3507 has no neural-network accelerator; the TinyEngine accelerator is on the MSPM0G5187.
  • Checked on an Intel Mac only.

Sources

Why this board

It is the board the models were first timed on and the one these scripts are written for; its 128 kB of flash holds all four models and their test windows in one image of 118.9 kB at -O3.

Versions, sizes and timing

Models636, 1,748, 8.5k and 33k weights and biases (after batch norm is folded in); 11,328, 33,856, 157,824 and 610,560 multiply-adds; int8 weights and activations, int32 accumulators; trained on UCI Room Occupancy Estimation (id 864, CC BY 4.0)
Accuracy on the held-out windows (int8)88.4%, 88.5%, 90.9%, 85.4%; empty versus occupied 100.0%, 99.8%, 100.0%, 98.6%; the C code matches the quantized ONNX model exactly on all 1,001 test windows
Cycles per answer at -O3, input step plus network (fastest)320,386; 723,842; 2,821,806; 10,352,016 at 80 MHz (clock read back as 80.85 to 80.90 MHz against the Mac's clock, 1.1% high from OpenOCD latency)
Cycles per answer at -Os374,048; 869,848; 3,195,175; 15,956,266 (4.68, 10.87, 39.94, 199.45 ms)
Model flash and RAM-Os 1.7 kB / 3.1 kB / 10.1 kB / 34.6 kB of flash and 1.1 kB / 1.1 kB / 2.1 kB / 4.1 kB of RAM; -O3 6.3 kB / 9.5 kB / 16.6 kB / 40.7 kB of flash, same RAM
ToolchainHarness: TI Arm Clang 5.1.1.LTS -O2, MSPM0 SDK 2.11.00.07; model libraries: TI Arm Clang 4.0.4.LTS; flash with UniFlash 9.6.0; results read with xPack OpenOCD 0.12.0; cycles counted by SysTick (the Cortex-M0+ has no cycle counter), read cost 8 cycles
Image size-O3 image: 118.9 kB of flash, 12.8 kB of RAM; -Os image: 95.3 kB of flash

Evidence

  • Ran on the MSPM0 G3507 on 2026-10-05 at 80 MHz: all four models matched the expected class and all four logits on all 20 stored test windows (20 of 20), at -O3 and at -Os. Fastest of five runs on the best window: 4.00 ms (636 weights) to 129.40 ms (33k weights) at -O3.
  • The raw 35 words the board wrote to RAM for the -O3 build, as read back over the debugger.
  • The flash output: the image loaded and verified.

Other boards

What the status words mean

Works ran here and did what it shouldCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why

Result grid

Project
LP-MSPM0G3507MSPM0G3507 chip
LP-MSPM0L1306MSPM0L1306 chip
LP-EM-CC2340R5CC2340R52 chip
LAUNCHXL-F2800137TMS320F2800137 chip
Run a small AI model on the chip
LP-MSPM0G3507WorksRoom-occupancy models with 636 to 33k weights: 4.0 to 129 ms as plain C at -O3
LP-MSPM0L1306Works3 of 4 room-occupancy models fit in 4 kB of RAM; the 8.5k-weight one runs in 84 to 100 ms
LP-EM-CC2340R5WorksAll four room-occupancy models run: 7.0 to 229 ms as plain C at -O3 at 48 MHz Measured results (data file)
LAUNCHXL-F2800137WorksAll four room-occupancy models run from flash:
Details1.1 to 30.8 ms with TI's model compiler at 120 MHz, 1.8 to 65.4 ms as plain C
Measured results (data file)

Works ran here and did what it shouldShould work it builds; only naming, packaging or build glue is in the way; hover for whichCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why

Experiments (12)

StatusWhat was triedResult
WorksHow big a neural network can the TI LP-MSPM0L1306 run in 4 kB of RAM?
MSPM0 L1306, 2026-10-06
The 8.5k-weight room-occupancy model runs in 84 to 100 ms with 1.3 kB of RAM spare against its measured 548-byte stack (0.8 kB against the 1 kB stack the build reserves); the 32.8k-weight model does not link, its...
WorksHow much faster is the TinyEngine NPU on a TI LP-MSPM0G5187 than its own CPU?
MSPM0 G5187, 2026-10-09
The TinyEngine NPU ran all four room-occupancy models with 20 of 20 test vectors matching: 3.0x faster than the best CPU build on the 636-weight model, 6.2x on the 1.7k-weight model, 16.7x on the 8.5k-weight model...
WorksDoes TI's compiler put this repo's room-occupancy models on the LP-AM13E230's NPU, and how much faster is it?
AM13E230, 2026-10-09
TI's NNC ran all four room-occupancy models on the AM13E230's TinyEngine NPU with 20 of 20 test vectors right, 4.7x, 6.7x, 8.8x and 2.4x faster than NNC's own CPU build (8k model: 5.544 ms to 0.630 ms at 200 MHz). The...
Not for this chipCan any room-occupancy model fit in the 1 kB of RAM on a TI LP-MSPM0C1104?
MSPM0 C1104, 2026-10-08
None of the four room-occupancy models links for the MSPM0 C1104; the smallest needs 1.2 kB of RAM for its buffers against 1 kB.
Can the LP-MSPM0G5187's NPU count people from a live light reading on the BP-BASSENSORSMKII?
MSPM0 G5187, 2026-10-10
The room-occupancy model runs on the NPU once a second. Its input is a live light reading from the BP-BASSENSORSMKII's OPT3001, taken over I2C. Each call takes 1.30 to 1.32 ms, within 1 percent of the time on stored...
WorksHow much does it cost to run code from flash on the LP-AM263P, and do TI's AI models care?
AM263P, 2026-10-10
Running code straight from the AM263P's flash works with only the USB cable. TI's own memcpy benchmark takes 8.7 times as long as from RAM with no extra cache and 2.4 times with TI's 64 kB cache; with smart...
WorksCan the ESP32-C6's low-power core run the 8.5k-weight room-occupancy model?
ESP32-C6-DevKitC-1, 2026-10-11
The 8k room-occupancy network runs on the ESP32-C6's low-power core and passes 20 of 20 test windows with every logit equal to the reference, in 214 ms (3.36 million LP cycles); the float input step does not fit, so...
Can TI's "OK Kilby" wake-word model listen to the LP-MSPM0G5187's own microphone and light an LED?
MSPM0 G5187, 2026-10-13
TI's wake-word model runs on the board's NPU from a rebuilt I2S microphone input and detected a synthetic "OK Kilby" 120 of 120 times across six macOS voices (replay through the serial port); the board's own...
WorksDo the room-occupancy models fit under Zephyr's 24 kB of RAM on the NXP FRDM-MCXA153?
FRDM-MCXA153, 2026-10-11
The largest room-occupancy model (32.8k weights) fits and passes 20 of 20 under Zephyr 4.4.2 on the FRDM-MCXA153 in 8.7 kB of the 24 kB the app region gets; the other 8 kB (SRAMX) is not needed.
WorksCan the LP-MSPM0G5187's TinyEngine NPU run fixed DSP filters faster than the CPU?
MSPM0 G5187, 2026-10-20
A 64-tap FIR, an 8-band filter bank, a max-pool peak detector with comparator and a 64-point DFT, built as fixed-weight network layers with no training, all compiled for the TinyEngine NPU and matched an integer...
WorksDoes a model run on the LP-AM13E230 straight from the file the training tool wrote, in float, with no vendor quantization step?
AM13E230, 2026-10-30
Nine models in the files their training tools wrote (four float32 CNNs from torch, a Keras CNN as float32 and int8 TFLite, a decision tree and a random forest from scikit-learn, an XGBoost model) ran on the AM13E230...
WorksHow fast is the LP-MSPM0G5187's NPU on MLPerf Tiny keyword spotting?
MSPM0 G5187, 2026-11-03
The MLPerf Tiny keyword-spotting DS-CNN, quantized with TI's post-training tool and compiled by NNC for the TinyEngine NPU, runs in 18.70 ms (53.46 inferences a second) on the MSPM0 G5187 at 80 MHz with all 11...

Source files

Get the code and tell us how it wentThe clone command, the board folder with its AGENTS.md, reports from others, and the three report forms.

Get the code

Clone the repository and open the board's folder below. AGENTS.md is a plain text file of notes for AI coding assistants, and llms.txt at the root indexes the site for one.

git clone https://github.com/Fox-Red-Labs/fox-red-labs.git

Code is BSD-3-Clause, writing is CC BY 4.0; third-party folders keep their own licenses.

Built it? Tell us

Built this, or got stuck? Report it on GitHub with a few short answers. Your report shows here in your words, marked as yours. A failure that repeats on the bench gets its fix here.