Table of Contents

Lab 2: Renode for MCU Emulation and Validation

Duration

2 hours:

Learning Objectives

After this laboratory, students should be able to:

Laboratory Scenario

The lab uses a Raspberry Pi Pico firmware project running in a Renode digital twin. Renode provides the RP2040 board model, UART capture, and a deterministic virtual I2C sensor. No physical Pico board or sensor is required.

[Virtual I2C sensor @ 0x52] -> sample stream -> [RP2040 firmware]

Each virtual sensor sample contains:

The firmware must classify every sample with two methods:

The goal is not to train a model during the lab. The model weights are already provided. Students focus on running firmware in a digital twin, reading the virtual sensor, implementing the inference formula, and comparing the two filtering methods.

Project Layout

The important files are:

firmware/main.c
firmware/model_weights.h
renode/run_test.resc
renode/run_metrics.resc
renode/sensor_i2c.repl
renode/peripherals/VirtualSensorStream.cs
docker/scripts/build_firmware.sh
docker/scripts/run_test.sh
docker/scripts/generate_report.py
docs/renode_primer.md
docs/exercise_guide.md
reference/firmware/main.c
output/report.html

Short description:

Part 1: Renode Theory

What Renode Is

Renode is an emulator for embedded systems. It can run firmware built for a microcontroller or SoC inside a virtual machine that includes CPUs, buses, memories, UARTs, timers, and peripherals.

For this laboratory, Renode gives us a repeatable digital twin:

This makes the exercise independent of physical boards, USB cables, sensor availability, and lab hardware differences.

Digital Twin Mental Model

A Renode lab scenario has three layers:

In this lab:

firmware/main.c                      -> compiled to firmware.elf
renode/peripherals/VirtualSensorStream.cs -> custom I2C peripheral
renode/sensor_i2c.repl               -> virtual wiring overlay
renode/run_test.resc                 -> Renode automation script

RESC Files

.resc files are Renode monitor scripts. They automate what an instructor could otherwise type manually in the Renode monitor.

The lab script is renode/run_test.resc. It performs these jobs:

Typical commands in this scenario:

path add @/opt/renode-rp2040
include @/workspace/renode/peripherals/VirtualSensorStream.cs
EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.I2C.VirtualSensorStream"
include @boards/initialize_raspberry_pico.resc
machine LoadPlatformDescription @/workspace/renode/sensor_i2c.repl
sysbus LoadELF @/workspace/build/firmware.elf
sysbus.uart0 CreateFileBackend @/workspace/output/uart_output.txt true
emulation RunFor "00:00:05"

Key idea: .resc files describe the experiment procedure.

REPL Files

.repl files describe platform topology: which peripherals exist and where they are connected.

This lab uses a small overlay instead of redefining the whole Pico:

sensor: I2C.VirtualSensorStream @ i2c0 0x52

Read it as:

Key idea: .repl files describe the virtual wires.

Custom Virtual Peripheral

VirtualSensorStream.cs is a minimal Renode I2C peripheral. It models only the behavior needed by this lab:

The component implements the Renode I2C peripheral interface. It is intentionally not a complete real sensor. For this exercise, deterministic behavior is more important than detailed physical realism.

The virtual wiring path is:

run_test.resc
  loads VirtualSensorStream.cs
  initializes Raspberry Pi Pico
  applies sensor_i2c.repl

sensor_i2c.repl
  connects VirtualSensorStream to i2c0 address 0x52

firmware/main.c
  initializes i2c0 on the Pico pins
  writes register 0x00
  reads 4-byte sample frames

Validation Surface

The validation harness does not inspect C variables directly. It checks the observable firmware behavior through UART output.

Important UART lines:

SAMPLE seq=... value=...
THRESHOLD seq=... decision=...
MODEL seq=... decision=... score=...
DISAGREE seq=...
SUMMARY threshold_keep=... threshold_drop=... model_keep=... model_drop=... disagreements=...

This is close to a real board workflow: the observable interface is serial output plus emulator logs and generated reports.

Part 2: Running The Starter

From the browser IDE, press Run in the side panel.

From a shell:

./run.sh up --build digital-twin

The starter code should build and read the sensor stream. The filter checks fail until students implement the TODO functions.

Expected final passing summary after implementation:

