本帖最后由 yang377156216 于 2022-9-15 13:43 编辑
#申请原创# @21小跑堂
前言刚刚接手的一个项目是一个严格要求国产化替代项目,所有器件都必须使用国产料,并且 MCU 的编译环境也必须是免费和开源的,调试和烧录器也得用国内厂家的工具,不得带有任何外商色彩。好吧,我第一个就想到了 RT-Thread 和配套的 IDE ,由于对 MM32 比较熟悉,在灵动官网一番选型后确认使用 MM32F3273G7P 这颗 M3 内核的 MCU 了,各种资源都较为符合应用需求,最让我欣慰的是 rtthread 的官方 github 仓中的 bsp 已经包含了 mm32f327x 系列芯片,这样缩短了我的开发周期,所以开始了全国产化平台开发之旅。
RT-Thread ENV 开发环境搭建首先需要了解 RT-Thread 以及其配套开发环境的话,可以直接进入官网提供的文档中心,里面包含了入门学习、进阶学习和应用开发这三个层次的文档,开发者可以根据自己的实际情况进行选择。接着要进行的是搭建好对应的开发环境,这里选择使用 ENV 环境而先不用 IDE 工具,因为这样所占 PC 资源要小很多。 RT-Thread 的 ENV 工具到底是个什么东西呢?它由以下内容构成: ENV 是 RT-Thread 推出的开发辅助工具,针对基于 RT-Thread 操作系统的项目工程,为用户提供编译构建环境 scons、图形化系统配置 meunuconfig 及在线软件包管理三大功能。menuconfig 提供了简单易用的配置剪裁工具,可对内核、组件和软件包进行自由裁剪,使整个系统可以像搭积木的方式进行构建。scons 作为默认的构建工具,它基于 Python 开发,因此我们需要先安装python 并且把它添加到环境变量中,这里我用的是 Python 2.7 版本,貌似 Python 3.X 是不能正常运行 SCons 的。另外最好也把 git 安装并设置好,因为很多源码组件都会用到它。 接着到官网将 ENV 工具下载好,下载链接如下: ENV工具下载链接:https://www.rt-thread.org/page/download.html 下载好后可以有两种方式进行打开 ENV 工具,一个是简单的双击 env.exe / env.bat ,二个是先将它进行一番设置后则可以在任意文件夹空白处右击控制台了,具体设置步骤如下图所示: 这里有一点需要注意,ENV 工具包所在的目录路径不能包含中文或空格,否则会报以下错误: 接着到 rtthread 的官方 github 仓中将源码包下载好,下载链接如下: https://github.com/RT-Thread/rt-thread 得到的源码包目录结构如下,其中 bsp 中包含了一些已经添加进去了的开发板或者芯片源工程: 如果前面说的 python 、git 以及相关注意事项都已经处理好,那么接下来可以进入到 bsp\mm32f327x 路径下并且在该路径下打开 env 控制台,使用 scons 进行编译构建示例源码了,其中包括了工程模板,通过 scons 构建好的工程,rtconfig.py 构建脚本等,如下图所示: 如果是使用 IAR 或 MDK 来进行工程开发,可以使用以下命令构建对应的工程: - 构建IAR工程:scons --target=iar
- 构建MDK工程:scons --target=mdk5 或 scons --target=mdk4
为了验证环境是否正常,这里使用 scons --target=mdk5 命令进行编译,可以看到已经可以正确编译了: 但由于 keil 和 iar 都属于商业开发软件而且都不属于国产的或者开源免费的,有违背本次的导入目标,于是想到使用 scons 的 gcc 构建方式,因为 ENV工具就已经带有 ARM GCC 编译器,输入 scons 命令直接编译 BSP,这时候默认使用的是 ARM GCC 编译器了。 但是又发现 mm32f327x 这个支持包中并没有将 gcc 的方式添加进去,所以得自己参照 stm32f103 任意一款开发板的支持包进行添加。
MM32F327X ENV GCC 支持首先需要添加芯片的 gcc 启动文件,在路径 bsp\mm32f327x\Libraries\MM32F327x\Source 下添加 startup_mm32f327x_gcc.s ,内容如下: - /**
- *************** (C) COPYRIGHT 2017 STMicroelectronics ************************
- * [url=home.php?mod=space&uid=288409]@file[/url] startup_mm32f3273g9p.s
- * [url=home.php?mod=space&uid=187600]@author[/url] MCD Application Team
- * [url=home.php?mod=space&uid=247401]@brief[/url] MM32F3273G9PDevices vector table for Atollic toolchain.
- * This module performs:
- * - Set the initial SP
- * - Set the initial PC == Reset_Handler,
- * - Set the vector table entries with the exceptions ISR address
- * - Configure the clock system
- * - Configure external SRAM mounted on MM32F3273G9P EVAL board
- * to be used as data memory (optional, to be enabled by user)
- * - Branches to main in the C library (which eventually
- * calls main()).
- * After Reset the Cortex-M3 processor is in Thread mode,
- * priority is Privileged, and the Stack is set to Main.
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2017 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
- .syntax unified
- .cpu cortex-m3
- .fpu softvfp
- .thumb
- .global g_pfnVectors
- .global Default_Handler
- /* start address for the initialization values of the .data section.
- defined in linker script */
- .word _sidata
- /* start address for the .data section. defined in linker script */
- .word _sdata
- /* end address for the .data section. defined in linker script */
- .word _edata
- /* start address for the .bss section. defined in linker script */
- .word _sbss
- /* end address for the .bss section. defined in linker script */
- .word _ebss
- .equ BootRAM, 0xF1E0F85F
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] This is the code that gets called when the processor first
- * starts execution following a reset event. Only the absolutely
- * necessary set is performed, after which the application
- * supplied main() routine is called.
- * @param None
- * @retval : None
- */
- .section .text.Reset_Handler
- .weak Reset_Handler
- .type Reset_Handler, %function
- Reset_Handler:
- /* Copy the data segment initializers from flash to SRAM */
- movs r1, #0
- b LoopCopyDataInit
- CopyDataInit:
- ldr r3, =_sidata
- ldr r3, [r3, r1]
- str r3, [r0, r1]
- adds r1, r1, #4
- LoopCopyDataInit:
- ldr r0, =_sdata
- ldr r3, =_edata
- adds r2, r0, r1
- cmp r2, r3
- bcc CopyDataInit
- ldr r2, =_sbss
- b LoopFillZerobss
- /* Zero fill the bss segment. */
- FillZerobss:
- movs r3, #0
- str r3, [r2], #4
- LoopFillZerobss:
- ldr r3, = _ebss
- cmp r2, r3
- bcc FillZerobss
- /* Call the clock system intitialization function.*/
- bl SystemInit
- /* Call static constructors */
- bl __libc_init_array
- /* Call the application's entry point.*/
- bl entry
- bx lr
- .size Reset_Handler, .-Reset_Handler
- /**
- * @brief This is the code that gets called when the processor receives an
- * unexpected interrupt. This simply enters an infinite loop, preserving
- * the system state for examination by a debugger.
- *
- * @param None
- * @retval : None
- */
- .section .text.Default_Handler,"ax",%progbits
- Default_Handler:
- Infinite_Loop:
- b Infinite_Loop
- .size Default_Handler, .-Default_Handler
- /******************************************************************************
- *
- * The minimal vector table for a Cortex M3. Note that the proper constructs
- * must be placed on this to ensure that it ends up at physical address
- * 0x0000.0000.
- *
- ******************************************************************************/
- .section .isr_vector,"a",%progbits
- .type g_pfnVectors, %object
- .size g_pfnVectors, .-g_pfnVectors
- g_pfnVectors:
- .word _estack
- .word Reset_Handler
- .word NMI_Handler
- .word HardFault_Handler
- .word MemManage_Handler
- .word BusFault_Handler
- .word UsageFault_Handler
- .word 0
- .word 0
- .word 0
- .word 0
- .word SVC_Handler
- .word DebugMon_Handler
- .word 0
- .word PendSV_Handler
- .word SysTick_Handler
- .word WWDG_IRQHandler
- .word PVD_IRQHandler
- .word TAMPER_IRQHandler
- .word RTC_IRQHandler
- .word FLASH_IRQHandler
- .word RCC_CRS_IRQHandler
- .word EXTI0_IRQHandler
- .word EXTI1_IRQHandler
- .word EXTI2_IRQHandler
- .word EXTI3_IRQHandler
- .word EXTI4_IRQHandler
- .word DMA1_Channel1_IRQHandler
- .word DMA1_Channel2_IRQHandler
- .word DMA1_Channel3_IRQHandler
- .word DMA1_Channel4_IRQHandler
- .word DMA1_Channel5_IRQHandler
- .word DMA1_Channel6_IRQHandler
- .word DMA1_Channel7_IRQHandler
- .word ADC1_2_IRQHandler
- .word FlashCache_IRQHandler
- .word 0
- .word CAN1_RX_IRQHandler
- .word 0
- .word EXTI9_5_IRQHandler
- .word TIM1_BRK_IRQHandler
- .word TIM1_UP_IRQHandler
- .word TIM1_TRG_COM_IRQHandler
- .word TIM1_CC_IRQHandler
- .word TIM2_IRQHandler
- .word TIM3_IRQHandler
- .word TIM4_IRQHandler
- .word I2C1_IRQHandler
- .word 0
- .word I2C2_IRQHandler
- .word 0
- .word SPI1_IRQHandler
- .word SPI2_IRQHandler
- .word UART1_IRQHandler
- .word UART2_IRQHandler
- .word UART3_IRQHandler
- .word EXTI15_10_IRQHandler
- .word RTCAlarm_IRQHandler
- .word OTG_FS_WKUP_IRQHandler
- .word TIM8_BRK_IRQHandler
- .word TIM8_UP_IRQHandler
- .word TIM8_TRG_COM_IRQHandler
- .word TIM8_CC_IRQHandler
- .word ADC3_IRQHandler
- .word 0
- .word SDIO_IRQHandler
- .word TIM5_IRQHandler
- .word SPI3_IRQHandler
- .word UART4_IRQHandler
- .word UART5_IRQHandler
- .word TIM6_IRQHandler
- .word TIM7_IRQHandler
- .word DMA2_Channel1_IRQHandler
- .word DMA2_Channel2_IRQHandler
- .word DMA2_Channel3_IRQHandler
- .word DMA2_Channel4_IRQHandler
- .word DMA2_Channel5_IRQHandler
- .word ETH_IRQHandler
- .word 0
- .word 0
- .word COMP1_2_IRQHandler
- .word 0
- .word 0
- .word OTG_FS_IRQHandler
- .word 0
- .word 0
- .word 0
- .word UART6_IRQHandler
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word 0
- .word UART7_IRQHandler
- .word UART8_IRQHandler
- .word BootRAM
- /*******************************************************************************
- *
- * Provide weak aliases for each Exception handler to the Default_Handler.
- * As they are weak aliases, any function with the same name will override
- * this definition.
- *
- *******************************************************************************/
- .weak NMI_Handler
- .thumb_set NMI_Handler,Default_Handler
- .weak HardFault_Handler
- .thumb_set HardFault_Handler,Default_Handler
- .weak MemManage_Handler
- .thumb_set MemManage_Handler,Default_Handler
- .weak BusFault_Handler
- .thumb_set BusFault_Handler,Default_Handler
- .weak UsageFault_Handler
- .thumb_set UsageFault_Handler,Default_Handler
- .weak SVC_Handler
- .thumb_set SVC_Handler,Default_Handler
- .weak DebugMon_Handler
- .thumb_set DebugMon_Handler,Default_Handler
- .weak PendSV_Handler
- .thumb_set PendSV_Handler,Default_Handler
- .weak SysTick_Handler
- .thumb_set SysTick_Handler,Default_Handler
- .weak WWDG_IRQHandler
- .thumb_set WWDG_IRQHandler,Default_Handler
- .weak PVD_IRQHandler
- .thumb_set PVD_IRQHandler,Default_Handler
- .weak TAMPER_IRQHandler
- .thumb_set TAMPER_IRQHandler,Default_Handler
- .weak RTC_IRQHandler
- .thumb_set RTC_IRQHandler,Default_Handler
- .weak FLASH_IRQHandler
- .thumb_set FLASH_IRQHandler,Default_Handler
- .weak RCC_CRS_IRQHandler
- .thumb_set RCC_CRS_IRQHandler,Default_Handler
- .weak EXTI0_IRQHandler
- .thumb_set EXTI0_IRQHandler,Default_Handler
- .weak EXTI1_IRQHandler
- .thumb_set EXTI1_IRQHandler,Default_Handler
- .weak EXTI2_IRQHandler
- .thumb_set EXTI2_IRQHandler,Default_Handler
- .weak EXTI3_IRQHandler
- .thumb_set EXTI3_IRQHandler,Default_Handler
- .weak EXTI4_IRQHandler
- .thumb_set EXTI4_IRQHandler,Default_Handler
- .weak DMA1_Channel1_IRQHandler
- .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
- .weak DMA1_Channel2_IRQHandler
- .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
- .weak DMA1_Channel3_IRQHandler
- .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
- .weak DMA1_Channel4_IRQHandler
- .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
- .weak DMA1_Channel5_IRQHandler
- .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
- .weak DMA1_Channel6_IRQHandler
- .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
- .weak DMA1_Channel7_IRQHandler
- .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
- .weak ADC1_2_IRQHandler
- .thumb_set ADC1_2_IRQHandler,Default_Handler
- .weak FlashCache_IRQHandler
- .thumb_set FlashCache_IRQHandler,Default_Handler
- .weak CAN1_RX_IRQHandler
- .thumb_set CAN1_RX_IRQHandler,Default_Handler
- .weak EXTI9_5_IRQHandler
- .thumb_set EXTI9_5_IRQHandler,Default_Handler
- .weak TIM1_BRK_IRQHandler
- .thumb_set TIM1_BRK_IRQHandler,Default_Handler
- .weak TIM1_UP_IRQHandler
- .thumb_set TIM1_UP_IRQHandler,Default_Handler
- .weak TIM1_TRG_COM_IRQHandler
- .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
- .weak TIM1_CC_IRQHandler
- .thumb_set TIM1_CC_IRQHandler,Default_Handler
- .weak TIM2_IRQHandler
- .thumb_set TIM2_IRQHandler,Default_Handler
- .weak TIM3_IRQHandler
- .thumb_set TIM3_IRQHandler,Default_Handler
- .weak TIM4_IRQHandler
- .thumb_set TIM4_IRQHandler,Default_Handler
- .weak I2C1_IRQHandler
- .thumb_set I2C1_IRQHandler,Default_Handler
- .weak I2C2_IRQHandler
- .thumb_set I2C2_IRQHandler,Default_Handler
- .weak SPI1_IRQHandler
- .thumb_set SPI1_IRQHandler,Default_Handler
- .weak SPI2_IRQHandler
- .thumb_set SPI2_IRQHandler,Default_Handler
- .weak UART1_IRQHandler
- .thumb_set UART1_IRQHandler,Default_Handler
- .weak UART2_IRQHandler
- .thumb_set UART2_IRQHandler,Default_Handler
- .weak UART3_IRQHandler
- .thumb_set UART3_IRQHandler,Default_Handler
- .weak EXTI15_10_IRQHandler
- .thumb_set EXTI15_10_IRQHandler,Default_Handler
- .weak RTCAlarm_IRQHandler
- .thumb_set RTCAlarm_IRQHandler,Default_Handler
- .weak OTG_FS_WKUP_IRQHandler
- .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
- .weak TIM8_BRK_IRQHandler
- .thumb_set TIM8_BRK_IRQHandler,Default_Handler
- .weak TIM8_UP_IRQHandler
- .thumb_set TIM8_UP_IRQHandler,Default_Handler
- .weak TIM8_TRG_COM_IRQHandler
- .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler
- .weak TIM8_CC_IRQHandler
- .thumb_set TIM8_CC_IRQHandler,Default_Handler
- .weak ADC3_IRQHandler
- .thumb_set ADC3_IRQHandler,Default_Handler
- .weak SDIO_IRQHandler
- .thumb_set SDIO_IRQHandler,Default_Handler
- .weak TIM5_IRQHandler
- .thumb_set TIM5_IRQHandler,Default_Handler
- .weak SPI3_IRQHandler
- .thumb_set SPI3_IRQHandler,Default_Handler
- .weak UART4_IRQHandler
- .thumb_set UART4_IRQHandler,Default_Handler
- .weak UART5_IRQHandler
- .thumb_set UART5_IRQHandler,Default_Handler
- .weak TIM6_IRQHandler
- .thumb_set TIM6_IRQHandler,Default_Handler
- .weak TIM7_IRQHandler
- .thumb_set TIM7_IRQHandler,Default_Handler
- .weak DMA2_Channel1_IRQHandler
- .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
- .weak DMA2_Channel2_IRQHandler
- .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
- .weak DMA2_Channel3_IRQHandler
- .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
- .weak DMA2_Channel4_IRQHandler
- .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
- .weak DMA2_Channel5_IRQHandler
- .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
- .weak ETH_IRQHandler
- .thumb_set ETH_IRQHandler,Default_Handler
- .weak COMP1_2_IRQHandler
- .thumb_set COMP1_2_IRQHandler,Default_Handler
- .weak OTG_FS_IRQHandler
- .thumb_set OTG_FS_IRQHandler,Default_Handler
- .weak UART6_IRQHandler
- .thumb_set UART6_IRQHandler,Default_Handler
- .weak UART7_IRQHandler
- .thumb_set UART7_IRQHandler,Default_Handler
- .weak UART8_IRQHandler
- .thumb_set UART8_IRQHandler,Default_Handler
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
阅读 scons 构建脚本可知,gcc 方式的 link 文件需要放在 drivers\linker_scripts ,并且得知可以设置 ENV 工具自带的 gcc 以外的编译器路径,只要自己在 rtconfig.py 中实际修改好即可: 于是添加 link.lds 在此目录下,内容如下: 到这里基本已经搭建好了 mm32f327x 的 ENV 的 gcc 编译环境,于是可以运行 scons 命令直接构建编译了,正常的话可以看到成功编译结果如下:
接下来可以使用 menuconfig 命令对整个工程的组件包进行增删配置,每次使用 menuconfig 对 bsp 进行配置后,都需要再使用 scons 命令对相应的工程进行重新生成,以便配置能生效,以下为配置主页: 为了使 bsp 包中只与本芯片/开发板有关,而其它无关项全部删除,可以使用 scons --dist 命令进行搭建项目框架,命令执行后,会在 bsp 包目录里面生成 dist 目录,它包含了整个mm32f327x 的工程,这样就打包成功了,只是需要注意生成 mdk 或者 iar 的时候需要避坑(需要手动将 keil 对应的context_rvds.S 文件,放入 dist 对应的 libcpu 目录下):
另外涉及到的知识点已经搭建好 rt-thread 的 env 开发环境了,还需要关注的一些开发时候会涉及到的知识点整理如下: pkgs --update 和 pkgs --upgrade 软件包管理和更新命令的使用 ; 使用 ENV 工具的条件有:RT-Thread 3.0+版本,低版本要做一些迁移,要有kconfig配置文件 ; menuconfig 启动后默认到当前目录下寻找 Kconfig 文件并解析。Kconfig 中可以通过 source 指定加载子 Kconfig 文件,这样根据 Kconfig 文件的内部调用结构,menuconfig 依次解析所有被引用的Kconfig 文件,生成内部的配置选项数据库解析 .config 文件,根据上一次的配置结果初始化各个配置选项的初值。给用户展示配置界面,并根据用户的选择更新内部数据库,最后 menuconfig 生成 .config 文件会自动生成配置头文件 rtconfig.h ,该文件对整个操作系统以及中间件进行裁剪、配置 ; 每一个 RT-Thread bsp 目录下都会存在下面三个文件:rtconfig.py、SConstruct 和 SConscript,它们控制 bsp 的编译。SConstruct 文件是 scons 默认解析的第一个脚本,因此 scons 命令必须在它所在的路径下执行,一般建议将 SConstruct 脚本与 rtconfig.py 脚本置于用户工程目录中。rtconfig.py 文件主要用于指定编译器以及安装路径。除此之外,该文件中定义了大量的变量,这些变量包括编译选项,汇编选项,链接选项。同目录下的 SConscript 文件表示 scons 中间加载类脚本,applications 目录下的 SConscript 文件为 scons 代码组织类脚本,它可以添加用户需要额外编译的 .c 文件,比如 led.c 。
开发环境已经搭建准备好,后面只需要在这个框架中添加自己的驱动和应用代码,以及编写好正确的编译脚本,结合 RT-Thread 丰富的组件以及 MM32-Link Mini 调试器(CMSIS-DAP Link)+PyOCD 方式的 RTT 输出打印功能,相信这趟国产替代之旅会很顺畅,大家也可以同我一起来尝试哟! 下面我附上我改过的 bsp-mm32f327x 支持包。
|