Skip to content

📝 Knowledge Test

/
Knowledge Test Score Board
—· 0%

Work through the questions below — your score updates as you go.

Keep going · grade bands mapped to DCU's honours scale

target18:45

Only your first attempt at each question counts toward this score. Reload the page to reset.

This section contains 25 interactive knowledge checks designed to test your understanding of the materials covered in Chapter 12. The questions cover the deployment of Rust on the ESP32 platform, managing limited memory and storage resources, applying advanced compiler and code-level optimisations, and utilising design patterns specifically tailored for the constraints of the edge.

Please remember that many of the quizzes have multiple correct answers, and you must select all applicable options to succeed. I have carefully balanced the lengths of the answers, so take your time to evaluate each option thoroughly.

Good luck!

Derek.


Q1
Concept Match

Match the ESP32 Architectures

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

Xtensa
drag a definition here…
RISC-V
drag a definition here…
espup
drag a definition here…
probe-rs
drag a definition here…

Definition Pool

A specialised toolchain installer required for Xtensa support in the Rust compiler.
The traditional dual-core architecture used in original ESP32 and ESP32-S3 models.
A modern toolkit for flashing and debugging embedded Rust applications over JTAG.
The modern, open-standard architecture used in newer models like the ESP32-C3 and C6.
Q2
Quiz
Select 0/3

Regarding the 'std' versus 'no_std' choice on the ESP32, which of the following statements are TRUE?

The 'std' approach leverages the ESP-IDF (FreeRTOS-based) operating system to provide services like threads and networking.
Using 'std' results in larger binary sizes but provides a more familiar, high-level developer experience for complex apps.
The 'no_std' approach is mandatory for all ESP32 models, as they lack the hardware required to run a standard library.
The 'no_std' approach is preferred for 'bare-metal' projects where absolute control over memory and timing is required.
Q3
Quiz
Select 0/2

Why is the ESP32-C3 considered particularly 'Rust-friendly' compared to the original ESP32?

Because it is the only model capable of running the Dioxus GUI framework in a bare-metal environment.
Because it features a built-in hardware accelerator designed specifically for the Rust borrow checker.
Because it lacks the complexity of dual-core synchronization, simplifying the initial development of no_std drivers.
Because its RISC-V architecture is natively supported by the standard upstream Rust compiler (rustc).
Q4
Code Cloze

Flashing and Monitoring

Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.

1# To flash your compiled binary to an ESP32 connected via USB, use:
2····· flash --monitor
3
4# To quickly scaffold a new bare-metal (no_std, esp-hal) project, use:
5·····-generate

Available Snippets

flash
cargo
espflash
create
probe-rs
esp
Q5
Concept Match

Match the Resource Constraints

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

Flash Memory
drag a definition here…
SRAM
drag a definition here…
Stack Overflow
drag a definition here…
Heap Fragmentation
drag a definition here…

Definition Pool

Persistent storage where the program code and constant data are stored; typically 4-16MB.
Volatile high-speed memory used for the stack and heap; often limited to 320-512KB.
A critical error occurring when deeply nested functions or large local variables exceed the allocated frame.
The buildup of small, unusable gaps in dynamic memory caused by frequent allocations and deallocations.
Q6
Code Output
Rust

Where does BUFFER live?

Read the code below, then choose the terminal output it produces and click Submit.

1// A global static buffer
2static BUFFER: [u8; 1024] = [0; 1024];
3
4fn main() {
5 // Where does this large array live?
6 println!("Buffer size: {} bytes", BUFFER.len());
7}
stdout
It is allocated on the stack every time main() is called.
stdout
It has a fixed place in the program's static memory (Flash or RAM).
stdout
It is dynamically allocated on the heap during system boot.
stdout
It is a virtual alias that consumes no physical memory at all.
Q7
Quiz
Select 0/2

Why is dynamic heap allocation (Box, Vec, String) often discouraged in safety-critical edge firmware?

Because the Rust standard library cannot provide thread-safety for heap-allocated data structures.
Because frequent allocations lead to memory fragmentation, which can cause 'Out of Memory' crashes over time.
Because heap allocation is non-deterministic; it may take a variable amount of time or fail unexpectedly.
Because the ESP32 hardware requires all variables to be stored in the CPU registers for maximum performance.
Q8
Quiz
Select 0/3

