2 hours:
After this laboratory, students should be able to:
.resc Renode scripts and .repl platform descriptions;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:
seq: sample number;value: signed sensor reading.The firmware must classify every sample with two methods:
if/else logic using minimum value, maximum value, and maximum jump thresholds.firmware/model_weights.h.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.
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:
firmware/main.c contains the student TODOs.firmware/model_weights.h contains the fixed-point model constants.renode/run_test.resc creates the Renode scenario, loads firmware, and captures UART output.renode/sensor_i2c.repl connects the virtual sensor to the Pico I2C bus.renode/peripherals/VirtualSensorStream.cs implements the deterministic I2C sensor stream.docker/scripts/run_test.sh validates the UART output and final summary.docker/scripts/generate_report.py creates output/report.html.reference/firmware/main.c contains the completed instructor reference implementation.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.
A Renode lab scenario has three layers:
firmware.elf;.resc script that creates, wires, runs, and observes the machine.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 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 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:
sensor;I2C.VirtualSensorStream;i2c0;0x52.
Key idea: .repl files describe the virtual wires.
VirtualSensorStream.cs is a minimal Renode I2C peripheral. It models only the behavior needed by this lab:
0x00;seq:uint16_be and value:int16_be;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
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.
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
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
Open renode/run_test.resc.
Tasks:
VirtualSensorStream.cs.sensor_i2c.repl.firmware.elf.Questions:
hints:
renode/sensor_i2c.repl;i2c0;0x52;/workspace/output/uart_output.txt.Files to inspect:
renode/peripherals/VirtualSensorStream.cs renode/sensor_i2c.repl firmware/main.c
Tasks:
VirtualSensorStream.cs, find the deterministic sample table.firmware/main.c, find the code that reads one sample from I2C.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 |
Open firmware/main.c and implement:
threshold_filter_should_keep
Rules:
THRESHOLD_MIN_VALUE;THRESHOLD_MAX_VALUE;previous_kept is greater than THRESHOLD_MAX_JUMP;Expected threshold drops:
seq=4 seq=6
After this exercise, some checks may still fail because the model filter is not implemented yet.
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:
Implement:
model_filter_should_keep
Rule:
score >= MODEL_KEEP_THRESHOLD_Q0;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
Use output/report.html and UART output to answer:
seq=2 and seq=7?hint:
Choose one:
VirtualSensorStream.cs and update the expected summary;docker/scripts/generate_report.py to make disagreements easier to inspect in the HTML report.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'
Check:
renode/sensor_i2c.repl connects the sensor to i2c0 at 0x52;Use evidence in this order:
output/report.html for the high-level failing check;output/uart_output.txt for firmware-side behavior;renode/run_test.resc and renode/sensor_i2c.repl for wiring issues;VirtualSensorStream.cs for sample stream issues.This is expected. The starter code reads the sensor but does not yet implement the threshold and model decisions correctly.