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
- LP-MSPM0G3507 LaunchPad development kit Buy the board: MSPM0G3507, 32 kB of RAM, 128 kB of flash.
- Micro-USB data cable power and programming
Set up your computer once: 1 step. Done already? Start at step 2.
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.gzon an Intel Mac,xpack-openocd-0.12.0-7-darwin-arm64.tar.gzon 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 --versionprints 5.1.1, and the foldersmspm0_sdk_2_11_00_07anduniflash_9.6.0are under/Applications/ti.
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 -eYou should see:
Serial Num:followed by your probe's serial number .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.shrefuses to run unless that probe is on the USB bus. The twoValue=lines of the connection filesdk-common/MSPM0G3507_<probe serial>.ccxmlselect the probe by serial number. ReplaceYOURSERIALin 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.shopens 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>.ccxmlYou should see:
grep -n YOURSERIALon those two files shows the changed lines, with your real number in place of the word. The filenameMSPM0G3507_<probe serial>.ccxmlis unchanged.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_syspllexample.mspm0g3507/mcu-bench/edgeai-sdk/occupancy/build.sh O3You 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.outexists. UseOsinstead ofO3to link the smaller, slower -Os libraries, at 95.3 kB of flash.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.outYou should see: UniFlash loads and then verifies:
Program verification successful fortheoccupancy.outpath. The program starts running.Wait for the whole run, then read the results table the program leaves in RAM.TERMINAL
It is 35 words at
0x202020bc, the symboloccinbuild-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.OCDis the folder you unpacked OpenOCD into;OCD_CFGis the tracked connection file the digit build uses for this same board;PROBEis 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 70000You 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.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 reads0, 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 claudegit clone --depth 1 --filter=blob:none https://github.com/Fox-Red-Labs/fox-red-labs.git && cd fox-red-labs
py start.py mspm0g3507 small-ai-model --assistant claudeIt runs the steps above and reports what it saw.
Not Claude Code? Copy this prompt instead.
If something goes wrong
| At step 1 | build.sh has the SDK and compiler paths written in its first lines (SDK= and CC=); edit them if yours live elsewhere. |
| Nothing is listed | The 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 change | So 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 exist | Which this script avoids by not using them. |
The script stops at Probe ... missing | The 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 finished | Or 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 20 | An 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
| Models | 636, 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 -Os | 374,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 | |
| Toolchain | Harness: 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
- MSPM0L1306, CC2340R5, F2800137, MSPM0G3519, MSPM0G5187, AM13E230, MSPM33C321A, CC1354P10, CC2755P10, CC35X1, TDA4VMCould work could work
- MSPM0C1104Not for this chip can't run it
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
Details
1.1 to 30.8 ms with TI's model compiler at 120 MHz, 1.8 to 65.4 ms as plain CWorks 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)
| Status | What was tried | Result |
|---|---|---|
| Works | How 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... |
| Works | How 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... |
| Works | Does 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 chip | Can 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... | |
| Works | How 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... |
| Works | Can 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... | |
| Works | Do 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. |
| Works | Can 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... |
| Works | Does 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... |
| Works | How 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
- Measured results (data file) (CC2340R5): the raw numbers
- Measured results (data file) (LAUNCHXL-F2800137): the raw numbers
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
- LP-MSPM0G3507: folder
mspm0g3507/.- README: the board's lab notebook (what was run, in order)
- Notes for an AI coding assistant working in this repository: notes for an AI assistant; copy it into your own project if you use one
- FAQ: errors and fixes
The other 3 board folders
- LP-MSPM0L1306: folder
mspm0l1306/.- README: the board's lab notebook (what was run, in order)
- Notes for an AI coding assistant working in this repository: notes for an AI assistant; copy it into your own project if you use one
- FAQ: errors and fixes
- LP-EM-CC2340R5: folder
cc2340r5/.- README: the board's lab notebook (what was run, in order)
- Notes for an AI coding assistant working in this repository: notes for an AI assistant; copy it into your own project if you use one
- FAQ: errors and fixes
- LAUNCHXL-F2800137: folder
c2000-launchpad/.- README: the board's lab notebook (what was run, in order)
- Notes for an AI coding assistant working in this repository: notes for an AI assistant; copy it into your own project if you use one
- FAQ: errors and fixes
- LP-MSPM0L1306: folder
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.