# Reading an Emcraft SOM-NRF9151 from brintOS This machine reaches an Emcraft SOM-NRF9151 on its Starter Kit through two USB devices that you grant to it from Chrome: a SEGGER J-Link on the kit's debug header, which openocd drives over SWD, and the kit's own USB-serial bridge, which carries the board's shell. Installing a release onto the board is not part of this image yet. Everything below only reads the board. ## 1. Your own copy of the machine Fork `https://brintos.io/sergei/core-image-brintos-nrf-sdk` into your account (`https://brintos.io/new?fork=sergei/core-image-brintos-nrf-sdk`), and work in your fork: a visitor's session on ours gets a read-only root. In your machine, turn on **Settings → General → Developer mode**. This image carries its own HardwareJS runtime in `/boot` and runs on it only in Developer mode; with it off, Expect cannot spawn its children and the console tools fail. ## 2. What connects where SOM-NRF9151 Starter Kit |-- debug header (P4) --- J-Link --- USB --- the computer running Chrome `-- console USB (FT230X) ----------- USB --- the same computer Grant both devices to the machine. The console is 115200 8N1. A board on another carrier can use a TTL-232R cable on its UART as the console instead (§7 says how the station finds it). ## 3. Check the station first With no board attached: brintos-selftest 99-nrf-station.test 99-som-nrf91.test 99-openocd.test 99-som-console.test ## 4. The board's shell som-console # the board's shell in picocom; C-a C-x leaves som-console --list # every USB-serial port this machine has minicom -b 115200 -D $(som-console --find) `som-console` finds the bridge by its USB id, not by its tty number, so it works in whatever order the devices were granted. Scripts take the node from `som-console --find`. ## 5. Probing and reading the chip The board config `board/emcraft-som-nrf9151.cfg` selects the J-Link and SWD and creates `nrf91.cpu`, with the flash bank `nrf91.flash` (bank 0) and the UICR bank `nrf91.uicr` (bank 1): openocd -f board/emcraft-som-nrf9151.cfg -c init -c "flash probe 0" -c shutdown prints `SWD DPIDR 0x6ba02477`, `Cortex-M33 r0p2` and `nRF9151-LACA 1024kB Flash, 256kB RAM`. `VTarget = 0.000 V` means the cable is on the wrong header or the wrong way round. A read needs no halt, so it runs with the application's watchdog live: openocd -f board/emcraft-som-nrf9151.cfg -c init -c "dump_image /tmp/flash.bin 0 0x100000" -c shutdown openocd -f board/emcraft-som-nrf9151.cfg -c init -c "flash read_bank 1 /tmp/uicr.bin" -c shutdown sha256sum /tmp/flash.bin /tmp/uicr.bin 1 MiB of flash took 57 s through a J-Link EDU Mini. `/tmp` is memory: copy what you keep off the machine before the session ends. Another SWD adapter, or another speed, is a variable set before the config: openocd -c "set BRINTOS_JTAG_IFACE interface/.cfg" -f board/emcraft-som-nrf9151.cfg ... openocd -c "set BRINTOS_JTAG_SPEED 2000" -f board/emcraft-som-nrf9151.cfg ... Keep the speed at 2000 kHz or below; above it, flash programming fails. ## 6. What the nRF9151 does not forgive Read these before anything that halts, erases or writes the chip: 1. **The application's watchdog.** The release's application resets the chip a few seconds after openocd halts it (3 to 6 s, measured on the previous release, which had the same 10 s nPM1300 watchdog), and the halted operation dies with `SWD: Read data parity mismatch`. Run `watchdog disable` on the board's shell first. It stays off across `reset halt` and comes back at the next boot. 2. **A reset of an erased chip locks debug access** (APPROTECT), and openocd's `program` starts with a reset. Erase, write and verify in one openocd session with no reset in between, and reset only after the verify passes. 3. **The UICR is write-once.** Emcraft's hex files carry UICR records. Never write them: strip everything from `0xFF0000` up, and compare the UICR rather than write it. ## 7. Installing a release The machine carries Emcraft's release 2.0-122 for the SOM (nRF Connect SDK 3.4.1), unmodified: two applications, each in its own directory beside a PROVENANCE file that gives its origin, sha256, the version its shell reports, and the oldest modem firmware it runs on. | Release | Where | |---|---| | `asset_tracker_v2` | `/usr/share/brintos-som/nrf9151/asset_tracker_v2/` | | `hello_mcuboot` | `/usr/share/brintos-som/nrf9151/hello_mcuboot/` | With the J-Link and the console both attached: som-program-nrf91 --app asset_tracker_v2 --check # probe; is the release compatible? writes nothing som-program-nrf91 --app asset_tracker_v2 # install it som-program-nrf91 --app hello_mcuboot # or the other one **The console is required.** `som-program-nrf91`, `--check` and `--dry-run` included, looks for the board's console bridge by its USB id: the Starter Kit's FT230X (`0403:6015`) or a TTL-232R cable (`0403:6001`), with `som-console --find --id "0403:6015 0403:6001"`. It refuses, touching nothing, when it finds none or more than one: grant the bridge, or name the port with `--console ` (`som-console --list` shows them). Without the console it cannot turn the watchdog off, read the modem or check what booted; `--no-console` runs without it and skips those steps. The station's window does the same search before Check, Install and the tests, and starts nothing until it finds exactly one console; its status then says FAIL with `som-console`'s message. With both kinds of bridge granted the search finds two: grant only the board's, or set `SOM_CONSOLE_ID` to its id, which replaces the list for the window, `som-program-nrf91` and `som-test-nrf91` alike. Recover needs no console. `som-program-nrf91` keeps every rule in §6 for you: it turns the watchdog off, holds the core halted to prove nothing resets it (12 s, or the watchdog's own timeout and 3 s more when the board's shell reports a longer one; `--gate ` holds longer, and with `--no-console` it warns that the watchdog is unknown), erases only the 4 KiB pages the image covers, writes and verifies in one session, compares the UICR instead of writing it, and checks after the reset that the board reports the version the PROVENANCE names. Pages outside the image (the application's settings, a provisioned SoftSIM) are kept; `--erase all` clears the whole 1 MiB instead. It ends with one PASS or FAIL line and the time the run took. **The nRF91's own watchdog (WDT0)** is read by the probe too. Once started it is not stopped by a soft reset, the only reset this station makes, so: if it keeps counting while the core is halted, the gate lasts its timeout and 3 s more, and then, unfed, it fires there, before anything is erased (a timeout longer than 600 s is refused outright) -- this station cannot write such a board. If it pauses while the core is halted, openocd's flash loader feeds it through RR[0] as it writes; any other reload register enabled is warned about, because the loader leaves it unfed. 2.0-122 does not start WDT0 (it uses the nPM1300's watchdog). **A backup** is taken only with `--backup`: into `/tmp`, the pages the erase will clear (all 1 MiB with `--erase all`), one file per range, listed with their sha256 in a `.pages` file; write each back with `--image --addr
`. **Interrupting a run.** A Ctrl-C (or a HUP or TERM) is honoured between steps, never inside an openocd session: a write in progress runs to its end, and the run then says what it left (exit 130, or 129/143). A write that fails keeps its retry session in `/tmp/som-nrf91-retry-`, which starts with a plain `halt` -- do not reset or power-cycle the board, run the retry. Until that session is gone, the next run refuses to start (it would reset a chip that may be half-written); `--ignore-retry` overrides it once the board has been rewritten another way. **The modem firmware.** This station cannot update the nRF9151's modem. Before it writes anything, `som-program-nrf91` reads the modem firmware over the console (`AT%SHORTSWVER`) and refuses one outside the release's rule: the same family as the release's `modem-min`, the same major.minor, and at or above its patch, so 2.0-122 takes `nrf91x1_2.0.2` or a later 2.0.x. Update the modem natively with `nrfutil device program --firmware mfw_nrf91x1_.zip`, then install again. The modem can be read only while the running application has an AT shell. When it cannot be read before the write, the run reads it again once the release has booted, and fails, saying the release is installed, if it is outside the rule or still unread. `som-test-nrf91` judges the modem by the same rule. Both say whether the release lists the version as one it was run on (`modem-validated` in PROVENANCE), which never changes the verdict. **A locked chip.** If the probe reports the chip locked (APPROTECT), recover it from here, with a release to install in the same session: som-recover-nrf91 --app asset_tracker_v2 --yes It erases everything through the chip's CTRL-AP, the UICR included, writes the two UICR words that keep the debug port open (0x50FA50FA at 0x00FF8000 and 0x00FF802C; 2.0-122 opens the port at boot only when both hold), writes and verifies the release with its own UICR records, and only then resets. After the reset it checks that the debug port stayed open and reads the UICR back. A board's saved UICR page goes back instead with `--uicr `, and is compared with the file byte for byte once the chip has reset: the key-slot part of the UICR, from 0x00FF8400, reads back erased until then. It refuses a chip whose debug access is open (`som-program-nrf91` installs it and keeps the UICR) unless `--force`, which reads the chip out first, and a chip whose erase protection is set, which no debugger can recover. Once its erase has run, it sets aside, as `som-nrf91-recovered-*`, any retry session a failed write left in `/tmp`: that session no longer describes the chip, and `som-program-nrf91` would refuse to start beside it. If the write after the erase fails, do not reset the board: the chip stays unlocked only until its next reset, and the run names the command to run at once, with `--force`, since the erase has left the debug port open. A run that fails keeps openocd's output from each of its sessions in `/tmp/som-recover-nrf91-