Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

📝 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

target15:00

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

This section contains 20 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 modern toolkit for flashing and debugging embedded Rust applications over JTAG.
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.
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 'no_std' approach is preferred for 'bare-metal' projects where absolute control over memory and timing is required.
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.
Q3
Quiz
Select 0/2

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

Because it lacks the complexity of dual-core synchronization, simplifying the initial development of no_std drivers.
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 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 ESP-IDF (std) project, use:
5·····-generate

Available Snippets

probe-rs
esp
cargo
create
espflash
flash
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.
A critical error occurring when deeply nested functions or large local variables exceed the allocated frame.
Volatile high-speed memory used for the stack and heap; often limited to 320-512KB.
The buildup of small, unusable gaps in dynamic memory caused by frequent allocations and deallocations.
Q6
Code Output
Rust

Predict the output: Static Buffers

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

1// A global static buffer stored in Flash or RAM
2static BUFFER: [u8; 1024] = [0; 1024];
3
4fn main() {
5 // In a no_std environment, 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 is stored in the program's data section (Flash/RAM) at compile time.
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 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.
Because the Rust standard library cannot provide thread-safety for heap-allocated data structures.
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.
Forcing the compiler to inline every function to eliminate the overhead of the 'call' instruction.
Replacing all recursive function calls with iterative loops to limit the number of active call frames.
Allocating temporary working memory on the heap (if available) instead of using local arrays.
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

Link-Time Optimisation; allows the compiler to optimise across different modules and crates.
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.
Controls parallel compilation; setting this to 1 allows for better global optimisation at the cost of speed.
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
3
fast
unwind
true
none
Q11
Quiz
Select 0/2

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

Using SIMD always reduces power consumption as it allows the CPU to finish tasks faster and sleep sooner.
SIMD allows a single CPU instruction to perform the same operation on multiple data points in parallel.
Rust's 'core::simd' module provides a safe way to write architecture-independent parallel code.
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 uses data from real execution runs to help the compiler make better branch prediction and inlining decisions.
It automatically compresses the binary's text section using a specialised LZMA algorithm.
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

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.
A pattern ensuring that hardware peripherals (like an I2C bus) are properly released when no longer used.
A pattern where the system behaviour is defined by its current mode (e.g., Idle, Polling, Error).
Q14
Code Order
Rust

Implementing a Simple State Machine

Drag the tiles to arrange the code in the correct order, then click Submit. Locked lines stay in place. Indentation is dynamically applied based on the location of braces.
enum DeviceState { Idle, Sampling, Error }
fn update(state: DeviceState) -> DeviceState {
match state {
DeviceState::Error => { reset(); DeviceState::Idle }
DeviceState::Idle => { start_timer(); DeviceState::Sampling }
DeviceState::Sampling => { if ok { DeviceState::Idle } else { DeviceState::Error } }
}
}
Q15
Quiz
Select 0/2

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

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 automatically handles the conversion between Big-Endian and Little-Endian network formats.
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 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 represent hardware peripherals (like GPIO) as types that take up zero bytes of RAM at runtime.
To enable the use of async/await on devices that lack a hardware-backed memory management unit.
Q17
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 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.
An advanced pattern using the type system to enforce valid sequences of operations at compile time.
A hardware component that resets the system if the software fails to 'kick' it within a timeout.
Q18
Quiz
Select 0/3

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

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

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

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 requiring all hardware peripherals to be initialised within the main() function's global scope.
By ensuring that only one part of the code can 'own' and therefore manipulate a specific hardware resource at a time.
Q20
Quiz
Select 0/3

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

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

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.