# RT-Robot-SmartCar **Repository Path**: jiaqinbi/rt-robot-smart-car ## Basic Information - **Project Name**: RT-Robot-SmartCar - **Description**: 基于NXP MK60DN512芯片和RT-Robot软件包制作的RTT BSP,代码仅为基于RTT的BSP制作部分。 - **Primary Language**: C - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 1 - **Created**: 2021-07-08 - **Last Updated**: 2024-08-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基于RT-Thread系统RT-Robot软件包的智能汽车开发 笔记
Author:Jiaqin Bi
## 0、前言 ------ **1、章节描述如下:** - **第一章**为制作`BSP`前的一些准备,如工具、文档、源码、`SDK`等; - **第二章**为使用`NXP K60` 官方`SDK`以及逐飞科技库文件结合方式制作的,可不看,但这是我第三章仅使用逐飞科技库文件制作`BSP`的基础; - **第三章**为使用逐飞科技库文件制作`BSP`的笔记,可跳过第二章直接看第三章,其包含了目录建立到文件复制到工程创建、驱动编写以及错误以及调试的所有步骤; - **第四章**为前三章通过其它不怎么好的方法解决问题而设置的对遗留的比较重要问题的解决方法,较为重要。 - **第五章**为对`BSP`组件和软件包支持的验证...**待完善** - **第六章**是最后`RT-Robot`软件包的支持...**待完善** **2、关于构建脚本、链接器、编译器配置文件等,二三章节会有所不同,链接器介绍在`2.8`小节有介绍;** ## 一、准备 ------ ### 1.1 必要文件的准备 - 以下文件均已放在`/准备文件/文档 `目录下 - `SDK`下载请点击:[SDK_MK60DN512xxx10](https://mcuxpresso.nxp.com/en/explore) - `MCUXpresso`下载请点击:[百度云](https://pan.baidu.com/s/1b8DLfm120bdzHihHUtQPzQ) 提取码:un16 - `rtthread`源码下载请点击:[rtt-github](https://github.com/RT-Thread/rt-thread) 或 [rtt-gitee](https://gitee.com/rtthread/rt-thread) - 逐飞科技源码,笔记中使用到的源码项目名为`2019` - 主控板原理图 - 数据手册、参考手册 ### 1.2 知识准备 #### 1.2.1 `scons` - `SCons` 使用 `SConscript` 和 `SConstruct` 文件来组织源码结构; - `SConstruct`、`SConscript` 文件中可以调用 `Python` 标准库进行各类复杂的处理; - **一个项目只有一个 `SConstruct`,但是会有多个 `SConscript`,一般情况下,每个存放有源代码的子目录下都会放置一个` SConscript`**; - **每一个 `RT-Thread BSP` 目录下都会存在下面三个文件:`rtconfig.py`、`SConstruct` 和 `SConscript`来控制 `BSP` 的编译***; - `BSP` 目录下的 `SConscript` 文件 会找到子源代码目录中的`SConscript `文件,从而将 `rtconfig.h` 中定义的宏对应的源代码加入到编译器中。 #### 1.2.2 `Kconfig` 1- `Kconfig` 文件是各种`menuconfig`配置界面的源文件,最终生成配置文件`rtconfig.h`配置系统。 - `BSP_DIR`变量定义了`BSP`根目录,默认是`.` (因为`Kconfig`文件放置于`BSP`板级支持包目录下),除非系统中定义了`BSP_ROOT`的环境变量; - `RTT_DIR`变量定义了`RT-Thread` **根目录**,因为板级包目录默认放置在`rt-thread/bsp`目录下,所以这个变量的默认值是`../..`,除非系统中定义了`RTT_ROOT`的环境变量; - `PKGS_DIR`变量定义了`RT-Thread`包根目录,一般它会从系统的环境变量`PKGS_ROOT`中获得,而如果使用`RT-Thread/env`工具,`env`工具在启动`console`终端时会默认地定义这个环境变量; #### 1.2.3 `env menuconfi`g支持 - `menuconfig` 中配置选项的修改方法 如果想在 `menuconfig` 的配置项中添加宏定义,则可以修改 `BSP` 下的 `Kconfig` 文件,修改方法可以在网络中搜索`Kconfig语法`关键字获得详细的说明文档,也可以参考 `RT-Thread` 中的 `Kconfig `文件或者已经支持过 `menuconfig` 的 `BSP` 中的 `Kconfig` 文件。 - **==新的项目添加 menuconfig 功能==** 这里的新项目指的是,**还未生成 .config 和 rtconfig.h** 的全新开发的项目。因为这两个文件,只有在 `menuconfig` 第一次保存时才会创建。具体流程如下: ```mermaid graph TB t1(拷贝BSP里面已有的kconfig文件或自己编写Kconfig文件放置到新bsp根目录下) t1-->t2(如若Kconfig文件为拷贝的文件,则修改RTT_ROOT所在目录) t2-->t3(保存,在新建的bsp下打开env,输入menuconfig) t3-->t4(保存退出,即可生成.config和rtconfig.h文件) ``` - 旧项目添加 `menuconfig`功能 这里的旧项目指的是已经经过一段时间的开发,而且项目中存在已经修改过的 `rtconfig.h`文件 ,但是没有使用过 `menuconfig` 来配置的项目。具体流程如下: ```mermaid graph TB t1(保存备份项目内的rtconfig.h文件) t1-->t2(env下输入scons --genconfig命令根据已有的rtconfig.h生成.config文件) t2-->t3(重复新项目添加menuconfig功能的步骤) t3-->t4(对比新生成的rtconfig.h和旧的rtconfig.h,不同处使用menuconfig进行修改) ``` #### 1.2.4 链接脚本文件 以iar使用的icf文件为例:略,请查看2.8小节和3.7小节。 ### 1.3 bsp空目录准备 ``` ############ 使用官方SDK和逐飞科技驱动 ############ mk60dn/ | -- application/ | | -- 待添加的文件 | -- board/ | | -- linker_scripts/ | | | -- 待添加的链接文件 | | -- MCUX_Config/ | | | -- 时钟、引脚及MCUX_Config配置文件 | | -- 待添加的文件(board.c等) | -- build/ | -- libraries/ | | -- drivers/ | | | -- 待添加的逐飞科技驱动文件`*.c` | | -- MK60D10/ | | |-- CMSIS/ | | |-- MK60D10/ | | -- seekfree/ | | | -- 待添加的逐飞科技驱动文件`*.c` | | -- templates/ | | | -- iar、keil等工程模板文件 | -- tools/ | | -- 待添加的使用工具、文件等 | -- docs/ | | -- figures/ | | | -- 待添加的readme中的图片 | | -- readme.xxx ``` ``` ############ 仅使用逐飞科技驱动 ############ mk60dn/ | -- application/ | | -- 待添加的文件 | -- board/ | | -- linker_scripts/ | | | -- 待添加的链接文件 | | -- 待添加的文件(board.c等) | -- build/ | -- libraries/ | | -- drivers/ | | | -- 待添加的自己编写的对接rtt的驱动文件,如drv_uart.* | | -- libraries/ | | | -- seekfree/ | | | -- zfkj/ | | | | -- 待添加的逐飞科技库文件`*.c | | -- seekfree/ | | | -- 待添加的库文件`*.c` | | -- startup/ | | | -- 待添加的逐飞科技的启动文件 | | -- templates/ | | | -- iar、keil等工程模板文件 | -- tools/ | | -- 待添加的使用工具、文件等 | -- docs/ | | -- figures/ | | | -- 待添加的readme中的图片 | | -- readme.xxx ``` ## 二、`BSP`创建(使用官方`SDK`以及逐飞科技的库文件) ------ **==bsp为mk60dn==** - 第二节较为冗余,且未制作成功,可不根绝步骤操作 - 第三节以第二节为基础,代码少做注释,可参考第二节对应小节 ### 2.1 工程目录的建立 参照`imxrt1052` ```markdown mk60dn/ | -- application/ | | -- main.c | | -- SConscript | | -- isr.c | | -- isr.h | -- board/ | | -- linker_scripts/ | | | -- link.icf | | | -- link.lds | | | -- link.sct | | -- MCUX_Config/ | | | -- clock_config.c | | | -- clock_config.h | | | -- pin_mux.c | | | -- pin_mux.h | | | -- clock_config.mex | | -- board.c | | -- board.h | | -- Kconfig | | -- SConscript | -- build/ | -- libraries/ | | -- drivers/ | | | -- `*.c` | | -- MK60D10/ | | |-- CMSIS/ | | |-- MK60D10/ | | -- seekfree/ | | -- templates/ | -- tools/ | -- docs/ | | -- figures/ | | -- readme.md ``` ### 2.2 时钟、外设文件的配置(可省略) ------ **经测试 ,此处配置的时钟文件会导致debug卡住** 打开`MCUXpresso Config Tools v5`软件,添加下载好的SDK,新建工程名为`MK60_Clock_config`的工程,选择IAR集成开发环境。 #### 2.2.1配置串口 根据电路原理图配置用于控制台调试输出的串口   #### 2.2.2 配置时钟 根据电路原理图配置时钟源,如下所示   #### 2.2.3保存工程 点击功能菜单栏的更新工程即可。 ### 2.3 文件的拷贝 拷贝过程如下表所示: | 源目录/文件 | 目标目录 | | :----------------------------------------------: | :------------------------------------------: | | SDK/CMSIS/ | mk60dn/libraries/MK60D10/ | | SDK/device/MK60D10/ | mk60dn/libraries/MK60D10/ | | 2019/libraries/drivers/src/*.c | mk60dn/libraries/drivers/ | | 2019/libraries/drivers/inc/*.h | mk60dn/libraries/drivers/ | | 2019/libraries/seekfree/ | mk60dn/libraries/seekfree/ | | 2019/libraries/templates/ | mk60dn/libraries/templates/ | | MK60_Clock_config/board/clock_config.* | mk60dn/board/MCU_Config/ | | MK60_Clock_config/board/pin_mux.* | mk60dn/board/MCU_Config/ | | 2019/Project/USER/src/`*.*` | mk60dn/application/ | | 2019/Project/IAR/program/linker/MK60xN512_10.icf | mk60dn/board/linker_scripts/`改名为link.icf` | | 2019/Project/USER/rtthread/board.c | mk60dn/board/ | ### 2.4 编写构建脚本`SConscript` **提示:编写SConscript不要轻易使用Tab键,格式换行时也需退格到首个字符然后使用空格进行对齐** ```python ############### /bsp/mk60dn/SConscript ############### # for module compiling import os from building import * cwd = GetCurrentDir() #获取当前路径 objs = [] #定义一个空的list型变量objs保存编译文件 list = os.listdir(cwd) #当前目录下的所有子目录都保存在list变量中 for d in list: #循环遍历子目录 path = os.path.join(cwd, d) #拼接当前目录和子目录为新路径 #判断新路径下是否有SConscript文件 if os.path.isfile(os.path.join(path, 'SConscript')): objs = objs + SConscript(os.path.join(d, 'SConscript')) #读出SConscript文件并加入list中 Return('objs') ``` ```python ############### /bsp/mk60dn/application/SConscript ############### #导入模块 import rtconfig from building import * cwd = GetCurrentDir() src = Glob('*.c') #得到当前目录下所有的C文件 #将当前路径和工程的SConstruct所在的路径保存到列表变量 CPPPATH 中 #CPPPATH = [cwd, str(Dir('#'))] CPPPATH = [cwd] #添加头文件搜索路径 #启动时入口函数的判断 #若编译器为gcc,则启动时跳转到entry函数 if rtconfig.CROSS_TOOL == 'gcc': CPPDEFINES = ['__START=entry'] else: CPPDEFINES = [] #创建组Applications #depend为空表示该组不依赖任何rtconfig.h宏 #CPPPATH为添加头文件搜索的路径 group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES) Return('group') ``` ```python ############### /bsp/mk60dn/board/SConscript ############### Import('RTT_ROOT') Import('rtconfig') from building import * cwd = GetCurrentDir() # 添加驱动文件,Split函数为正则表达式匹配时常用的分割函数 src = Split(""" board.c MCUX_Config/clock_config.c MCUX_Config/pin_mux.c """) # 添加头文件路径 CPPPATH = [cwd,cwd + '/MCUX_Config'] # 链接时的参数 #cpu型号参考SDK下的fsl_device_registers.h文件 #CPPDEFINES = ['CPU_MK60DN512VLQ10'] CPPDEFINES = ['CPU_MK60DN512VLQ10', 'STD=C99', 'SKIP_SYSCLK_INIT'] if rtconfig.CROSS_TOOL == 'keil': CPPDEFINES.append('__FPU_PRESENT=1') group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES) Return('group') ``` ```python ############### /bsp/mk60dn/libraries/SConscript ############### Import('rtconfig') from building import * cwd = GetCurrentDir() path = [cwd + '/drivers',cwd + '/MK60D10/CMSIS/Include',cwd + '/MK60D10/MK60D10', cwd + '/MK60D10/MK60D10/drivers', cwd + '/MK60D10/MK60D10/cmsis_drivers', cwd + '/MK60D10/MK60D10/mcuxpresso', '/MK60D10/MK60D10/utilities',cwd + '/seekfree'] src = Split(''' MK60D10/MK60D10/system_MK60D10.c MK60D10/MK60D10/drivers/fsl_common.c MK60D10/MK60D10/drivers/fsl_clock.c drivers/common.c drivers/misc.c drivers/MK60DN10_port.c ''') # 添加不同编译器下的启动文件 if rtconfig.CROSS_TOOL == 'gcc': src += ['MK60D10/MK60D10/gcc/startup_MK60D10.S'] elif rtconfig.CROSS_TOOL == 'keil': src += ['MK60D10/MK60D10/arm/startup_MK60D10.s'] elif rtconfig.CROSS_TOOL == 'iar': src += ['MK60D10/MK60D10/iar/startup_MK60D10.s'] if GetDepend(['BSP_USING_GPIO']): src += ['MK60D10/MK60D10/drivers/fsl_gpio.c'] if GetDepend(['BSP_USING_UART']): src += ['MK60D10/MK60D10/drivers/fsl_uart.c'] if GetDepend(['BSP_USING_I2C']): src += ['MK60D10/MK60D10/drivers/fsl_i2c.c'] if GetDepend(['BSP_USING_SPI']): src += ['MK60D10/MK60D10/drivers/fsl_dspi.c'] if GetDepend(['BSP_USING_RTC']): src += ['MK60D10/MK60D10/drivers/fsl_rtc.c'] if GetDepend(['BSP_USING_WDT']): src += ['MK60D10/MK60D10/drivers/fsl_wdog.c'] if GetDepend(['BSP_USING_ADC']): src += ['MK60D10/MK60D10/drivers/fsl_adc16.c'] #************************************************************ #if GetDepend(['BSP_USING_SDRAM']): # src += ['MK60D10/MK60D10/drivers/fsl_semc.c'] #if GetDepend(['BSP_USING_LCD']): # src += ['MK60D10/MK60D10/drivers/fsl_elcdif.c'] #if GetDepend(['RT_USING_USB_HOST']) or GetDepend(['RT_USING_USB_DEVICE']): # src += ['MK60D10/MK60D10/drivers/fsl_usdhc.c'] #if GetDepend(['BSP_USING_CAN']): # src += ['MK60D10/MK60D10/drivers/fsl_flexcan.c'] #************************************************************ if GetDepend(['BSP_USING_ETH']): src += ['MK60D10/MK60D10/drivers/fsl_enet.c'] if GetDepend(['RT_USING_AUDIO']): src += ['MK60D10/MK60D10/drivers/fsl_sai.c'] if GetDepend(['BSP_USING_DMA']): src += ['MK60D10/MK60D10/drivers/fsl_dmamux.c'] src += ['MK60D10/MK60D10/drivers/fsl_edma.c'] src += ['MK60D10/MK60D10/drivers/fsl_dspi_edma.c'] src += ['MK60D10/MK60D10/drivers/fsl_uart_edma.c'] src += ['MK60D10/MK60D10/drivers/fsl_sai_edma.c'] src += ['MK60D10/MK60D10/drivers/fsl_i2c_edma.c'] group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path) Return('group') ``` ```python ############### /bsp/libraries/drivers/SConscript ############### from building import * src = [] cwd = [] CPPDEFINES = [] cwd = GetCurrentDir() if GetDepend('BSP_USING_GPIO'): src += ['MK60DN10_gpio.c'] if GetDepend('BSP_USING_UART'): src += ['MK60DN10_uart.c'] #************************************ #if GetDepend('BSP_USING_HWTIMER'): # src += ['drv_hwtimer.c'] #************************************ if GetDepend('BSP_USING_RTC'): src += ['MK60DN10_rtc.c'] if GetDepend('BSP_USING_SPI'): src += ['MK60DN10_spi.c'] if GetDepend('BSP_USING_I2C'): src += ['MK60DN10_i2c.c'] if GetDepend('BSP_USING_WDT'): src += ['MK60DN10_wdog.c'] if GetDepend('BSP_USING_PWM'): src += ['MK60DN10_ftm.c'] src += ['MK60DN10_cmt.c'] if GetDepend('BSP_USING_ADC'): src += ['MK60DN10_adc.c'] src+=['MK60DN10_lptmr.c'] src+=['MK60DN10_pit.c'] src+=['MK60DN10_sdhc.c'] path = [cwd] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path, CPPDEFINES=CPPDEFINES) Return('group') ``` ### 2.5 编写构建脚本SConstruct ```python 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=[]) if rtconfig.PLATFORM == 'armcc': # env = Environment(tools = ['mingw'], env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, # overwrite cflags, because cflags has '--C99' CXXCOM = '$CXX -o $TARGET --cpp -c $CXXFLAGS $_CCCOMCOM $SOURCES') else: env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, CXXCOM = '$CXX -o $TARGET -c $CXXFLAGS $_CCCOMCOM $SOURCES') 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') # prepare building environment objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) objs = objs + SConscript('libraries/SConscript') objs = objs + SConscript('libraries/drivers/SConscript') # make a building DoBuilding(TARGET, objs) ``` ### 2.6 编写构建脚本Kconfig ```python ############### /bsp/mk60dn/Kconfig ############### mainmenu "RT-Thread Configuration" config RTT_DIR string option env="RTT_ROOT" default "../.." config PKGS_DIR string option env="PKGS_ROOT" default "packages" source "$RTT_DIR/Kconfig" source "$PKGS_DIR/Kconfig" source "libraries/Kconfig" source "board/Kconfig" ``` ```python ############### /bsp/mk60dn/board/Kconfig ############### menu "Hardware Drivers Config" config SOC_MK60DN512VLQ10 bool select SOC_MK60DN512_SERIES select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN default y 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" select RT_USING_SERIAL default y if BSP_USING_UART config BSP_USING_UART0 bool "Enable UART0" default y endif endmenu menu "Onboard Peripheral Drivers" config BSP_USING_Peripheral bool "Not write..." default y endmenu menu "Board extended module Drivers" endmenu endmenu ``` ```python ############### /bsp/mk60dn/libraries/Kconfig ############### config SOC_MK60DN512_SERIES bool select ARCH_ARM_CORTEX_M4 ``` ### 2.7 编写编译器配置文件rtconfig.py ```python ''' rtconfig.py 是一个 RT-Thread 标准的编译器配置文件,控制了大部分编译选项,是一个使用 python 语言编写的脚本文件,主要用于完成以下工作: 指定编译器(从支持的多个编译器中选择一个你现在使用的编译器) 指定编译器参数,如编译选项、链接选项等。 ''' import os import sys # toolchains options ARCH='arm' CPU='cortex-m4' CROSS_TOOL='gcc' if os.getenv('RTT_CC'): CROSS_TOOL = os.getenv('RTT_CC') if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') # cross_tool provides the cross compiler # EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' EXEC_PATH = r'C:/XXX' #未安装 elif CROSS_TOOL == 'keil': PLATFORM = 'armcc' EXEC_PATH = r'C:/Keil_v5' elif CROSS_TOOL == 'iar': PLATFORM = 'iar' EXEC_PATH = r'C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.32' if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') #BUILD = 'debug' BUILD = 'release' if PLATFORM == 'gcc': PREFIX = 'arm-none-eabi-' CC = PREFIX + 'gcc' CXX = PREFIX + 'g++' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' TARGET_EXT = 'elf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' STRIP = PREFIX + 'strip' DEVICE = ' -mcpu=' + CPU + ' -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections' #k64f CFLAGS = DEVICE + ' -g -Wall -D__ASSEMBLY__ -D__FPU_USED' CFLAGS = DEVICE + ' -Wall -D__FPU_PRESENT -eentry' #k64f AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb ' AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb -D__START=entry' LFLAGS = DEVICE + ' -lm -lgcc -lc' + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds' CPATH = '' LPATH = '' if BUILD == 'debug': #k64f CFLAGS += ' -O0 -gdwarf-2' CFLAGS += ' -gdwarf-2' AFLAGS += ' -gdwarf-2' CFLAGS += ' -O0' else: #k64f CFLAGS += ' -O2' CFLAGS += ' -O2 -Os' #k64f POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' #rt1052 # POST_ACTION = OBJCPY + ' -O binary --remove-section=.boot_data --remove-section=.image_vertor_table --remove-section=.ncache $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' # module setting CXXFLAGS = ' -Woverloaded-virtual -fno-exceptions -fno-rtti ' M_CFLAGS = CFLAGS + ' -mlong-calls -fPIC ' M_CXXFLAGS = CXXFLAGS + ' -mlong-calls -fPIC' M_LFLAGS = DEVICE + CXXFLAGS + ' -Wl,--gc-sections,-z,max-page-size=0x4' +\ ' -shared -fPIC -nostartfiles -static-libgcc' M_POST_ACTION = STRIP + ' -R .hash $TARGET\n' + SIZE + ' $TARGET \n' elif PLATFORM == 'armcc': CC = 'armcc' CXX = 'armcc' AS = 'armasm' AR = 'armar' LINK = 'armlink' TARGET_EXT = 'axf' #k64f DEVICE = ' --cpu Cortex-M4.fp ' DEVICE = ' --cpu ' + CPU + '.fp.sp' CFLAGS = DEVICE + ' --apcs=interwork' AFLAGS = DEVICE #k64f # LFLAGS = DEVICE + ' --info sizes --info totals --info unused --info veneers --list rtthread.map --scatter "board\linker_scripts\link.sct"' LFLAGS = DEVICE + ' --libpath "' + EXEC_PATH + '\ARM\ARMCC\lib" --info sizes --info totals --info unused --info veneers --list rtthread.map --scatter "board\linker_scripts\link.sct"' #k64f # LFLAGS += ' --keep *.o(.rti_fn.*) --keep *.o(FSymTab) --keep *.o(VSymTab)' #K64f EXEC_PATH += '/ARM/ARMCC/bin/' if BUILD == 'debug': CFLAGS += ' -g -O0' AFLAGS += ' -g' else: CFLAGS += ' -O2' CXXFLAGS = CFLAGS CFLAGS += ' --c99' POST_ACTION = 'fromelf -z $TARGET' #k64f # POST_ACTION = 'fromelf --bin $TARGET --output rtthread.bin \nfromelf -z $TARGET' elif PLATFORM == 'iar': CC = 'iccarm' CXX = 'iccarm' AS = 'iasmarm' AR = 'iarchive' LINK = 'ilinkarm' TARGET_EXT = 'out' DEVICE = ' -D__FPU_PRESENT' CFLAGS = DEVICE CFLAGS += ' --diag_suppress Pa050' CFLAGS += ' --no_cse' CFLAGS += ' --no_unroll' CFLAGS += ' --no_inline' CFLAGS += ' --no_code_motion' CFLAGS += ' --no_tbaa' CFLAGS += ' --no_clustering' CFLAGS += ' --no_scheduling' CFLAGS += ' --debug' CFLAGS += ' --endian=little' CFLAGS += ' --cpu=' + CPU CFLAGS += ' -e' CFLAGS += ' --fpu=None' CFLAGS += ' --dlib_config "' + EXEC_PATH + '/arm/INC/c/DLib_Config_Normal.h"' CFLAGS += ' -Ol' CFLAGS += ' --use_c++_inline' AFLAGS = '' AFLAGS += ' -s+' AFLAGS += ' -w+' AFLAGS += ' -r' AFLAGS += ' --cpu ' + CPU AFLAGS += ' --fpu None' if BUILD == 'debug': CFLAGS += ' --debug' CFLAGS += ' -On' else: CFLAGS += ' -Oh' LFLAGS = ' --config "board/linker_scripts/link.icf"' LFLAGS += ' --redirect _Printf=_PrintfTiny' LFLAGS += ' --redirect _Scanf=_ScanfSmall' LFLAGS += ' --entry __iar_program_start' CXXFLAGS = CFLAGS EXEC_PATH = EXEC_PATH + '/arm/bin/' POST_ACTION = 'ielftool --bin $TARGET rtthread.bin' def dist_handle(BSP_ROOT): cwd_path = os.getcwd() sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools')) from sdk_dist import dist_do_building dist_do_building(BSP_ROOT) ``` ### 2.8 修改链接脚本 **MK60DN512ZVLQ10 flash=512KB RAM=256KB** IAR使用的链接脚本为icf文件 icf文件编写参考 -> [菜鸟详解iar的icf文件](https://blog.csdn.net/sunheshan/article/details/32701697) icf文件的作用: - 定义了芯片存储空间的大小 -> ROM和RAM的大小和起始、结束地址 - 定义堆栈大小和对齐方式 - 定义额外块,区域等 - ... `link.icf`链接脚本代码直接使用的裸机程序的代码,如下所示: ```assembly /*###ICF### Section handled by ICF editor, don't touch! ****/ /*-Editor annotation file-*/ /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ /*-Specials-*/ define symbol __ICFEDIT_intvec_start__ = 0x00000000; /*-Memory Regions-*/ define symbol __ICFEDIT_region_ROM_start__ = 0x00000000; define symbol __ICFEDIT_region_ROM_end__ = 0x0007ffff; define symbol __ICFEDIT_region_RAM_start__ = 0x1fff0000; define symbol __ICFEDIT_region_RAM_end__ = 0x1fffffff; /*-Sizes-*/ define symbol __ICFEDIT_size_cstack__ = 0x2000; define symbol __ICFEDIT_size_heap__ = 0x4000; /**** End of ICF editor section. ###ICF###*/ define symbol __region_RAM2_start__ = 0x20000000; define symbol __region_RAM2_end__ = 0x2000ffff; define symbol __FlashConfig_start__ = 0x00000400; define symbol __FlashConfig_end__ = 0x0000040f; define memory mem with size = 4G; define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to (__FlashConfig_start__ - 1)] | mem:[from (__FlashConfig_end__+1) to __ICFEDIT_region_ROM_end__]; define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__] | mem:[from __region_RAM2_start__ to __region_RAM2_end__]; define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; define region FlashConfig_region = mem:[from __FlashConfig_start__ to __FlashConfig_end__]; initialize by copy { readwrite }; do not initialize { section .noinit }; place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; place in FlashConfig_region {section FlashConfig}; place in ROM_region { readonly }; place in RAM_region { readwrite, block CSTACK, block HEAP }; ``` MDK使用的是sct文件,`link.sct`文件如下: ```assembly //未写 ``` ### 2.9、工程创建 ------ **启动流程如下所示**  #### 2.9.1 IAR工程创建 - 首先需要对于控制台未指定串口设备的配置,来说,需要通过`env`下的`menuconfig`图形配置界面配置默认控制台设备,本工程中使用的`uart0`,在`/bsp/mk60dn`下打开`env`,输入`menuconfig`配置如下所示:  - 然后直接保存退出会生成`.config`和`rtconfig.h`文件 - 然后`env`下输入`sons --target=iar`会按照模板生成`iar` 工程 - 打开工程修改芯片型号和`Debug`方式,如`3.8.1`小节 - **编译会出错,按照错误提示进行相关修改即可** #### 2.9.2 IAR配置 - 项目名右键`Options -->` - `General Options --> Target --> Device --> NXP --> KinetisK --> K6x --> NXP MK60DN512Zxxx10` - `Library Configuration --> Library --> Full` - 检查`Linker --> Config --> Linker configuration file` 是否为 `$PROJ_DIR$\board\linker_scripts\link.icf` - `Debuguer --> Driver --> J-Link/J-Trace` - `Debuguer --> J-Link/J-Trace --> Connection -- > SWD` #### 2.9.3 文件修改 - 启动文件中`SystemInit`改为`Start` - 对比逐飞科技与官方`SDK`的`MK60D10.h`进行相关修改 - 将官方的`system_MK60D10.*`替换为逐飞科技的`system_MK60D10.*` - `board.c`中做了`ostick`、`uart`、动态内存等的初始化 - 其它错误、以及修改的文件未列出 #### 2.9.4 错误以及演示 如果遇到如下错误,请检查`iar`配置工程的芯片是否正确,`项目名->右键Options->General Options->Target Device`是否为`NXP MK60DN512Zxxx10`  如果遇到串口打印输出乱码,请使用逐飞科技的`system_MK60D10.*`替换官方SDK的`system_MK60D10.*`,并修改`startup_MK60D10.s`启动入口函数为`Start`。  ------ - `board.c`中不要使用`MCUXpresso Config Tools`创建的时钟初始化函数,下载运行会卡住; - `board.c`中可不使用`BOARD_InitPins()`函数; 修改文件、解决错误编译下载之后,显示无法使用`finsh`组件,经过`debug`调试定位在`finsh`无法动态申请内存块,调整了大小也无法解决,如下所示:  而后在`rtconfig.h`中使用了`nano`的`rtconfig.h`中对`finsh`的配置,能显示`msh>`,但是无法输入字符 ```c /* Command shell */ #if 1 #define RT_USING_FINSH #define FINSH_THREAD_NAME "tshell" #define FINSH_USING_HISTORY #define FINSH_HISTORY_LINES 5 #define FINSH_USING_SYMTAB #define FINSH_USING_DESCRIPTION #define FINSH_THREAD_PRIORITY 20 #define FINSH_THREAD_STACK_SIZE 4096 #define FINSH_CMD_SIZE 80 #define FINSH_USING_MSH #define FINSH_USING_MSH_DEFAULT #define FINSH_USING_MSH_ONLY #define FINSH_ARG_MAX 10 #endif /* 1 */ #if 0 //#define RTE_USING_FINSH #if defined(RTE_USING_FINSH) #define RT_USING_FINSH #endif //RTE_USING_FINSH #define RT_USING_FINSH #define RT_USING_CONSOLE #define RT_CONSOLEBUF_SIZE 128 #if defined(RT_USING_FINSH) #define FINSH_USING_MSH #define FINSH_USING_MSH_ONLY #define __FINSH_THREAD_PRIORITY 5 #define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1) #define FINSH_THREAD_STACK_SIZE 1024 #define FINSH_HISTORY_LINES 1 #define FINSH_USING_SYMTAB #endif #endif /* 0 */ ``` 如下所示:  **==随后在`第三节`中创建的BSP仅使用了逐飞科技的库文件,此问题在第三节中给出解决办法==** ## 三、BSP创建(未使用官方驱动)--仅使用逐飞科技的库 ------ **==bsp为mk60dn-1==** ### 3.1 工程目录的建立 ```markdown mk60dn-1/ | -- application/ | | -- main.c | | -- SConscript | | -- isr.c | | -- isr.h | -- board/ | | -- linker_scripts/ | | | -- link.icf | | | -- link.lds | | | -- link.sct | | -- board.c | | -- board.h | | -- Kconfig | | -- SConscript | -- build/ | -- libraries/ | | -- drivers/ | | | -- `drv_xxx.c` | | | -- `drv_xxx.h` | | | -- SConscript | | -- libraries/ | | |-- seekfree/ | | | | -- `*.c` | | | | -- `*.h` | | |-- zfkj/ | | | | -- `*.c` | | | | -- `*.h` | | | | -- SConscript | | -- startup/ | | | -- CoreSupport/ | | | | -- `core_xxx.h` | | | -- DeviceSupport/ | | | | -- gcc/ | | | | | -- startup_MK60D10.S | | | | -- IAR-ARM/ | | | | | -- startup_MK60D10.s | | | | -- MDK-ARM/ | | | | | -- startup_MK60D10.s | | | | -- `MK60D10.h` | | | | -- `system_MK60D10.h` | | | | -- `system_MK60D10.c` | | -- templates/ | | | -- iar 、 keil 的工程模板文件 | -- tools/ | -- docs/ | | -- figures/ | | -- readme.md ``` ### 3.2 文件的拷贝 | 源目录/文件 | 目标目录 | | :----------------------------------------------: | :--------------------------------------------: | | 2019/Project/USER/src/`*.*` | mk60dn-1/application/ | | 2019/Project/IAR/program/linker/MK60xN512_10.icf | mk60dn-1/board/linker_scripts/`改名为link.icf` | | 2019/Project/USER/rtthread/board.c | mk60dn-1/board/ | | 2019/libraries/drivers/inc/*.h | mk60dn-1/libraries/libraries/zfkj/ | | 2019/libraries/drivers/src/*.c | mk60dn-1/libraries/libraries/zfkj/ | | 2019/libraries/seekfree/*.h | mk60dn-1/libraries/libraries/seekfree/ | | 2019/libraries/seekfree/*.c | mk60dn-1/libraries/libraries/seekfree/ | | 2019/libraries/startup/ | mk60dn-1/libraries/startup/ | | 2019/libraries/templates/ | mk60dn-1/libraries/templates/ | | | | ### 3.3 编写构建脚本`SConscript` ```python ############### /bsp/mk60dn-1/SConscript ############### # for module compiling import os from building import * cwd = GetCurrentDir() #获取当前路径 objs = [] #定义一个空的list型变量objs保存编译文件 list = os.listdir(cwd) #当前目录下的所有子目录都保存在list变量中 for d in list: #循环遍历子目录 path = os.path.join(cwd, d) #拼接当前目录和子目录为新路径 #判断新路径下是否有SConscript文件 if os.path.isfile(os.path.join(path, 'SConscript')): objs = objs + SConscript(os.path.join(d, 'SConscript')) #读出SConscript文件并加入list中 Return('objs') ``` ```python ############### /bsp/mk60dn-1/application/SConscript ############### import rtconfig from building import * cwd = GetCurrentDir() src = Glob('*.c') CPPPATH = [cwd, str(Dir('#'))] # add for startup script if rtconfig.CROSS_TOOL == 'gcc': CPPDEFINES = ['__START=entry'] else: CPPDEFINES = [] group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES) Return('group') ``` ```python ############### /bsp/mk60dn-1/board/SConscript ############### Import('RTT_ROOT') Import('rtconfig') from building import * cwd = GetCurrentDir() # 添加驱动文件,Split函数为正则表达式匹配时常用的分割函数 src = Split(""" board.c ../rtconfig.h """) # 添加头文件路径 CPPPATH = [cwd] # 链接时的参数 #cpu型号参考SDK下的fsl_device_registers.h文件 #CPPDEFINES = ['CPU_MK60DN512VLQ10'] CPPDEFINES = ['CPU_MK60DN512VLQ10', 'STD=C99', 'SKIP_SYSCLK_INIT'] if rtconfig.CROSS_TOOL == 'keil': CPPDEFINES.append('__FPU_PRESENT=1') group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES) Return('group') ``` ```python ############### /bsp/mk60dn-1/libraries/SConscript ############### Import('rtconfig') from building import * cwd = GetCurrentDir() path = [cwd + '/drivers', cwd + '/libraries/zfkj', cwd + '/libraries/seekfree', cwd + '/startup/DeviceSupport', cwd + '/startup/CoreSupport'] src = Split(''' startup/DeviceSupport/system_MK60D10.c libraries/zfkj/common.c libraries/zfkj/misc.c libraries/zfkj/MK60DN10_port.c libraries/zfkj/MK60DN10_adc.c libraries/zfkj/MK60DN10_cmt.c libraries/zfkj/MK60DN10_dac.c libraries/zfkj/MK60DN10_dma.c libraries/zfkj/MK60DN10_flash.c libraries/zfkj/MK60DN10_ftm.c libraries/zfkj/MK60DN10_gpio.c libraries/zfkj/MK60DN10_i2c.c libraries/zfkj/MK60DN10_lptmr.c libraries/zfkj/MK60DN10_pit.c libraries/zfkj/MK60DN10_port.c libraries/zfkj/MK60DN10_rtc.c libraries/zfkj/MK60DN10_sdhc.c libraries/zfkj/MK60DN10_spi.c libraries/zfkj/MK60DN10_systick.c libraries/zfkj/MK60DN10_uart.c libraries/zfkj/MK60DN10_wdog.c ''') if rtconfig.CROSS_TOOL == 'gcc': src += ['startup/DeviceSupport/gcc/startup_MK60D10.S'] elif rtconfig.CROSS_TOOL == 'keil': src += ['startup/DeviceSupport/MDK-ARM/startup_MK60D10.s'] elif rtconfig.CROSS_TOOL == 'iar': src += ['startup/DeviceSupport/IAR-ARM/startup_MK60D10.s'] group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path) Return('group') ``` ```python ############### /bsp/mk60dn-1/libraries/drivers/SConscript ############### from building import * cwd = GetCurrentDir() # 直接添加了所有的驱动文件,暂时未作menuconfig板级支持代码的配置 src = Glob('*.c') CPPPATH = [cwd] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) 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')) group = group + objs Return('group') ``` ### 3.4 编写构建脚本`SConstruct` ```python 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=[]) if rtconfig.PLATFORM == 'armcc': # env = Environment(tools = ['mingw'], env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, # overwrite cflags, because cflags has '--C99' CXXCOM = '$CXX -o $TARGET --cpp -c $CXXFLAGS $_CCCOMCOM $SOURCES') else: env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, AR = rtconfig.AR, ARFLAGS = '-rc', LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, CXXCOM = '$CXX -o $TARGET -c $CXXFLAGS $_CCCOMCOM $SOURCES') 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') # prepare building environment objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) objs = objs + SConscript('libraries/SConscript') objs = objs + SConscript('libraries/drivers/SConscript') # make a building DoBuilding(TARGET, objs) ``` ### 3.5 编写构建脚本Kconfig ```python ############### /bsp/mk60dn-1/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 "$RTT_DIR/Kconfig" source "$PKGS_DIR/Kconfig" source "libraries/Kconfig" source "board/Kconfig" ``` ```python ############### /bsp/mk60dn-1/board/Kconfig ############### menu "Hardware Drivers Config" config SOC_MK60DN512VLQ10 bool select SOC_MK60DN512_SERIES select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN default y 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" select RT_USING_SERIAL default y if BSP_USING_UART config BSP_USING_UART0 bool "Enable UART0" default y config BSP_USING_UART1 bool "Enable UART1" default n endif endmenu menu "Onboard Peripheral Drivers" config BSP_USING_Peripheral bool "Not write..." default y endmenu menu "Board extended module Drivers" endmenu endmenu ``` ```python ############### /bsp/mk60dn-1/libraries/Kconfig ############### config SOC_MK60DN512_SERIES bool select ARCH_ARM_CORTEX_M4 ``` ### 3.6 编写编译器配置文件rtconfig.py ```python import os import sys # toolchains options ARCH='arm' CPU='cortex-m4' CROSS_TOOL='gcc' if os.getenv('RTT_CC'): CROSS_TOOL = os.getenv('RTT_CC') if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') # cross_tool provides the cross compiler # EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' EXEC_PATH = r'C:/XXX' elif CROSS_TOOL == 'keil': PLATFORM = 'armcc' EXEC_PATH = r'C:/Keil_v5' elif CROSS_TOOL == 'iar': PLATFORM = 'iar' EXEC_PATH = r'C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.32' if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') #BUILD = 'debug' BUILD = 'release' if PLATFORM == 'gcc': PREFIX = 'arm-none-eabi-' CC = PREFIX + 'gcc' CXX = PREFIX + 'g++' AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' TARGET_EXT = 'elf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' STRIP = PREFIX + 'strip' DEVICE = ' -mcpu=' + CPU + ' -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections' #k64f CFLAGS = DEVICE + ' -g -Wall -D__ASSEMBLY__ -D__FPU_USED' CFLAGS = DEVICE + ' -Wall -D__FPU_PRESENT -eentry' #k64f AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb ' AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb -D__START=entry' LFLAGS = DEVICE + ' -lm -lgcc -lc' + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds' CPATH = '' LPATH = '' if BUILD == 'debug': #k64f CFLAGS += ' -O0 -gdwarf-2' CFLAGS += ' -gdwarf-2' AFLAGS += ' -gdwarf-2' CFLAGS += ' -O0' else: #k64f CFLAGS += ' -O2' CFLAGS += ' -O2 -Os' #k64f POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' #rt1052 # POST_ACTION = OBJCPY + ' -O binary --remove-section=.boot_data --remove-section=.image_vertor_table --remove-section=.ncache $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' # module setting CXXFLAGS = ' -Woverloaded-virtual -fno-exceptions -fno-rtti ' M_CFLAGS = CFLAGS + ' -mlong-calls -fPIC ' M_CXXFLAGS = CXXFLAGS + ' -mlong-calls -fPIC' M_LFLAGS = DEVICE + CXXFLAGS + ' -Wl,--gc-sections,-z,max-page-size=0x4' +\ ' -shared -fPIC -nostartfiles -static-libgcc' M_POST_ACTION = STRIP + ' -R .hash $TARGET\n' + SIZE + ' $TARGET \n' elif PLATFORM == 'armcc': CC = 'armcc' CXX = 'armcc' AS = 'armasm' AR = 'armar' LINK = 'armlink' TARGET_EXT = 'axf' #k64f DEVICE = ' --cpu Cortex-M4.fp ' DEVICE = ' --cpu ' + CPU + '.fp.sp' CFLAGS = DEVICE + ' --apcs=interwork' AFLAGS = DEVICE #k64f # LFLAGS = DEVICE + ' --info sizes --info totals --info unused --info veneers --list rtthread.map --scatter "board\linker_scripts\link.sct"' LFLAGS = DEVICE + ' --libpath "' + EXEC_PATH + '\ARM\ARMCC\lib" --info sizes --info totals --info unused --info veneers --list rtthread.map --scatter "board\linker_scripts\link.sct"' #k64f # LFLAGS += ' --keep *.o(.rti_fn.*) --keep *.o(FSymTab) --keep *.o(VSymTab)' #K64f EXEC_PATH += '/ARM/ARMCC/bin/' if BUILD == 'debug': CFLAGS += ' -g -O0' AFLAGS += ' -g' else: CFLAGS += ' -O2' CXXFLAGS = CFLAGS CFLAGS += ' --c99' POST_ACTION = 'fromelf -z $TARGET' #k64f # POST_ACTION = 'fromelf --bin $TARGET --output rtthread.bin \nfromelf -z $TARGET' elif PLATFORM == 'iar': CC = 'iccarm' CXX = 'iccarm' AS = 'iasmarm' AR = 'iarchive' LINK = 'ilinkarm' TARGET_EXT = 'out' DEVICE = ' -D__FPU_PRESENT' CFLAGS = DEVICE CFLAGS += ' --diag_suppress Pa050' CFLAGS += ' --no_cse' CFLAGS += ' --no_unroll' CFLAGS += ' --no_inline' CFLAGS += ' --no_code_motion' CFLAGS += ' --no_tbaa' CFLAGS += ' --no_clustering' CFLAGS += ' --no_scheduling' CFLAGS += ' --debug' CFLAGS += ' --endian=little' CFLAGS += ' --cpu=' + CPU CFLAGS += ' -e' CFLAGS += ' --fpu=None' CFLAGS += ' --dlib_config "' + EXEC_PATH + '/arm/INC/c/DLib_Config_Normal.h"' CFLAGS += ' -Ol' CFLAGS += ' --use_c++_inline' AFLAGS = '' AFLAGS += ' -s+' AFLAGS += ' -w+' AFLAGS += ' -r' AFLAGS += ' --cpu ' + CPU AFLAGS += ' --fpu None' if BUILD == 'debug': CFLAGS += ' --debug' CFLAGS += ' -On' else: CFLAGS += ' -Oh' LFLAGS = ' --config "board/linker_scripts/link.icf"' LFLAGS += ' --redirect _Printf=_PrintfTiny' LFLAGS += ' --redirect _Scanf=_ScanfSmall' LFLAGS += ' --entry __iar_program_start' CXXFLAGS = CFLAGS EXEC_PATH = EXEC_PATH + '/arm/bin/' POST_ACTION = 'ielftool --bin $TARGET rtthread.bin' def dist_handle(BSP_ROOT): cwd_path = os.getcwd() sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools')) from sdk_dist import dist_do_building dist_do_building(BSP_ROOT) ``` ### 3.7 修改链接脚本 ==基础知识查看一下`2.8`小节== ```link.icf``` ```python /*###ICF### Section handled by ICF editor, don't touch! ****/ /*-Editor annotation file-*/ /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ /*-Specials-*/ define symbol __ICFEDIT_intvec_start__ = 0x00000000; /*向量表的起始地址*/ /*-Memory Regions-*/ define symbol __ICFEDIT_region_ROM_start__ = 0x00000000; /*ROM的起始地址*/ define symbol __ICFEDIT_region_ROM_end__ = 0x0007ffff; /*ROM的结束地址*/ define symbol __ICFEDIT_region_RAM_start__ = 0x1fff0000; /*RAM的起始地址*/ define symbol __ICFEDIT_region_RAM_end__ = 0x2000ffff; /*RAM的结束地址*/ /*-Sizes-*/ define symbol __ICFEDIT_size_cstack__ = 0x400; define symbol __ICFEDIT_size_heap__ = 0x800; /**** End of ICF editor section. ###ICF###*/ /*定义芯片的存储空间大小*/ define memory mem with size = 4G; /*----ROM的大小*/ define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to (__FlashConfig_start__ - 1)] | mem:[from (__FlashConfig_end__+1) to __ICFEDIT_region_ROM_end__]; /*----RAM的大小*/ define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__] | mem:[from __region_RAM2_start__ to __region_RAM2_end__]; /*----堆与栈的大小,8字节对齐*/ define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; /*启动时将RW数据搬移到RAM中,即进行RW数据的初始化*/ initialize by copy { readwrite }; /*不初始化有.noinit性质的块*/ do not initialize { section .noinit }; /*----在0x00000000处放置.intvec,及向量表*/ place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; /*----在ROM中放置只读数据和代码*/ place in ROM_region { readonly }; /*----在RAM中放置可读写数据、堆和栈*/ place in RAM_region { readwrite, block CSTACK, block HEAP }; ``` ### 3.8 工程创建 - 首先需要对于控制台未指定串口设备的配置,来说,需要通过`env`下的`menuconfig`图形配置界面配置默认控制台设备,本工程中使用的`uart0`,在`/bsp/mk60dn`下打开`env`,输入`menuconfig`配置如下所示:  - 保存退出会生成`.config`和`rtconfig.h`文件 - 然后`env`下输入`sons --target=iar`会按照模板生成`iar` 工程 - 打开工程修改芯片型号和`Debug`方式,如`3.8.1`小节 - **编译会出错,按照错误提示进行相关修改即可** #### 3.8.1 IAR配置 - 项目名右键`Options -->` - `General Options --> Target --> Device --> NXP --> KinetisK --> K6x --> NXP MK60DN512Zxxx10` - `Library Configuration --> Library --> Full` - 检查`Linker --> Config --> Linker configuration file` 是否为 `$PROJ_DIR$\board\linker_scripts\link.icf` - `Debuguer --> Driver --> J-Link/J-Trace` - `Debuguer --> J-Link/J-Trace --> Connection -- > SWD` #### 3.8.2 错误修改 - 若启动文件为官方文件,请修改`SystemInit`为`Start` - `finsh`内存大小配置为512字节,内存大了会提示`finsh`内存申请失败,如默认大小为4096,如下所示  当改为`512`字节时,申请成功,如下所示: 当`rtconfig.h`中对`finsh`的 配置使用的是`nano`中的配置的时候,`finsh`内存为`1024`,同样申请成功,如下所示:  ==但是申请成功之后无法使用**`finsh`**==,经过调试和查看官网文档,发现是未成功注册`uart`设备,如下所示 经过`Debug`下`k60`和`stm32f1` `finsh`的初始化流程对比,且根据上面断言`rt_device_read`错误,最终定位发现问题,在`shell.c`中找不到对接的串口设备,缺少对接`rtt`的串口注册驱动,打印输出也为`NULL`。定位代码在`shell.c`中,如下所示:  那么接下来就==对接一下串口驱动吧,详见`3.9.1`小节==,而后返回此处。 编写完`drv_uart.c`文件后,创建添加对应头文件,并在`board.c`中调用了`rt_hw_uart_init`函数,下载即可成功,如下所示:  - 还有些许其它错误,由于笔记是分阶段记录,所以有些错误会遗漏,但是根据`iar`给的提示都能够解决。 #### 3.8.3 menuconfig配置调试 现在通过上述步骤,`BSP`制作基本完成,可通过`menuconfig`配置打印一下`rtt`初始化的步骤,如下所示:  通过`menuconfig`配置之后,在env中输入`scons --target=iar`,重新生成一下工程,就会发现rtconfig.h中多了刚才的配置 ```c #define RT_DEBUG #define RT_DEBUG_INIT_CONFIG #define RT_DEBUG_INIT 1 ``` 编译下载可在串口中可以看到初始化流程,如下所示:  初始化流程大概如下: ```mermaid graph TB t1(board init satrt) --> t2(show version) --> t3(组件初始化) --> t4(board init end) t4 --> t5(组件初始化) --> t6(结束) ``` rtt启动函数放在components.c中,代码如下 ```c int rtthread_startup(void) { rt_hw_interrupt_disable(); /* board level initialization * NOTE: please initialize heap inside board initialization. */ rt_hw_board_init(); /* show RT-Thread version */ rt_show_version(); /* timer system initialization */ rt_system_timer_init(); /* scheduler system initialization */ rt_system_scheduler_init(); #ifdef RT_USING_SIGNALS /* signal system initialization */ rt_system_signal_init(); #endif /* create init_thread */ rt_application_init(); /* timer thread initialization */ rt_system_timer_thread_init(); /* idle thread initialization */ rt_thread_idle_init(); #ifdef RT_USING_SMP rt_hw_spin_lock(&_cpus_lock); #endif /*RT_USING_SMP*/ /* start scheduler */ rt_system_scheduler_start(); /* never reach here */ return 0; } ``` ### 3.9 驱动编写 #### 3.9.1串口驱动 -- 重要 首先查阅完官网的串口注册流程之后,总结串口注册流程如下: ```mermaid graph TB t1(注册以及对接开始) --> t2(rt_hw_board_init) t2 --> t3(rt_hw_usart_init) t3 --> t4(rt_hw_serial_register) t4 --> t5(rt_device_register) t5 -- 如果已经注册了此设备 --> t6(结束,返回-RT_ERROR) t5 -- 如果没有注册此设备 --> t7(注册,返回RT_EOK) ``` 串口驱动注册成功以后,还需要对接`finsh`控制台,即设置`finsh`控制台输出的串口设备,流程如下所示: ```mermaid graph TB rt_device_register --> rt_console_set_device --> rt_device_find rt_device_find --> drt_device_open --> device_init ``` 其实finsh控制台对接串口就一个`rt_console_set_device`函数,最后参考`frdm-k64f` `bsp`的串口驱动做了些许修改,最终在调试中解决问题,串口驱动`drv_uart.c`代码如下所示: ```c /* * @filename: drv_uart.c * @Descripttion: * @version: V1.0 * @Author: Bi Jiaqin * @Date: 2020-07-23 20:41:18 * @LastEditors: Bi Jiaqin * @LastEditTime: 2020-07-23 20:41:19 */ #include "rtthread.h" #include