Skip to content

Commit 50d776d

Browse files
committed
platformio setup
0 parents  commit 50d776d

File tree

358 files changed

+127398
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

358 files changed

+127398
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/ci-pipeline.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI Pipeline
2+
3+
on:
4+
push:
5+
6+
jobs:
7+
run-pipeline:
8+
name: Run CI Pipeline
9+
runs-on: ubuntu-22.04
10+
continue-on-error: true
11+
12+
steps:
13+
- name: Checkout this repo
14+
uses: actions/checkout@v4
15+
with:
16+
submodules: true
17+
18+
- name: Install dependencies
19+
run: |
20+
sudo apt update \
21+
&& sudo apt install --no-install-recommends -y xz-utils cmake ninja-build lcov gcc g++ make libc6-dev
22+
wget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz -O /tmp/arm-gcc.tar.xz
23+
tar -xf /tmp/arm-gcc.tar.xz -C /opt
24+
echo "/opt/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin" >> $GITHUB_PATH
25+
26+
- name: Build firmware binary debug
27+
run: ./scripts/run.sh build debug
28+
29+
- name: Build firmware binary release
30+
run: ./scripts/run.sh build release
31+
32+
- name: Build and run unit tests
33+
run: |
34+
./scripts/run.sh cleanall
35+
./scripts/run.sh test
36+
37+
- name: Run formatting check
38+
uses: waterloo-rocketry/actions/clang-format-check@main
39+
with:
40+
clang-format-config-path: 'src/third_party/rocketlib/.clang-format'
41+
c-source-files: 'src/application/*/*.c src/application/*/*.h src/drivers/*/*.c src/drivers/*/*.h src/common/*/*.h src/common/*/*c'

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.pio
2+
.vscode/.browse.c_cpp.db*
3+
.vscode/c_cpp_properties.json
4+
.vscode/launch.json
5+
.vscode/ipch

.gitmodules

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[submodule "src/third_party/canlib"]
2+
path = src/third_party/canlib
3+
url = https://github.com/waterloo-rocketry/canlib
4+
[submodule "src/third_party/rocketlib"]
5+
path = src/third_party/rocketlib
6+
url = https://github.com/waterloo-rocketry/rocketlib
7+
[submodule "tests/mocks/fff"]
8+
path = tests/mocks/fff
9+
url = https://github.com/meekrosoft/fff.git
10+
[submodule "tests/external/googletest"]
11+
path = tests/external/googletest
12+
url = https://github.com/google/googletest.git
13+
[submodule "src/third_party/CMSIS-DSP"]
14+
path = src/third_party/CMSIS-DSP
15+
url = https://github.com/ARM-software/CMSIS-DSP

.vscode/extensions.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
// See http://go.microsoft.com/fwlink/?LinkId=827846
3+
// for the documentation about the extensions.json format
4+
"recommendations": [
5+
"platformio.platformio-ide"
6+
],
7+
"unwantedRecommendations": [
8+
"ms-vscode.cpptools-extension-pack"
9+
]
10+
}

