笔者的开发板主控MCU为STM32F303VCT6,但是在RT-Thread的例程中暂时还没有支持STM32F3系列的BSP例程,想必跟这款芯片用的比较少有关吧。但是在实际的工作中难免会遇到自己所用的MCU无法找到例程的情况,而且这种情况应该还不少,所以掌握怎么在相似的MCU工程的基础上将程序移植到自己的MCU上就变得有意义了。
首先要下载好RT-Thread源码,下载的方法可以有以下三种:
1. 从GitHub下载,下载网址为:https://github.com/RT-Thread/rt-thread
2. 从Gitee下载,下载网址为:https://gitee.com/rtthread/rt-thread
3. 从百度网盘、论坛等地方下载。
以上三种下载方式笔者更推荐前面两种,原因是从其他地方下载的源码可能已经被修改过了,被修改过的源码一方面无法确定修改的部分是否会引入bug,另一方面学习的时候你会把别人修改过的误以为是官方发布的,学习到的不是正宗的官方版本,这样在跟其他人交流探讨的时候就会有问题。
要移植前首先需要准备好一个例程的MCU跟你所用的MCU尽可能相似的例程作为基础,笔者所用的MCU是STM32F303,是contex-m4内核,所以自然最省事的就是找一个同是contex-m4内核的例程,当然,你找其他内核的也不是不可以,但是要改的东西相对会对些,又何必给自己找麻烦呢,对吧。笔者选的是STM32F407的安富莱的V5开发板的BSP作为基础(路径为:…\rt-thread-master\bsp\stm32\stm32f407-armfly-v5)。
除了上面两个准备工作外还要准备一个STM32F303的HAL工程,这个可以用STM32CubeMX自动生成,只所以要准备这个工程是因为我们需要用这个工程的STM32F3的HAL驱动去替换掉原例程中的其他MCU的HAL驱动。
除了准备一个基础例程外,还需要准备好RT-Thread的配置工具ENV,具体的下载安装及使用教程可以看这里:Env 用户手册 (rt-thread.org)。
准备工作做好后便可以正式开搞了。总的思路其实就是把所有跟STM32407相关的文件都用STM32F303的对应文件来替代。
1. 首先打开路径…\rt-thread-master\bsp\stm32\stm32f407-armfly-v5进入到如下图所示界面
2. 在图1空白处单击右键会弹出如图2所示窗口,选择并点击ConEmu Here。如果你右击没有出现ConEmu Here可能是因为你还没有安装并设置好ENV,请参考Env 用户手册 (rt-thread.org)重新设置或安装并设置好ENV工具。
3. 点击图2的ConEmu Here后会弹出图3所示的窗口,该窗口便是用于构建新工程的窗口。
4. 在图3所示的窗口上输入 menuconfig 程序运行一会后便会打开图4所示的窗口。
在图4窗口中你可以根据需要选择你所需要的组件,具体的操作方式依然是可以参考Env 用户手册 (rt-thread.org),操作完后记得保存后再退出,不然就白设置了。笔者这里没有做任何修改直接退出。
退出后回到图5界面,在图5界面中输入 scons --target=mdk5 开始构建并编译MDK5工程。
构建完成后如图6所示
笔者不喜欢一堆跟工程不相关的东西放在一起,所以笔者一般喜欢在构建完成后执行 scons --dist 将有关的文件打包到一起,执行完 scons --dist 后控制台会输出如图7所示的信息,并且在…\rt-thread-master\bsp\stm32\stm32f407-armfly-v5路径下会生成一个 dist 的文件夹,这个文件夹里面存放的就是你刚刚构建的完整且干净(不包含不相关文件)的工程,里面包含了一个文件夹和一个压缩包如图9所示,压缩包其实就是文件夹进行压缩后所得。这个文件夹里面包含了工程所需的所有文件,所以就是单独把它拷到别的地方去也是能正确编译正常烧录正常运行的。
将dist目录下的文件夹复制到一个合适的目录下并修改文件夹名,笔者这里将文件名改成了MCU的型号:stm32f303vct6,然后打开 …\stm32f303vct6\libraries,打开后可以看到如图10所示的两个文件夹及一个名为Kconfig的文件,将第二个文件夹的名字改成STM32F3xx_HAL。当然这一步可以省略,但是为了文件好管理和好识别,建议还是不要省略。
接下来就是要用STM32F303的文件替换掉STM32F407的相关文件了。打开用STM32CubeMX生成的STM32F3x的工程文件夹,找到目录下的 Drivers 文件夹并打开,将Drivers 文件夹下的两个文件夹复制。
打开…\stm32f303vct6\libraries\STM32F3xx_HAL,可以看到如图11的两个文件夹和一个名为SConscript文件,将两个文件夹删除,然后将步骤10 中复制的两个文件夹粘贴到该路径下。
到这一步已经完成了大部分文件的替换,其他一些零散文件通过编译的错误来一个个替换。
用MDK5打开工程,全局编译下,不出所料的话会是一大堆错误,如图12所示。大致看下大多数报错都是stm32f4xx_hal_xxxx 文件找不到,这个也在意料之中,因为从上面的步骤我们可以知道这些文件已经被我们替换成stm32f3xx_hal_xxxx文件了,接下来我们要做的就是在MDK中也将这些stm32f4xx_hal_xxxx换成stm32f3xx_hal_xxxx。
点击MDK工具栏上的品字形图标,弹出 Manage Project Items窗口,选中中间框中的Libraries,右边框框对应的出现了stm32f4xx_hal_xxx等文件如图13所示。
将图13所示中的右边框框的文件全部删除掉,并按需从…\stm32f303vct6\libraries\STM32F3xx_HAL\STM32F3xx_HAL_Driver\Src 目录下添加stm32f3xx_hal_xxx驱动文件,添加完后如图14所示。
点击OK后回到主界面。
点击魔术棒弹出 Options for Target窗口并按图15重新选则实际使用的MCU型号。
点击图15的OK后回到主界面再进行一次全编译,不出意外的话还是有一堆错误,如图16所示。
这次报的错误中几乎都是找不到头文件,说到头文件我们可以想到需要指定头文件,我们在前面对文件夹名字做了修改,那头文件路径自然也得重新指定。
还是点击魔术棒图像弹出Options for Target窗口,点击图17中的①标识上方的 C/C++弹出图17的画面,将②标识上面的STM32F407xx更改成STM32F303xx。
点击图17中的③上面的三个小点,然后将弹出的窗口拉到底,便如图18所示。双击图18中的①标识下方的文字中的STM32F4都改成STM32F3,②上方的同理将STM32F4都改成STM32F3,其本质是指定真实的STM32F3 HAL驱动的文件的路径。
点击OK回到主界面后重新编译下。还是报了很多错误,其中最后一条说是找不到 stm32f3xx_hal_conf.h 文件,接下来我们就根据错误一条一条的将缺失的文件找回来,怎么找呢?当然是根据我们之前用STM32CubeMX创建的工程啦。
打开STM32CubeMX创建的工程并全局搜索stm32f3xx_hal_conf.h,如图21所示,在搜索的结果中双击任意一条,跳转到其中一个文件,然后找到stm32f3xx_hal_conf.h并将鼠标放到它上面右击,然后在弹出的窗口中点击③所在的条目。
完成23步后便打开了stm32f3xx_hal_conf.h文件,如图22所示将鼠标放到打开的stm32f3xx_hal_conf.h文件标题上右击在弹出的窗口中点击Open Containing Folder便打开了这个文件所在的目录。
完成24步后将弹出图23所示的文件目录,可以看到该目录下一共有三个文件,将这三个文件复制备用。
回到移植的工程中来,按图24所示,先按①找到main.h并双击打开main.h文件,同样的操作将鼠标放到main.h文件标题上,右键并点击③弹出main.h所在的文件夹。
弹出的文件夹中也包含了三个文件,如图25所示,将这三个文件删除,并用图23的三个文件替换,替换完后如图26所示。
回到移植工程的主界面会提示重新加载,按确认即可。确认后重新编译下。
编译后查看报错如图27所示,说的是找不到stm32f4xx.h,我们在这个工程中本来就不需要stm32f4xx.h,我们实际需要的是stm32f4xx.h,所以将stm32f4xx.h全部替换成stm32f3xx.h
按快捷键唤出查找替换窗口,按图28所示顺序操作,然后点击下方的Replace All按钮执行替换。
替换完成后再次编译发现报的错越来越多,但不要慌,从最后一个开始个个击破,耐住性子按步骤按思路一个一个来你会发现后面某一个操作一下子就能消掉几十个错误,所以错误越来越多也并没有什么可怕的。先来看最后一个错误,最后一个报错是找不到stm32f4xx_hal.h文件,同样的方法将stm32f4xx_hal.h换成stm32f3xx_hal.h。
替换完后再次编译,查看报错信息,如图30所示,从中可以看到报的错大部分都是与UART相关的标识符未定义,出现这么大量的未定义,很容易联想到要么是头文件没有包含,要么就是UART这部分没有使能编译。
查看uart相关的文件stm32f3xx_hal_uart.c可以看到,该文件中从170行开始都是灰色的,也就是说170行以下的都没有使能参与编译。再看169行,该行是一个预编译命令,所以原因已经很明显了,由于没有定义宏 HAL_UART_MODULE_ENABLED,所以才会出现一大对于UART相关的标识符没有定义。
全文搜索HAL_UART_MODULE_ENABLED,结果如图32所示,由图32可以看到红框所示的内容显示在stm32f3xx_hal_conf.h文件中#define HAL_UART_MODULE_ENABLED被注释掉了,双击红框文字跳到stm32f3xx_hal_conf.h文件中#define HAL_UART_MODULE_ENABLED所在的行,将注释去掉,重新编译,发现UART相关的标识符未定义的错误没有了。
重新编译后看最后一个错误,如图33所示,报的是DMA_FIFOMODE_DISABLE未定义,双击错误信息跳转到出错的地方,可以看到,报错的语句上面是一个预处理命令#if,只有#if的条件成立,报错的那句语句才有被编译也才有机会出错,观察#if的条件,发现这些条件原本是不应该不满足的,因为我们用的是STM32F3,但是实际情况确实满足了,由于我们是以STM32F407为基础移植的,所以很容易想到一定是我们还没有将SOC_SERIES_STM32F4改成SOC_SERIES_STM32F3所导致的报错。
如图34所示,将鼠标放置到SOC_SERIES_STM32F4上并右击在弹出的窗口中点击Go To Definition Of ‘SOC_SERIES_STM32F4’ 跳转到SOC_SERIES_STM32F4的定义处。
完成步骤36后跳转到图35所示的界面,由图35可以看到,这里定义了SOC_SERIES_STM32F4,用时其下面还定义了SOC_STM32F407IG,这两个都是要被更改成我们实际用的STM32F303VCT6的,修改后如图36所示。修改完后保存并重新编译。
如图37所示双击最后一个报错后跳到了SystemClock_Config函数中,该函数是针对STM32F407写的报错也是正常的,我们要做的就是用STM32CubeMX创建的工程中的SystemClock_Config函数来替换掉这个函数。
重新编译查看报错,大多数都stm32f4xx_hap_msp.c文件中报的错,这是针对STM32F4的文件我们自然是不能用的,找到stm32f4xx_hap_msp.c的路径(查找的方法前面有过介绍),可以看到stm32f4xx_hap_msp.c的路径下的文件如图39所示。图39的这两个文件都要找STM32CubeMX创建的工程中的对应的文件来替换。
替换完后回到MDK主窗口可以看到stm32f4xx_hap_msp.c文件前面多了一个黄色的感叹号,这意味着该文件找不到了。将鼠标放在①中点击右键移除stm32f4xx_hap_msp.c,然后双击①上面的Drivers在弹出的窗口中选择步骤39中替换成的stm32f3xx_hap_msp.c。
重新编译,报错如图41所示,说是找不到startup_stm32f407xx.s,这个文件stm32f4xx_hap_msp.c一样是要被替换掉的。找到STM32CubeMX创建的工程中的startup_stm32f303xc.s并将其复制到…\stm32f303vct6\libraries\STM32F3xx_HAL\STM32F3xx_HAL_Driver\Src路径下。
在MDK中删除掉startup_stm32f407xx.s并添加startup_stm32f303xc.s。
重新编译后报错如图42所示,在STM32CubeMX创建的工程中搜索其中一个标识符,比如搜索APBPrescTable,搜索结果如图43所示。 由图43可知,移植的工程中缺失的APBPrescTable是在system_stm32f3xx.c中定义的,而移植工程中正是因为少了这个文件所以报的错。在STM32CubeMX创建的工程中双击搜索结果跳到该文件并找出该文件所有的目录,然后将其复制到移植的工程的…\stm32f303vct6\libraries\STM32F3xx_HAL\STM32F3xx_HAL_Driver\Src的目录下。
回到移植工程主目录,将system_stm32f3xx.c文件添加到Libraries中,添加完后如图44所示,然后重新编译。编译结果如图45所示,0错误0警告。
至此,移植过程基本结束了,接下来就是测试下移植是否成功,RT-Thread是否能真正跑起来。
打开main.c,找到main函数,按开发板的实际硬件链接修改灯的引脚号,修改完后如图46所示。修改完后重新编译,没错误后下载到板子。
不出意外的话此时应该出意外了,灯竟然没反应。。。。。。
仿真跟踪发现运行到图47中的187行就卡死了,这行是初始化堆栈的,卡死的原因极有可能就是堆栈的地址设置有问题。
跳转到HEAP_BEGIN后可以看到如图48所示,在这里FLASH的大小被设置成了1024K,比实际的256K大了4倍,SRAM的大小别设置成了128K,也比实际大了4倍。
将FLASH和SRAM的大小按实际芯片大小修改后重新编译下载。
不出意外的话此时不会出意外,灯按预期闪烁了起来。
至此,整个移植算是真正完成了,累死宝宝了。