开发板移植RTOS操作系统,RTOS操作系统适配开发板整理大全_use_rtos

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149


* 如下图所示:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201203165736360.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NzajkyNTMxOQ==,size_16,color_FFFFFF,t_70)


2、烧录程序到 stm32 指南者中


`说明:`在烧录过程请参考博客:[stm32 应用实例—— USART 串口通讯]( ),这篇博客写得很详细,里面有 keil 烧录前的设置、烧录的方法、串口调试助手等等。


3、烧录结果显示


* LED 等闪烁:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201203175335389.gif#pic_center)
* 串口助手显示:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201203174454472.gif#pic_center)


### 三、总结


FreeRTOS 的移植看起来繁琐,但是熟练了以后就轻松了。采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。这里我们使用 FreeRTOS ,这是国外的,而国内也有这样的实时操作系统——RT-Thread,是适合我们国内的。


### 四、参考资料


1、[野火 FreeRTOS视频教学 配套书籍《FreeRTOS内核实现与应用开发实战指南》配套例程源码]( )  
 2、[STM32指南者完成基于FreeRTOS的多任务程序]( )


## 五、手把手教你使用RT-Thread制作GD32系列BSP


已剪辑自: https://zhuanlan.zhihu.com/p/452434318


熟悉RT-Thread的朋友都知道,RT-Thread提供了许多BSP,但不是所有的板子都能找到相应的BSP,这时就需要移植新的BSP。RT-Thread的所有BSP中,最完善的BSP就是STM32系列,但从2020年下半年开始,国内出现史无前例的芯片缺货潮,芯片的交期和价格不断拉升,STM32的价格也是水涨船高,很多朋友也在考虑使用国产替代,笔者使用的兆易创新的GD32系列,我看了下RT-Thread中GD系列BSP,都是玩家各自为政,每个人都是提交自己使用的板子的BSP,充斥着大量冗余的代码,对于有强迫症的我就非常不爽,就根据手头的板子,参看STM32的BSP架构,构建了GD32的BSP架构。


笔者使用的开发板是兆易创新设计的GD32407V-START开发板。其主控芯片为GD32F407VKT6,主频168MHz,内部3072K Flash,192KB SRAM,资源相当丰富。


![img](https://img-blog.csdnimg.cn/img_convert/a6cbf6defde610482c63d7661e1b6fcc.jpeg)


### 1 BSP 框架制作


在具体移植GD32407V-START的BSP之前,先做好GD32的BSP架构。BSP 框架结构如下图所示:


![img](https://img-blog.csdnimg.cn/img_convert/1ca93e056a3277618fb390889a4d06a5.jpeg)


GD32的BSP架构主要分为三个部分:libraries、tools和具体的Boards,其中libraries包含了GD32的通用库,包括每个系列的Firmware Library以及适配RT-Thread的drivers;tools是生成工程的Python脚本工具;另外就是Boards文件,当然这里的Boards有很多,我这里值列举了GD32407V-START。


这里先谈谈libraries和tools的构建,然后在后文单独讨论具体板级BSP的制作。


#### 1.1 Libraries构建


Libraries文件夹包含兆易创新提供的HAL库,这个直接在兆易创新的官网就可以下载。


下载地址:[http://www.gd32mcu.com/cn/download/]( )


然后将GD32F4xx\_Firmware\_Library复制到libraries目录下,其他的系列类似。


![img](https://img-blog.csdnimg.cn/img_convert/2abe22969ab8d86be1bb49fe0bb083c2.jpeg)


GD32F4xx\_Firmware\_Library就是官方的文件,基本是不用动的,只是在文件夹中需要添加构建工程的脚本文件SConscript,其实也就是Python脚本。


![img](https://img-blog.csdnimg.cn/img_convert/72cafc65ca97c387966363b080b93922.jpeg)


SConscript文件的内容如下:



import rtconfig #导包
from building import *

get current directory

cwd = GetCurrentDir() #获取当然路径

The set of source files associated with this SConscript file.

src = Split(‘’’
CMSIS/GD/GD32F4xx/Source/system_gd32f4xx.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_gpio.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_rcu.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_exti.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_misc.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_syscfg.c
‘’')#将括号中的字符串分割后成列表(list),以便包含到工程中

if GetDepend([‘RT_USING_SERIAL’]):#如果打开了RT_USING_SERIAL的宏,则会包含以下源文件
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_usart.c’]

if GetDepend([‘RT_USING_I2C’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_i2c.c’]

if GetDepend([‘RT_USING_SPI’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_spi.c’]

if GetDepend([‘RT_USING_CAN’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_can.c’]

if GetDepend([‘BSP_USING_ETH’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_enet.c’]

if GetDepend([‘RT_USING_ADC’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_adc.c’]

if GetDepend([‘RT_USING_DAC’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_dac.c’]

if GetDepend([‘RT_USING_RTC’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_rtc.c’]

if GetDepend([‘RT_USING_WDT’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_wwdgt.c’]
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_fwdgt.c’]

if GetDepend([‘RT_USING_SDIO’]):
src += [‘GD32F4xx_standard_peripheral/Source/gd32f4xx_sdio.c’]

#头文件路径
path = [
cwd + ‘/CMSIS/GD/GD32F4xx/Include’,
cwd + ‘/CMSIS’,
cwd + ‘/GD32F4xx_standard_peripheral/Include’,]

CPPDEFINES = [‘USE_STDPERIPH_DRIVER’]
#定义一个组,组名为’Libraries’, depend为空表示依赖任何一个其他宏,另外当前的头文件路径添加到工程中
group = DefineGroup(‘Libraries’, src, depend = [‘’], CPPPATH = path, CPPDEFINES = CPPDEFINES)

Return(‘group’)


该文件主要的作用就是添加库文件和头文件路径,一部分文件是属于基础文件,因此直接调用Python库的Split包含,另外一部分文件是根据实际的应用需求添加的。


这里是以GD32F4来举例的,其他系列的都是类似的。


接下来说说Kconfig文件,这里是对内核和组件的功能进行配置,对RT-Thread的组件进行自由裁剪。


如果使用RT-Thread studio,则通过RT-Thread Setting可以体现Kconfig文件的作用。


![img](https://img-blog.csdnimg.cn/img_convert/cb04376c33a5cd62f7354f9c0f6b3929.jpeg)


如果使用ENV环境,则在使用 menuconfig配置和裁剪 RT-Thread时体现。


![img](https://img-blog.csdnimg.cn/img_convert/39b05c398765be84bff40efd06ca020e.jpeg)


后面所有的Kconfig文件都是一样的逻辑。下表列举一些常用的Kconfig句法规则。




| 关键词 | 说明 |
| --- | --- |
| config | 此关键字定义了一新的配置选项 |
| menuconfig | 此关键字和前面的关键字很相似,但它在前面的基础上要求所有的子选项作为独立的行显示。 |
| choice/endchoice | 该关键字定义了一组选择项。 |
| comment | 这里定义了在配置过程中显示给用户的注释,该注释还将写进输出文件中。格式说明: comment “eg: description content” |
| menu / endmenu | 这里定义了一个菜单,所有依赖于此菜单的选项都是它的子选项。 |
| if/endif | 这里定义了if结构。 |
| source | 读取其他具体的配置文件,其他配置文件会被解析。 |


Kconfig的语法规则网上资料很多,自行去学习吧。


bsp/gd32/libraries/Kconfig内容如下:



config SOC_FAMILY_GD32
bool

config SOC_SERIES_GD32F4
bool
select ARCH_ARM_CORTEX_M4
select SOC_FAMILY_GD32


因为该架构目前笔者只移植了GD32F4的,因此这里的内容比较少,如果有些的系列,直接参考F4的配置例子在这里加就可以了。


![img](https://img-blog.csdnimg.cn/img_convert/3f7d68653782c0b8777487b5b9f0cab2.jpeg)


最后谈谈gd32\_drivers,这个文件夹就是GD32的外设驱动文件夹,为上层应用提供调用接口。


该文件夹是整个GD32共用的,因此在编写和修改都要慎重。关于drv\_xxx文件在后句具体移植BSP的时候讲解,这里主要将整体架构,SConscript和Kconfig的作用和前面的一样,只是具体的内容不同罢了。


好了,先看bsp/gd32/libraries/gd32\_drivers/SConscript文件。



import(‘RTT_ROOT’)
import(‘rtconfig’)
from building import *

cwd = GetCurrentDir()

add the general drivers.

src = Split(“”"
“”")

add pin drivers.

if GetDepend(‘RT_USING_PIN’):
src += [‘drv_gpio.c’]

add usart drivers.

if GetDepend([‘RT_USING_SERIAL’]):
src += [‘drv_usart.c’]

add adc drivers.

if GetDepend(‘RT_USING_ADC’):
src += [‘drv_adc.c’]

add i2c drivers.

if GetDepend([‘RT_USING_I2C’, ‘RT_USING_I2C_BITOPS’]):
if GetDepend(‘BSP_USING_I2C0’) or GetDepend(‘BSP_USING_I2C1’) or GetDepend(‘BSP_USING_I2C2’) or GetDepend(‘BSP_USING_I2C3’):
src += [‘drv_soft_i2c.c’]

add spi drivers.

if GetDepend(‘RT_USING_SPI’):
src += [‘drv_spi.c’]

add spi flash drivers.

if GetDepend(‘RT_USING_SFUD’):
src += [‘drv_spi_flash.c’, ‘drv_spi.c’]

add hwtimer drivers.

if GetDepend(‘RT_USING_HWTIMER’):
src += [‘drv_hwtimer.c’]

add rtc drivers.

if GetDepend(‘RT_USING_RTC’):
src += [‘drv_rtc.c’]

add iwdt drivers.

if GetDepend(‘RT_USING_WDT’):
src += [‘drv_iwdt.c’]

path = [cwd]

group = DefineGroup(‘Drivers’, src, depend = [‘’], CPPPATH = path)

Return(‘group’)


和GD32F4xx\_Firmware\_Library文件夹中的SConscript是类似的。


bsp/gd32/libraries/gd32\_drivers/Kconfig文件结构如下:



if BSP_USING_USBD
config BSP_USBD_TYPE_FS
bool

“USB Full Speed (FS) Core”

config BSP_USBD_TYPE_HS
bool

“USB High Speed (HS) Core”

config BSP_USBD_SPEED_HS
bool

“USB High Speed (HS) Mode”

config BSP_USBD_SPEED_HSINFS
bool

“USB High Speed (HS) Core in FS mode”

config BSP_USBD_PHY_EMBEDDED
bool

“Using Embedded phy interface”

config BSP_USBD_PHY_UTMI
bool

“UTMI: USB 2.0 Transceiver Macrocell Interace”

config BSP_USBD_PHY_ULPI
bool

“ULPI: UTMI+ Low Pin Interface”

endif


#### 1.2 Tools构建


该文件夹就是工程构建的脚本,



import os
import sys
import shutil

cwd_path = os.getcwd()
sys.path.append(os.path.join(os.path.dirname(cwd_path), ‘rt-thread’, ‘tools’))

def bsp_update_board_kconfig(dist_dir):

change board/kconfig path

if not os.path.isfile(os.path.join(dist_dir, ‘board/Kconfig’)):
return

with open(os.path.join(dist_dir, ‘board/Kconfig’), ‘r’) as f:
data = f.readlines()
with open(os.path.join(dist_dir, ‘board/Kconfig’), ‘w’) as f:
for line in data:
if line.find(‘…/libraries/gd32_drivers/Kconfig’) != -1:
position = line.find(‘…/libraries/gd32_drivers/Kconfig’)
line = line[0:position] + ‘libraries/gd32_drivers/Kconfig"\n’
f.write(line)

BSP dist function

def dist_do_building(BSP_ROOT, dist_dir):
from mkdist import bsp_copy_files
import rtconfig

print(“=> copy gd32 bsp library”)
library_dir = os.path.join(dist_dir, ‘libraries’)
library_path = os.path.join(os.path.dirname(BSP_ROOT), ‘libraries’)
bsp_copy_files(os.path.join(library_path, rtconfig.BSP_LIBRARY_TYPE),
os.path.join(library_dir, rtconfig.BSP_LIBRARY_TYPE))

print(“=> copy bsp drivers”)
bsp_copy_files(os.path.join(library_path, ‘gd32_drivers’), os.path.join(library_dir, ‘gd32_drivers’))
shutil.copyfile(os.path.join(library_path, ‘Kconfig’), os.path.join(library_dir, ‘Kconfig’))

bsp_update_board_kconfig(dist_dir)


以上代码很简单,主要使用了Python的OS模块的join函数,该函数的作用就是连接两个或更多的路径名。最后将BSP依赖的文件复制到指定目录下。


在使用scons --dist 命令打包的时候,就是依赖的该脚本,生成的dist 文件夹的工程到任何目录下使用,也就是将BSP相关的库以及内核文件提取出来,可以将该工程任意拷贝。


需要注意的是,使用scons --dist打包后需要修改board/Kconfig中的库路径,因此这里调用了bsp\_update\_board\_kconfig方法修改。


![img](https://img-blog.csdnimg.cn/img_convert/8d95136234934da85ea9732fa58c2574.jpeg)


#### 1.3 gd32407v-start构建


该文件夹就gd32407v-start的具体BSP文件,文件结构如下:


![img](https://img-blog.csdnimg.cn/img_convert/91a32452bfcf74b34acc28dc5da42c42.jpeg)


在后面将具体讲解如何构建该部分内容。


### 2 BSP移植


#### 2.1 Keil环境准备


目前市面通用的MDK for ARM版本有Keil 4和Keil 5:使用Keil 4建议安装4.74及以上;使用Keil 5建议安装5.20以上版本。笔者的MDK是5.30。


从MDK的官网可以下载得到MDK的安装包,然后安装即可,关于的MDK安装请看笔者的教程。


MDK安装教程:[https://blog.csdn.net/bruceoxl/article/details/108548573]( )


MDK下载地址:[https://www.keil.com/download/product/]( )


![img](https://img-blog.csdnimg.cn/img_convert/3169aea9177c65fc5bbc1919adaeb9fa.jpeg)


安装完成后会自动打开,我们将其关闭。


接下来我们下载GD32F30x的软件支持包。


下载地址:[http://www.gd32mcu.com/cn/download]( )


![img](https://img-blog.csdnimg.cn/img_convert/398c8fbaccdced214147ca652d682e05.png)


下载好后双击GigaDevice.GD32F4xx\_DFP.2.1.0.pack运行即可:


![img](https://img-blog.csdnimg.cn/img_convert/984ca28a47131b1399ad53202b32a7b1.jpeg)


点击[Next]即可安装完成。


![img](https://img-blog.csdnimg.cn/img_convert/b3e0ce74bed9971bb18c1abaa5383588.jpeg)


安装成功后,重新打开Keil,则可以在File->Device Database中出现Gigadevice的下拉选项,点击可以查看到相应的型号。


![img](https://img-blog.csdnimg.cn/img_convert/05f5df7c6b02d9bb5fda6982f8b743af.jpeg)


#### 2.2 BSP工程制作


**1.构建基础工程**


首先看看RT-Thread代码仓库中已有很多BSP,而我要移植的是Cortex-M4内核。这里我找了一个相似的内核,把它复制一份,并修改文件名为:gd32407v-start。这样就有一个基础的工程。然后就开始增删改查,完成最终的BSP,几乎所有的BSP的制作都是如此。


**2.修改BSP构建脚本**


bsp/gd32/gd32407v-start/Kconfig修改后的内容如下:



mainmenu “RT-Thread Configuration”

config BSP_DIR
string
option env=“BSP_ROOT”
default “.”

config RTT_DIR
string
option env=“RTT_ROOT”
default “…/…/…”

config PKGS_DIR
string
option env=“PKGS_ROOT”
default “packages”

source “ R T T D I R / K c o n f i g " s o u r c e " RTT_DIR/Kconfig" source " RTTDIR/Kconfig"source"PKGS_DIR/Kconfig”
source “…/libraries/Kconfig”
source “board/Kconfig”


该文件是获取所有路径下的Kconfig。


bsp/gd32/gd32407v-start/SConscript修改后的内容如下:



for module compiling

import os
Import(‘RTT_ROOT’)
from building import *

cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)

for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, ‘SConscript’)):
objs = objs + SConscript(os.path.join(d, ‘SConscript’))

Return(‘objs’)


该文件是用于遍历当前目录的所有文件夹。


bsp/gd32/gd32407v-start/SConstruct修改后的内容如下:



import os
import sys
import rtconfig

if os.getenv(‘RTT_ROOT’):
RTT_ROOT = os.getenv(‘RTT_ROOT’)
else:
RTT_ROOT = os.path.normpath(os.getcwd() + ‘/…/…/…’)

sys.path = sys.path + [os.path.join(RTT_ROOT, ‘tools’)]
try:
from building import *
except:
print(‘Cannot found RT-Thread root directory, please check RTT_ROOT’)
print(RTT_ROOT)
exit(-1)

TARGET = ‘rtthread.’ + rtconfig.TARGET_EXT

DefaultEnvironment(tools=[])
env = Environment(tools = [‘mingw’],
AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
AR = rtconfig.AR, ARFLAGS = ‘-rc’,
CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS,
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath(‘PATH’, rtconfig.EXEC_PATH)

if rtconfig.PLATFORM == ‘iar’:
env.Replace(CCCOM = [‘$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES’])
env.Replace(ARFLAGS = [‘’])
env.Replace(LINKCOM = env[“LINKCOM”] + ’ --map rtthread.map’)

Export(‘RTT_ROOT’)
Export(‘rtconfig’)

SDK_ROOT = os.path.abspath(‘./’)

if os.path.exists(SDK_ROOT + ‘/libraries’):
libraries_path_prefix = SDK_ROOT + ‘/libraries’
else:
libraries_path_prefix = os.path.dirname(SDK_ROOT) + ‘/libraries’

SDK_LIB = libraries_path_prefix
Export(‘SDK_LIB’)

prepare building environment

objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False)

gd32_library = ‘GD32F4xx_Firmware_Library’
rtconfig.BSP_LIBRARY_TYPE = gd32_library

include libraries

objs.extend(SConscript(os.path.join(libraries_path_prefix, gd32_library, ‘SConscript’)))

include drivers

objs.extend(SConscript(os.path.join(libraries_path_prefix, ‘Drivers’, ‘SConscript’)))

make a building

DoBuilding(TARGET, objs)


该文件用于链接所有的依赖文件,并调用make进行编译。


**3.修改开发环境信息**


bsp/gd32/gd32407v-start/cconfig.h修改后的内容如下:



#ifndef CCONFIG_H__
#define CCONFIG_H__
/* Automatically generated file; DO NOT EDIT. /
/
compiler configure file for RT-Thread in GCC*/

#define HAVE_NEWLIB_H 1
#define LIBC_VERSION “newlib 2.4.0”

#define HAVE_SYS_SIGNAL_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_PTHREAD_H 1

#define HAVE_FDSET 1
#define HAVE_SIGACTION 1
#define GCC_VERSION_STR “5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]”
#define STDC “2011”

#endif


该文件是是编译BSP的环境信息,需根据实时修改。


**4.修改KEIL的模板工程**


双击:template.uvprojx即可修改模板工程。


修改为对应芯片设备:


![img](https://img-blog.csdnimg.cn/img_convert/d5b6baf2eb79a1768f7eab95828c978b.jpeg)


修改FLASH和RAM的配置:


![img](https://img-blog.csdnimg.cn/img_convert/fe5dee9d08ed88f8ca1fe981bb44b872.jpeg)


修改可执行文件名字:


![img](https://img-blog.csdnimg.cn/img_convert/bc909d1a1323f435f0796aaea6ed6608.jpeg)


修改默认调试工具:CMSIS-DAP Debugger。


![img](https://img-blog.csdnimg.cn/img_convert/6d8215dd75b22b055231fa527a926444.jpeg)


修改编程算法:GD32F4xx FMC。


![img](https://img-blog.csdnimg.cn/img_convert/be26aae5bd9d0facc6ba21e990d676a7.jpeg)


**5.修改board文件夹**


(1) 修改bsp/gd32/gd32407v-start/board/linker\_scripts/link.icf


修改后的内容如下:



/###ICF### Section handled by ICF editor, don’t touch! /
/
-Editor annotation file-
/
/
IcfEditorFile=“ T O O L K I T D I R TOOLKIT_DIR TOOLKITDIR\config\ide\IcfEditor\cortex_v1_0.xml” /
/
-Specials-
/
define symbol ICFEDIT_intvec_start = 0x08000000;
/
-Memory Regions-/
define symbol ICFEDIT_region_ROM_start = 0x08000000;
define symbol ICFEDIT_region_ROM_end = 0x082FFFFF;
define symbol ICFEDIT_region_RAM_start = 0x20000000;
define symbol ICFEDIT_region_RAM_end = 0x2002FFFF;
/
-Sizes-/
define symbol ICFEDIT_size_cstack = 0x2000;
define symbol ICFEDIT_size_heap = 0x2000;
/
*** End of ICF editor section. ###ICF###*/

export symbol ICFEDIT_region_RAM_end;

define symbol region_RAM1_start = 0x10000000;
define symbol region_RAM1_end = 0x1000FFFF;

define memory mem with size = 4G;
define region ROM_region = mem:[from ICFEDIT_region_ROM_start to ICFEDIT_region_ROM_end];
define region RAM_region = mem:[from ICFEDIT_region_RAM_start to ICFEDIT_region_RAM_end];
define region RAM1_region = mem:[from region_RAM1_start to region_RAM1_end];

define block CSTACK with alignment = 8, size = ICFEDIT_size_cstack { };
define block HEAP with alignment = 8, size = ICFEDIT_size_heap { };

initialize by copy { readwrite };
do not initialize { section .noinit };

keep { section FSymTab };
keep { section VSymTab };
keep { section .rti_fn* };
place at address mem:ICFEDIT_intvec_start { readonly section .intvec };

place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK, block HEAP };
place in RAM1_region { section .sram };


该文件是IAR编译的链接脚本,根据《GD32F407xx\_Datasheet\_Rev2.1》可知,GD32F407VKT6的flash大小为3072KB,SRAM大小为192KB,因此需要设置ROM和RAM的起始地址和堆栈大小等。


(2) 修改bsp/gd32/gd32407v-start/board/linker\_scripts/link.ld


修改后的内容如下:



/* Program Entry, set to mark it as “used” and avoid gc /
MEMORY
{
CODE (rx) : ORIGIN = 0x08000000, LENGTH = 3072k /
3072KB flash /
DATA (rw) : ORIGIN = 0x20000000, LENGTH = 192k /
192KB sram */
}
ENTRY(Reset_Handler)
_system_stack_size = 0x200;

SECTIONS
{
.text :
{
. = ALIGN(4);
_stext = .;
KEEP((.isr_vector)) / Startup code */
. = ALIGN(4);
(.text) / remaining code /
(.text.) /
remaining code */
(.rodata) / read-only data (constants) */
(.rodata)
*(.glue_7)
*(.glue_7t)
(.gnu.linkonce.t)

/* section information for finsh shell /
. = ALIGN(4);
__fsymtab_start = .;
KEEP(
(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);

/* section information for initial. /
. = ALIGN(4);
__rt_init_start = .;
KEEP(
(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);

. = ALIGN(4);
_etext = .;
} > CODE = 0

/* .ARM.exidx is sorted, so has to go in its own output section. /
__exidx_start = .;
.ARM.exidx :
{
(.ARM.exidx .gnu.linkonce.armexidx.
)

/* This is used by the startup in order to initialize the .data secion */
_sidata = .;
} > CODE
__exidx_end = .;

/* .data section which is used for initialized data */

.data : AT (_sidata)
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_sdata = . ;

*(.data)
(.data.)
(.gnu.linkonce.d)

. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_edata = . ;
} >DATA

.stack :
{
. = . + _system_stack_size;
. = ALIGN(4);
_estack = .;
} >DATA

__bss_start = .;
.bss :
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .;

*(.bss)
(.bss.)
*(COMMON)

. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_ebss = . ;

*(.bss.init)
} > DATA
__bss_end = .;

_end = .;

/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { (.comment) }
/
DWARF debug sections.

  • Symbols in the DWARF debugging sections are relative to the beginning
  • of the section so we begin them at 0. /
    /
    DWARF 1 */
    .debug 0 : { *(.debug) }
    .line 0 : { (.line) }
    /
    GNU DWARF 1 extensions */
    .debug_srcinfo 0 : { *(.debug_srcinfo) }
    .debug_sfnames 0 : { (.debug_sfnames) }
    /
    DWARF 1.1 and DWARF 2 */
    .debug_aranges 0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { (.debug_pubnames) }
    /
    DWARF 2 */
    .debug_info 0 : { (.debug_info .gnu.linkonce.wi.) }
    .debug_abbrev 0 : { *(.debug_abbrev) }
    .debug_line 0 : { *(.debug_line) }
    .debug_frame 0 : { *(.debug_frame) }
    .debug_str 0 : { *(.debug_str) }
    .debug_loc 0 : { *(.debug_loc) }
    .debug_macinfo 0 : { (.debug_macinfo) }
    /
    SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames 0 : { *(.debug_varnames) }
    }

该文件是GCC编译的链接脚本,根据《GD32F407xx\_Datasheet\_Rev2.1》可知,GD32F407VKT6的flash大小为3072KB,SRAM大小为192KB,因此CODE和DATA 的LENGTH分别设置为3072KB和192KB,其他芯片类似,但其实地址都是一样的。


(3) 修改bsp/gd32/gd32407v-start/board/linker\_scripts/link.sct


该文件是MDK的连接脚本,根据《GD32F407xx\_Datasheet\_Rev2.1》手册,因此需要将 LR\_IROM1 和 ER\_IROM1 的参数设置为 0x00300000;RAM 的大小为192k,因此需要将 RW\_IRAM1 的参数设置为 0x00030000。



; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00300000 { ; load region size_region
ER_IROM1 0x08000000 0x00300000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00030000 { ; RW data
.ANY (+RW +ZI)
}
}


(4) 修改bsp/gd32/gd32407v-start/board/board.h文件


修改后内容如下:



#ifndef BOARD_H
#define BOARD_H

#include “gd32f4xx.h”
#include “drv_usart.h”
#include “drv_gpio.h”

#include “gd32f4xx_exti.h”

#define EXT_SDRAM_BEGIN (0xC0000000U) /* the begining address of external SDRAM /
#define EXT_SDRAM_END (EXT_SDRAM_BEGIN + (32U * 1024 * 1024)) /
the end address of external SDRAM */

// Internal SRAM memory size[Kbytes] <8-64>
// Default: 64
#ifdef ICCARM
// Use *.icf ram symbal, to avoid hardcode.
extern char ICFEDIT_region_RAM_end;
#define GD32_SRAM_END &ICFEDIT_region_RAM_end
#else
#define GD32_SRAM_SIZE 192
#define GD32_SRAM_END (0x20000000 + GD32_SRAM_SIZE * 1024)
#endif

#ifdef __CC_ARM
extern int Image R W I R A M 1 RW_IRAM1 RWIRAM1ZIKaTeX parse error: Expected 'EOF', got '#' at position 8: Limit; #̲define HEAP_BEG…RW_IRAM1 Z I ZI ZILimit)
#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 GD32_SRAM_END

#endif


值得注意的是,不同的编译器规定的堆栈内存的起始地址 HEAP\_BEGIN 和结束地址 HEAP\_END。这里 HEAP\_BEGIN 和 HEAP\_END 的值需要和前面的链接脚本是一致的,需要结合实际去修改。


(5) 修改bsp/gd32/gd32407v-start/board/board.c文件


修改后的文件如下:



#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include <board.h>

/**

  • @brief This function is executed in case of error occurrence.
  • @param None
  • @retval None
    /
    void Error_Handler(void)
    {
    /
    USER CODE BEGIN Error_Handler /
    /
    User can add his own implementation to report the HAL error return state /
    while (1)
    {
    }
    /
    USER CODE END Error_Handler */
    }

/** System Clock Configuration
*/
void SystemClock_Config(void)
{
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
NVIC_SetPriority(SysTick_IRQn, 0);
}

/**

  • This is the timer interrupt service routine.

/
void SysTick_Handler(void)
{
/
enter interrupt */
rt_interrupt_enter();

rt_tick_increase();

/* leave interrupt */
rt_interrupt_leave();
}

/**

  • This function will initial GD32 board.
    /
    void rt_hw_board_init()
    {
    /
    NVIC Configuration /
    #define NVIC_VTOR_MASK 0x3FFFFF80
    #ifdef VECT_TAB_RAM
    /
    Set the Vector Table base location at 0x10000000 /
    SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK);
    #else /
    VECT_TAB_FLASH /
    /
    Set the Vector Table base location at 0x08000000 */
    SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);
    #endif

SystemClock_Config();

#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif

#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

#ifdef BSP_USING_SDRAM
rt_system_heap_init((void *)EXT_SDRAM_BEGIN, (void *)EXT_SDRAM_END);
#else
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
}


该文件重点关注的就是SystemClock\_Config配置,SystemCoreClock的定义在system\_gd32f4xx.c中定义的。


(6) 修改bsp/gd32/gd32407v-start/board/Kconfig文件


修改后内容如下:



menu “Hardware Drivers Config”

config SOC_GD32407V
bool
select SOC_SERIES_GD32F4
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN
default y

menu “Onboard Peripheral Drivers”

endmenu

menu “On-chip Peripheral Drivers”

config BSP_USING_GPIO
bool “Enable GPIO”
select RT_USING_PIN
default y

menuconfig BSP_USING_UART
bool “Enable UART”
default y
select RT_USING_SERIAL
if BSP_USING_UART
config BSP_USING_UART1
bool “Enable UART1”
default y

config BSP_UART1_RX_USING_DMA
bool “Enable UART1 RX DMA”
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
default n
endif

menuconfig BSP_USING_SPI
bool “Enable SPI BUS”
default n
select RT_USING_SPI
if BSP_USING_SPI
config BSP_USING_SPI1
bool “Enable SPI1 BUS”
default n

config BSP_SPI1_TX_USING_DMA
bool “Enable SPI1 TX DMA”
depends on BSP_USING_SPI1
default n

config BSP_SPI1_RX_USING_DMA
bool “Enable SPI1 RX DMA”
depends on BSP_USING_SPI1
select BSP_SPI1_TX_USING_DMA
default n
endif

menuconfig BSP_USING_I2C1
bool “Enable I2C1 BUS (software simulation)”
default n
select RT_USING_I2C
select RT_USING_I2C_BITOPS
select RT_USING_PIN
if BSP_USING_I2C1
config BSP_I2C1_SCL_PIN
int “i2c1 scl pin number”
range 1 216
default 24
config BSP_I2C1_SDA_PIN
int “I2C1 sda pin number”
range 1 216
default 25
endif
source “…/libraries/gd32_drivers/Kconfig”

endmenu

menu “Board extended module Drivers”

endmenu

endmenu


这个文件就是配置板子驱动的,这里可根据实际需求添加。


(7) 修改bsp/gd32/gd32407v-start/board/SConscript文件


修改后内容如下:



import os
import rtconfig
from building import *

Import(‘SDK_LIB’)

cwd = GetCurrentDir()

add general drivers

src = Split(‘’’
board.c
‘’')

path = [cwd]

startup_path_prefix = SDK_LIB

if rtconfig.CROSS_TOOL == ‘gcc’:
src += [startup_path_prefix + ‘/GD32F4xx_Firmware_Library/CMSIS/GD/GD32F4xx/Source/GCC/startup_gd32f4xx.s’]
elif rtconfig.CROSS_TOOL == ‘keil’:
src += [startup_path_prefix + ‘/GD32F4xx_Firmware_Library/CMSIS/GD/GD32F4xx/Source/ARM/startup_gd32f4xx.s’]
elif rtconfig.CROSS_TOOL == ‘iar’:
src += [startup_path_prefix + ‘/GD32F4xx_Firmware_Library/CMSIS/GD/GD32F4xx/Source/IAR/startup_gd32f4xx.s’]

CPPDEFINES = [‘GD32F407’]
group = DefineGroup(‘Drivers’, src, depend = [‘’], CPPPATH = path, CPPDEFINES = CPPDEFINES)

Return(‘group’)


该文件主要添加board文件夹的.c文件和头文件路径。另外根据开发环境选择相应的汇编文件,和前面的libraries的SConscript语法是一样,文件的结构都是类似的,这里就没有注释了。


到这里,基本所有的依赖脚本都配置完成了,接下来将通过menuconfig配置工程。


6\*\*.menuconfig配置\*\*


关闭套接字抽象层。


![img](https://img-blog.csdnimg.cn/img_convert/aca37c3a7c4bba4046cb1476d904621e.png)


关闭网络设备接口。


![img](https://img-blog.csdnimg.cn/img_convert/5d70e4e99663a8b977ef6761b8615f26.png)


关闭LWIP协议栈。


![img](https://img-blog.csdnimg.cn/img_convert/d679a2404bff383a96413b928c92fb79.jpeg)


GD32407V-START板载没有以太网,因此这里主要是关闭网络相关的内容,当然GD32407V-START的资源丰富,不关这些其实也不影响,如果是其他MCU,根据实际需求自行修改吧。


**7.驱动修改**


一个基本的BSP中,串口是必不可少的,所以还需要编写串口驱动,这里使用的串口2作为调试串口。


板子上还有LED灯,主要要编写GPIO驱动即可。


关于串口和LED的驱动可以查看源码,这里就不贴出来了。


**8.应用开发**


笔者在applications的main.c中添加LED的应用代码,



#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

/* defined the LED2 pin: PC6 */
#define LED2_PIN GET_PIN(C, 6)

int main(void)
{
int count = 1;

/* set LED2 pin mode to output */
rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);

while (count++)
{
rt_pin_write(LED2_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED2_PIN, PIN_LOW);
rt_thread_mdelay(500);
}

return RT_EOK;
}


当然,这需要GPIO驱动的支持。


**9.使用ENV编译工程**


在env中执行:scons


![img](https://img-blog.csdnimg.cn/img_convert/958d39fe68eba9c36d5e3ddb5f73ae99.png)


编译成功打印信息如下:


![img](https://img-blog.csdnimg.cn/img_convert/c650a9d34336dad03ec2c7cf56d7249d.png)


**10.使用env生成MDK工程**


在env中执行:scons --target=mdk5


![img](https://img-blog.csdnimg.cn/img_convert/ae8dbb6feab220150a79218df8733a7a.jpeg)


生成MDK工程后,打开MDK工程进行编译


![img](https://img-blog.csdnimg.cn/img_convert/1e69ef5811ff6c65f3e22582a63f6000.png)


成功编译打印信息如下:


![img](https://img-blog.csdnimg.cn/img_convert/f03d3f3fe04fc73e8c2abdf6ab8ca511.png)


【注】笔者没有IAR环境,有兴趣的朋友自行去开发吧。


#### 2.3使用GD-Link 下载调试GD32


前面使用ENV和MDK成功编译可BSP,那么接下来就是下载调试环节,下载需要下载器,而GD32部分开发板自带GD-link,可以用开发板上自带的GD-link调试仿真代码,不带的可外接GD-link模块,还是很方便的。具体操作方法如下。


1.第一次使用GD-link插入电脑后,会自动安装驱动。


在Options for Target -> Debug 中选择“CMSIS-DAP Debugger”,部分客户反馈找不到这一驱动器选项,那是因为MDK版本过低,只有Keil4.74以上的版本和Keil5才支持CMSIS-DAP Debugger选项。


![img](https://img-blog.csdnimg.cn/img_convert/79bc01fe51b7d1d04677f5ec77122559.jpeg)


2.在Options for Target -> Debug ->Settings勾选SWJ、 Port选择 SW。右框IDcode会出现”0xXBAXXXXX”。


![img](https://img-blog.csdnimg.cn/img_convert/9b331da678e17c8e37c1f243b3e3519b.jpeg)


3.在Options for Target -> Debug ->Settings -> Flash Download中添加GD32的flash算法。


![img](https://img-blog.csdnimg.cn/img_convert/90fe203146910e8b845269851ae6aade.jpeg)


4.单击下图的快捷方式“debug”, 即可使用GD-Link进行仿真。


![img](https://img-blog.csdnimg.cn/img_convert/a417a7de3101c83360ddff1d7fdd5a42.jpeg)


当然啦,也可使用GD-Link下载程序。


![img](https://img-blog.csdnimg.cn/img_convert/e1e6ff01a18b9d8e2e02186094bf9487.png)


下载程序成功后,打印信息如下:


![img](https://img-blog.csdnimg.cn/img_convert/220bc2dbec03a02a206e45842a716ae1.jpeg)


接上串口,打印信息如下:


![img](https://img-blog.csdnimg.cn/img_convert/22e2630692e3f14102c33daa13c91fe3.jpeg)


同时LED会不断闪烁。


#### 2.4 RT-Thread studio开发


当然,该工程也可导出使用rt-thread studio开发。


先使用scons --dist导出工程。


![img](https://img-blog.csdnimg.cn/img_convert/f616b2337fe753ed004d20265641c838.jpeg)


再将工程导入rt-thread studio中


![img](https://img-blog.csdnimg.cn/img_convert/543b08d57bc9b7f8a7c055fa6a8a6f5c.jpeg)


最后,就可在rt-thread studio就可进行开发工作了。


![img](https://img-blog.csdnimg.cn/img_convert/909e59db383f813fe2eb0481d493769e.jpeg)


当然啦,后面也可在rt-thread studio中新建工程时选择笔者提交的GD32407V-START的BSP。


关于BSP的移植就到这里了,当然还有很多内容,这里只是抛砖引玉。最后希望更多的朋友加入进来,为国产RTOS贡献自己的力量吧。


GD32 BSP: [https://gitee.com/ouxiaolong/GD32\_RT-Thread]( )


RT-Thread :[https://github.com/Ouxiaolong/rt-thread/tree/master/bsp/gd32]( )


## 六、RT-Thread官方的移植方法


### STM32系列驱动介绍


在 RT-Thread 实时操作系统中,各种各样的设备驱动是通过一套 I/O 设备管理框架来管理的。设备管理框架给上层应用提供了一套标准的设备操作 API,开发者通过调用这些标准设备操作 API,可以高效地完成和底层硬件外设的交互。设备管理框架的结构如下图所示:


![rt_device](https://img-blog.csdnimg.cn/img_convert/925c58852ce963c818ca846093aee346.png)


使用 I/O 设备管理框架开发应用程序,有如下优点:


* 使用同一套标准的 API 开发应用程序,使应用程序具有更好的移植性
* 底层驱动的升级和修改不会影响到上层代码
* 驱动和应用程序相互独立,方便多个开发者协同开发


### [1. 驱动分类介绍]( )


本小节介绍 BSP 提供的不同类别驱动的概念,对一个 BSP 而言,有如下三类驱动:


* **板载外设驱动**:指 MCU 之外,开发板上外设,例如 TF 卡、以太网和 LCD 等
* **片上外设驱动**:指 MCU 芯片上的外设,例如硬件定时器、ADC 和看门狗等
* **扩展模块驱动**:指可以通过扩展接口或者杜邦线连接的开发板的模块,例如 ESP8266 模块


这三种外设的示意图如下所示:


![Peripheral](https://img-blog.csdnimg.cn/img_convert/7809461d128a6258e0aa6ba379a3e27a.png)


### [2. 外设驱动的使用方法]( )


当前 RT-Thread 提供的驱动库已经支持 STM32 多个系列的 BSP。点击下表中的驱动名称,即可跳转到对应驱动框架的介绍文档。开发者可以通过阅读相关资料,了解如何在应用开发中通过设备驱动框架来使用这些外设驱动。


#### [2.1 片上外设]( )




| 序号 | 驱动 | 简介 |
| --- | --- | --- |
| 1 | [GPIO]( ) | 操作 GPIO 管脚 |
| 2 | [UART]( ) | 通过串口收发数据 |
| 3 | [soft I2C]( ) | 通过软件 I2C 收发数据 |
| 4 | [SPI]( ) | 通过 SPI 收发数据 |
| 5 | [ADC]( ) | 测量管脚上的模拟量 |
| 6 | SDIO | 通过 SDIO 读写数据 |
| 7 | [TIMER]( ) | 使用硬件定时器实现测量时间和定时执行回调函数功能 |
| 8 | [PWM]( ) | 在特定的管脚输出 PWM 波形 |
| 9 | [RTC]( ) | 设置和读取时间 |
| 10 | [WDT]( ) | 看门狗驱动 |
| 11 | [QSPI]( ) | 通过 SPI(1、2、4线) 收发数据 |


#### [2.2 板载外设]( )




| 序号 | 驱动 | 简介 |
| --- | --- | --- |
| 1 | SD | 适用于 SPI 接口或 SDIO 接口的 SD(TF) 卡 |
| 2 | ETH PHY | 以太网 |
| 3 | USB PHY | USB |
| 4 | LCD | 显示屏 |


#### [2.3 扩展模块]( )




| 序号 | 驱动 | 简介 |
| --- | --- | --- |
| 1 | ESP8266 | 串口转 WIFI 模块 |
| 2 | ENC28J60 | SPI 接口的以太网控制器 |


#### [2.4 驱动示例代码]( )


在 RT-Thread 的 `examples\test` 目录下,有 RT-Thread 提供的基于不同外设驱动的示例代码。在 env 工具中开启 BSP 中要测试的驱动,并将 `examples\test` 中对应的驱动框架测试文件加入工程,即可快速测试 BSP 中提供的驱动。


### STM32 系列 BSP 制作教程


已剪辑自: <https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/STM32%E7%B3%BB%E5%88%97BSP%E5%88%B6%E4%BD%9C%E6%95%99%E7%A8%8B>


为了让广大开发者更好、更方便地使用 BSP 进行开发,RT-Thread 开发团队重新整理了现有的 STM32 系列的 BSP,推出了新的 BSP 框架。新的 BSP 框架在易用性、移植便利性、驱动完整性、代码规范性等方面都有较大提升,在新的 BSP 框架下进行开发,可以大大提高应用的开发效率。


和 RT-Thread 以往提供的 BSP 不同,在新的 BSP 文件夹中将不会包含固件库、外设驱动等可以被多个 BSP 引用的代码文件。而是将这些通用的文件统一存放在 Library 文件夹中,通过在特定 BSP 中引用这些文件的方式,来包含 BSP 中所需的库文件或者驱动文件。这种方式不仅大大提高了代码复用率,降低了 BSP 的维护成本,而且可以更方便地给开发者提供更丰富的驱动文件,让开发者可以更容易地找到自己需要的资源。


新的 BSP 框架还引入了 CubeMX 工具,可以使用该工具来对 BSP 中使用的外设引脚进行配置。CubeMX 工具提供了图形化的配置界面,这种图形化的配置方式对开发者来说更加直观,不仅可以让开发者灵活地配置 BSP 中使用的资源,并且可以让开发者对资源的使用情况一目了然。


新 BSP 框架的主要特性如下:


* 提供多系列 BSP 模板,大大降低新 BSP 的添加难度;
* 每个 BSP 都配有齐全的驱动文件,开发者可以方便地使用所有驱动;
* 开发者可以使用 CubeMX 工具对 BSP 进行图形化配置;


### [1. BSP 框架介绍]( )


BSP 框架结构如下图所示:


![BSP 框架图](https://img-blog.csdnimg.cn/img_convert/b79cf5ea32c9b796f0cfb3e699871abc.png)


每一个 STM32 系列的 BSP 由三部分组成,分别是通用库、BSP 模板和特定开发板 BSP,下面的表格以 F1 系列 BSP 为例介绍这三个部分:


项目 文件夹 说明




|  |  |  |
| --- | --- | --- |
| 通用库 | stm32/libraries | 用于存放 HAL 库以及基于 HAL 库的多系列通用外设驱动文件 |
| F1 系列 BSP 工程模板 | stm32/libraries/templates/stm32f10x | F1系列 BSP 模板,可以通过修改该模板制作更多 F1系列 BSP |
| 特定开发板 BSP | stm32/stm32f103-atk-nano | 在 BSP 模板的基础上修改而成 |


### [2. 知识准备]( )


制作一个 BSP 的过程就是构建一个新系统的过程,因此想要制作出好用的 BSP,要对 RT-Thread 系统的构建过程有一定了解,需要的知识准备如下所示:


* 掌握 STM32 系列 BSP 的使用方法

 了解 BSP 的使用方法,可以阅读 [BSP 说明文档]( ) 中使用教程表格内的文档。了解外设驱动的添加方法可以参考《外设驱动添加指南》。
* 了解 Scons 工程构建方法

 RT-Thread 使用 Scons 作为系统的构建工具,因此了解 Scons 的常用命令对制作新 BSP 是基本要求。
* 了解设备驱动框架

 在 RT-Thread 系统中,应用程序通过设备驱动框架来操作硬件,因此了解设备驱动框架,对添加 BSP 驱动是很重要的。
* 了解 Kconfig 语法

 RT-Thread 系统通过 menuconfig 的方式进行配置,而 menuconfig 中的选项是由 Kconfig 文件决定的,因此想要对 RT-Thread 系统进行配置,需要对 kconfig 语法有一定了解。
* 熟悉 CubeMX 工具的使用

 在新的 STM32 系列 BSP 中利用了 CubeMX 工具对底层硬件进行配置,因此需要了解 CubeMX 工具的使用方法。


### [3. BSP 制作方法]( )


本节以制作正点原子 `stm32f103-atk-nano` 开发板的 BSP 为例,讲解如何为一个新的开发板添加 BSP。


BSP 的制作过程分为如下五个步骤:


1. 复制通用模板
2. 使用 CubeMX 工具配置工程
3. 修改 BSP 中的 Kconfig 文件
4. 修改构建工程相关文件
5. 重新生成工程


在接下来的章节中将会详细介绍这五个步骤,帮助开发者快速创建所需要的 BSP。


#### [3.1 复制通用模板]( )


制作新 BSP 的第一步是复制一份同系列的 BSP 模板作为基础,通过对 BSP 模板的修改来获得新 BSP。目前提供的 BSP 模板系列如下表所示:


工程模板 说明




|  |  |
| --- | --- |
| libraries/templates/stm32f0xx | F0 系列 BSP 模板 |
| libraries/templates/stm32f10x | F1 系列 BSP 模板 |
| libraries/templates/stm32f4xx | F4 系列 BSP 模板 |
| libraries/templates/stm32f7xx | F7 系列 BSP 模板 |
| libraries/templates/stm32l4xx | L4 系列 BSP 模板 |


本次示例所用的 F1 系列 BSP 模板文件夹结构如下所示:


![F1 系列 BSP 模板文件夹内容](https://img-blog.csdnimg.cn/img_convert/4ec01e2bffde01bd6c09537542299200.png)


本次制作的 BSP 为 F1 系列,因此拷贝模板文件夹下的 `stm32f10x` 文件夹,并将该文件夹的名称改为 `stm32f103-atk-nano` ,如下图所示:


![复制通用模板](https://img-blog.csdnimg.cn/img_convert/12fa852d1d304aa54b7015edde166e72.png)


在接下来的 BSP 的制作过程中,将会修改 board 文件夹内的配置文件,将 F1 系列的 BSP 模板变成一个适用于正点原子 `stm32f103-atk-nano` 开发板的 BSP ,下表总结了 board 文件夹中需要修改的内容:


项目 需要修改的内容说明




|  |  |
| --- | --- |
| CubeMX\_Config (文件夹) | CubeMX 工程 |
| linker\_scripts (文件夹) | BSP 特定的链接脚本 |
| board.c/h | 系统时钟、GPIO 初始化函数、芯片存储器大小 |
| Kconfig | 芯片型号、系列、外设资源 |
| SConscript | 芯片启动文件、目标芯片型号 |


#### [3.2 使用 CubeMX 配置工程]( )


在制作 BSP 的第二步,需要创建一个基于目标芯片的 CubeMX 工程。默认的 CubeMX 工程在 **CubeMX\_Config** 文件夹中,双击打开 `CubeMX_Config.ioc` 工程,如下图所示:


![open_cubemx](https://img-blog.csdnimg.cn/img_convert/c7f3c11912aeb57a76e1d20b64f30ac0.png)


在 CubeMX 工程中将芯片型号为修改芯片型号为 STM32F103RBTx 。


##### [3.2.1 生成 CubeMX 工程]( )


配置系统时钟、外设引脚等,步骤如下图所示:


1. 打开外部时钟、设置下载方式、打开串口外设(注意只需要选择串口外设引脚即可,无需配置其他参数):


![配置芯片引脚](https://img-blog.csdnimg.cn/img_convert/7f4cd69056307d569e5dcd2d7e643643.png)


1. 配置系统时钟:


![配置系统时钟](https://img-blog.csdnimg.cn/img_convert/0ded2249b9920b2b01cc77d539e7753e.png)


1. 设置项目名称,并在指定地址重新生成 CubeMX 工程:


![生成对应的配置代码](https://img-blog.csdnimg.cn/img_convert/917ed19e13133766647a167e73fefe96.png)


注意:在生成代码时,不要勾选以下选项(即:不让其生成单独的 .c/.h 驱动文件,直接全部更新到 rt-thread 要使用的 stm32xxx\_hal\_msp.c 文件中)


![generate-code](https://img-blog.csdnimg.cn/img_convert/9832ce30257e6a6e8368726d17f58f7c.png)


最终 CubeMX 生成的工程目录结构如下图所示:


![CubeMX 图7](https://img-blog.csdnimg.cn/img_convert/74edea1764462ebae9b3a213c92a4cc9.png)


##### [3.2.2 拷贝初始化函数]( )


在 **board.c** 文件中存放了函数 `SystemClock_Config()` ,该函数负责初始化系统时钟。当使用 CubeMX 工具对系统时钟重新配置的时候,需要更新这个函数。


该函数由 CubeMX 工具生成,默认存放在`board/CubeMX_Config/Src/main.c` 文件中。但是该文件并没有被包含到我们的工程中,因此需要将这个函数从 main.c 中拷贝到 board.c 文件中。在整个 BSP 的制作过程中,这个函数是唯一要拷贝的函数,该函数内容如下所示:


![board_1](https://img-blog.csdnimg.cn/img_convert/328f1229efae7fd7dfd50882a399e3b4.png)


在 **board.h** 文件中配置了 FLASH 和 RAM 的相关参数,这个文件中需要修改的是 `STM32_FLASH_SIZE` 和 `STM32_SRAM_SIZE` 这两个宏控制的参数。本次制作的 BSP 所用的 STM32F103RBTx 芯片的 flash 大小为 128k,ram 的大小为 20k,因此对该文件作出如下的修改:


![修改 board.h](https://img-blog.csdnimg.cn/img_convert/ab1155739854821b90bb6b2c265b56f0.png)


##### [3.2.3 堆内存配置讲解]( )


通常情况下,系统 RAM 中的一部分内存空间会被用作堆内存。下面代码的作用是,在不同编译器下规定堆内存的起始地址 **HEAP\_BEGIN** 和结束地址 **HEAP\_END**。这里 **HEAP\_BEGIN** 和 **HEAP\_END** 的值需要和后面 [3.4.1 修改链接脚本](# 3.4.1 修改链接脚本) 章节所修改的配置相一致。


在某些系列的芯片中,芯片 RAM 可能分布在不连续的多块内存区域上。此时堆内存的位置可以和系统内存在同一片连续的内存区域,也可以存放在一片独立的内存区域中。例如在 L4 系列的芯片上,就可以将堆内存配置在起始地址为 `0x20000000` 的大小为 96k 的内存空间,而将 `0x10000000` 开始的 32k 内存空间用作系统运行内存。


![heap_config](https://img-blog.csdnimg.cn/img_convert/21cf980e81bd8e284e8c8ce607dced99.png)


#### [3.3 修改 Kconfig 选项]( )


在本小节中修改 `board/Kconfig` 文件的内容有如下两点:


* 芯片型号和系列
* BSP 上的外设支持选项


芯片型号和系列的修改如下表所示:


宏定义 意义 格式




|  |  |  |
| --- | --- | --- |
| SOC\_STM32F103RB | 芯片型号 | SOC\_STM32xxx |
| SOC\_SERIES\_STM32F1 | 芯片系列 | SOC\_SERIES\_STM32xx |


关于 BSP 上的外设支持选项,一个初次提交的 BSP 仅仅需要支持 GPIO 驱动和串口驱动即可,因此在配置选项中只需保留这两个驱动配置项,如下图所示:


![修改 Kconfig](https://img-blog.csdnimg.cn/img_convert/fe2664bd07bc16edb3aa0f60e4168af5.png)


#### [3.4 修改工程构建相关文件]( )


接下来需要修改用于构建工程相关的文件。


##### [3.4.1 修改链接脚本]( )


**linker\_scripts** 链接文件如下图所示:


![需要修改的链接脚本](https://img-blog.csdnimg.cn/img_convert/891863649355a30e3a4c68ee72bded54.png)


下面以 MDK 使用的链接脚本 link.sct 为例,演示如何修改链接脚本:


![linkscripts_change](https://img-blog.csdnimg.cn/img_convert/c9c3dff99dcecbe2f03cac9e669a6a36.png)


本次制作 BSP 使用的芯片为 STM32F103RB,FLASH 为 128k,因此修改 LR\_IROM1 和 ER\_IROM1 的参数为 0x00020000。RAM 的大小为20k, 因此修改 RW\_IRAM1 的参数为 0x00005000。这样的修改方式在一般的应用下就够用了,后续如果有特殊要求,则需要按照链接脚本的语法来根据需求修改。修改链接脚本时,可以参考 [**3.2.3 堆内存配置讲解**](# 3.2.3 堆内存配置讲解) 章节来确定 BSP 的内存分配。


其他两个链接脚本的文件分别为 IAR 使用的 link.icf 和 gcc 编译器使用的 link.lds,修改的方式也是类似的,如下图所示:


* link.icf 修改内容

 ![link_icf](https://img-blog.csdnimg.cn/img_convert/4ab0149da704db111c6d18f1444ee999.png)
* link.lds 修改内容

 ![link_lds](https://img-blog.csdnimg.cn/img_convert/56e2ab96c8762310ef0ed03414aee9b2.png)


##### [3.4.2 修改构建脚本]( )


**SConscript** 脚本决定 MDK/IAR 工程的生成以及编译过程中要添加文件。


在这一步中需要修改芯片型号以及芯片启动文件的地址,修改内容如下图所示:


![修改启动文件和芯片型号](https://img-blog.csdnimg.cn/img_convert/1b4ff1e38bb2e931197d769a7b4cd7a9.png)


注意:如果在文件夹中找不到相应系列的 .s 文件,可能是多个系列的芯片重用了相同的启动文件,此时可以在 CubeMX 中生成目标芯片的工程,查看使用了哪个启动文件,然后再修改启动文件名。


##### [3.4.3 修改工程模板]( )


**template** 文件是生成 MDK/IAR 工程的模板文件,通过修改该文件可以设置工程中使用的芯片型号以及下载方式。MDK4/MDK5/IAR 的工程模板文件,如下图所示:


![MDK/IAR 工程模板](https://img-blog.csdnimg.cn/img_convert/082f439d3523865a32587d2dcb854c0a.png)


下面以 MDK5 模板的修改为例,介绍如何修改模板配置:


![选择芯片型号](https://img-blog.csdnimg.cn/img_convert/ff447a2b951b8cbefaa1101c5c4141c2.png)


修改程序下载方式:


![配置下载方式](https://img-blog.csdnimg.cn/img_convert/f918c8d93228f508e9d2433f4de9ac46.png)


#### [3.5 重新生成工程]( )


重新生成工程需要使用 Env 工具。


在 Env 界面输入命令 menuconfig 对工程进行配置,并生成新的 rtconfig.h 文件。如下图所示:


![输入menuconfig进入配置界面](https://img-blog.csdnimg.cn/img_convert/83f19d1d0f5b2a428aaf9c23e9a66131.png)


![选择要打开的外设](https://img-blog.csdnimg.cn/img_convert/d5fc4e965ddad962e51c2c61c7a4844e.png)


下面以重新生成 MDK 工程为例,介绍如何重新生成 BSP 工程。


使用 env 工具输入命令 `scons --target=mdk5` 重新生成工程,如下图所示:


![重新生成 BSP 工程](https://img-blog.csdnimg.cn/img_convert/3f6ec99a0a66b050b5f51bc0232d8094.png)


重新生成工程成功:


![重新生成 BSP 工程](https://img-blog.csdnimg.cn/img_convert/4abc93d7360a7332892fbbe964c2391b.png)


到这一步为止,新的 BSP 就可以使用了。


接下来我们可以分别使用命令 `scons --target=mdk4` 和 `scons --target=iar`,来更新 MDK4 和 IAR 的工程,使得该 BSP 变成一个完整的,可以提交到 GitHub 的 BSP (MDK4工程的制作为可选)。


感谢每一位贡献代码的开发者,RT-Thread 将与你一同成长。


### [4. 规范]( )


本章节介绍 RT-Thread STM32 系列 BSP 制作与提交时应当遵守的规范 。开发人员在 BSP 制作完成后,可以根据本规范提出的检查点对制作的 BSP 进行检查,确保 BSP 在提交前有较高的质量 。


#### [4.1 BSP 制作规范]( )


STM32 BSP 的制作规范主要分为 3 个方面:工程配置,ENV 配置和 IDE 配置。在已有的 STM32 系列 BSP 的模板中,已经根据下列规范对模板进行配置。在制作新 BSP 的过程中,拷贝模板进行修改时,需要注意的是不要修改这些默认的配置。BSP 制作完成后,需要对新制作的 BSP 进行功能测试,功能正常后再进行代码提交。


下面将详细介绍 BSP 的制作规范。


##### [4.1.1 工程配置]( )


* 遵从RT-Thread 编码规范,代码注释风格统一
* main 函数功能保持一致
	+ 如果有 LED 的话,main 函数里**只放一个** LED 1HZ 闪烁的程序
* 在 `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\_SECOND)
* BSP 中需要打开调试选项中的断言(宏:RT\_DEBUG)
* 系统空闲线程栈大小统一设置为 256(宏:IDLE\_THREAD\_STACK\_SIZE)
* 开启组件自动初始化(宏:RT\_USING\_COMPONENTS\_INIT)
* 需要开启 user main 选项(宏:RT\_USING\_USER\_MAIN)
* FinSH 默认只使用 MSH 模式(宏:FINSH\_USING\_MSH\_ONLY)


##### [4.1.3 IDE 配置]( )


* 使能下载代码后自动运行
* 使能 C99 支持
* 使能 One ELF Section per Function(MDK)
* MDK/IAR 生成的临时文件分别放到build下的 MDK/IAR 文件夹下
* MDK/GCC/IAR 生成 bin 文件名字统一成 rtthread.bin


#### [4.2 BSP 提交规范]( )


* 提交前请认真修改 BSP 的 README.md 文件,README.md 文件的外设支持表单只填写 BSP 支持的外设,可参考其他 BSP 填写。查看文档[《STM32系列驱动介绍》]( )了解驱动分类。
* 提交 BSP 分为 2 个阶段提交:
	+ 第一阶段:基础 BSP 包括串口驱动和 GPIO 驱动,能运行 FinSH 控制台。完成 MDK4、MDK5 、IAR 和 GCC 编译器支持,如果芯片不支持某款编译器(比如MDK4)可以不用做。 BSP 的 README.md 文件需要填写第二阶段要完成的驱动。
	+ 第二阶段:完成板载外设驱动支持,所有板载外设使用 menuconfig 配置后就能直接使用。若开发板没有板载外设,则此阶段可以不用完成。不同的驱动要分开提交,方便 review 和合并。
* 只提交 BSP 必要的文件,删除无关的中间文件,能够提交的文件请对照其他 BSP。
* 提交 STM32 不同系列的 Library 库时,请参考 f1/f4 系列的 HAL 库,删除多余库文件
* 提交前要对 BSP 进行编译测试,确保在不同编译器下编译正常
* 提交前要对 BSP 进行功能测试,确保 BSP 的在提交前符合工程配置章节中的要求


我有疑问: [RT-Thread 官方论坛]( )


### STM32 系列外设驱动添加指南


已剪辑自: <https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/STM32%E7%B3%BB%E5%88%97%E5%A4%96%E8%AE%BE%E9%A9%B1%E5%8A%A8%E6%B7%BB%E5%8A%A0%E6%8C%87%E5%8D%97>


本文档是为需要给现有的 STM32 BSP 添加更多外设驱动的开发者准备的。通过阅读本文,开发者可以按照自己的实际情况给现有 BSP 添加自己需要的驱动。


* 熟练使用 ENV 工具,参考:[RT-Thread env 工具用户手册]( )
* 熟悉 Kconfig 语法
* 熟悉 STM32CubeMX 工具
* 对 RT-Thread 设备驱动框架有一定了解


本章节以添加片上外设驱动为例,讲解如何为 BSP 添加更多可用驱动。如果想使用的片上外设是 `片上外设配置菜单` 里没有的,就需要开发者自己添加了。下面我们将演示如何为 stm32f429-atk-apollo BSP 添加 SPI3 驱动。


没有安装 stm32cubemx 软件的可以访问 STM32cube中文网:http://www.stm32cube.com/ ,在 `资源下载` 里下载 stm32cubemx 软件。


阿波罗 BSP 默认只支持 SPI1、SPI2 和 SPI5,是不支持 SPI3 的。开发者如果需要使用 SPI3,则需要自己添加。


![spi_config](https://img-blog.csdnimg.cn/img_convert/da2d262a1ac01bf158ae4c5f8ea94686.png)


添加 SPI3 的外设支持需要以下几步:


#### [1)打开 STM32CubeMX 工程]( )


打开 BSP 的 STM32CubeMX 配置文件。


![1543486779576](https://img-blog.csdnimg.cn/img_convert/6ae5ca2040d57b91a03cf6ae41450d35.png)


按图示顺序配置 SPI3,并生成代码。


![1543487684698](https://img-blog.csdnimg.cn/img_convert/63e5ac057376467029ecbfd75830b5c1.png)


为 BSP 添加驱动时,STM32CubeMX 工具可以快速的完成**使能外设**和**配置管脚**的工作。而外设初始化,中断配置,DMA配置等等则由 RT-Thread 提供的驱动文件来完成。也就是说,虽然 STM32CubeMX 生成了多个文件用来初始化外设,但 RT-Thread 只使用了 STM32CubeMX 生成的 `stm32fxx_hal_msp.c` 文件和 `stm32fxx_hal_conf.h` 文件。


对于不同的外设驱动,通过 STM32CubeMX 工具配置的内容也不一样。开发者可以参考本文档的附录 CubeMX 配置说明章节来了解不同外设的配置方法。


#### [3)修改 Kconfig 文件]( )


打开 board 文件夹下的 Konfig 文件,拷贝 SPI2 的配置项,并重命名 SPI2 为 SPI3。


![1543542657074](https://img-blog.csdnimg.cn/img_convert/fcf59d67f96e5712bd1e8d78bae2183c.png)


经过上一步的修改,此时重新打开 ENV 工具,在 menuconfig 中就会出现添加的 SPI3 的配置项。


![1543543081284](https://img-blog.csdnimg.cn/img_convert/f5fde84122cdb79e169a581f14bfb8b6.png)


使用 ENV 重新生成工程并打开,检查原有驱动文件是否支持新添加的驱动(查看是否有新驱动的配置文件,中断函数,DMA配置和中断函数等等),如不支持,需参考现有驱动添加相关的代码。


![spi_code](https://img-blog.csdnimg.cn/img_convert/3926cad0fab69853de9f9094862d11e7.png)


检查完工程后,编译下载到开发板,程序会自动开始运行。输入 `list_device` 命令,可以看到 spi3 总线已经注册到内核,说明驱动已经添加成功。


![1543543446786](https://img-blog.csdnimg.cn/img_convert/57fc28e050b2c089aa03b30a49ff2c98.png)


* 部分驱动如果没有适配 BSP 所属的 STM32 系列,请等待 RT-Thread 团队更新。
	+ 驱动文件对 STM32 系列的支持情况可以查看 [STM32系列驱动介绍文档]( )。
* 对于驱动文件或文档说明,有任何建议或者意见,欢迎反馈到 [RT\_Thread GitHub]( ) 网站或 [RT-Thread 官方论坛]( )。
* 在生成代码时,不要勾选以下选项(即:不让其生成单独的 .c/.h 驱动文件,直接全部更新到 RT-Thread 要使用的 stm32xxx\_hal\_msp.c 文件中)


![generate-code](https://img-blog.csdnimg.cn/img_convert/9832ce30257e6a6e8368726d17f58f7c.png)


#### [5.1 CubeMX配置说明]( )


本小节介绍 STM32 系列的 BSP 是如何利用 CubeMX 工具对 BSP 进行配置的。


就像文档中提到的那样,STM32 系列的 BSP 只利用了 CubeMX 工具生成的 `stm32XXxx_hal_conf.h` 和 `stm32XXxx_hal_msp.c` 文件。在 HAL 库中, `stm32XXxx_hal_conf.h` 文件里提供的宏开关会决定 HAL 库将哪些外设驱动添加到工程中。 而 `stm32XXxx_hal_msp.c` 文件中则存放了在 CubeMX 工具中开启的外设驱动的配置代码。


#### [5.2 外设配置总结]( )


当开发者想要在 BSP 中添加更多驱动时,需要使用 CubeMX 工具来配置这些外设。对于绝大多数驱动的配置,只需要在工具中使能相应的外设即可。但是对于一些复杂的外设,则需要更多的配置内容。下表展示了不同驱动在 CubeMX 工具配置步骤的总结:


序号 驱动 CubeMx 工程中的配置情况(**加粗部分为必做步骤**)




|  |  |  |
| --- | --- | --- |
| 1 | GPIO | 无需任何操作 |
| 2 | UART | **开启该外设** ,然后配置所需要的引脚(或者使用默认引脚) |
| 3 | SPI | **开启该外设** ,然后配置所需要的引脚(或者使用默认引脚) |
| 4 | I2C | 依赖于PIN 驱动,无需任何操作 |
| 5 | TIMER | **使能 internal Clock 时钟** ,详细内容可参考5.3章节 |
| 7 | PWM | **首先使能 internal Clock 时钟,然后为 channelx 选项选择PWM Generation CHx,** 最后配置所需要的引脚(或者使用默认引脚) ,详细内容可参考5.3章节 |
| 8 | ADC | **开启该外设,然后选择使用的通道** ,详细内容可参考5.3章节 |
| 9 | RTC | **开启该外设,然后在时钟树状图里将 RTC 选择为 LSE 时钟** |
| 10 | Watchdog | **开启该外设** |
| 11 | EMAC | **配置 ETH 外设的工作模式(一般为 RMII 模式)** |
| 12 | SDRAM | **需要根据板载的 SDRAM 型号配置片选脚,地址线,数据线等** |
| 13 | SDIO | **开启该外设,配置引脚(或者使用默认引脚),SDIO会改变时钟结构,故需重新配置时钟并修改board.c** |


#### [5.3 复杂外设配置说明]( )


本章节着重介绍配置步骤较为复杂的驱动。


##### [5.3.1 TIMER 外设驱动添加说明]( )


1. 打开 STM32CubeMX 工程,设置 timer 在 Cube 里的选项,如下图所示:

 ![timer CubeMX 配置](https://img-blog.csdnimg.cn/img_convert/58b72d4eb39023c0697158eb32f5148c.png)
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

 ![timer Kconfig 配置](https://img-blog.csdnimg.cn/img_convert/718a964903ac05d2589bbde9ce17fea9.png)


	1. 打开工程进行编译,工程会提示 TIM11\_CONFIG 未定义。 可以在 stm32/libraries/HAL\_Drivers/config/f4/tim\_config.h 中进行定义,如下图所示:![timer 编译](https://img-blog.csdnimg.cn/img_convert/ec27584041dd45caef67aeaa41cb039e.png)![timer 编译](https://img-blog.csdnimg.cn/img_convert/e7c3e0edaf8133774029a2454b81f1ab.png)


##### [5.3.2 PWM 外设驱动添加说明]( )


1. 打开 STM32CubeMX 工程,设置 PWM 在 Cube 里的选项,如下图所示:

 ![pwm CubeMX 配置](https://img-blog.csdnimg.cn/img_convert/2f9ecaa48ee428650f5d01df69ab3d3c.png)
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

 ![pwm Kconfig 配置](https://img-blog.csdnimg.cn/img_convert/775dbc50ec7fb1a47a4ca0b15bee4f0a.png)
3. 打开工程进行编译,工程会提示 PWM2\_CONFIG 未定义。 可以在 stm32/libraries/HAL\_Drivers/config/f4/pwm\_config.h 中进行定义,如下图所示:

 ![pwm 编译](https://img-blog.csdnimg.cn/img_convert/d98d505122443f684a97c7a4829ef9f0.png)![pwm 编译](https://img-blog.csdnimg.cn/img_convert/098adcb52b5674089e9d09b7bcf1ad2a.png)


##### [5.3.3 ADC 外设驱动添加说明]( )


1. 打开 STM32CubeMX 工程,设置 ADC 在 Cube 里的选项,如下图所示:

 ![adc CubeMX 配置](https://img-blog.csdnimg.cn/img_convert/d3cba4e1391431bf46f0076889c021cb.png)
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

 ![adc Kconfig 配置](https://img-blog.csdnimg.cn/img_convert/05097f2dd5e9b437b1ee77e481ef523a.png)
3. 打开工程进行编译,工程会提示 ADC1\_CONFIG 未定义。 可以在 stm32/libraries/HAL\_Drivers/config/f4/adc\_config.h 中进行定义,如下图所示:

 ![adc 编译](https://img-blog.csdnimg.cn/img_convert/1e1894f3b40f73012a48b9664c33e159.png)![adc 编译](https://img-blog.csdnimg.cn/img_convert/5160aa1c8e4010764bde29c48ff37f3f.png)


##### [5.3.4 编码器外设驱动添加说明]( )


1. 打开 STM32CubeMX 工程,设置 TIMER 在 Cube 里的选项,如下图所示:

 ![pulse_encoder CubeMX 配置](https://img-blog.csdnimg.cn/img_convert/1813f38a0e51825052a2fbde524c4e9f.png)
2. 打开 stm32/stm32f407-atk-explorer/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

 ![pulse_encoder Kconfig 配置](https://img-blog.csdnimg.cn/img_convert/6c48553eb8330182d252338e5530292f.png)
3. 打开工程进行编译,工程会提示 PULSE\_ENCODER4\_CONFIG 未定义。 可以在 stm32/libraries/HAL\_Drivers/config/f4/pulse\_encoder\_config.h 中进行定义,如下图所示:

 ![pulse_encoder 编译](https://img-blog.csdnimg.cn/img_convert/9017b264adea5152f87ced6e30c5833f.png)![pulse_encoder 编译](https://img-blog.csdnimg.cn/img_convert/7c19fd04959a7f7343048808f820cca9.png)


我有疑问: [RT-Thread 官方论坛]( )


## 七、LiteOS移植指南


### 概述


* **[什么是移植,为什么要移植]( )**
* **[指南适用范围]( )**
* **[移植目录结构]( )**


#### 什么是移植,为什么要移植


对于嵌入式设备,由于芯片型号和外设差异较大,且资源有限,所以物联网操作系统无法像 Windows/Linux 那样适配集成所有驱动,因此通常会先适配部分芯片/开发板。为了让操作系统运行在其他芯片/开发板上,此时就需要移植。


开发板的移植包括 CPU架构移植、板级/外设驱动移植和操作系统的移植。


#### 指南适用范围


本指南基于STM32芯片平台,以正点原子STM32F407开发板为例介绍如何快速移植LiteOS,其中并不涉及CPU架构移植。


#### 移植目录结构


表格列出了LiteOS源码的目录,其中加粗字体的目录/文件在移植过程中需要修改。


**表 1** LiteOS源码目录




| 一级目录 | 二级目录/文件 | 说明 |
| --- | --- | --- |
| arch |  | 芯片架构支持 |
| build |  | LiteOS编译系统需要的配置及脚本 |
| compat |  | LiteOS提供的CMSIS-RTOS 1.0和2.0接口 |
| components |  | 组件代码 |
| demos |  | 组件和内核的demo |
| doc |  | LiteOS使用文档 |
| include |  | components中各模块的头文件 |
| kernel |  | 内核代码 |
| lib |  | libc/zlib/posix接口 |
| osdepends |  | LiteOS提供的部分OS适配接口 |
| targets | bsp | 通用板级支持包 |
|  | Cloud\_STM32F429IGTx\_FIRE | 野火STM32F429(ARM Cortex M4)开发板的开发工程源码包 |
|  | qemu-virt-a53 | Coretex A53的qemu开发工程源码包 |
|  | realview-pbx-a9 | Coretex A9的qemu开发工程源码包 |
|  | STM32F072\_Nucleo | STM32F072\_Nucleo(ARM Cortex M0)开发板的开发工程源码包 |
|  | STM32F103\_FIRE\_Arbitrary | 野火STM32F103(ARM Cortex M3)霸道开发板的开发工程源码包 |
|  | STM32F769IDISCOVERY | STM32F769IDISCOVERY(ARM Cortex M7)开发板的开发工程源码包 |
|  | … | 其他开发板的开发工程源码包 |
|  | Kconfig |  |
|  | Makefile |  |
|  | **targets.mk** |  |
| tools | **build/config** | LiteOS支持的各开发板的编译配置文件,移植新的开发板时,需要在这个目录下增加这个新开发板的编译配置文件 |
|  | menuconfig | LiteOS编译所需的menuconfig脚本 |
| Makefile |  | 整个LiteOS的Makefile |
| **.config** |  | 开发板的编译配置文件,默认为Cloud\_STM32F429IGTx\_FIRE开发板的配置文件,移植时需要替换成新开发板的编译配置文件 |


target目录下保存了当前已经支持的开发板工程源码。当移植新开发板时,应该在target目录下增加该开发板的目录,目录结构和代码可以参考当前已支持的开发板的目录。例如:


* STM32F4系列的移植可以参考Cloud\_STM32F429IGTx\_FIRE工程。
* STM32F7系列的移植可以参考STM32F769IDISCOVERY工程。
* STM32L4系列的移植可以参考STM32L431\_BearPi工程。


### 环境准备


* **[获取LiteOS源代码]( )**
* **[硬件环境]( )**
* **[软件环境]( )**


#### 获取LiteOS源代码


[LiteOS源码仓]( )在码云上,使用master分支。


#### 硬件环境


##### 开发板


本指南以国内主流STM32学习板-正点原子STM32F407开发板为例进行移植。该开发板的介绍可参考官方网站:[探索者STM32F407开发板]( )。


##### 烧录仿真器


JLink。


#### 软件环境


##### 简介


本指南主要基于LiteOS Studio集成开发环境进行移植,烧录工具为JLink,同时使用STM32CubeMX软件生成裸机工程。


##### 安装STM32CubeMX


[STM32CubeMX下载]( ),本指南使用的是6.0.1版本。


##### 安装LiteOS Studio


除了LiteOS Studio,同时还需要安装git工具、arm-none-eabi软件、make构建软件、C/C++扩展、JLink烧录软件,这些软件的安装均可参考[LiteOS Studio安装指南]( )。


所有软件安装完毕后,需要重启计算机。



> 
> [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qw8KdraL-1665821485116)(https://github.com/LiteOS/LiteOS/raw/master/doc/public\_sys-resources/icon-notice.gif)]]( ) **须知:** 对于板载STLink仿真器的STM32开发板,需要先把STLink仿真器刷成JLink仿真器,再按照JLink的方式烧写。可以参考LiteOS Studio官方文档的“STM32工程示例”中的[“ST-Link仿真器单步调测”]( )。
> 
> 
> 


##### 验证LiteOS Studio集成开发环境


在正式开始移植前,可以先验证当前开发环境是否能成功编译LiteOS代码并完成烧录。目前[开源LiteOS]( )支持了若干开发板,如:Cloud\_STM32F429IGTx\_FIRE、STM32F769IDISCOVERY、STM32L431\_BearPi等。可以视情况验证环境:


* 没有官方已适配的开发板,可以先使用LiteOS已支持的开发板工程验证编译功能。暂时不验证烧录功能,在下一章节“[测试裸机工程]( )”中再验证。
* 有官方已适配的开发板,使用开发板对应的工程验证编译和烧录功能。即:
	+ 对于Cloud\_STM32F429IGTx\_FIRE开发板,在LiteOS Studio中配置目标板信息时,选择STM32F429IG。
	+ 对于STM32F769IDISCOVERY开发板,在LiteOS Studio中配置目标板信息时,选择STM32F769NI。
	+ 对于STM32L431\_BearPi 开发板,在LiteOS Studio中配置目标板信息时,选择STM32L431RC。


验证方法可以参考LiteOS Studio官方文档的“STM32工程示例”中的[“使用入门”]( )(只需关注其中的“打开工程”、“目标板配置”、“编译配置-编译代码”和“烧录配置-烧录”)。


### 创建裸机工程


* **[简介]( )**
* **[新建工程]( )**
* **[配置芯片外设]( )**
* **[配置工程]( )**
* **[生成裸机工程代码]( )**
* **[测试裸机工程]( )**


#### 简介


STM32CubeMX 是意法半导体(ST) 推出的一款图形化开发工具,支持 STM32 全系列产品,能够让用户轻松配置芯片外设引脚和功能,并一键生成C语言的裸机工程。


裸机工程可以为移植提供硬件配置文件和外设驱动文件,同时可以测试开发板的基本功能。以下介绍正点原子STM32F407的裸机工程创建过程。


#### 新建工程


1. 打开STM32CubeMX软件,点击菜单栏“File”在下拉菜单中选择“New Project”,如下图所示:

 **图 1** 新建工程 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAfEOlv3-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E6%96%B0%E5%BB%BA%E5%B7%A5%E7%A8%8B.png)]]( )
2. 选择开发板芯片。

 选择对应的开发板MCU(对于正点原子STM32F407开发板,选择STM32F407ZG),如下图所示:

 **图 2** 设置开发板芯片 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGRsCMo9-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%AE%BE%E7%BD%AE%E5%BC%80%E5%8F%91%E6%9D%BF%E8%8A%AF%E7%89%87.png)]]( )


#### 配置芯片外设


##### 简介


可以根据需要,自定义配置外设。这里仅配置了最基本的时钟、串口和LED灯、以及烧录调试方式,已经能满足LiteOS运行所需的基本硬件需求。


##### 配置时钟


1. 配置时钟引脚。

 选择“Pinout & Configuration”标签页,在左边的“System Core”中选择RCC,设置HSE(High Speed Clock,外部高速时钟)为Crystal/ Ceramic Resonator(晶振/陶瓷谐振器),即采用外部晶振作为 HSE 的时钟源,如下图所示:

 **图 1** 配置时钟引脚 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQUs4vzF-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E6%97%B6%E9%92%9F%E5%BC%95%E8%84%9A.png)]]( )
2. 配置时钟频率。

 将标签页切换为“Clock Configuration”。STM32F407芯片的最高时钟为168MHz,在HCLK处输入168并且回车即可完成配置,如下图所示。其他开发板的配置方式也类似。

 **图 2** 配置时钟频率 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JLY8nCCq-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E6%97%B6%E9%92%9F%E9%A2%91%E7%8E%87.png)]]( )


##### 配置串口和LED灯


将标签页切换回“Pinout & Configuration”。下图是正点原子STM32F407开发板的配置方法。对于其他开发板,可以参考开发板的原理图进行相应配置。


**图 1** 配置串口和LED引脚 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9IH1qAGw-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E4%B8%B2%E5%8F%A3%E5%92%8CLED%E5%BC%95%E8%84%9A.png)]]( )


##### 配置烧录调试方式


仍然在“Pinout & Configuration”标签页中,在左边的“System Core”中选择“SYS”,将“Debug”设置为“Serial Wire”,即SWD接口。该接口适用于STLink和JLink。


**图 1** 设置烧录调试方式 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tNVqZXZE-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%AE%BE%E7%BD%AE%E7%83%A7%E5%BD%95%E8%B0%83%E8%AF%95%E6%96%B9%E5%BC%8F.png)]]( )


#### 配置工程


工程配置中,需要设置工程名、代码保存路径、编译工具链/IDE、代码使用的堆栈大小以及HAL库版本。CubeMX 可以生成 Makefile、MDK-ARM、IAR 等 IDE 工程。本指南基于GCC编译工具链,所以Toolchain/IDE需要选择Makefile。将标签页切换到“Project Manager”,选择左边的“Project”标签,如下图所示:


**图 1** 工程配置 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQLX4acz-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E5%B7%A5%E7%A8%8B%E9%85%8D%E7%BD%AE.png)]]( )


为便于外设相关代码维护,建议勾选生成外设驱动的.c/.h文件。选择左边的“Code Generator”标签,如下图所示:


**图 2** 生成代码配置 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLpn2TqI-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%94%9F%E6%88%90%E4%BB%A3%E7%A0%81%E9%85%8D%E7%BD%AE.png)]]( )


#### 生成裸机工程代码


按以上步骤设置完外设和工程配置后,就可以生成裸机工程代码了,如下图所示:


**图 1** 生成工程 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OhmF7Ulc-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%94%9F%E6%88%90%E5%B7%A5%E7%A8%8B.png)]]( )


生成的裸机工程目录结构如下表所示:


**表 1** 裸机工程目录结构




| 目录/文件 | 说明 |
| --- | --- |
| build | 该目录用于存放编译生成的文件 |
| Core | 用户代码和开发板的基本配置文件 |
| Drivers | STM32 官方HAL 库 |
| Makefile | 裸机工程的Makefile |
| startup\_stm32f407xx.s | 芯片启动文件,主要包含堆栈定义等 |
| STM32F407ZGTx\_FLASH.ld | 裸机工程的链接脚本 |


#### 测试裸机工程


##### 编写测试程序


下面在裸机工程Core\Src\main.c文件中编写测试代码,实现串口循环输出并且LED灯闪烁:


1. 添加头文件:

 

#include <stdio.h>

2. 在main()函数的while(1)循环中添加如下代码:

 

printf(“hello\n”);
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);

3. /\* USER CODE BEGIN 4 \*/中添加函数:

 

attribute((used)) int _write(int fd, char *ptr, int len)
{
(void)HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
return len;
}



##### 使用LiteOS Studio测试裸机工程


1. 配置目标板。

 在“工程配置”界面中点击“目标板”,在“操作”列中点击“+”后,在出现的空行中填入STM32F407开发板信息,选中新增的开发板后,点击确认按钮保存,如下图所示:

 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XO5thnH7-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%9B%AE%E6%A0%87%E6%9D%BF%E9%85%8D%E7%BD%AE.png)]]( )
2. 编译。

 在裸机工程根目录下的Makefile文件上点击右键->设置为Makefile文件,然后编译工程,编译生成的二进制镜像文件在工程根目录的build目录下,如下图所示:

 **图 1** 编译裸机工程 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffrZjrzJ-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%BC%96%E8%AF%91%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B.png)]]( )
3. 烧录。


	1. 配置烧录器。
	
	 在“工程配置”界面中点击“烧录器”,参照下图进行配置,要烧录的二进制镜像文件就是上一步编译生成的bin文件,配置项中的“连接速率”、“加载地址”保持默认即可。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSSG8ppV-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E5%99%A8%E9%85%8D%E7%BD%AE.png)]]( )
	2. 点击“工具栏”上的“烧录”按钮,进行烧录。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMJSmLt0-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%8C%89%E9%92%AE.png)]]( )
	
	 烧录成功后,可以在终端界面看到如下输出:
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdeY0rfx-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E8%BE%93%E5%87%BA.png)]]( )
	3. 查看串口输出。
	
	 点击“工具栏”上“串口终端”图标[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xyeMfk3-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E4%B8%B2%E5%8F%A3%E7%BB%88%E7%AB%AF%E6%8C%89%E9%92%AE.png)]]( ),打开串口终端界面。如下图,只需设置与开发板连接的实际端口号,并打开串口开关。开发板按下复位RESET按钮后,即可在“串口终端”界面中看到不断输出hello,同时也可以观察到开发板的LED灯闪烁。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kro6Ah7g-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B%E4%B8%B2%E5%8F%A3%E8%BE%93%E5%87%BA.png)]]( )



> 
> [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xb9rnk0c-1665821485121)(https://github.com/LiteOS/LiteOS/raw/master/doc/public\_sys-resources/icon-note.gif)]]( ) **说明:** 如果想更详细的了解LiteOS Studio的使用,可以参考LiteOS Studio官方文档的[“STM32工程示例”]( )。
> 
> 
> 


### 移植适配


* **[移植步骤]( )**
* **[增加新开发板的目录]( )**
* **[适配外设驱动和HAL库配置文件]( )**
* **[配置系统时钟]( )**
* **[适配串口初始化文件]( )**
* **[修改链接脚本]( )**
* **[适配编译配置]( )**
* **[在LiteOS Studio上验证]( )**


#### 移植步骤


下面的移植工作会基于现有的裸机工程进行,大致步骤如下:


1. 增加新移植开发板的目录。


![img](https://img-blog.csdnimg.cn/img_convert/47e3de24ff7b94e677b033ff9cdff5dc.png)
![img](https://img-blog.csdnimg.cn/img_convert/7251e3862e9bf4f259b7ab687270fc50.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

doc/figures/%E7%9B%AE%E6%A0%87%E6%9D%BF%E9%85%8D%E7%BD%AE.png)]]( )
2. 编译。

 在裸机工程根目录下的Makefile文件上点击右键->设置为Makefile文件,然后编译工程,编译生成的二进制镜像文件在工程根目录的build目录下,如下图所示:

 **图 1** 编译裸机工程 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffrZjrzJ-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%BC%96%E8%AF%91%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B.png)]]( )
3. 烧录。


	1. 配置烧录器。
	
	 在“工程配置”界面中点击“烧录器”,参照下图进行配置,要烧录的二进制镜像文件就是上一步编译生成的bin文件,配置项中的“连接速率”、“加载地址”保持默认即可。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSSG8ppV-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E5%99%A8%E9%85%8D%E7%BD%AE.png)]]( )
	2. 点击“工具栏”上的“烧录”按钮,进行烧录。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMJSmLt0-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%8C%89%E9%92%AE.png)]]( )
	
	 烧录成功后,可以在终端界面看到如下输出:
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdeY0rfx-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E8%BE%93%E5%87%BA.png)]]( )
	3. 查看串口输出。
	
	 点击“工具栏”上“串口终端”图标[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xyeMfk3-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E4%B8%B2%E5%8F%A3%E7%BB%88%E7%AB%AF%E6%8C%89%E9%92%AE.png)]]( ),打开串口终端界面。如下图,只需设置与开发板连接的实际端口号,并打开串口开关。开发板按下复位RESET按钮后,即可在“串口终端”界面中看到不断输出hello,同时也可以观察到开发板的LED灯闪烁。
	
	 [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kro6Ah7g-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B%E4%B8%B2%E5%8F%A3%E8%BE%93%E5%87%BA.png)]]( )



> 
> [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xb9rnk0c-1665821485121)(https://github.com/LiteOS/LiteOS/raw/master/doc/public\_sys-resources/icon-note.gif)]]( ) **说明:** 如果想更详细的了解LiteOS Studio的使用,可以参考LiteOS Studio官方文档的[“STM32工程示例”]( )。
> 
> 
> 


### 移植适配


* **[移植步骤]( )**
* **[增加新开发板的目录]( )**
* **[适配外设驱动和HAL库配置文件]( )**
* **[配置系统时钟]( )**
* **[适配串口初始化文件]( )**
* **[修改链接脚本]( )**
* **[适配编译配置]( )**
* **[在LiteOS Studio上验证]( )**


#### 移植步骤


下面的移植工作会基于现有的裸机工程进行,大致步骤如下:


1. 增加新移植开发板的目录。


[外链图片转存中...(img-8VxRF1je-1715549647162)]
[外链图片转存中...(img-MBxxq4OZ-1715549647162)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值