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:

  1. Model sensor lifecycle as explicit states.
  2. Handle errors and retries with safe transitions.
  3. Integrate timing constraints and watchdog behavior.
  4. 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

  1. State machine: INIT -> CALIBRATE -> READY -> READ -> READY.
  2. Error handling: Fail to ERROR and retry or reset.
  3. Timing: Enforce sample interval (e.g., 10 Hz).
  4. 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

  1. On each tick, evaluate current state.
  2. Perform allowed action or transition.
  3. 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:

  1. Timing and tick loops
    • Fixed-rate scheduling
  2. Sensor I/O
    • I2C/SPI reads and timeouts
  3. Error recovery
    • Retry limits and safe fallback

5.5 Questions to Guide Your Design

  1. What is the maximum time allowed for a sensor read?
  2. How many retries are safe before failing?
  3. 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

  1. Why are state machines critical in embedded systems?
  2. How do you handle transient faults safely?
  3. 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:

  1. Add state enum and transitions.
  2. Simulate sensor reads.

Checkpoint: UART shows state transitions.

Phase 2: Core Functionality (4-5 days)

Goals:

  • Integrate real sensor I/O.

Tasks:

  1. Add driver with timeouts.
  2. Validate calibration and read loop.

Checkpoint: Sensor data printed at fixed rate.

Phase 3: Polish & Edge Cases (2-3 days)

Goals:

  • Fault handling.

Tasks:

  1. Implement error state and retry.
  2. 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

  1. Calibration failure enters ERROR.
  2. Read timeout triggers retry.
  3. 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.
  • 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.

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.