Inspired by stm32-makefile, this repository is an example project demonstrating how to use an STM32 microcontroller with uCOS-III. The project runs on the Nucleo-144 development board targeting the STM32F767ZI microcontroller with the TE Connectivity Weather Shield attached. The project uses:
- CMake (Build System)
- GNU ARM Embedded Toolchain (Compiler)
- STM32CubeF7 MCU Firmware Package (BSP/Drivers)
- uCOS-III, uC-CPU, uC-Lib (RTOS)
- OpenOCD (Debug)
This project was created while reading uCOS-III The Real-Time Kernel (STM32 version, 2009). There are example projects associated with this book, but building up an application from scratch is a useful to understand...
- Which files are kernel code vs. user code.
- Clear separation is done using Git submodules.
- What kernel APIs must be called and which ones are optional based on the application requirements.
- The code is thoroughly commented with book references.
Currently there are 3 tasks:
app_task
: This task doesn't do much except creating other tasks and then toggling an LED every 1 second. In a larger system, this task might have more responsibility like centralized error handling.logger_task
: Example of a logger that leverages uCOS features. Since we don't want multiple tasks competing for a stateful hardware resource,logger_task
is the exclusive owner ofbsp_uart.c
. Other tasks log to the serial console by sending this task a message. A memory pool is used such that other tasks don't need to worry about potentially overwriting buffers and can move on right after calling the logger APIs.sensor_task
: Sincelogger_task
is a "consumer", this project would be boring without an interesting "producer". Since the Nucleo-144 doesn't have any sensors on it, the TE Connectivity Weather Shield is used. This shield has 5 environmental sensors that read some combination of temperature, pressure, and humidity. The task is designed to be generic should that multiple instances of it could be created for each sensor.
The BSP modules are also designed to leverage uCOS features:
bsp_led.c
andbsp_sensor.c
: These drivers protect all API calls (except initialization) with a mutex. This allows them to be used by multiple tasks safely. This pattern works when hardware access is quick and not stateful, like LED toggling and small I2C transactions.bsp_uart.c
: As mentioned above, this driver is not protected with a mutex since it is owned by a single task. However a semaphore is used to synchronize the UART transmit API call with the interrupt service routine (ISR). This allows uCOS to perform a context switch during a UART transmit if necessary since the transmit processing will be done from the interrupt handler.
- Dig deeper into the MS8607 sensor settings, as the current use is very simple and minimal.
- May need some calibration to get more accurate results.
- Support more Weather Shield sensors by adding them to
bsp_sensor.c
. Create multiple instances ofsensor_task
for each of them, passing inSensor_TypeDef
as an input to the task.- This requires making the task data (TCB, stack) arrays that are indexed with the
Sensor_TypeDef
task input argument.
- This requires making the task data (TCB, stack) arrays that are indexed with the
- Switch to "dynamic tick" to save power.
- This requires programming a one-shot timer to avoid waking up unnecessarily every tick.
- Enter low-power mode during the idle task to save power.
- Use DMA in
bsp_uart.c
, to minimize the number of interrupts during a transmit. - Integrate a tool or build something to visualize context switches. Also try to use the uCOS statistics task.
This project uses roughly the same tooling as stm32-makefile, so please see that project for installation advice. The only new dependency is cmake
, which can be easily installed with system package managers like brew install cmake
on macOS. The submodules can be downloaded with git submodule init && git submodule update
. It is assumed that arm-none-eabi-gcc
is in the system path.
Some other helpful tools are used in the Makefile:
astyle
: Enforce language specific coding conventions. Install withbrew install astyle
.pyserial
: Used for serial console (logger output). Install withpip3 install pyserial
.
- Simply run
make
to build the project. - In another terminal, start the GDB server by running
make gdb-server
. - In another terminal, view the logs using
make serial-console
. - Run
make gdb-client
to download the code and start debugging.
If everything is working, the logs on the serial console should look like:
[0][Application Task] App Task Heartbeat
[170][Sensor Task] Temperature: 27.040001
[170][Sensor Task] Humidity: 36.201996
[170][Sensor Task] Pressure: 997.739990
[170][Sensor Task] Number of Sensor Readings = 1
[1000][Application Task] App Task Heartbeat
[1222][Sensor Task] Temperature: 27.040001
[1222][Sensor Task] Humidity: 36.209625
[1222][Sensor Task] Pressure: 997.710022
[1222][Sensor Task] Number of Sensor Readings = 2
[2000][Application Task] App Task Heartbeat
[2274][Sensor Task] Temperature: 27.040001
[2274][Sensor Task] Humidity: 36.194366
[2274][Sensor Task] Pressure: 997.710022
[2274][Sensor Task] Number of Sensor Readings = 3
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
OSIntEnter();
CPU_CRITICAL_EXIT();
// Handle interrupt, clear pending bits
OSIntExit();
- Lots of whitespace and comments for readability.
- Language specific style (braces, spacing, etc) is enforced using
astyle
. - Templated uCOS code is unchanged (Cfg, os_app_hooks) from the uCOS coding style.
- For readability and to match the book, uCOS API arguments are placed on individual lines with (sometimes unnecessary) type casts.
- Task-level code (Source):
- APIs will pass error info to caller using a pointer as the final argument to match uCOS API style.
- Naming:
- Globals:
UpperCamelCase
. - Locals:
lower_snake_case
. - Functions:
lower_snake_case
.
- Globals:
- BSP-level code (BSP):
- APIs will pass error info to caller using the return value.
- Naming: Copy STM32 HAL and uCOS style.
- Includes:
- Ordering:
- Relative header for current C file (if applicable).
- Project includes.
- Project library includes (BSP, uCOS, STM32 HAL).
- Standard library includes.
- Every file (source or header) should only include files needed by that individual file.
- Do not make assumptions based on include ordering or lazily use includes from other headers.
- Application should only access hardware through the BSP.
bsp.h
will be the only include file used by applications to use hardware functionality.
- Ordering: