You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ubuntu上为STM32F412xx搭建GCC ARM编译器并通过CMake构建Demo项目

Great start with the compiler and tooling setup! Let's wrap this up into a complete STM32F412xx "Hello, World!" project using CMake. Here's a step-by-step guide to fill in the gaps:

1. Create a CMake Toolchain File for STM32F412xx

This file tells CMake how to use your cross-compiler for ARM Cortex-M4 targets. Create a file named arm-none-eabi-gcc.cmake in your project root:

# arm-none-eabi-gcc.cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)

# Point to your cross-compiler
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)

# Core compiler flags tailored for STM32F412xx
set(CMAKE_C_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -Os -Wall -Wextra -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions")
set(CMAKE_ASM_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -x assembler-with-cpp")

# Linker flags (update the linker script path to match your file)
set(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_SOURCE_DIR}/stm32f412xx_flash.ld -Wl,--gc-sections -Wl,-Map=hello_world.map")

# Configure CMake to search for libraries/headers only in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
2. Project Structure

Organize your files like this:

stm32-hello-world/
├── arm-none-eabi-gcc.cmake
├── stm32f412xx_flash.ld      # Linker script (get from STM32CubeMX or ST's official libraries)
├── stm32f412xx_startup.s     # Startup assembly file (also from CubeMX/ST libraries)
├── CMakeLists.txt
└── src/
    └── main.c

Note: You can generate the linker script and startup file using STM32CubeMX by selecting your STM32F412xx device and exporting minimal project files.

3. Root CMakeLists.txt

Create the main build configuration file in your project root:

cmake_minimum_required(VERSION 3.16)
project(stm32-hello-world C ASM)

# Target MCU (adjust if you're using a specific variant like STM32F412ZGTx)
set(TARGET_MCU STM32F412xx)

# Include directories (add ST HAL/LL headers here if you use them later)
include_directories(
    src
    # Uncomment below if using ST HAL:
    # ${CMAKE_SOURCE_DIR}/Drivers/STM32F4xx_HAL_Driver/Inc
)

# Collect source files
file(GLOB SOURCES
    src/*.c
    stm32f412xx_startup.s
)

# Build the ELF executable
add_executable(${PROJECT_NAME}.elf ${SOURCES})

# Post-build steps: convert ELF to bin/hex and print size
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
    COMMAND arm-none-eabi-objcopy -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
    COMMAND arm-none-eabi-objcopy -O ihex ${PROJECT_NAME}.elf ${PROJECT_NAME}.hex
    COMMAND arm-none-eabi-size ${PROJECT_NAME}.elf
)
4. "Hello, World!" Demo Code

Create src/main.c with a simple UART-based "Hello World" (adjust UART pins/clock to match your board):

#include <stdint.h>

// Register addresses for USART2 and GPIOA (STM32F412xx)
#define USART2_BASE 0x40004400
#define USART2_CR1 (*(volatile uint32_t*)(USART2_BASE + 0x00))
#define USART2_BRR (*(volatile uint32_t*)(USART2_BASE + 0x0C))
#define USART2_TDR (*(volatile uint32_t*)(USART2_BASE + 0x28))
#define USART2_ISR (*(volatile uint32_t*)(USART2_BASE + 0x1C))

#define RCC_BASE 0x40023800
#define RCC_AHB1ENR (*(volatile uint32_t*)(RCC_BASE + 0x30))
#define RCC_APB1ENR (*(volatile uint32_t*)(RCC_BASE + 0x40))

#define GPIOA_BASE 0x40020000
#define GPIOA_MODER (*(volatile uint32_t*)(GPIOA_BASE + 0x00))
#define GPIOA_AFRL (*(volatile uint32_t*)(GPIOA_BASE + 0x20))

void uart_init(void) {
    // Enable clocks for GPIOA and USART2
    RCC_AHB1ENR |= (1 << 0);
    RCC_APB1ENR |= (1 << 17);

    // Configure PA2 as AF7 (USART2 TX)
    GPIOA_MODER &= ~(3 << 4);
    GPIOA_MODER |= (2 << 4);
    GPIOA_AFRL &= ~(0xF << 8);
    GPIOA_AFRL |= (7 << 8);

    // Set 115200 baud rate (for 16MHz APB1 clock)
    USART2_BRR = 0x0683;
    // Enable TX and USART peripheral
    USART2_CR1 |= (1 << 3) | (1 << 13);
}

void uart_send_char(char c) {
    while (!(USART2_ISR & (1 << 7))); // Wait for TX buffer to be empty
    USART2_TDR = c;
}

void uart_send_string(const char* str) {
    while (*str) {
        uart_send_char(*str++);
    }
}

int main(void) {
    uart_init();
    while (1) {
        uart_send_string("Hello, World!\r\n");
        // Simple delay loop
        for (volatile uint32_t i = 0; i < 1000000; i++);
    }
}
5. Build and Flash the Project

Run these commands from your project root to compile and deploy:

# Create build directory
mkdir build && cd build

# Configure CMake with the toolchain file
cmake .. -DCMAKE_TOOLCHAIN_FILE=../arm-none-eabi-gcc.cmake

# Build the project
make

# Flash to STM32 using ST-Link
st-flash write stm32-hello-world.bin 0x8000000

You can now connect a UART-to-USB adapter to your board's USART2 TX pin (PA2) and see "Hello, World!" printed at 115200 baud.

内容的提问来源于stack exchange,提问作者Stefan Jaritz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:45:30