Which of the following is a valid strategy for reducing stack usage in an ESP32 application?

Moving large local buffers into static memory using the 'static' keyword or 'lazy_static' crate.
Allocating temporary working memory on the heap (if available) instead of using local arrays.
Replacing all recursive function calls with iterative loops to limit the number of active call frames.
Forcing the compiler to inline every function to eliminate the overhead of the 'call' instruction.
Q9
Concept Match

Match the Compiler Optimisations

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

LTO
drag a definition here…
codegen-units
drag a definition here…
panic=abort
drag a definition here…
opt-level='z'
drag a definition here…

Definition Pool

Controls parallel compilation; setting this to 1 allows for better global optimisation at the cost of speed.
A special optimisation flag that instructs the compiler to prioritise minimum binary size over speed.
Disables stack unwinding, significantly reducing the size of the final compiled binary.
Link-Time Optimisation; allows the compiler to optimise across different modules and crates.
Q10
Code Cloze

Cargo.toml Release Profile

Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.

1[profile.release]
2# Optimise for size
3opt-level = "·····"
4
5# Disable stack unwinding for smaller binaries
6panic = "·····"
7
8# Perform global optimisations during linking
9lto = "·····"

Available Snippets

s
abort
true
3
none
fast
unwind
Q11
Quiz
Select 0/2

Regarding SIMD (Single Instruction, Multiple Data) on edge devices, which statement is true?

Rust's 'core::simd' module provides a safe way to write architecture-independent parallel code.
SIMD allows a single CPU instruction to perform the same operation on multiple data points in parallel.
Using SIMD always reduces power consumption as it allows the CPU to finish tasks faster and sleep sooner.
SIMD is only available on high-end Nvidia Jetson modules and is not supported by any ESP32 chip.
Q12
Quiz
Select 0/1

What is the primary benefit of 'Profile-Guided Optimisation' (PGO)?

It identifies and deletes all code paths that are never executed during the provided test runs.
It automatically compresses the binary's text section using a specialised LZMA algorithm.
It uses data from real execution runs to help the compiler make better branch prediction and inlining decisions.
It allows the developer to manually assign specific functions to the fastest CPU cores.
Q13
Concept Match

Match the Design Patterns

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

State Machine
drag a definition here…
Observer
drag a definition here…
Facade
drag a definition here…
RAII
drag a definition here…

Definition Pool

A pattern where the system behaviour is defined by its current mode (e.g., Idle, Polling, Error).
A pattern ensuring that hardware peripherals (like an I2C bus) are properly released when no longer used.
Allows components to subscribe and react to events, such as a new sensor reading being available.
A simplified interface that hides the complexity of direct hardware register manipulation.
Q14
Code Cloze
Rust

Implementing a Simple State Machine

Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.

1enum DeviceState { Idle, Sampling, Error }
2
3// start_timer() and reset() are hardware helpers defined elsewhere
4fn update(state: DeviceState, ok: bool) -> DeviceState {
5 // Choose the next state from the current one
6 ····· state {
7 // Idle: start the sample timer and move on to sampling
8 DeviceState::Idle => { start_timer(); DeviceState::····· }
9 // Sampling: back to Idle if the reading was ok, otherwise flag a fault
10 DeviceState::Sampling => { if ok { DeviceState::Idle } else { DeviceState::····· } }
11 DeviceState::Error => { reset(); DeviceState::Idle }
12 }
13}

Available Snippets

switch
Sampling
Fault
Ready
match
if
Error
Q15
Quiz
Select 0/2

How does the 'Newtype' pattern contribute to safety in embedded Rust drivers?

It automatically handles the conversion between Big-Endian and Little-Endian network formats.
It provides a zero-cost abstraction to add domain-specific methods to primitive types like u32.
It forces the compiler to store the wrapped value in a dedicated hardware-protected memory region.
It allows the developer to create a unique type for things like 'Celsius' versus 'Fahrenheit', preventing accidental mixing.
Q16
Quiz
Select 0/2

Why is the 'Zero-Sized Type' (ZST) pattern often used in no_std Rust for hardware ownership?

To represent hardware peripherals (like GPIO) as types that take up zero bytes of RAM at runtime.
To bypass the Rust borrow checker when multiple drivers need to access the same physical register.
To allow the compiler to track whether a specific hardware pin is currently 'owned' by a driver at compile time.
To enable the use of async/await on devices that lack a hardware-backed memory management unit.
Q17
Quiz
Select 0/1

In Zephyr, what is the primary advantage of using 'memory slabs' for allocation instead of a standard kernel heap?

Slabs automatically encrypt data to protect sensitive sensor readings.
They are required for running Rust code, which cannot use a standard heap.
Memory slabs allow for the dynamic resizing of objects at runtime.
They provide deterministic, fixed-size allocation that prevents heap fragmentation.
Q18
Quiz
Select 0/1

Which Zephyr subsystem is responsible for automatically entering low-power idle or sleep states when threads are blocked?

The Kconfig Optimizer
The Devicetree Resolver
The West Meta-subsystem
The Power Management (PM) subsystem
Q19
Concept Match

Match Zephyr AIoT Components

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

MCUboot
drag a definition here…
mbedTLS
drag a definition here…
TensorFlow Lite
drag a definition here…
MCUmgr
drag a definition here…

Definition Pool

The underlying library used for encrypted socket communication (TLS).
Provides secure boot and support for signed firmware images.
A Zephyr module providing an inference runtime for TinyML models.
The protocol used for managing over-the-air (OTA) firmware updates.
Q20
Quiz
Select 0/1

In the Zephyr development workflow, what is the role of the 'west' meta-tool?

It is the primary compiler for Xtensa and RISC-V architectures.
It automatically translates C++ classes into Zephyr-compatible C structs.
It manages the multi-repository source tree and wraps the CMake build system.
It is a functional simulator used to model multi-node edge networks.
Q21
Quiz
Select 0/1

In Rust, a channel lets one thread send values to another through a queue. How is this message-passing pattern typically realised in native Zephyr C code?

Zephyr does not support inter-thread communication patterns.
Through the use of kernel threads paired with message queues or FIFOs.
By bypassing the RTOS and writing directly to CPU registers.
By using global variables guarded by volatile keywords.
Q22
Concept Match

Match the Final Concepts

Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.

Determinism
drag a definition here…
Critical Section
drag a definition here…
Watchdog Timer
drag a definition here…
Typestate
drag a definition here…

Definition Pool

A hardware component that resets the system if the software fails to 'kick' it within a timeout.
An advanced pattern using the type system to enforce valid sequences of operations at compile time.
A region of code that must execute without interruption, often protected by disabling interrupts.
The property where a system produces identical output for a given input in a fixed timeframe.
Q23
Quiz
Select 0/3

Which of the following is a common cause of non-deterministic behaviour in a Rust application?

The use of 'match' expressions with too many arms, which causes the CPU's branch predictor to fail.
Relying on a global heap allocator without a real-time-aware allocation strategy (like a TLSF allocator).
Spawning background threads on a multi-core chip without using deterministic scheduling or locking.
The use of standard 'HashMap' collections, as their iteration order is deliberately randomised for security.
Q24
Quiz
Select 0/2

How does Rust's ownership system naturally support the 'Resource Acquisition Is Initialisation' (RAII) pattern?

By requiring all hardware peripherals to be initialised within the main() function's global scope.
By automatically calling the Drop trait's method as soon as a variable goes out of scope, releasing its resources.
By preventing the program from compiling if a hardware resource is not used within 100 lines of its acquisition.
By ensuring that only one part of the code can 'own' and therefore manipulate a specific hardware resource at a time.
Q25
Quiz
Select 0/3

What is the ultimate goal of combining Rust's safety features with rigorous resource management on the edge?

To ensure that edge nodes can be updated remotely without any risk of bricking the device due to memory errors.
To enable high-fidelity user interactions and reliable data processing on low-cost, low-power hardware.
To produce software that is 'correct by construction', minimising the requirement for expensive field debugging.
To eliminate the need for hardware-level watchdogs by guaranteeing that software can never crash.

Congratulations on completing the Chapter 12 Knowledge Test and the final module of the book! You have now explored the full lifecycle of edge programming: from the fundamentals of hardware and C++, through the robust safety of Rust, to advanced networking, concurrency, and embedded optimisation. Use these principles to build the next generation of reliable, secure, and intelligent smart nodes.

Derek.