ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

华大半导体 HC32 使用 Nimmake 编译指南

华大半导体 HC32 使用 Nimmake 编译指南 华大半导体 HC32 使用 Nimmake 编译指南详细版主线型号HC32F460 / Cortex-M4F适用系列HC32F460、HC32F448、HC32F4A0、HC32L136、HC32F005、HC32L110 等支持 GCC/Makefile 的系列构建方式arm-none-eabi-gcc NimmakePython 构建脚本1. 可行性结论华大半导体 HC32 系列基于 ARM Cortex-M 内核官方提供完整的 CMSIS 支持、DDL 驱动库、启动文件、系统初始化代码以及 Keil DFP 设备支持包内含启动文件、头文件、Flash 算法等。虽然官方 SDK 主要面向 Keil/IAR但底层均为标准 ARM GCC 兼容格式配合 xPack ARM GCC 工具链和 Nimmake 构建脚本完全可以实现命令行裸机编译。官方已提供的底层素材素材来源说明启动文件DFP 包 / SDKstartup_HC32F460.sARM 汇编GCC 可用设备头文件DFP 包 / SDKhc32f460.h寄存器定义系统初始化SDKsystem_hc32f460.c含SystemInit()CMSIS 核心SDK / ARM 官方core_cm4.h等DDL 驱动库SDKGPIO、USART、SPI、I2C、TIM、ADC 等配置文件SDKddl_config.h裁剪外设Flash 算法DFP 包.flm文件用于 J-Link / 烧录器需要自行补充的素材素材说明GCC 链接脚本.ld官方 DFP 提供的是.sctKeil/.icfIAR需自行编写或从 GCC 示例中提取.ldGCC 版启动文件DFP 中的.s为 ARM 汇编语法GCC 可直接使用但需确认伪指令兼容编译宏需根据型号定义如HC32F460、USE_DDL华大官方提供 VSCode EIDE 插件支持其底层使用 GNU Arm Embedded Toolchain可作为 GCC 兼容性的参考。2. 为什么用 Nimmake痛点Makefile 写法Nimmake 写法芯片参数手写-mcpucortex-m4 -mfpufpv4-sp-d16 -mfloat-abihardCORTEX_M4F_CFG.clone()一行预设DDL 源文件列表手动 glob 或逐行写换型号就改Parties自动扫描src/**/*.c换型号改 CPU、链接脚本、启动文件、宏多处同步只改Chip预设和Parties路径头文件路径-I逐条写漏一个就报错Parties自动收集inc/ddl_config.h 裁剪需手动管理配置头文件路径作为全局 Include 统一注入多目标每个 target 写一套规则多个Program对象即可缓存需手动配ccache--cache内置支持跳转补全无--compiledb生成compile_commands.json烧录命令手写openocd -f ...Phony目标封装nimmake flash3. 环境准备3.1 安装 Nimmakepipinstallnimmake验证nimmake--version3.2 安装 ARM GCC 工具链推荐使用xPack ARM Embedded GCC# macOSbrewinstallxpack-arm-none-eabi-gcc# Windows (Scoop)scoopinstallxpack-arm-none-eabi-gcc验证arm-none-eabi-gcc--versionarm-none-eabi-size--versionarm-none-eabi-objcopy--version3.3 获取 HC32 SDK 素材方式一从华大官网下载 SDK访问华大半导体官网www.hdsc.com.cn。进入对应芯片页面如 HC32F460。下载DDL 驱动库如hc32f460_ddl_Rev2.1.0.zip。解压后得到driver/— DDL 驱动源码mcu/common/— CMSIS 核心、启动文件、系统初始化example/— 示例工程方式二从 DFP 包中提取下载HDSC.HC32F460_DFP.x.x.x.pack可从华大官网或 GitHubhdscmcu/pack获取。用解压软件打开.pack文件本质是 ZIP。提取Device/Include/hc32f460.hDevice/Source/GCC/startup_HC32F460.s如有 GCC 目录Device/Source/system_hc32f460.c方式三用 VSCode EIDE 导入安装 VSCode EIDE 插件后可一键导入 Keil 工程自动还原目录结构与编译配置底层使用 GCC 工具链。可从中提取 GCC 兼容的启动文件和链接脚本。3.4 素材自检清单startup_HC32F460.s— 启动文件ARM 汇编GCC 可用hc32f460.h— 设备头文件system_hc32f460.c— 系统初始化core_cm4.h— CMSIS 核心头文件DDL 驱动库driver/目录ddl_config.h— DDL 配置头文件链接脚本hc32f460_flash.ld需自行编写见第 5 章arm-none-eabi-gcc可执行4. 工程目录结构推荐按重编频率分层hc32-nimmake/ |-- Nimmake.py # 构建脚本唯一需要维护的文件 |-- App/ # 应用代码最常改 | |-- inc/ | | |-- main.h | |-- src/ | |-- main.c |-- Device/ # 启动 系统初始化几乎不改 | |-- startup_HC32F460.s | |-- system_hc32f460.c |-- Libraries/ # DDL 驱动库几乎不改 | |-- HC32F460_DDL/ | |-- driver/ | | |-- inc/ | | | |-- hc32f460.h | | | |-- hc32f460_gpio.h | | | |-- hc32f460_usart.h | | | |-- ddl_config.h | | |-- src/ | | |-- hc32f460_gpio.c | | |-- hc32f460_usart.c | |-- mcu/ | |-- common/ | |-- core_cm4.h |-- ld/ # 链接脚本 | |-- hc32f460_flash.ld |-- tools/ # 烧录脚本可选 |-- openocd_hc32.cfg分层理由App/每次改代码只重编这一层Device/和Libraries/作为静态库首次编译后缓存ld/独立存放换型号时只需替换链接脚本5. 链接脚本编写官方 DFP 提供的是 Keil.sct格式需自行编写 GCC.ld。以下为 HC32F460512 KB Flash 192 KB SRAM示例/* ld/hc32f460_flash.ld */ ENTRY(Reset_Handler) MEMORY { FLASH (rx) : ORIGIN 0x00000000, LENGTH 512K SRAM (rwx) : ORIGIN 0x20000000, LENGTH 192K } _estack ORIGIN(SRAM) LENGTH(SRAM); SECTIONS { .isr_vector : { . ALIGN(4); KEEP(*(.isr_vector)) . ALIGN(4); } FLASH .text : { . ALIGN(4); *(.text) *(.text.*) *(.rodata) *(.rodata.*) . ALIGN(4); _etext .; } FLASH .data : { . ALIGN(4); _sdata .; *(.data) *(.data.*) . ALIGN(4); _edata .; } SRAM AT FLASH _sidata LOADADDR(.data); .bss : { . ALIGN(4); _sbss .; *(.bss) *(.bss.*) *(COMMON) . ALIGN(4); _ebss .; } SRAM . ALIGN(4); _end .; }注意 1不同型号 Flash/SRAM 大小不同需根据具体芯片调整LENGTH。注意 2HC32F460 的 Flash 起始地址为0x00000000部分型号为0x01000000具体以参考手册存储器映射为准。HC32F4A0 等大 Flash 型号还需考虑 1 MB 以上分区与 OTFDEC 加密区。6. 完整 Nimmake.py# Nimmake.pyfromnimmakeimport*# 1. 芯片预设ChipCORTEX_M4F_CFG.clone()Chip.CPUcortex-m4Chip.FPUfpv4-sp-d16Chip.ABIhardChip.MACROS[HC32F460,USE_DDL,]# 2. 工具链ToolchainUpdate(Chip)Refresh()# 3. 编译选项CFLAGS[-O2,-g,-ffunction-sections,-fdata-sections,-Wall,-Wno-unused-function,]LDFLAGS[-TROOT/ld/hc32f460_flash.ld,-Wl,--gc-sections,-Wl,-MapBUILD/firmware.map,--specsnano.specs,--specsnosys.specs,]# 4. PartyDDL 驱动库静态库DDLParty(DDL)DDL.SourcesGlob(Libraries/HC32F460_DDL/driver/src/*.c)DDL.Includes[Libraries/HC32F460_DDL/driver/inc,Libraries/HC32F460_DDL/mcu/common,]DDL.BuildTypestaticlib# 5. PartyDevice启动文件 系统初始化DeviceParty(Device)Device.Sources[Device/startup_HC32F460.s,Device/system_hc32f460.c,]Device.Includes[Libraries/HC32F460_DDL/driver/inc,Libraries/HC32F460_DDL/mcu/common,]Device.Dependencies[DDL]# 6. PartyApp应用代码AppParty(App)App.SourcesGlob(App/src/*.c)App.Includes[App/inc,Libraries/HC32F460_DDL/driver/inc,Libraries/HC32F460_DDL/mcu/common,]App.Dependencies[Device]# 7. ProgramProgramProg(firmware)Program.Parties[App]Program.CFLAGSCFLAGS Program.LDFLAGSLDFLAGS# 8. 后处理生成 bin 打印体积AfterBuilddefpost_build(ctx):elfctx.Output bin_fileelf.replace(.elf,.bin)hex_fileelf.replace(.elf,.hex)Run(farm-none-eabi-objcopy -O binary{elf}{bin_file})Run(farm-none-eabi-objcopy -O ihex{elf}{hex_file})Run(farm-none-eabi-size{elf})# 9. 烧录目标Phonydefflash(ctx):使用 OpenOCD CMSIS-DAP / J-Link 烧录elfctx.Program.Output Run(f openocd -f interface/cmsis-dap.cfg \\ -f target/stm32f4x.cfg \\ -c init \\ -c reset halt \\ -c flash write_image erase{elf} \\ -c reset run \\ -c exit )Phonydefgdb(ctx):启动 GDB 调试elfctx.Program.Output Run(farm-none-eabi-gdb{elf})Phonydeferase(ctx):擦除芯片Run( openocd -f interface/cmsis-dap.cfg \\ -f target/stm32f4x.cfg \\ -c init \\ -c reset halt \\ -c stm32f4x mass_erase 0 \\ -c exit )DefaultTarget(Program)7. 逐段解析7.1 芯片预设ChipCORTEX_M4F_CFG.clone()Chip.CPUcortex-m4Chip.FPUfpv4-sp-d16Chip.ABIhardHC32F460 是 Cortex-M4F带单精度 FPU主频最高 200 MHz。CORTEX_M4F_CFG已包含-mthumb -mcpucortex-m4 -mfpufpv4-sp-d16 -mfloat-abihard无需手写。7.2 编译宏Chip.MACROS[HC32F460,# 型号宏决定头文件中寄存器定义USE_DDL,# 使用 DDL 驱动库]华大 DDL 库通过ddl_config.h裁剪外设无需像 STM32 标准库那样定义USE_STDPERIPH_DRIVER。7.3 链接脚本LDFLAGS[-TROOT/ld/hc32f460_flash.ld,-Wl,--gc-sections,-Wl,-MapBUILD/firmware.map,--specsnano.specs,--specsnosys.specs,]--gc-sections配合-ffunction-sections -fdata-sections裁剪未使用代码nano.specs使用 newlib-nano显著减小体积nosys.specs提供_sbrk/_write等系统调用的空实现7.4 Parties 分层Party类型说明DDLstaticlibDDL 驱动库编译为.a几乎不重编Deviceobject启动文件 system_hc32f460.cAppobject用户代码每次修改只重编这一层7.5 HC32 专属注意点1. 启动文件语法华大 DFP 中的启动文件为 ARM 汇编语法.sGCC 可直接使用。如果从 Keil 工程中拷贝确认不是 Keil 专有语法如AREA/PRESERVE8等GCC 的 GNU as 需.section/.globl。若遇语法报错把向量表段改为 GCC 写法.section .isr_vector, a, %progbits .align 2 .globl __Vectors __Vectors: .long _estack .long Reset_Handler ...2._estack与链接脚本链接脚本中必须定义_estack启动文件中通过它初始化栈指针。HC32F460 有 192KB SRAM如果 SRAM 大小与实际芯片不符上电即 HardFault。3. VTOR 向量表偏移system_hc32f460.c中的SystemInit()会设置 VTOR。做 Bootloader App 时App 中需重新设置SCB-VTORAPP_FLASH_OFFSET;4. ddl_config.hDDL 库通过ddl_config.h控制各外设驱动的编译开关。确保该文件在 Include 路径中否则编译报DDL config file is not included错误。5. RAM 分块HC32F460 SRAM 物理上分 RAM0/RAM1/RAMH 等多块。若工程用到 DMA 双缓冲区需在链接脚本里把对应缓冲区放到指定块如 RAMH避免放到不可 DMA 访问区域。8. 常用命令命令说明nimmake编译默认目标nimmake --dry-run预览命令不实际执行nimmake --compiledb生成compile_commands.jsonnimmake --cache启用编译缓存nimmake -n仅编译不链接nimmake -c清理构建目录nimmake flash烧录固件nimmake erase擦除芯片nimmake gdb启动 GDB9. 烧录方案9.1 OpenOCD CMSIS-DAP / J-LinkHC32F460 与 STM32F4 内存布局相似多数情况下可用stm32f4x.cfgopenocd-finterface/cmsis-dap.cfg\-ftarget/stm32f4x.cfg\-cprogram firmware.elf verify reset exit如果 OpenOCD 没有 HC32 专用 target可尝试自定义 cfg参考 HC32 参考手册中的 Flash 控制器寄存器或使用 J-Link。9.2 J-Link需先安装华大 Flash 算法.flm到 J-Link 安装目录JLinkDevices或Devices目录JLinkExe-deviceHC32F460-ifSWD-speed4000-CommanderScriptflash.jlinkflash.jlink内容h loadbin firmware.bin 0x00000000 r g q9.3 官方 ISP 工具华大提供XHSC MCU Programmer和ISP 下载工具支持 UART ISP 模式将 BOOT 引脚拉高后上电进入 ISP 模式使用官方工具通过 UART 下载firmware.bin9.4 华大离线编程器华大官方 Cortex-M 离线编程器支持全系列 HC32 芯片适合量产烧录。10. printf 重定向使用nosys.specs时需重写_write才能通过 USART 输出。注意 HC32 DDL 的 USART API 与 STM32 标准库不同/* App/src/uart_printf.c */#includestdio.h#includeunistd.h#includehc32f460.h#includehc32f460_usart.hint_write(intfd,char*ptr,intlen){if(fdSTDOUT_FILENO||fdSTDERR_FILENO){for(inti0;ilen;i){while(RESETUart_GetStatus(M0P_USART1)/* 等 TXE */);Uart_SendData(M0P_USART1,(uint8_t)ptr[i]);}returnlen;}return-1;}DDL 中发送单字节的接口按型号可能命名为Uart_SendData或USART_WriteData以对应 DDL 头文件为准。若不重写_write而用nosys.specsprintf 会静默丢弃输出不报错。11. 型号迁移型号内核预设宏FlashSRAM备注HC32F460M4FCORTEX_M4F_CFGHC32F460512K192K200 MHz主力型号HC32F448M4FCORTEX_M4F_CFGHC32F448256K64K中端通用HC32F4A0M4FCORTEX_M4F_CFGHC32F4A02048K384K大容量双 bank flashHC32F4A2M4FCORTEX_M4F_CFGHC32F4A21024K288K大屏显示向HC32L136M0CORTEX_M0PLUS_CFGHC32L136128K32K低功耗 M0无 FPUHC32L110M0CORTEX_M0PLUS_CFGHC32L110128K32K低功耗LCD 段码驱动HC32F005M0CORTEX_M0PLUS_CFGHC32F00532K4K低成本小容量HC32F052M0CORTEX_M0PLUS_CFGHC32F052128K16K家电控制向迁移时只需修改Nimmake.py中的三处ChipCORTEX_M4F_CFG.clone()# 换预设M0 用 CORTEX_M0PLUS_CFGChip.MACROS[HC32F448,USE_DDL]# 换型号宏LDFLAGS[-TROOT/ld/hc32f448_flash.ld,...]# 换链接脚本M0 型号无 FPU迁移到 HC32L136 / HC32F005 时应改用CORTEX_M0PLUS_CFG预设不含-mfpu/-mfloat-abi否则链接器会报 FPU 属性冲突。12. Bootloader App12.1 Flash 分区示例HC32F460区域地址大小用途Bootloader0x0000000032 KB引导程序App0x00008000剩余应用程序12.2 App 链接脚本修改/* ld/hc32f460_app.ld */ MEMORY { FLASH (rx) : ORIGIN 0x00008000, LENGTH 480K SRAM (rwx): ORIGIN 0x20000000, LENGTH 192K }12.3 App 中设置 VTOR/* App/src/main.c */intmain(void){SCB-VTOR0x00008000;/* 偏移向量表 */SystemInit();/* ... */}12.4 Nimmake 多目标BootloaderProg(bootloader)Bootloader.Parties[App_BL]Bootloader.LDFLAGS[-TROOT/ld/hc32f460_boot.ld,-Wl,--gc-sections]ApplicationProg(app)Application.Parties[App]Application.LDFLAGS[-TROOT/ld/hc32f460_app.ld,-Wl,--gc-sections]DefaultTarget(Bootloader,Application)13. FreeRTOS 集成将 FreeRTOS 作为独立 Party源文件含FreeRTOS.c、tasks.c、portable/GCC/ARM_CM4F/port.c及heap_4.cFreeRTOSParty(FreeRTOS)FreeRTOS.Sources[Middlewares/FreeRTOS/Source/*.c,Middlewares/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c,Middlewares/FreeRTOS/Source/portable/MemMang/heap_4.c,]FreeRTOS.Includes[Middlewares/FreeRTOS/Source/include,Middlewares/FreeRTOS/Source/portable/GCC/ARM_CM4F,]FreeRTOS.BuildTypestaticlibApp.Dependencies[Device,FreeRTOS]踩坑点中断向量重定向HC32 DDL 的中断名如SysTick_Handler、PendSV_Handler、SVCall_Handler必须与 FreeRTOSport.c中定义的 handler 名一致。若 DDL 用了Int000_Handler这类弱别名需在 startup 或FreeRTOSConfig中把向量重定向到 FreeRTOS 的 handler。configKERNEL_PORT_END与 FPUM4F 用ARM_CM4Fport带 FPU 上下文保存不要用ARM_CM3port。xPortSysTickHandlerSysTick 优先级设为最低避免与 DDL 外设中断优先级冲突。configTOTAL_HEAP_SIZE根据heap_4堆需求配置HC32F460 的 192K SRAM 足够。14. FAQ问题原因与解决启动文件编译报unknown directive/bad register拷贝到的是 Keil 版启动文件AREA/PRESERVE8语法换成 GCC 版或改写向量表段为.section。DDL config file is not includedddl_config.h没在 Include 路径或未定义DDL_GXX_ENABLE等开关。把driver/inc加入 Includes。cannot find -lxxx/-T未生效-T路径拼写错误或相对路径不对用ROOT拼绝对路径或--dry-run检查实际链接命令。上电即 HardFault_estack与 SRAM 实际大小不符或栈区放在了不可访问的 RAM 块。核对链接脚本 SRAM LENGTH。use of main FPU is incompatible with architectureABI / 预设混用M0 型号误用了CORTEX_M4F_CFG改回CORTEX_M0PLUS_CFG。printf 无输出未重写_write或 USART 未初始化就调用 printf。确保main里先初始化串口再 printf。OpenOCDtarget halted unexpectedlyFlash 算法不匹配HC32 建议用 J-Link 官方.flm或换正确的 target cfg。J-LinkCannot find flash algorithm未把华大.flm拷到 J-LinkDevices目录或设备名不对。map 文件找不到符号-Wl,-Map拼错或BUILD变量为空用 Nimmake 内置BUILD路径拼接。编译体积过大未开--gc-sections或未用nano.specsDDL 未在ddl_config.h裁剪未用外设。DDL 与 SPL 混用报错HC32 只有 DDL 一套库不存在 SPL若从其他国产 MCU 抄了USE_STDPERIPH_DRIVER宏删除即可。15. 体积分析arm-none-eabi-size firmware.elf-Wl,-Mapfirmware.map生成 map 文件后可分析各段占比。裁剪手段-ffunction-sections -fdata-sections-Wl,--gc-sections删除未引用的函数/数据。--specsnano.specs用 newlib-nano 替代 newlibprintf 体积从数十 KB 降到数 KB。ddl_config.h裁剪把不用的外设驱动宏置OFFDDL 源文件虽被编译但--gc-sections会连带删除未调用的部分。-Os替代-O2牺牲少量性能换体积。移除未用中断向量向量表占 Flash未用的 handler 指向默认IntDefaultHandler。16. 最小可跑 Checklist确认arm-none-eabi-gcc --version可用。从 SDK/DFP 拿到startup_HC32F460.s、hc32f460.h、system_hc32f460.c。编写/取到hc32f460_flash.ld确认_estack与 SRAM 大小。确认ddl_config.h已开 GPIO 驱动宏。Nimmake.py中Chip.MACROS含HC32F460、USE_DDL。nimmake --dry-run检查编译/链接命令行无报错、路径正确。nimmake编译生成firmware.elf/bin/hexsize打印正常。用 J-Link/OpenOCD/ISP 烧录firmware.bin。复位后 LED 闪烁 / 串口打印成功工程跑通。说明文中启动文件名、DDL 接口名、Flash 起始地址等以华大对应型号官方 SDK / 参考手册为准。若你的目标型号与本文主线 HC32F460 差异较大如 HC32F4A0 双 Bank Flash、HC32L 低功耗系列 M0 无 FPU请按第 11 章迁移表同步调整预设、宏与链接脚本。
返回列表