Skip to content

Instantly share code, notes, and snippets.

@fdelbos
Last active November 12, 2024 06:35
Show Gist options
  • Save fdelbos/1cf987d75f2954a11161a18c943e2d67 to your computer and use it in GitHub Desktop.
Save fdelbos/1cf987d75f2954a11161a18c943e2d67 to your computer and use it in GitHub Desktop.
STM32 project setup with cmake and CubeMX

STM32 project setup

Tools

Install gcc arm none eabi

We will install gcc in an upper directory, so that we can reuse it in all our projects

  • create the dir: mkdir stm32 && cd stm32
  • go to the download page and find the latest version
wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
tar -xvf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
ln -s gcc-arm-none-eabi-10.3-2021.10 gcc
  • create an .envrc file
echo 'export PATH=$PATH:`realpath $(pwd)/gcc/bin`' > .envrc
direnv allow
  • check it worked
whereis arm-none-eabi-gcc
arm-none-eabi-gcc: /home/fred/work/toto/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc

STM32CubeMX

  • Create New project
  • Select board
  • Start Project (init all peripherials with default)
  • Go to the "Project Manager" tab and setup the project name and path
  • Set "Toolchain" as "STM32CubeIDE"
  • in "Code Generator" select "Copy only necessary library files"

CMake

  • Go to to generated project
  • Create a git repo and add cubemx.cmake as submodule:
git init
git submodule add https://github.com/patrislav1/cubemx.cmake.git
  • Create CMakeLists.txt (replace usblcd by the name of yout ioc file):
cat << \EOT > CMakeLists.txt
cmake_minimum_required(VERSION 3.22)

set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cubemx.cmake/arm-gcc.cmake")

set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)

include(cubemx.cmake/cubemx.cmake)

project(usblcd)
add_executable(
	usblcd
	usr/lcd.c
)

# code folder
target_include_directories(usblcd PRIVATE "usr")

cubemx_target(
    TARGET usblcd
    IOC "${CMAKE_CURRENT_LIST_DIR}/usblcd.ioc"
)

# set the correct target if necessarry (see: ./Drivers/CMSIS/Device/ST/STM32F0xx/Include/stm32f0xx.h)
# target_compile_options(usblcd PRIVATE -DSTM32F030x8)

# warnings
target_compile_options(usblcd PRIVATE
	-Wall
	-Wextra
	-Wno-unused-parameter
	-Wshadow
	-Wformat=2
	-Wstrict-overflow
	-fvisibility=hidden
	-fno-strict-aliasing
	-Werror
)

# debug
# target_compile_options(usblcd PRIVATE -Og -Wall -g -gdwarf-2)

# production
target_compile_options(usblcd PRIVATE
	-s
	-Os
	-DNDEBUG
)

target_compile_definitions(usblcd PRIVATE
	USE_FULL_LL_DRIVER
	USE_HAL_DRIVER
)
EOT

Build

  • Add .clang-format
cat << \EOT > .clang-format
---
BasedOnStyle: LLVM
ColumnLimit: 0
UseTab: ForIndentation
IndentWidth: 4
TabWidth: 4
AllowShortIfStatementsOnASingleLine: false
IndentAccessModifiers: false
AccessModifierOffset: -4
EmptyLineBeforeAccessModifier: LogicalBlock
EOT
  • generate vscode project:
mkdir -p .vscode

cat << \EOT > .vscode/cmake-kits.json
[{
	"name": "arm-gcc from CMake Toolchain",
	"toolchainFile": "${workspaceRoot}/cubemx.cmake/arm-gcc.cmake"
}]
EOT

cat << \EOT > .vscode/settings.json
{
	"editor.formatOnSave": true,
	"C_Cpp.formatting": "Disabled",
	"clang-format.executable": "/usr/bin/clang-format"
}
EOT
  • generate build env:
mkdir -p build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../cubemx.cmake/arm-gcc.cmake ..
  • compile: make
  • flash: make flash
  • reset: make reset

How to redirect the printf function to a UART

see this reference article: https://community.st.com/s/article/how-to-redirect-the-printf-function-to-a-uart-for-debug-messages

  • check virtual com port and connect:
sudo dmesg | grep tty
[994945.768623] cdc_acm 3-1.4:1.2: ttyACM0: USB ACM device

# if set on 8bits including parity (the default value) 
screen /dev/ttyACM0 115200
# use Ctrl-a k to exit

# or minicom
minicom --device  /dev/ttyACM0

If LPUART1 is available

Then leave everything by default and add the following:

/* USER CODE BEGIN Init */
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
/* USER CODE END Init */

/* USER CODE BEGIN PFP */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
/* USER CODE END PFP */

/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_Delay(50);
printf("Hello!\n\r");
}
/* USER CODE END 3 */

/* USER CODE BEGIN 4 */
PUTCHAR_PROTOTYPE {
	/* Place your implementation of fputc here */
	/* e.g. write a character to the USART1 and Loop until the end of transmission */
	HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);

	return ch;
}
/* USER CODE END 4 */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment