> For the complete documentation index, see [llms.txt](https://dev.solid-run.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dev.solid-run.com/solidsense-aiot/solidsense-aiot-mcu.md).

# SolidSense AIOT — MCU firmware

Software Flashing and Usage

The AIOT carries an **STM32U031C8** microcontroller alongside the i.MX8 SOM. It runs as an **I2C slave at address 0x18** and gives the SOM access to the peripherals that are wired to the MCU rather than to the SOM directly.

The SOM issues commands; the MCU executes them and returns a response.

### What it does

* **LED** — turn on, turn off, read state
* **IR presence sensor** (STHS34PF80) — presence and motion detection with a configurable threshold, reported through an interrupt line
* **Accelerometer** (ISM330DHCX) — wake-up on motion with a configurable threshold
* **GNSS** (u-blox MIA-M10) — reachable only from the MCU. The firmware passes the receiver's NMEA stream through to the SOM unchanged, so gpsd can consume it directly
* **Battery charger** (BQ25638) — power source, charge state, and an estimated state of charge
* **Real-time clock** — kept from GNSS by the MCU itself, with no involvement from the SOM. Runs from a 32.768 kHz crystal and survives an MCU reset
* **Interrupts** — a single read reports pending MCU, IR and accelerometer events

## Firmware and protocol reference

Source, protocol reference and build instructions:

[**https://github.com/SolidRun/ss-aiot-mcu**](https://github.com/SolidRun/ss-aiot-mcu)

The **README** in that repository is the authoritative description of the I2C interface — every command, its exact request and response length, the meaning of the status byte, the sensor threshold ranges, the GNSS passthrough, and the current known limitations. It is maintained alongside the firmware, so it always matches the code.

Deliberately not duplicated here: command bytes and payload formats. Read them from the README for the firmware revision you are actually running.

## Flashing

The MCU is programmed over SWD through the AIOT's debug header (J5006). Two probes are documented below — an **STLINK-V3** driven from the STM32CubeProgrammer GUI, and a **SEGGER J-Link** driven from the command line. Either one is sufficient; pick whichever you have. Both need a firmware image first.

### Getting the firmware image

Build it from source — clone the repository above, import the project into STM32CubeIDE, and build. The `.hex` is produced in the build output directory.

{% file src="/files/EOidIAuvVJvN1ObSXXul" %}

### Programming with STLINK-V3

#### equipment

<table><thead><tr><th width="421.98046875">Part Name</th><th width="86.59765625">Qty.</th><th width="121.7578125">Picture</th></tr></thead><tbody><tr><td>USB-C Cable</td><td>1</td><td><img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2FKY17QOHB8DEvSxmbETcu%2Funknown.png?alt=media&amp;token=07ced94e-a9d4-4d43-b29d-10031bd15774" alt="" data-size="original"></td></tr><tr><td>STLINK-V3</td><td>1</td><td><img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2FxLfOzflC4sfSRO9uq4G8%2Funknown.png?alt=media&amp;token=b5d2c664-e4d9-4738-99f6-56ef33ae2cba" alt="" data-size="original"></td></tr><tr><td>Micro USB-B Cable</td><td>1</td><td><img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2F4sljqHwUwC7uzmHL9qJb%2Funknown.png?alt=media&amp;token=c9ef3a5a-8ae1-4ca6-96d2-d499531e9695" alt="" data-size="original"></td></tr><tr><td>ST-LINK V3 SWD/JTAG programming cable (10/20-pin adapter set)</td><td>1</td><td><img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2F941F9TdhLBBQjECKgnnM%2Funknown.png?alt=media&amp;token=ae122577-e34b-446a-98b8-37beaf592767" alt="" data-size="original"></td></tr></tbody></table>

The flashing process requires a local computer with the following software installed:

STM32CubeProgrammer:

{% embed url="<https://www.st.com/en/development-tools/stm32cubeprog.html>" %}

#### Preparing the AIOT for flashing

<figure><img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2FTbYjrUasgHPvt7kyBNyY%2Fimage.png?alt=media&amp;token=9215303b-5382-4fe2-9100-6da9e1d159e1" alt=""><figcaption></figcaption></figure>

Connect STLINK-V3 (CN5) to the computer via micro USB.\
Connect the AIOT (J5006) to the STLINK (STDC14) using the ST-LINK V3 SWD/JTAG programming cable. Ensure that the cable is connected to the AIOT in the correct orientation, as shown in the image.

<img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2FU1koLI32jVtQaa2UdAxN%2Funknown.png?alt=media&amp;token=227fcf8a-db24-4ab3-8170-6a8b4bed2bf5" alt="" height="183" width="161">

Connect the AIOT to the computer using a USB cable.

Turn ON the AIOT using the designated switch.

#### Programming

Open STM32CubeProgrammer:

<img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2F7IKaNPcrNl6UvhAIAZHO%2Funknown.png?alt=media&amp;token=35a92954-7260-4214-ac99-5ec9c40ef972" alt="" height="197" width="346">

Select Erasing & Programming from the left menu. (1)

Find the appropriate Port and connect. (2)

Load the appropriate HEX file. (3)

Verify the selections according to the image. (4)

Click Start Programming. (5)

After the successful completion message is displayed, you can proceed to the testing process.

### Programming with J-Link

#### equipment

<table><thead><tr><th width="421.98046875">Part Name</th><th width="86.59765625">Qty.</th></tr></thead><tbody><tr><td>USB-C Cable (optional — see below)</td><td>1</td></tr><tr><td>SEGGER J-Link (standard ARM 20-pin JTAG connector)</td><td>1</td></tr><tr><td>USB-B Cable</td><td>1</td></tr><tr><td>ARM 20-pin to 10-pin JTAG adapter and cable</td><td>1</td></tr></tbody></table>

The flashing process requires a local computer with the following software installed:

J-Link Software and Documentation Pack — this provides the `JLinkExe` command-line tool (`JLink.exe` on Windows):

{% embed url="<https://www.segger.com/downloads/jlink/>" %}

#### Preparing the AIOT for flashing

Connect the J-Link to the computer via USB.

Connect the AIOT (J5006) to the J-Link using the ARM 20-pin to 10-pin JTAG adapter and cable — J5006 is a standard ARM 10-pin debug header, so this is the same adapter set used with the STLINK-V3 above. Ensure that the cable is connected to the AIOT in the correct orientation, as shown in the image.

<img src="https://1160211108-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCsmHoAD7oNPYQbYxSWHU%2Fuploads%2FU1koLI32jVtQaa2UdAxN%2Funknown.png?alt=media&amp;token=227fcf8a-db24-4ab3-8170-6a8b4bed2bf5" alt="" height="183" width="161">

The J-Link supplies power to the MCU through the debug connector, so the AIOT does not have to be powered over USB-C to be flashed — the probe alone is enough.

Connect the AIOT to the computer using a USB cable and turn it ON using the designated switch only if you also want the rest of the board running, for example to run the [quick check](#quick-check-from-linux) over I2C once the firmware is programmed.

#### Programming

Start J-Link Commander and enter the commands below, substituting the path to your `.hex` file:

```
$ JLinkExe -NoGui 1
J-Link> si SWD                        # select the SWD interface
J-Link> speed 4000                    # SWD clock in kHz
J-Link> device STM32U031C8Ux          # part name, sets up the flash bank
J-Link> connect
J-Link> r                             # reset and halt the core
J-Link> h
J-Link> erase                         # optional, forces a full rewrite
J-Link> loadfile Aiot_437f4e4.hex     # erase, program and verify
J-Link> r                             # reset ...
J-Link> g                             # ... and run the new firmware
J-Link> qc                            # quit
```

The same commands can be placed in a plain text file (without the `J-Link>` prompts) and run non-interactively:

```
JLinkExe -NoGui 1 -ExitOnError 1 -CommandFile <file>
```

A successful run reports `Verifying flash ... Done` followed by `Bank 0 @ 0x08000000: 1 range affected`, after which you can proceed to the testing process.

Two messages look like errors but are not:

* `Bank 0 @ 0x08000000: Skipped. Contents already match` — the device already holds this image, so erase, program and verify were skipped. Add the `erase` command shown above to force a rewrite.
* `Communication timed out: ...` printed **after** `qc` — emitted while the USB session is being closed, once flashing has already completed. Judge success by the exit status, not by this line.

### Quick check from Linux

The MCU should appear at `0x18`:

```
i2cdetect -y -r <bus>
```

Turn the LED on — a write-only command, and the easiest thing to confirm visually:

```
i2ctransfer -y <bus> w3@0x18 0x10 0x01 0x00
```

Read the charger status — a 3-byte payload, so the response is 5 bytes:

```
i2ctransfer -y <bus> w3@0x18 0x12 0x05 0x00 r5@0x18
```

**Read exactly `2 + DATA_LEN` bytes.** The MCU arms each response with an exact length and has nothing to send past it. Asking for more bytes than the response contains leaves the MCU holding SCL low, and the bus stays stuck for roughly ten seconds until the firmware's recovery timer releases it. The per-command lengths are in the README.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://dev.solid-run.com/solidsense-aiot/solidsense-aiot-mcu.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
