Embedded Systems
Microcontrollers, real-time operating systems, and interfacing.
Embedded Systems
Embedded systems are specialized computing systems that are part of larger devices or machines, designed to perform specific tasks. They combine hardware and software to interact with physical systems, process sensor data, and control actuators in real-time applications.
Microcontroller Architecture
Basic Components
Central Processing Unit (CPU)
Memory Hierarchy
ARM Cortex-M Architecture (Example)
Core Components
- Processor Core: ARM Cortex-M0/M3/M4/M7
- NVIC: Nested Vectored Interrupt Controller
- SysTick: System timer
- MPU: Memory Protection Unit (higher models)
Memory Map
Address Range Peripheral
0x00000000-0x1FFFFFFF Code memory (Flash)
0x20000000-0x3FFFFFFF Data memory (RAM)
0x40000000-0x5FFFFFFF Peripherals
0xE0000000-0xFFFFFFFF System control
Memory Organization
Harvard vs Von Neumann Architecture
Memory Parameters
Real-Time Operating Systems (RTOS)
Task Management
Task States
Scheduling Algorithms
Round Robin
Rate Monotonic Scheduling (RMS)
Earliest Deadline First (EDF)
Real-Time Constraints
Deadline Types
- Hard Real-Time: Missing deadline is a system failure
- Firm Real-Time: Missing deadline causes data loss but continues operation
- Soft Real-Time: Missing deadline degrades service quality
Response Time Analysis
For Rate Monotonic Schedulability:
Where is computation time and is period of task .
Context Switching
Context Switch Time
Where:
- : Time to save current task state
- : Time to restore next task state
- : Time to select next task
Peripherals and Interfaces
Digital I/O
GPIO Configuration
Port Operations
Analog-to-Digital Conversion (ADC)
ADC Resolution
Where is number of bits.
Quantization Error
ADC Conversion Time
Serial Communication Protocols
UART (Universal Asynchronous Receiver/Transmitter)
SPI (Serial Peripheral Interface)
I²C (Inter-Integrated Circuit)
Interrupt Systems
Interrupt Processing
Nesting and Priority
Critical Sections
\text{Disable interrupts}: \text{ENTER_CRITICAL} \text{Enable interrupts}: \text{EXIT_CRITICAL}Vector Table
Power Management
Power Consumption Analysis
Low Power Modes
Sleep Modes
- Sleep: CPU stopped, peripherals active
- Deep Sleep: CPU and some peripherals stopped
- Hibernate: Minimal power consumption (RTC only)
Dynamic Voltage Scaling
Microcontroller Programming
Boot Process
Memory Management
Interface Design
Sensor Integration
Digital Sensors
Analog Sensors
Actuator Control
Digital Actuators
PWM for Motor Control
Communication Protocols
CAN Bus (Controller Area Network)
Ethernet Communication
Real-Time Programming
Time Management
System Tick Timer
Time Stamping
Synchronization Primitives
Semaphores
Mutexes
Message Queues
Hardware Abstraction Layer (HAL)
Abstraction Benefits
Common HAL Functions
- GPIO:
HAL_GPIO_Init(),HAL_GPIO_Write(),HAL_GPIO_Read() - UART:
HAL_UART_Transmit(),HAL_UART_Receive(),HAL_UART_IRQHandler() - ADC:
HAL_ADC_Start(),HAL_ADC_PollForConversion(),HAL_ADC_GetValue()
Design Considerations
Timing Constraints
Memory Constraints
Safety and Reliability
Real-World Application: IoT Sensor Node Design
Design of an Internet of Things (IoT) sensor node involves balancing power consumption, processing capability, and real-time constraints.
IoT System Analysis
# IoT sensor node design parameters
iot_node = {
'microcontroller': 'ARM Cortex-M4',
'cpu_frequency': 168, # MHz
'flash_memory': 512, # KB
'ram_size': 192, # KB
'sensors': ['temperature', 'humidity', 'pressure', 'accelerometer'],
'wireless_protocol': 'WiFi + Bluetooth LE',
'sampling_rate': 1, # Hz (once per second)
'transmission_rate': 0.1, # Hz (once every 10 seconds)
'battery_capacity': 2000, # mAh
'sleep_power': 0.015, # mA (deep sleep current)
'active_power': 120, # mA (active processing and wireless)
'sleep_duty_cycle': 0.95 # 95% of time in sleep mode
}
# Calculate power consumption
active_time_per_sample = 0.02 # 20ms for sensor reading and processing
sleep_time = 1.0 - active_time_per_sample # Time spent in sleep between samples
# Power calculation for 24-hour period
sampling_period = 1 / iot_node['sampling_rate'] # seconds
active_current_24h = (active_time_per_sample * iot_node['active_power']) / sampling_period # mA averaged over sampling period
sleep_current_24h = (sleep_time * iot_node['sleep_power']) / sampling_period # mA averaged over sampling period
total_current_draw = active_current_24h + sleep_current_24h # mA
# Transmission power consideration
transmission_duration = 0.1 # 100ms for data transmission
transmission_frequency = iot_node['transmission_rate']
transmission_power = 150 # mA for WiFi transmission
transmission_current_24h = (transmission_duration * transmission_power * transmission_frequency) # mA averaged over 24h
# Total daily consumption
total_daily_current = total_current_draw + transmission_current_24h # mA
daily_energy_consumption = total_daily_current * 24 # mA·h
# Calculate operational lifetime
battery_capacity_mah = iot_node['battery_capacity'] # mAh
operational_days = battery_capacity_mah / daily_energy_consumption # days of operation
# Memory usage analysis
code_size = 120 # KB (estimated program size)
stack_size = 2 # KB (estimated stack usage)
heap_size = 1 # KB (estimated heap usage)
static_data = 5 # KB (global variables)
total_memory_used = code_size + stack_size + heap_size + static_data # KB
memory_utilization = total_memory_used / iot_node['flash_memory'] # Fraction
ram_utilization = (stack_size + heap_size + static_data) / iot_node['ram_size'] # Fraction
# Performance analysis
cpu_utilization_active = active_time_per_sample / sampling_period # Fraction of time CPU is active
cpu_utilization_overall = cpu_utilization_active * (1 - iot_node['sleep_duty_cycle']) # Accounting for sleep mode
# Calculate real-time capability
tasks = [
{'name': 'sensor_reading', 'period': 1.0, 'wcet': 0.01}, # 10ms WCET
{'name': 'data_processing', 'period': 1.0, 'wcet': 0.005}, # 5ms WCET
{'name': 'wireless_tx', 'period': 10.0, 'wcet': 0.05} # 50ms WCET
]
# Calculate total utilization
total_utilization = sum(task['wcet'] / task['period'] for task in tasks)
print(f"IoT Sensor Node Design Analysis:")
print(f" MCU: {iot_node['microcontroller']} at {iot_node['cpu_frequency']} MHz")
print(f" Memory: {iot_node['flash_memory']} KB Flash, {iot_node['ram_size']} KB RAM")
print(f" Sampling rate: {iot_node['sampling_rate']} Hz")
print(f" Transmission rate: {iot_node['transmission_rate']} Hz")
print(f" Sleep duty cycle: {iot_node['sleep_duty_cycle']*100:.1f}%")
print(f"\nPower Analysis:")
print(f" Active current: {iot_node['active_power']} mA")
print(f" Sleep current: {iot_node['sleep_power']} mA")
print(f" Daily energy consumption: {daily_energy_consumption:.2f} mA·h")
print(f" Estimated battery life: {operational_days:.1f} days ({operational_days/365:.2f} years)")
print(f" Total CPU utilization: {cpu_utilization_overall*100:.2f}%")
print(f"\nMemory Analysis:")
print(f" Total memory used: {total_memory_used} KB")
print(f" Flash utilization: {memory_utilization*100:.1f}%")
print(f" RAM utilization: {ram_utilization*100:.1f}%")
print(f"\nTask Analysis:")
for task in tasks:
print(f" {task['name']}: WCET={task['wcet']*1000:.0f}ms, Period={task['period']}s, Utilization={(task['wcet']/task['period'])*100:.2f}%")
print(f"\n Total task utilization: {total_utilization*100:.2f}%")
print(f" Schedulable: {'Yes' if total_utilization < 1.0 else 'No (exceeds 100%)'}")
# Performance assessment
if operational_days > 365: # More than 1 year
power_efficiency = "Excellent - multi-year battery life"
elif operational_days > 30: # More than 1 month
power_efficiency = "Good - monthly to yearly battery replacement"
elif operational_days > 7: # More than 1 week
power_efficiency = "Fair - weekly battery replacement"
else:
power_efficiency = "Poor - frequent battery replacement required"
print(f"\n Power efficiency: {power_efficiency}")
# Memory constraints assessment
if ram_utilization > 0.9:
memory_issue = "Memory constrained - consider optimization"
elif flash_utilization > 0.9:
memory_issue = "Program memory constrained - consider optimization"
else:
memory_issue = "Memory utilization acceptable"
print(f" Memory constraints: {memory_issue}")
Power Management Strategies
Implementing effective power saving for extended battery operation.
Your Challenge: Real-Time System Design
Design a real-time embedded system for automotive engine control and analyze its timing constraints.
Goal: Calculate task schedules and assess real-time performance requirements.
Engine Control System Parameters
import math
# Automotive engine control unit (ECU) parameters
ecu_params = {
'engine_speed': 3000, # RPM (revolutions per minute)
'cylinder_count': 4, # Number of cylinders
'tasks': [
{'name': 'fuel_injection', 'period_ms': 10, 'wcet_us': 1500, 'deadline_ms': 10}, # Every 10ms
{'name': 'ignition_timing', 'period_ms': 15, 'wcet_us': 2000, 'deadline_ms': 15}, # Every 15ms
{'name': 'sensor_sampling', 'period_ms': 5, 'wcet_us': 800, 'deadline_ms': 5}, # Every 5ms
{'name': 'idle_control', 'period_ms': 50, 'wcet_us': 3000, 'deadline_ms': 50}, # Every 50ms
{'name': 'diagnostic_check', 'period_ms': 100, 'wcet_us': 5000, 'deadline_ms': 100}, # Every 100ms
{'name': 'emissions_monitor', 'period_ms': 1000, 'wcet_us': 2000, 'deadline_ms': 1000} # Every second
],
'clock_frequency': 168, # MHz (microcontroller clock)
'scheduler_type': 'RMS', # Rate-monotonic scheduling
'interrupt_latency': 2, # microseconds
'context_switch_time': 5, # microseconds
'safety_margin': 0.1 # 10% safety margin for timing
}
# Calculate task periods in seconds
for task in ecu_params['tasks']:
task['period_s'] = task['period_ms'] / 1000
task['wcet_s'] = task['wcet_us'] / 1e6
# Calculate CPU utilization
cpu_utilization = sum(task['wcet_s'] / task['period_s'] for task in ecu_params['tasks'])
# For RMS schedulability analysis
n_tasks = len(ecu_params['tasks'])
utilization_bound = n_tasks * (2**(1/n_tasks) - 1)
# Calculate actual execution times after accounting for overhead
overhead_time_us = ecu_params['interrupt_latency'] + ecu_params['context_switch_time']
total_overhead_time_s = len(ecu_params['tasks']) * overhead_time_us / 1e6 # Convert to seconds
# Adjust task execution times for overhead
for task in ecu_params['tasks']:
task['adjusted_wcet_s'] = task['wcet_s'] + (overhead_time_us / 1e6)
# Calculate adjusted utilization
adjusted_utilization = sum(task['adjusted_wcet_s'] / task['period_s'] for task in ecu_params['tasks'])
# Apply safety margin
required_utilization = adjusted_utilization * (1 + ecu_params['safety_margin'])
# Calculate response time analysis for each task using iterative method
response_times = []
for task in ecu_params['tasks']:
# Initialize response time
Ri = task['adjusted_wcet_s']
prev_Ri = 0
# Iterate until convergence
while abs(Ri - prev_Ri) > 0.000001:
prev_Ri = Ri
# Calculate response time: Ri = Ci + ∑(ceil(Ri/Tj) * Cj) for all higher priority tasks
higher_priority_tasks = [t for t in ecu_params['tasks'] if t['period_s'] <= task['period_s']]
interference = sum(math.ceil(Ri/t['period_s']) * t['adjusted_wcet_s'] for t in higher_priority_tasks if t != task)
Ri = task['adjusted_wcet_s'] + interference
# Check if response time exceeds deadline
if Ri > task['deadline_ms'] / 1000:
break
response_times.append(Ri)
# Determine if system is schedulable
schedulable = all(rt <= t['deadline_ms']/1000 for rt, t in zip(response_times, ecu_params['tasks']))
# Calculate worst-case scenario for engine timing
# Engine fires each cylinder every 720° crank angle for 4-cylinder
engine_cycle_degrees = 720 # Total crankshaft degrees in full cycle
degrees_per_rev = 360
cylinder_spacing = engine_cycle_degrees / ecu_params['cylinder_count'] # Degrees between cylinder firings
# Calculate time per cylinder firing
rev_time = 60 / ecu_params['engine_speed'] # Seconds per revolution
firing_interval = rev_time * degrees_per_rev / cylinder_spacing # Interval between cylinder firings
# Analyze fuel injection timing constraints
injection_task = next(t for t in ecu_params['tasks'] if t['name'] == 'fuel_injection')
max_injection_delay = injection_task['deadline_ms'] / 1000 # Maximum allowable delay in seconds
# Calculate required accuracy
degrees_per_second = 360 / rev_time
max_allowable_timing_error = max_injection_delay * degrees_per_second # Maximum angular timing error in degrees
# Calculate memory requirements
program_memory_kb = 128 # Estimated program size
data_memory_kb = 32 # Estimated variable storage
stack_space_kb = 8 # Stack requirement per task (worst case)
min_stack_space = len(ecu_params['tasks']) * stack_space_kb # Minimum required stack space
memory_utilization = (program_memory_kb + data_memory_kb + min_stack_space) / 512 # Assuming 512KB total
Analyze the real-time performance of the engine control system and assess schedulability.
Hint:
- Calculate total CPU utilization and compare with schedulability bound
- Use response time analysis to verify deadline satisfaction
- Consider the relationship between engine speed and task timing
- Evaluate the impact of system overhead on performance
# TODO: Calculate real-time system parameters
cpu_utilization = 0 # Fraction (0-1 scale) of CPU utilization
utilization_bound = 0 # Theoretical limit for schedulability
schedulable = False # Whether system is schedulable
response_times = [] # List of calculated response times for each task
max_allowable_timing_error = 0 # Degrees (angular timing error for engine control)
memory_utilization = 0 # Fraction (0-1 scale) of memory utilization
# Calculate CPU utilization from the analysis above
cpu_utilization = adjusted_utilization
# Calculate utilization bound
utilization_bound = n_tasks * (2**(1/n_tasks) - 1)
# Calculate schedulability
schedulable = required_utilization <= utilization_bound and all(rt <= t['deadline_ms']/1000 for rt, t in zip(response_times, ecu_params['tasks']))
# Calculate response times (from analysis above)
response_times = [rt*1000 for rt in response_times] # Convert back to ms for reporting
# Calculate max allowable timing error from analysis above
max_allowable_timing_error = max_allowable_timing_error
# Calculate memory utilization from analysis above
memory_utilization = memory_utilization
# Print results
print(f"Real-time ECU analysis:")
print(f" CPU utilization: {cpu_utilization:.4f} ({cpu_utilization*100:.2f}%)")
print(f" Schedulability bound: {utilization_bound:.4f} ({utilization_bound*100:.2f}%)")
print(f" System schedulable: {schedulable}")
print(f" Memory utilization: {memory_utilization*100:.2f}%")
print(f" Max timing error allowed: {max_allowable_timing_error:.3f} degrees")
print(f" Engine speed: {ecu_params['engine_speed']} RPM")
print(f"\nTask response times:")
for task, resp_time in zip(ecu_params['tasks'], response_times):
deadline_met = resp_time <= task['deadline_ms']
print(f" {task['name']}: {resp_time:.3f}ms response, {task['deadline_ms']}ms deadline - {'✓' if deadline_met else '✗'}")
# Performance assessment
if cpu_utilization < 0.7:
performance_level = "Under-utilized - room for additional functionality"
elif cpu_utilization < 0.85:
performance_level = "Well-balanced - good performance with adequate margin"
elif cpu_utilization < 0.95:
performance_level = "Heavily utilized - may need optimization"
else:
performance_level = "Over-utilized - not schedulable with current design"
print(f"\n Performance level: {performance_level}")
# Timing precision assessment
if max_allowable_timing_error < 2.0: # Less than 2 degrees error allowed
timing_precision = "High precision timing - critical for engine performance"
elif max_allowable_timing_error < 5.0: # Less than 5 degrees
timing_precision = "Good precision timing - adequate for most applications"
else:
timing_precision = "Relaxed timing - less critical for engine control"
print(f" Timing precision requirement: {timing_precision}")
# Recommendations based on analysis
recommendations = []
if not schedulable:
recommendations.append("System not schedulable - reduce task WCETs or increase periods")
if cpu_utilization > 0.9:
recommendations.append("High CPU utilization - consider hardware upgrade or optimization")
if memory_utilization > 0.8:
recommendations.append("High memory utilization - optimize data structures")
if max_allowable_timing_error < 1.0:
recommendations.append("Critical timing requirements - consider dedicated hardware for timing-critical tasks")
print(f" Recommendations: {recommendations if recommendations else ['System appears well-designed for current requirements']}")
How would you modify your ECU design if the engine required cylinder deactivation technology that needs additional real-time control tasks while maintaining the same overall CPU budget?
ELI10 Explanation
Simple analogy for better understanding
Self-Examination
What are the key differences between microcontrollers and microprocessors in embedded applications?
How do real-time operating systems ensure deterministic task execution?
What are the design considerations for interfacing sensors and actuators in embedded systems?