RT-Thread HC32 系列 BSP 制作教程:从模板复制到工程生成的完整实战指南
RT-Thread HC32 系列 BSP 制作教程从模板复制到工程生成的完整实战指南【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread本文以 RT-Thread 开源仓库中 XHSC小华半导体HC32 系列的 BSP 框架为对象系统讲解如何基于通用模板制作一个新的开发板 BSP。文章以官方评估板ev_hc32f4a0_lqfp176的制作全过程为例覆盖 BSP 框架结构、board 配置、Kconfig 修改、链接脚本与构建脚本调整、Env 工程重生成以及 BSP 制作与提交规范帮助开发者掌握为任意 HC32 芯片/开发板新增 BSP 的完整方法与最佳实践。1. 背景为什么要重构 HC32 系列 BSP为了让开发者更方便地使用 BSP 进行开发XHSC 开发团队重新整理了 RT-Thread 仓库中现有的 HC32 系列 BSP推出了新的 BSP 框架。新框架在易用性、移植便利性、驱动完整性、代码规范性等方面都有较大提升其核心思想是将公共代码与特定开发板代码分离在bsp/hc32下的libraries 文件夹中统一存放可以被多个 BSP 引用的固件库DDL 库以及基于 DDL 库的多系列通用外设驱动文件每个特定开发板 BSP只通过引用方式包含自己需要的库文件或驱动文件而不重复维护副本。这种设计大大提高了代码复用率、降低了 BSP 的维护成本同时可以为开发者提供更丰富的驱动文件使其更容易找到所需资源。新 BSP 框架的主要特性包括提供多系列 BSP 模板大大降低新 BSP 的添加难度每个 BSP 都配有齐全的驱动文件开发者可以方便地使用所有驱动。以 F4 系列为例通用库与特定开发板 BSP 的分工如下表所示项目文件夹说明通用库bsp/hc32/libraries存放 DDL 库以及基于 DDL 库的多系列通用外设驱动文件其驱动源码位于bsp/hc32/libraries/hc32_drivers下特定开发板 BSPbsp/hc32/ev_hc32f4a0_lqfp176在 BSP 模板的基础上修改而成仅包含与这块开发板强相关的配置与链接文件仓库中bsp/hc32目录下现有的官方与第三方 BSP 包括ev_hc32f334_lqfp64F334、ev_hc32f448_lqfp80、ev_hc32f460_lqfp100_v2、ev_hc32f467_lqfp144、ev_hc32f472_lqfp100、ev_hc32f4a0_lqfp176、ev_hc32f4a2_lqfp176、ev_hc32f4a8_lqfp176以及立创开发板的lckfb-hc32f4a0-lqfp100完整支持情况可参见 HC32 BSP 说明。2. 制作前的知识准备制作一个 BSP 的过程就是构建一个新系统的过程。想要制作出好用的 BSP需要对 RT-Thread 系统的构建过程有一定了解建议先掌握以下四个方面的知识掌握 HC32 系列 BSP 的使用方法可阅读 HC32 BSP 说明 中使用教程表格内的文档例如 外设驱动使用教程 和 外设驱动介绍了解外设驱动的添加方法可参考《外设驱动添加指南》。了解 Scons 工程构建方法RT-Thread 使用 Scons 作为系统的构建工具掌握 Scons 的常用命令如scons、scons --targetmdk5等是制作新 BSP 的基本要求。了解设备驱动框架在 RT-Thread 系统中应用程序通过设备驱动框架来操作硬件了解设备驱动框架对添加 BSP 驱动很重要。了解 Kconfig 语法RT-Thread 系统通过 menuconfig 方式进行配置menuconfig 中的选项由 Kconfig 文件决定因此需要对 Kconfig 语法有一定了解。3. BSP 制作方法本节以制作 XHSC 官方评估板ev_hc32f4a0_lqfp176的 BSP 为例讲解如何为一个新的开发板添加 BSP。制作过程分为以下五个步骤复制 BSP 通用模板BOARD 配置修改 BSP 中的 Kconfig 文件修改构建工程相关文件重新生成工程3.1 复制 BSP 通用模板制作新 BSP 的第一步是复制一份同系列的 BSP 作为基础通过对 BSP 的修改来获得新 BSP。本次示例制作的 BSP 为 HC32F4A0 系列因此直接复制同系列的ev_hc32f4a0_lqfp176文件夹并将该文件夹名称改为所要制作的 BSP 的名字示例中保持原名不变。在 BSP 的制作过程中主要修改board文件夹内的配置文件。下表总结了board文件夹中需要修改的内容项目需要修改的内容说明linker_scripts 文件夹BSP 特定的链接脚本board.c/h系统时钟、GPIO 初始化函数、芯片存储器大小board_config.c/h外设管脚配置及初始化Kconfig芯片型号、系列、外设资源SConscript芯片启动文件、目标芯片型号3.2 修改 board 配置3.2.1 配置外设管脚在board_config.c文件中实现了外设管脚相关配置。例如函数rt_hw_board_uart_init中配置了 USART1 和 USART6 的管脚源码位于 board_config.c#if defined(RT_USING_SERIAL) rt_err_t rt_hw_board_uart_init(CM_USART_TypeDef *USARTx) { rt_err_t result RT_EOK; switch ((rt_uint32_t)USARTx) { #if defined(BSP_USING_UART1) case (rt_uint32_t)CM_USART1: /* Configure USART RX/TX pin. */ GPIO_SetFunc(USART1_RX_PORT, USART1_RX_PIN, USART1_RX_FUNC); GPIO_SetFunc(USART1_TX_PORT, USART1_TX_PIN, USART1_TX_FUNC); break; #endif #if defined(BSP_USING_UART6) case (rt_uint32_t)CM_USART6: /* Configure USART RX/TX pin. */ GPIO_SetFunc(USART6_RX_PORT, USART6_RX_PIN, USART6_RX_FUNC); GPIO_SetFunc(USART6_TX_PORT, USART6_TX_PIN, USART6_TX_FUNC); break; #endif default: result -RT_ERROR; break; } return result; } #endif其他外设如 I2C、ADC、SPI、CAN、ETH、SDIO、QSPI、SDRAM 等的管脚配置函数也以同样的模式组织在board_config.c中均通过#if defined(BSP_USING_xxx)条件编译与 Kconfig 选项联动。在board_config.h中实现了管脚的宏定义可根据实际使用的管脚进行修改。以 USART1 为例源码位于 board_config.h#if defined(BSP_USING_UART1) #define USART1_RX_PORT (GPIO_PORT_H) #define USART1_RX_PIN (GPIO_PIN_13) #define USART1_RX_FUNC (GPIO_FUNC_33) #define USART1_TX_PORT (GPIO_PORT_H) #define USART1_TX_PIN (GPIO_PIN_15) #define USART1_TX_FUNC (GPIO_FUNC_32) #endif每个外设宏均用对应的BSP_USING_xxx宏包裹只有通过 menuconfig 使能了该外设管脚宏才会生效。修改时只需将PORT、PIN、FUNC三要素替换为目标引脚的取值引脚复用功能号需查阅芯片数据手册。3.2.2 配置系统时钟在board.c文件中存放了函数SystemClock_Config()该函数负责初始化系统时钟。源码位于 board.c示例中系统主频配置为 240MHz可根据实际使用进行修改/* PCLK0, HCLK Max 240MHz */ /* PCLK1, PCLK4 Max 120MHz */ /* PCLK2, PCLK3 Max 60MHz */ /* EX BUS Max 120MHz */ CLK_SetClockDiv(CLK_BUS_CLK_ALL, (CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 | CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 | CLK_HCLK_DIV1)); ... /* VCO (8/1)*120 960MHz */ stcPLLHInit.u8PLLState CLK_PLL_ON; stcPLLHInit.PLLCFGR_f.PLLM 1UL - 1UL; stcPLLHInit.PLLCFGR_f.PLLN 120UL - 1UL; stcPLLHInit.PLLCFGR_f.PLLP 4UL - 1UL; ... CLK_SetSysClockSrc(CLK_SYSCLK_SRC_PLL);从源码可以看到HC32F4A0 的时钟链路为外部晶振XTAL8MHz→ PLLH 倍频到 960MHz VCO → 分频得到 240MHz 系统主频同时 PCLK1/PCLK4 最高 120MHz、PCLK2/PCLK3 最高 60MHz。若使能了 USBBSP_USING_USBD/BSP_USING_USBH/RT_USING_CHERRYUSB还会额外配置 PLLX 以产生 480MHz 供 USB 使用。此外board.c中还包含SystemBase_Config()Flash Cache/预取配置、PeripheralClock_Config()外设时钟源和PeripheralRegister_Unlock()外设寄存器解锁等函数。3.2.3 配置 FLASH 和 RAM在board.h文件中配置了 FLASH 和 RAM 的相关参数这个文件中需要修改的是HC32_FLASH_SIZE和HC32_SRAM_SIZE这两个宏控制的参数。源码位于 board.h#define HC32_FLASH_ERASE_GRANULARITY (8 * 1024) #define HC32_FLASH_WRITE_GRANULARITY (4) #define HC32_FLASH_SIZE (2 * 1024 * 1024) #define HC32_FLASH_START_ADDRESS (0) #define HC32_FLASH_END_ADDRESS (HC32_FLASH_START_ADDRESS HC32_FLASH_SIZE) #define HC32_SRAM_SIZE (512) #define HC32_SRAM_END (0x1FFE0000 HC32_SRAM_SIZE * 1024)示例中 HC32F4A0 的 Flash 为 2MB、SRAM 为 512KB。制作新 BSP 时必须按照目标芯片的实际存储器容量修改这两个宏HC32_SRAM_END会被后续堆内存配置所引用。3.2.4 配置堆内存通常情况下系统 RAM 中的一部分内存空间会被用作堆内存。board.h中通过条件编译在不同编译器下规定堆内存的起始地址HEAP_BEGIN和结束地址HEAP_END#ifdef __ARMCC_VERSION extern int Image$$RW_IRAM2$$ZI$$Limit; #define HEAP_BEGIN (Image$$RW_IRAM2$$ZI$$Limit) #elif __ICCARM__ #pragma section HEAP #define HEAP_BEGIN (__segment_end(HEAP)) #else extern int __bss_end; #define HEAP_BEGIN (__bss_end) #endif #define HEAP_END HC32_SRAM_END这里HEAP_BEGIN和HEAP_END的值需要和后面 3.4.1 修改链接脚本 章节所修改的配置相一致MDKARMCC堆起始取链接脚本中RW_IRAM2区域的 ZI 段结束地址IAR取名为HEAP的段结尾GCC取__bss_end。在某些系列的芯片中芯片 RAM 可能分布在不连续的多块内存区域上。此时堆内存的位置可以和系统内存在同一片连续的内存区域也可以存放在一片独立的内存区域中只需保证HEAP_BEGIN/HEAP_END与链接脚本对应区域的边界一致即可。3.2.5 配置中断在irq_config.h文件中统一分配了外设使用的中断号。HC32F4A0 系列的中断可灵活配置用户可根据实际使用情况灵活调整外设中断号。源码位于 irq_config.h例如#define BSP_EXTINT0_IRQ_NUM INT022_IRQn #define BSP_EXTINT0_IRQ_PRIO DDL_IRQ_PRIO_DEFAULT /* DMA1 ch0 */ #define BSP_DMA1_CH0_IRQ_NUM INT038_IRQn #define BSP_DMA1_CH0_IRQ_PRIO DDL_IRQ_PRIO_DEFAULT每个中断都以BSP_xxx_IRQ_NUM中断向量号和BSP_xxx_IRQ_PRIO中断优先级成对定义驱动源码通过这两个宏向 RT-Thread 的中断管理注册中断服务函数。由于 HC32 系列的中断号可以在一定范围内灵活映射制作新 BSP 时应避免中断号冲突并按需调整优先级。3.3 修改 Kconfig 选项本小节需要修改board/Kconfig文件的内容主要有两点芯片型号和系列BSP 上的外设支持选项芯片型号和系列的修改如下表所示对应 board/Kconfig 中的配置宏定义意义格式SOC_HC32F4A0SI芯片型号SOC_HC32xxxSOC_SERIES_HC32F4芯片系列SOC_SERIES_HC32xx实际 Kconfig 中的写法为config SOC_HC32F4A0SI bool select SOC_SERIES_HC32F4 select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN default y其中SOC_HC32F4A0SI为芯片型号选择项select SOC_SERIES_HC32F4将其归入 HC32F4 系列同时自动勾选组件自动初始化和 user main。关于 BSP 上的外设支持选项一个初次提交的 BSP 仅仅需要支持 GPIO 驱动和串口驱动即可因此在配置选项中只需保留这两个驱动配置项。GPIO 与串口在 Kconfig 中的定义如下config BSP_USING_GPIO bool Enable GPIO select RT_USING_PIN select BSP_USING_TCA9539 default y menuconfig BSP_USING_UART bool Enable UART default y select RT_USING_SERIAL if BSP_USING_UART menuconfig BSP_USING_UART1 bool Enable UART1 default y if BSP_USING_UART1 config BSP_UART1_RX_USING_DMA bool Enable UART1 RX DMA depends on BSP_USING_UART1 RT_SERIAL_USING_DMA default n config BSP_UART1_RX_BUFSIZE int Set UART1 RX buffer size range 64 65535 depends on RT_USING_SERIAL_V2 default 256 ... endif ... endif注意 Kconfig 中每个外设选项都会select对应的 RT-Thread 组件例如BSP_USING_GPIO自动勾选RT_USING_PINBSP_USING_UART自动勾选RT_USING_SERIAL保证硬件驱动与上层框架联动。3.4 修改工程构建相关文件3.4.1 修改链接脚本linker_scripts链接文件位于board/linker_scripts文件夹下包含三种编译器使用的脚本下面以 MDK 使用的链接脚本link.sct为例展示如何修改链接脚本。本次制作 BSP 使用的芯片为 HC32F4A0FLASH 为 2M因此修改LR_IROM1和ER_IROM1的参数为0x00200000RAM 的大小为 512k因此修改RW_IRAM2的参数为0x0007FFF8起始地址为0x1FFE0008RAM 起始地址 0x1FFE0000 处预留了 8 字节的 noinit 段。实际 link.sct 内容如下LR_IROM1 0x00000000 0x00200000 { ; load region size_region ER_IROM1 0x00000000 0x00200000 { ; load address execution address *.o (RESET, First) *(InRoot$$Sections) .ANY (RO) .ANY (XO) } RW_IRAM1 0x1FFE0000 UNINIT 0x00000008 { ; RW data *(.bss.noinit) } RW_IRAM2 0x1FFE0008 0x0007FFF8 { ; RW data .ANY (RW ZI) .ANY (RAMCODE) } RW_IRAMB 0x200F0000 0x00001000 { ; RW data .ANY (RW ZI) } }这样的修改方式在一般的应用下就够用了后续如果有特殊要求例如自定义存储区域划分则需要按照链接脚本的语法根据实际需求修改。注意此处的区域边界必须与 3.2.4 节HEAP_BEGIN/HEAP_END的配置保持一致。其他两个链接脚本分别为 IAR 使用的link.icf和 GCC 编译器使用的link.ld修改的方式类似link.icf修改内容link.ld修改内容3.4.2 修改构建脚本SConscript脚本决定 MDK/IAR 工程的生成以及编译过程中要添加的文件。在这一步中需要修改芯片型号以及芯片启动文件的地址。实际 board/SConscript 内容如下import os from building import * cwd GetCurrentDir() # add general drivers src Split( board.c board_config.c ) path [cwd] path [cwd /ports] path [cwd /config] path [cwd /config/usb_config] CPPDEFINES [HC32F4A0, __DEBUG] group DefineGroup(Drivers, src, depend [], CPPPATH path, CPPDEFINES CPPDEFINES) Return(group)其中CPPDEFINES [HC32F4A0, __DEBUG]定义了目标芯片型号宏启动文件和 DDL 库会依赖该宏选择芯片型号编译路径则包含了ports、config等配置目录。注意若复制的是同系列的 BSP 来进行修改这个文件可不做修改。3.4.3 修改工程模板template文件是生成 MDK/IAR 工程的模板文件通过修改该文件可以设置工程中使用的芯片型号以及下载方式。MDK5/IAR 的工程模板文件位于 BSP 根目录下下面以 MDK5 模板的修改为例介绍如何修改模板配置。首先修改芯片型号使生成的工程与目标芯片匹配然后修改程序下载方式例如选择对应的 J-Link/ST-Link 仿真器及 Flash 下载算法3.5 重新生成工程重新生成工程需要使用 Env 工具RT-Thread 官方提供的命令行配置环境。3.5.1 重新生成 rtconfig.h 文件在 Env 界面输入命令menuconfig对工程进行配置并生成新的 rtconfig.h 文件在配置界面中选择要打开的外设例如使能 UART1、GPIO 等初次提交的 BSP 只需保留 GPIO 与串口驱动3.5.2 重新生成 MDK/IAR 工程下面以重新生成 MDK 工程为例介绍如何重新生成 BSP 工程。使用 Env 工具输入命令scons --targetmdk5重新生成工程重新生成工程成功后的输出如下到这一步为止新的 BSP 就可以使用了。接下来我们可以分别使用命令scons --targetmdk4、scons --targetiar、scons --targeteclipse来更新 MDK4、IAR 和 GCC 的工程使得该 BSP 变成一个完整的、可以提交到 GitHub 的 BSPMDK4 工程的制作为可选。4. 规范本章节介绍 RT-Thread HC32 系列 BSP 制作与提交时应当遵守的规范。开发人员在 BSP 制作完成后可以根据本规范提出的检查点对制作的 BSP 进行检查确保 BSP 在提交前有较高的质量。4.1 BSP 制作规范HC32 BSP 的制作规范主要分为 3 个方面工程配置、ENV 配置和 IDE 配置。在已有的 HC32 系列 BSP 的模板中已经根据下列规范对模板进行配置。在制作新 BSP 的过程中拷贝模板进行修改时需要注意不要修改这些默认的配置。BSP 制作完成后需要对新制作的 BSP 进行功能测试功能正常后再进行代码提交。4.1.1 工程配置遵从 RT-Thread 编码规范代码注释风格统一main 函数功能保持一致如果有 LED 的话main 函数里只放一个LED 1HZ 闪烁的程序。仓库中 main.c 即为典型示例int main(void) { /* set LED_GREEN_PIN pin mode to output */ rt_pin_mode(LED_GREEN_PIN, PIN_MODE_OUTPUT); while (1) { rt_pin_write(LED_GREEN_PIN, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(LED_GREEN_PIN, PIN_LOW); rt_thread_mdelay(500); } }在rt_hw_board_init中需要完成堆的初始化调用rt_system_heap_init默认只初始化 GPIO 驱动和 FinSH 对应的串口驱动不使用 DMA当使能板载外设驱动时应做到不需要修改代码就能编译下载使用提交前应检查 GCC/MDK/IAR 三种编译器直接编译或者重新生成后编译是否成功使用dist命令对 BSP 进行发布检查使用dist命令生成的工程是否可以正常使用。4.1.2 ENV 配置系统心跳统一设置为 1000宏RT_TICK_PER_SECONDBSP 中需要打开调试选项中的断言宏RT_DEBUG系统空闲线程栈大小统一设置为 512宏IDLE_THREAD_STACK_SIZE开启组件自动初始化宏RT_USING_COMPONENTS_INIT在board/Kconfig的SOC_HC32F4A0SI中通过select默认开启需要开启 user main 选项宏RT_USING_USER_MAIN同样由 Kconfig 默认 selectFinSH 默认只使用 MSH 模式宏FINSH_USING_MSH_ONLY。4.1.3 IDE 配置使能下载代码后自动运行使能 C99 支持使能 One ELF Section per FunctionMDKMDK/IAR 生成的临时文件分别放到 build 下的 MDK/IAR 文件夹下MDK/GCC/IAR 生成 bin 文件名字统一成rtthread.bin。4.2 BSP 提交规范提交前请认真修改 BSP 的 README.md 文件README.md 文件的外设支持表单只填写 BSP 支持的外设可参考其他 BSP 填写。查看文档 HC32 系列驱动介绍 了解驱动分类。提交 BSP 分为 2 个阶段提交第一阶段基础 BSP 包括串口驱动和 GPIO 驱动能运行 FinSH 控制台。完成 MDK4、MDK5、IAR 和 GCC 编译器支持如果芯片不支持某款编译器比如 MDK4可以不用做。BSP 的 README.md 文件需要填写第二阶段要完成的驱动。第二阶段完成板载外设驱动支持所有板载外设使用 menuconfig 配置后就能直接使用。若开发板没有板载外设则此阶段可以不用完成。不同的驱动要分开提交方便 review 和合并。只提交 BSP 必要的文件删除无关的中间文件能够提交的文件请对照其他 BSP。提交前要对 BSP 进行编译测试确保在不同编译器下编译正常。提交前要对 BSP 进行功能测试确保 BSP 在提交前符合工程配置章节中的要求。5. 小结制作一个 HC32 系列 BSP 的核心流程可以概括为复制模板 → 修改 board 配置 → 修改 Kconfig → 修改构建文件 → 重新生成工程五个环节。只要严格按照 HC32 系列 BSP 制作教程 中的步骤操作并遵守工程配置、ENV 配置、IDE 配置以及分阶段提交的规范就能快速、规范地为新的 HC32 芯片或开发板产出可用的 BSP。在制作过程中board目录下的 board.c、board.h、board_config.c、board_config.h、Kconfig、SConscript 以及linker_scripts下的三个链接脚本是最关键的修改对象建议以仓库中现有的多个 HC32 BSP 为参照进行比对修改以确保配置一致性与可维护性。【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考