Embedded Software Development
Input: $ARGUMENTS
Overview
Embedded software runs on hardware with real-time constraints, limited resources, and physical consequences for bugs. This procedure covers the specific challenges: hardware interfaces, real-time requirements, debugging without full OS support, and testing on physical systems.
Steps
Step 1: Define Hardware Interface
- What hardware does the software control? (sensors, actuators, communication)
- What are the interfaces? (GPIO, SPI, I2C, UART, CAN, USB)
- What are the timing requirements? (sample rates, control loop frequency)
- What are the resource constraints? (RAM, flash, CPU speed)
- Get/create hardware documentation (pinouts, timing diagrams, datasheets)
Step 2: Design Software Architecture
- Choose RTOS vs bare-metal vs Linux (based on complexity and timing needs)
- Define task/thread structure with priorities
- Separate: hardware abstraction layer, control logic, communication, safety
- Define interfaces between layers (so logic can be tested without hardware)
Step 3: Implement Incrementally
- Start with hardware bring-up: can you blink an LED? Read a sensor?
- Add one peripheral at a time, verify each works
- Build control logic on top of verified hardware layer
- Add communication last
- → INVOKE: /pb (progressive building) — each layer works before adding next
Step 4: Test
- Unit test control logic off-hardware (mock the HAL)
- Integration test on hardware with known inputs
- Stress test: edge cases, maximum rates, error conditions
- Safety test: what happens on sensor failure? Communication loss? Power glitch?
Step 5: Debug
- Use logic analyzer/oscilloscope for timing issues
- Use serial/JTAG debug for software issues
- Add instrumentation (timing pins, debug output) early
- Common embedded bugs: race conditions, stack overflow, interrupt priority inversion, DMA conflicts
When to Use
- Robotics, IoT, motor control, sensor systems
- Any software running on microcontrollers or embedded Linux
Verification
- Hardware interfaces documented
- Architecture separates hardware from logic
- Incremental bring-up (not all-at-once)
- Logic testable without hardware
- Safety/failure cases tested