Cover
Title Page
Copyright and Credits
About Packt
Contributors
Table of Contents
Preface
Section 1: Introduction and RTOS Concepts
Chapter 1: Introducing Real-Time Systems
Technical requirements
What is real-time anyway?
The ranges of timing requirements
The ways of guaranteeing real-time behavior
Types of real-time systems
Hardware
Bare-metal firmware
RTOS-based firmware
RTOS-based software
Carefully crafted OS software
Defining RTOS
Hard real-time systems
Firm real-time systems
Soft real-time systems
The range of RTOSes
The RTOS used in this book
Deciding when to use an RTOS
Summary
Questions
Chapter 2: Understanding RTOS Tasks
Technical requirements
Introducing super loop programming
The basic super loop
Super loops in real-time systems
Achieving parallel operations with super loops
Introducing interrupts
Interrupts and super loops
Introducing DMA
Scaling a super loop
Comparing RTOS tasks to super loops
Achieving parallel operations with RTOS tasks
Theoretical task programming model
Round-robin scheduling
Preemptive-based scheduling
RTOS tasks versus super loops – pros and cons
Summary
Questions
Further reading
Chapter 3: Task Signaling and Communication Mechanisms
Technical requirements
RTOS queues
Simple queue send
Simple queue receive
Full queue send
Empty queue receive
Queues for inter-task communication
RTOS semaphores
Counting semaphores
Binary semaphores
RTOS mutexes
Priority inversion
Mutexes minimize priority inversion
Summary
Questions
Section 2: Toolchain Setup
Chapter 4: Selecting the Right MCU
Technical requirements
The importance of MCU selection
MCU considerations
Core considerations
Physical size
ROM
RAM
The CPU clock rate
Interrupt processing
Price
Availability
Hardware peripherals
Connectivity
Memory protection units
Hardware floating-point units
Digital signal processing functions
Direct memory access channels
Communication interfaces
Hardware crypto engines
Timing hardware
Integrated analog
Dedicated touch interfaces
Display interfaces
External memory support
Real-time clock
Audio support
Power consumption
Power efficiency
Low-power modes
Wake-up time
Power supply voltage
Migrating MCUs mid-project
Importance of pin compatibility
Peripheral similarity
The concept of an MCU family
Development board considerations
What a development platform is and why it matters
Evaluation kits
Low-cost demonstration boards
Introducing the STM32 product line
Mainstream
High performance
The heterogeneous multi-core approach
Low power
Wireless
How our development board was selected
Requirements
Requirements justification
Choosing the dev board
Summary
Questions
Further reading
Chapter 5: Selecting an IDE
Technical requirements
The IDE selection criteria
Free MCU vendor IDEs and hardware-centric IDEs
STM32CubeIDE
Platform-abstracted IDEs
ARM Mbed Studio
Arduino IDE
Open source/free IDEs
AC6 System Workbench for STM32 (S4STM32)
Eclipse CDT and GCC
Microsoft Visual Studio Code
Proprietary IDEs
ARM/Keil uVision
IAR Embedded Workbench
Rowley CrossWorks
SEGGER Embedded Studio
SysProgs Visual GDB
Selecting the IDE used in this book
Considering STM32Cube
Device selection
Hardware bring-up
Middleware setup
Code generation trade-offs
Setting up our IDE
Installing STM32CubeIDE
Importing the source tree into STM32CubeIDE
Summary
Questions
Further reading
Chapter 6: Debugging Tools for Real-Time Systems
Technical requirements
The importance of excellent debugging tools
RTOS-aware debugging
RTOS visualization
Using SEGGER J-Link
Hardware options
Segger J-Trace
SEGGER J-Link
SEGGER J-Link on-board
Installing J-Link
Converting ST-Link to J-Link
Using SEGGER Ozone
File types used in the examples
Installing SEGGER Ozone
Creating Ozone projects
Attaching Ozone to the MCU
Viewing tasks
Task-based stack analysis
Using SEGGER SystemView
Installing SystemView
SystemView installation
Source code configuration
Using SystemView
Other great tools
Test-driven development
Static analysis
Percepio Tracealyzer
Traditional testing equipment
Summary
Questions
Further reading
Section 3: RTOS Application Examples
Chapter 7: The FreeRTOS Scheduler
Technical requirements
Creating tasks and starting the scheduler
Hardware initialization
Defining task functions
Creating tasks
Checking the return value
Starting the scheduler
Deleting tasks
The task deletes itself
Deleting a task from another task
Trying out the code
Task memory allocation
Heap allocated tasks
Statically allocated tasks
Memory protected task creation
Task creation roundup
Understanding FreeRTOS task states
Understanding different task states
Running
Ready
Blocked
Suspended
Optimizing task states
Optimizing to reduce CPU time
Optimizing to increase performance
Optimizing to minimize power consumption
Troubleshooting startup problems
None of my tasks are running!
Task creation failed
Scheduler returns unexpectedly
Important notes
Summary
Questions
Further reading
Chapter 8: Protecting Data and Synchronizing Tasks
Technical requirements
Using semaphores
Synchronization via semaphores
Setting up the code
Understanding the behavior
Wasting cycles – synchronization by polling
Setting up the code
Understanding the behavior
Time-bound semaphores
Setting up the code
Understanding the behavior
Counting semaphores
Priority inversion (how not to use semaphores)
Setting up the code
Task A (highest priority)
Task B (medium priority)
Task C (low priority)
Understanding the behavior
Using mutexes
Fixing priority inversion
Setting up the code
Understanding the behavior
Avoiding mutex acquisition failure
Avoiding race conditions
Failed shared resource example
Using software timers
Setting up the code
Oneshot timers
Repeat timers
Understanding the behavior
Software timer guidelines
Example use cases
Considerations
Limitations
Summary
Questions
Further reading
Chapter 9: Intertask Communication
Technical requirements
Passing data through queues by value
Passing one byte by value
Passing a composite data type by value
Understanding how queues affect execution
Important notes on the examples
Passing data through queues by reference
When to pass by reference
Important notes
Direct task notifications
Passing simple data using task notifications
Other options for task notifications
Comparing direct task notifications to queues
Summary
Questions
Further reading
Section 4: Advanced RTOS Techniques
Chapter 10: Drivers and ISRs
Technical requirements
Introducing the UART
Setting up the UART
Creating a polled UART driver
Analyzing the performance
Pros and cons of a polled driver
Usage of polled drivers
Differentiating between tasks and ISRs
Using the FreeRTOS API from interrupts
Creating ISR-based drivers
Queue-based driver
uartPrintOutTask
startReceiveInt
USART2_IRQHandler
Tips for linking ISRs
startUart4Traffic
Performance analysis
A buffer-based driver
startReceiveInt
uartPrintOutTask
USART2_IRQHandler
startUart4Traffic
Performance analysis
Creating DMA-based drivers
Configuring DMA peripherals
A buffer-based driver with DMA
Performance analysis
Stream buffers (FreeRTOS 10+)
Using the stream buffer API
Setting up double-buffered DMA
Populating the stream buffer
Improving the stream buffer
Analyzing the performance
Choosing a driver model
How is the calling code designed?
How much delay is acceptable?
How fast is data moving?
What type of device are you interfacing?
When to use queue-based drivers
When to use buffer-based drivers
When to use stream buffers
Using third-party libraries (STM HAL)
Summary
Questions
Further reading
Chapter 11: Sharing Hardware Peripherals across Tasks
Technical requirements
Understanding shared peripherals
Defining the peripheral driver
Introducing the STM USB driver stack
Using the stock CDC drivers
Developing a StreamBuffer USB virtual COM port
Public functions
Private functions
Putting it all together
Using mutexes for access control
Extending VirtualCommDriver
Guaranteeing atomic transactions
Summary
Questions
Chapter 12: Tips for Creating a Well-Abstracted Architecture
Technical requirements
Understanding abstraction
Grasping an abstraction is fast
An example with abstraction
An example without abstraction
Abstractions provide flexibility
Why abstraction is important
Recognizing opportunities to reuse code
Avoiding the copy-paste-modify trap
Writing reusable code
Writing reusable drivers
Developing an LED interface
Reusing code containing tasks
Testing flexible code
Organizing source code
Choosing locations for source files
Dealing with changes
Summary
Questions
Further reading
Chapter 13: Creating Loose Coupling with Queues
Technical requirements
Understanding queues as interfaces
Queues make excellent interface definitions
Queues increase flexibility
Queues make testing easier
Creating a command queue
Deciding on queue contents
Defining the architecture
ledCmdExecutor
Frame decoding
The USB virtual comm driver
Using the code
Reusing a queue definition for a new target
The queue interface
The iPWM interface
Summary
Questions
Chapter 14: Choosing an RTOS API
Technical requirements
Understanding generic RTOS APIs
Advantages of generic APIs
Disadvantages of generic APIs
Comparing FreeRTOS and CMSIS-RTOS
Considerations during migration
Cross-referencing CMIS-RTOS and FreeRTOS functions
Delay functions
EventFlags
Kernel control and information
Message queues
Mutexes and semaphores
Semaphores
Thread flags
Thread control/information
Timers
Memory pools
Creating a simple CMSIS-RTOS v2 application
FreeRTOS and POSIX
Creating a simple FreeRTOS POSIX application
Pros and cons to using the POSIX API
Deciding which API to use
When to use the native FreeRTOS API
When to use the CMSIS-RTOS API
When to use the POSIX API
Summary
Questions
Further reading
Chapter 15: FreeRTOS Memory Management
Technical requirements
Understanding memory allocation
Static memory
Stack memory
Heap memory
Heap fragmentation
Static and dynamic allocation of FreeRTOS primitives
Dynamic allocation examples
Creating a task
Creating a queue
Static allocation examples
Creating a task
Creating a queue
Eliminating all dynamic allocation
Comparing FreeRTOS heap implementations
Choosing your RTOS heap implementation
Replacing malloc and free
Implementing FreeRTOS memory hooks
Keeping an eye on stack space
Keeping an eye on heap space
Using a memory protection unit (MPU)
Summary
Questions
Further reading
Chapter 16: Multi-Processor and Multi-Core Systems
Technical requirements
Introducing multi-core and multi-processor systems
Exploring multi-core systems
Heterogeneous multi-core systems
Inter-core communication
Legacy application extension
High-demand hard real-time systems
Homogeneous multi-core systems
Exploring multi-processor systems
Distributed systems
Parallel development
Design reuse
High-reliability systems
Exploring inter-processor communication
Choosing the right communication medium
Communication standards
Controller area network
Ethernet
Inter-integrated communication bus
Local interconnect network
Modbus
Serial peripheral interface
USB as an inter-processor communication bus
Choosing between multi-core and multi-processor systems
When to use multi-core MCUs
When to use multi-processor systems
Summary
Questions
Further reading
Chapter 17: Troubleshooting Tips and Next Steps
Technical requirements
Useful tips
Using tools to analyze threads
Keeping an eye on memory usage
Stack overflow checking
Fixing SystemView dropped data
Using assertions
configAssert
Debugging a hung system with configAssert()
Collecting the data
Digging deeper – SystemView data breakpoints
Next steps
Summary
Questions
Assessments
Other Books You May Enjoy
Index