SUMMARY threshold_keep=8 threshold_drop=2 model_keep=6 model_drop=4 disagreements=2
>>> ALL CHECKS PASSED - sensor filters behave as expected <<<

The HTML report is written to:

output/report.html

Part 3: Exercise Data

The virtual sensor emits this deterministic stream:

Seq Value Intended role
0 500 normal baseline
1 506 small normal movement
2 612 borderline jump
3 520 return to normal
4 785 high outlier
5 532 normal
6 340 low outlier
7 650 borderline jump
8 545 normal
9 498 normal

The threshold filter should reject only the gross high and low outliers:

seq=4
seq=6

The tiny model should reject the two gross outliers and two borderline jumps:

seq=2
seq=4
seq=6
seq=7

Therefore, the two methods disagree at:

seq=2
seq=7

Part 4: Exercises

Exercise 1: Identify The Renode Scenario

Open renode/run_test.resc.

Tasks:

  1. Find the command that loads VirtualSensorStream.cs.
  2. Find the command that initializes the Raspberry Pi Pico machine.
  3. Find the command that applies sensor_i2c.repl.
  4. Find the command that loads firmware.elf.
  5. Find where UART output is written.

Questions:

  1. Which file describes the virtual sensor wiring?
  2. Which bus is the sensor attached to?
  3. What I2C address does the sensor use?
  4. Which output file contains firmware UART logs?

hints:

Exercise 2: Follow One Sensor Sample End To End

Files to inspect:

renode/peripherals/VirtualSensorStream.cs
renode/sensor_i2c.repl
firmware/main.c

Tasks:

  1. In VirtualSensorStream.cs, find the deterministic sample table.
  2. Find the code that returns a 4-byte sample frame.
  3. In firmware/main.c, find the code that reads one sample from I2C.
  4. Run the validation and locate the UART line for seq=0.

Fill the table:

Step File Evidence
Sensor provides sample table
REPL connects sensor to I2C
Firmware reads sample frame
Firmware prints sample
Harness validates sample count

Exercise 3: Implement The Threshold Filter

Open firmware/main.c and implement:

threshold_filter_should_keep

Rules:

Expected threshold drops:

seq=4
seq=6

After this exercise, some checks may still fail because the model filter is not implemented yet.

Exercise 4: Implement The Tiny Fixed-Point Model Score

Open:

firmware/main.c
firmware/model_weights.h

Implement:

model_filter_score

The model uses two features:

abs_center = abs(value - MODEL_CENTER_VALUE)
abs_jump   = abs(value - previous_kept)

The score formula is:

score = MODEL_BIAS_Q0
      + MODEL_WEIGHT_ABS_CENTER_Q0 * abs_center
      + MODEL_WEIGHT_ABS_JUMP_Q0 * abs_jump;

This model is intentionally tiny:

Exercise 5: Implement The TinyML Keep/Drop Decision

Implement:

model_filter_should_keep

Rule:

Expected model drops:

seq=2
seq=4
seq=6
seq=7

Run the validation again. The final summary should be:

SUMMARY threshold_keep=8 threshold_drop=2 model_keep=6 model_drop=4 disagreements=2

Exercise 6: Compare The Two Methods

Use output/report.html and UART output to answer:

  1. Which samples are rejected by both methods?
  2. Which samples are accepted by the threshold filter but rejected by the model?
  3. Why do the two methods disagree at seq=2 and seq=7?
  4. Which method is easier to explain?
  5. Which method is easier to tune if the data distribution changes?

hint:

Exercise 7: Optional Extension

Choose one:

Common Problems

Docker Socket Errors

If Docker cannot connect to the daemon, try:

DOCKER_HOST=unix:///var/run/docker.sock ./run.sh up --build digital-twin

If group membership was just changed and the current shell has not picked it up, use:

sg docker -c 'DOCKER_HOST=unix:///var/run/docker.sock ./run.sh up --build digital-twin'

Firmware Builds But Samples Are Wrong

Check:

Validation Fails After Editing

Use evidence in this order:

  1. output/report.html for the high-level failing check;
  2. output/uart_output.txt for firmware-side behavior;
  3. renode/run_test.resc and renode/sensor_i2c.repl for wiring issues;
  4. VirtualSensorStream.cs for sample stream issues.

Starter Code Fails Filter Checks

This is expected. The starter code reads the sensor but does not yet implement the threshold and model decisions correctly.