Toolchain Installation and Setup
To establish a robust development environment for the MM32F5330 microcontroller using Visual Studio Code, several core components must be installed sequentially. Begin by installing the VSCode editor itself. Following this, install the MinGW environment to provide necessary Unix-like tools on Windows. CMake is required for build system generation, and the Ninja build system is recommended for speed.
Within the VSCode extension marketplace, install the following plugins:
- C/C++ Extension Pack
- CMake Tools
- CMake
For cross-compilation, download and install the ARM GNU Toolchain (specifically the mingw-w64 version targeting arm-none-eabi). Ensure all binaries are added to the system PATH environment variable.
Project Build Configuraton
The core of the build system lies in the CMakeLists.txt file. This script defines the compiler toolchain, target architecture, and source file inclusion. Below is a configured example tailored for the Cortex-M33 core found in the MM32 series.
cmake_minimum_required(VERSION 3.20)
# Define the system and compiler tools
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
set(CMAKE_AR arm-none-eabi-ar)
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
# Project Definition
project(mm32_firmware_project C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Architecture Flags
add_compile_options(-mcpu=cortex-m33 -mthumb -mthumb-interwork)
add_compile_options(-ffunction-sections -fdata-sections -fno-common)
# Build Type Optimization
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
add_compile_options(-Ofast)
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_options(-Og -g)
endif ()
# Preprocessor Definitions
add_compile_definitions(USE_STDPERIPH_DRIVER)
add_compile_definitions(CUSTOM_HSE_VAL)
# Include Paths
include_directories(
.
./board
./device
./device/CMSIS/Include
./device/drivers
)
# Source Collection
file(GLOB SOURCE_FILES
./application/*.c
./board/*.c
./device/armgcc/*.S
./device/drivers/*.c
./device/*.c
./*.c
)
# Linker Configuration
set(LD_SCRIPT_PATH D:/mini-f5330_blinky_led_armgcc/device/armgcc/linker/mm32f5333d_flash.ld)
add_link_options(-T ${LD_SCRIPT_PATH})
add_link_options(-Wl,-gc-sections,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map)
add_link_options(-specs=nano.specs -specs=nosys.specs -u _printf_float)
# Executable Target
add_executable(firmware.elf ${SOURCE_FILES})
# Post-Build Artifacts
set(OUTPUT_HEX ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
set(OUTPUT_BIN ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)
add_custom_command(TARGET firmware.elf POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:firmware.elf> ${OUTPUT_HEX}
COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:firmware.elf> ${OUTPUT_BIN}
COMMENT "Generating HEX and BIN files"
)
Memory Layout Definition
The linker script defines the physical memory map for the device, specifying flash and RAM regions along with stack and heap sizes. The following script configures the memory for the MM32F5333 variant.
/* Memory Origins */
FLASH_ORG = 0x08000000;
FLASH_LEN = 0x00020000;
RAM_ORG = 0x20000000;
RAM_LEN = 0x00008000;
/* System Resources */
STACK_SZ = 0x00000800;
HEAP_SZ = 0x00000C00;
MEMORY {
FLASH (rx) : ORIGIN = FLASH_ORG, LENGTH = FLASH_LEN
RAM (xrw) : ORIGIN = RAM_ORG, LENGTH = RAM_LEN
}
ENTRY(Reset_Handler)
SECTIONS {
.text : {
KEEP(*(.vectors))
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
*(.rodata*)
KEEP(*(.eh_frame*))
} > FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH
__exidx_end = .;
.copy.table : {
. = ALIGN(4);
__copy_table_start__ = .;
LONG (__etext)
LONG (__data_start__)
LONG ((__data_end__ - __data_start__) / 4)
__copy_table_end__ = .;
} > FLASH
.zero.table : {
. = ALIGN(4);
__zero_table_start__ = .;
__zero_table_end__ = .;
} > FLASH
__etext = ALIGN(4);
.data : AT (__etext) {
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
__data_end__ = .;
} > RAM
.bss : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (COPY) : {
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
. = . + HEAP_SZ;
. = ALIGN(8);
__HeapLimit = .;
} > RAM
.stack (ORIGIN(RAM) + LENGTH(RAM) - STACK_SZ) (COPY) : {
. = ALIGN(8);
__StackLimit = .;
. = . + STACK_SZ;
. = ALIGN(8);
__StackTop = .;
} > RAM
PROVIDE(__stack = __StackTop);
ASSERT(__StackLimit >= __HeapLimit, "Stack overflow detected")
}
Application Logic Implementation
The main application initializes the hardware abstraction layer and enters a continuous loop to toggle GPIO pins connected to LEDs. This serves as a verification that the toolchain and hardware configuration are functioning correctly.
int main(void)
{
Board_Initialize();
Start_LED_Sequence();
while (1)
{
/* Main idle loop */
}
}
The LED control logic is encapsulated in a separate function to manage the toggling of specific ports and pins with a defined delay interval.
void Start_LED_Sequence(void)
{
printf("\r\nExecuting %s\r\n", __FUNCTION__);
Configure_GPIO_Pins();
while (1)
{
GPIO_IO_Toggle(GPIOB, GPIO_Pin_10);
GPIO_IO_Toggle(GPIOB, GPIO_Pin_11);
GPIO_IO_Toggle(GPIOC, GPIO_Pin_6);
GPIO_IO_Toggle(GPIOC, GPIO_Pin_7);
PLATFORM_DelayMS(100);
}
}
Compilasion and Flashing
Configure the CMake Tools extension in VSCode to select the appropriate kit (ARM GCC) and variant. Trigger the build process to generate the ELF, HEX, and BIN files. Once compilation succeeds, use the POWERWRITE utility to flash the generated binary onto the evaluation board. Upon reset, the LEDs should begin toggling, indicating successful deployment.