LICENSE.md

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# STM32 Embedded Project Template
2+
Template repo for STM32(H7) projects on the team. Based on [Processor 2025 Firmware](https://github.com/waterloo-rocketry/cansw_processor_canards). It includes a unit test framework and pipeline.
3+
4+
## READ FIRST: How to customize this template
5+
1. Inside `.devcontainer/Dockerfile`, edit the following:
6+
7+
- `ENV BOARD_NAME="<board_name>"` e.g. "proc
8+
- `ENV STM_DEVICE="<chip_family>"` e.g. STM32H750xx
9+
- `ENV STM_DEVICE_EXACT="<chip_model>"` e.g. STM32H750ZBTX
10+
11+
2. Open STM32CubeMX and generate the .ioc file for your specific chip **in a temporary location**. Make sure you set the following:
12+
- Under `Project Manager`->`Project`
13+
- Project Name - whatever you want, be consistent
14+
- Application Structure -> Advanced, leave "Do not generate the main" **unchecked**
15+
- Toolchain -> STM32CubeIDE, **check** "Generate Under Root"
16+
17+
- Under `Project Manager`->`Code Generator`
18+
- Select "Copy only the necessary files"
19+
- Check all 4 boxes under "Generated files"
20+
- Leave everything else unchanged
21+
22+
- Under `Pinout & Configuration`, two peripherals need to be enabled by default. These are FDCANx, which interfaces with canlib, and UART4, which interfaces with our custom `printf` library. If your board does not use one or both of these libraries, you will need to update CMake to not look for them.
23+
- The FDCAN handle is passed to canlib at init, so you can use any one (the HAL sources will generate reagrdless)
24+
- The UART4 handle is hard coded into `/workspaces/stm32_template/src/third_party/printf/printf.c`, line 269, and simply needs to be changed to match the UART you want to use. It is hardcoded so that you can printf from anywhere without needing to confirm your printf was initialized every time.
25+
26+
3. Replace `PLACEHOLDER.ioc` in the root directory with your ioc file
27+
4. Open the ioc in CubeMX from the new location, and generate code
28+
29+
## Project Structure
30+
- `src/drivers/`: custom peripheral driver modules
31+
- `src/application/`: high-level application logic modules
32+
- `src/third_party/`: third-party libraries
33+
- `src/common/`: shared resources specific to this project
34+
- `tests/`: everything for [testing](#Unit-Testing)
35+
- Everything else is autogenerated by STM32CubeIDE with few modifications
36+
37+
## Developer Setup
38+
This project is not dependent on STM32CubeIDE.
39+
Code editing, unit testing, and building should be done in the devcontainer.
40+
Only running/debugging on target should be done in STM32CubeIDE.
41+
42+
#### 1. Clone repo
43+
- Clone repo and initialize submodules: ```
44+
git clone --recurse-submodules https://github.com/waterloo-rocketry/cansw_processor_canards ```
45+
- (Note: if you choose to clone with ssh instead, you have to manually setup ssh forwarding in the devcontainer.)
46+
47+
#### 2. Open project in devcontainer
48+
The devcontainer has everything setup for editing, unit testing, and building. Most dev work should occur in it.
49+
- Open the project using vscode devcontainers.
50+
- [Install devcontainers](https://code.visualstudio.com/docs/devcontainers/tutorial)
51+
- In a new vscode window, use `Ctrl+Shift+P`, search `Dev Containers: Open Folder In Container...`, then select this project folder
52+
- The first time opening the project will take several minutes to build the devcontainer. Subsequent times will be instant.
53+
54+
#### 3. Build and test project in devcontainer
55+
*Recommended: use vscode cmake plugin:*
56+
- Open the CMake plugin tab from the sidebar
57+
- Under `Configure`, select which build type you want
58+
- Hover over `Build`, click the build icon to build the configuration
59+
- The build preset should automatically be selected (eg, `Build Firmware (Debug) preset`)
60+
61+
#### 4. Run/debug in STM32CubeIDE
62+
STM32CubeIDE is required for flashing/debugging on hardware. NOTE: STM32CubeIDE is not able to *build* this project. STM32CubeIDE is only used to *flash* the build from step 3.
63+
- Import the project into STM32CubeIDE (version 1.16.1 recommended): `File -> Import... -> Existing Projects into Workspace`
64+
- Build the project firmware binary using vscode (step 3)
65+
- Use an ST-Link programmer to connect to processor board.
66+
- Use STM32CubeIDE launch/debug as usual
67+
- NOTE: since the project can't be built in STM32CubeIDE, auto-building before launch is turned off. **Remember to always build the project after making edits.**
68+
69+
## Unit Testing
70+
We use GoogleTest and Fake Function Framework (fff) for unit testing. All testing-related files are in `tests/`.
71+
- Tests are built from `tests/CMakeLists.txt` which is separate from the project's main build config. Building and running tests is done via cmake.
72+
- Test source code should be written in `tests/unit/`.
73+
- Mocks should be made with fff in `tests/mocks/`.
74+
75+
### Add a test
76+
- Add a new test group file in `tests/unit/`. See `test_dummy.cpp` for example of test structure.
77+
- Add the test group to the cmake build system by editing `tests/CMakeLists.txt`:
78+
- At the bottom of the file, add the new test group using the `add_test_group()` helper.
79+
(Read the comments + existing examples explaining how it works)
80+
81+
### Add a mock
82+
We do not include the STM32 HAL library nor FreeRTOS when compiling the project for unit tests.
83+
So if a source file uses a HAL or FreeRTOS file, those files and their functions must be mocked using fff.
84+
This works similarly for mocking other proc modules that a test interacts with but doesn't test.
85+
86+
Example 1:
87+
- `src/drivers/gpio/gpio.c` uses FreeRTOS semaphores via `#include "semphr.h`.
88+
- In the actual firmware, the real `semphr.h` is included when compiling. But for unit tests, the real `semphr.h` is not included when compiling. So, the unit tests fail to compile (it can't find a `semphr.h` file).
89+
- To correct this we add a "fake" `semphr.h` in `tests/mocks/semphr.h`. All files in this folder are included when compiling unit test, so the tests now compile.
90+
- The gpio code uses functions from the real `semphr.h` like `xSemaphoreTake()`. These don't exist in our fake `semphr.h` yet.
91+
- To correct this we need to create a mock `xSemaphoreTake()` function using fff.
92+
[fff's Readme](https://github.com/meekrosoft/fff?tab=readme-ov-file#hello-fake-world) describes how to create fake functions. Here's the mock for `xSemaphoreTake()`:
93+
```
94+
// The func to mock: BaseType_t xSemaphoreTake(SemaphoreHandle_t arg0, TickType_t arg1)
95+
96+
DECLARE_FAKE_VALUE_FUNC(BaseType_t, xSemaphoreTake, SemaphoreHandle_t, TickType_t);
97+
```
98+
First we put the *declaration* (`DECLARE_FAKE...`) in `mocks/semphr.h`. Then, put the actual *definition* (`DEFINE_FAKE...`) in the corresponding `mocks/semphr.c`.
99+
- Now in the gpio tests, we can access the mocked semaphore functions via fff to test that the gpio code uses semaphores correctly.
100+
101+
Example 2:
102+
- `src/application/estimator/estimator.c` takes input from flightphase via `#include "application/flight_phase/flight_phase.h`.
103+
- To test estimator, we will test various inputs from flightphase. But we don't want to be testing flightphase at the same time.
104+
So, mock flightphase.
105+
- The real `flight_phase.h` header is built in unit tests, but the source file `flight_phase.c` is not.
106+
- Since a function *declaration* for `get_flight_phase()` exists in the header, we can use fff's `DEFINE_FAKE...` to create a
107+
fake *definition* of that `get_flight_phase()`. That definition should be in the test .cpp file, or in the mocks folder if it's applicable for wider use.
108+
- (Note: unlike example 1 where the header isn't included in unit tests, the flightphase header is included so it doesnt need a `DECLARE_FAKE...`)
109+
110+
### Run/debug tests
111+
- Build in vscode using cmake (see step 3 above)
112+
- The default `Build Unit Tests With Coverage preset` also automatically runs all tests and generates coverage report.
113+
- View the coverage report html pages in `build/test/coverage_report` in a local browser
114+
- Use the vscode cmake `Launch` and `Debug` tabs to run/debug individual test groups (cmake shows the available test groups)
115+
116+
117+
## Debugging on hardware
118+
- Use STM32CubeIDE debugging as directed above
119+
- The ST-link programmer has a serial output so you can listen to uart4 from a laptop COM port. The printf library (NOT THE STDLIB PRINTF) is configured to print strings to that COM port. Use `printf_("string to print..")` - note the `_` character.
120+
- This should rarely be used. Please instead learn how to use the debugger (breakpoints, dynamic print breakpoints, step, etc) for efficient and pleasant debugging.
121+
122+
## Code Standards
123+
This project follows the [team-wide embedded coding standard](https://docs.waterloorocketry.com/general/standards/embedded-coding-standard.html).
124+
- The devcontainer sets up vscode format-on-save to automatically use the team's clang-format.
125+
- In case you want to format manually, the script can be run from the project root directory:
126+
```bash
127+
./scripts/format.sh
128+
```
129+
130+
- Rocketlib is included at `src/third_party/rocketlib`.
131+
- Developers should be aware of the BARR Standard and make an effort to follow it.
132+
133+
## Adding Log Messages
134+
When adding a new type of data log message, all of the following should be updated:
135+
- src/application/logger/log.h
136+
- Add a new enum value to `log_data_type_t`:
137+
```diff
138+
typedef enum {
139+
+ LOG_TYPE_XXX = M(unique_small_integer),
140+
} log_data_type_t;
141+
```
142+
- Add a struct definition of your message's data fields to `log_data_container_t`:
143+
```diff
144+
typedef union __attribute__((packed)) {
145+
+ struct __attribute__((packed)) {
146+
+ uint32_t l;
147+
+ float f;
148+
+ // ...
149+
+ } typename;
150+
} log_data_container_t;
151+
```
152+
- scripts/logparse.py
153+
- Add a new format spec to the `FORMATS` dict:
154+
```diff
155+
FORMATS = {
156+
+ M(unique_small_integer): Spec(name, format, [field, ...]),
157+
}
158+
```
159+
160+
## Notes
161+
- Auto-gen stm32 files used STM32CubeMX Version: 6.12.1-RC4,
162+
STM32CubeIDE version 1.16.1
163+

include/README

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
This directory is intended for project header files.
3+
4+
A header file is a file containing C declarations and macro definitions
5+
to be shared between several project source files. You request the use of a
6+
header file in your project source file (C, C++, etc) located in `src` folder
7+
by including it, with the C preprocessing directive `#include'.
8+
9+
```src/main.c
10+
11+
#include "header.h"
12+
13+
int main (void)
14+
{
15+
...
16+
}
17+
```
18+
19+
Including a header file produces the same results as copying the header file
20+
into each source file that needs it. Such copying would be time-consuming
21+
and error-prone. With a header file, the related declarations appear
22+
in only one place. If they need to be changed, they can be changed in one
23+
place, and programs that include the header file will automatically use the
24+
new version when next recompiled. The header file eliminates the labor of
25+
finding and changing all the copies as well as the risk that a failure to
26+
find one copy will result in inconsistencies within a program.
27+
28+
In C, the convention is to give header files names that end with `.h'.
29+
30+
Read more about using header files in official GCC documentation:
31+
32+
* Include Syntax
33+
* Include Operation
34+
* Once-Only Headers
35+
* Computed Includes
36+
37+
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

lib/README

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
This directory is intended for project specific (private) libraries.
3+
PlatformIO will compile them to static libraries and link into the executable file.
4+
5+
The source code of each library should be placed in a separate directory
6+
("lib/your_library_name/[Code]").
7+
8+
For example, see the structure of the following example libraries `Foo` and `Bar`:
9+
10+
|--lib
11+
| |
12+
| |--Bar
13+
| | |--docs
14+
| | |--examples
15+
| | |--src
16+
| | |- Bar.c
17+
| | |- Bar.h
18+
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19+
| |
20+
| |--Foo
21+
| | |- Foo.c
22+
| | |- Foo.h
23+
| |
24+
| |- README --> THIS FILE
25+
|
26+
|- platformio.ini
27+
|--src
28+
|- main.c
29+
30+
Example contents of `src/main.c` using Foo and Bar:
31+
```
32+
#include <Foo.h>
33+
#include <Bar.h>
34+
35+
int main (void)
36+
{
37+
...
38+
}
39+
40+
```
41+
42+
The PlatformIO Library Dependency Finder will find automatically dependent
43+
libraries by scanning project source files.
44+
45+
More information about PlatformIO Library Dependency Finder
46+
- https://docs.platformio.org/page/librarymanager/ldf.html

platformio.ini

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; PlatformIO Project Configuration File
2+
;
3+
; Build options: build flags, source filter
4+
; Upload options: custom upload port, speed and extra flags
5+
; Library options: dependencies, extra library storages
6+
; Advanced options: extra scripting
7+
;
8+
; Please visit documentation for the other options and examples
9+
; https://docs.platformio.org/page/projectconf.html
10+
11+
[env:genericSTM32H750VB]
12+
platform = ststm32
13+
board = genericSTM32H750VB
14+
framework = stm32cube

0 commit comments

Comments
 (0)