Project 5: Embedded Sensor State Machine (Arduino/STM32)
Build a sensor controller that uses explicit states and safe transitions under real-time constraints.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Advanced |
| Time Estimate | 1-2 weeks |
| Language | C (embedded) |
| Prerequisites | Microcontroller basics, GPIO/I2C/SPI |
| Key Topics | State machines, timing, fault handling |
1. Learning Objectives
By completing this project, you will:
- Model sensor lifecycle as explicit states.
- Handle errors and retries with safe transitions.
- Integrate timing constraints and watchdog behavior.
- Avoid invalid operations based on current state.
2. Theoretical Foundation
2.1 Core Concepts
- Embedded state machines: States like INIT, CALIBRATE, READY, READ, ERROR.
- Temporal correctness: Timing matters; some operations must happen within deadlines.
- Fault handling: Error states must be recoverable or fail-safe.
2.2 Why This Matters
Embedded systems cannot restart freely. If state handling is wrong, devices lock up or deliver bad data.
2.3 Historical Context / Background
Sensor firmware typically uses state machines because polling loops and interrupts must coordinate without race conditions.
2.4 Common Misconceptions
- “Polling is enough”: Without explicit state, error recovery fails.
- “Errors are rare”: In embedded systems, transient faults are common.
3. Project Specification
3.1 What You Will Build
A microcontroller app that reads a sensor (mock or real), handles calibration, sampling, and error states, and reports readings over UART.
3.2 Functional Requirements
- State machine: INIT -> CALIBRATE -> READY -> READ -> READY.
- Error handling: Fail to ERROR and retry or reset.
- Timing: Enforce sample interval (e.g., 10 Hz).
- Reporting: UART output of state and sensor values.
3.3 Non-Functional Requirements
- Reliability: No unsafe transitions.
- Responsiveness: Reads must meet timing requirements.
- Safety: Error state must be deterministic.
3.4 Example Usage / Output
[INIT] booting
[CALIBRATE] ok
[READY] waiting
[READ] temp=24.3C
[READY]
3.5 Real World Outcome
On the serial monitor, you see state transitions and sensor values in real time:
[READ] accel=(0.01, 0.02, 0.98)
[READ] accel=(0.00, 0.01, 0.99)
[ERROR] sensor timeout
[RECOVER] retry ok
4. Solution Architecture
4.1 High-Level Design
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ timer/ISR │────▶│ state machine│────▶│ sensor I/O │
└──────────────┘ └──────────────┘ └──────────────┘
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| State machine | Control flow and transitions | Enum with explicit states |
| Sensor driver | I2C/SPI read | Timeout handling |
| Scheduler | Timing loop | Fixed interval ticks |
4.3 Data Structures
typedef enum {
ST_INIT,
ST_CALIBRATE,
ST_READY,
ST_READ,
ST_ERROR
} SensorState;
typedef struct {
SensorState state;
int retry_count;
uint32_t last_sample_ms;
} SensorCtx;
4.4 Algorithm Overview
Key Algorithm: Tick-driven state machine
- On each tick, evaluate current state.
- Perform allowed action or transition.
- On error, enter ERROR and retry with limit.
Complexity Analysis:
- Time: O(1) per tick.
- Space: O(1).
5. Implementation Guide
5.1 Development Environment Setup
# Arduino IDE or STM32 toolchain
5.2 Project Structure
project-root/
├── src/
│ ├── main.c
│ ├── sensor.c
│ └── state.c
└── platform/
└── uart.c
5.3 The Core Question You’re Answering
“What is the device allowed to do right now, given its current state and timing constraints?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Timing and tick loops
- Fixed-rate scheduling
- Sensor I/O
- I2C/SPI reads and timeouts
- Error recovery
- Retry limits and safe fallback
5.5 Questions to Guide Your Design
- What is the maximum time allowed for a sensor read?
- How many retries are safe before failing?
- What happens if calibration fails?
5.6 Thinking Exercise
If a sensor read blocks longer than expected, how do you prevent the system from missing other tasks?
5.7 The Interview Questions They’ll Ask
- Why are state machines critical in embedded systems?
- How do you handle transient faults safely?
- What timing guarantees does your loop provide?
5.8 Hints in Layers
Hint 1: Mock sensor
- Start with fake readings.
Hint 2: Add timeouts
- Fail reads that exceed a threshold.
Hint 3: Add retries
- Limited retries before ERROR.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Embedded state machines | “Making Embedded Systems” | FSM chapters |
| Timing | “Real-Time Concepts for Embedded Systems” | Scheduling |
5.10 Implementation Phases
Phase 1: Foundation (3-4 days)
Goals:
- Implement state machine with mock sensor.
Tasks:
- Add state enum and transitions.
- Simulate sensor reads.
Checkpoint: UART shows state transitions.
Phase 2: Core Functionality (4-5 days)
Goals:
- Integrate real sensor I/O.
Tasks:
- Add driver with timeouts.
- Validate calibration and read loop.
Checkpoint: Sensor data printed at fixed rate.
Phase 3: Polish & Edge Cases (2-3 days)
Goals:
- Fault handling.
Tasks:
- Implement error state and retry.
- Add watchdog reset logic if needed.
Checkpoint: Errors are recovered safely.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Timing | busy loop vs timer | timer tick | Predictability |
| Error handling | infinite retries vs limit | limit | Avoid lockup |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| State transitions | Valid sequences | INIT->CALIBRATE->READY |
| Timing | Sample rate | 10 Hz loop |
| Faults | Recovery | Timeout triggers ERROR |
6.2 Critical Test Cases
- Calibration failure enters ERROR.
- Read timeout triggers retry.
- Recovery returns to READY.
6.3 Test Data
Simulated sensor timeouts
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Blocking I/O | Missed ticks | Add timeouts |
| Implicit state | Random behavior | Explicit enum |
| No recovery | Dead device | Retry/ERROR path |
7.2 Debugging Strategies
- Print state transitions to UART.
- Use LED blink patterns for ERROR state.
7.3 Performance Traps
Heavy logging can break timing; throttle UART output.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a manual reset command.
8.2 Intermediate Extensions
- Add low-power sleep state.
8.3 Advanced Extensions
- Implement event-driven FSM with interrupts.
9. Real-World Connections
9.1 Industry Applications
- IoT devices: Sensor firmware is state-driven.
- Safety systems: Error states prevent unsafe outputs.
9.2 Related Open Source Projects
- Zephyr RTOS: Many sensor drivers use FSMs.
- Arduino libs: Examples of stateful sensor drivers.
9.3 Interview Relevance
- Demonstrates real-time control flow discipline.
10. Resources
10.1 Essential Reading
- Making Embedded Systems - state machines and reliability.
10.2 Video Resources
- Search: “embedded state machine example”.
10.3 Tools & Documentation
- Arduino or STM32 SDK docs.
10.4 Related Projects in This Series
11. Self-Assessment Checklist
11.1 Understanding
- I can describe each state and transition.
- I can explain timing constraints.
11.2 Implementation
- Sensor reads happen at correct frequency.
- Errors trigger safe recovery.
11.3 Growth
- I can design a fail-safe FSM for other devices.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Working state machine with mock sensor data.
Full Completion:
- Real sensor reads with timeout handling.
Excellence (Going Above & Beyond):
- Event-driven FSM with interrupts and low-power state.
This guide was generated from SPRINT_3_CONTROL_FLOW_STATE_PROJECTS.md. For the complete learning path, see the parent directory README.