工程配置指南



下面以淘宝上广泛存在的STM32F103C8T6核心板为例,建立一个闪烁LED的工程: stm32f103c8HiXwos

以下说明对Windows系统和Ubuntu系统都是通用的。

img


搭建开发环境


选择模板

xwbd文件夹中有一些名字为*stm32fxxxHiXwos*的工程,这些工程都只有一个闪烁的LED 等少量功能,可以复制这些工程作为模板。


改名

  1. 可以将工程文件夹改成自己的工程名称,名称需要符合C语言符号的规则,因为名称会在 源码中以宏定义的形式出现,"-", "@"等符号会引起语法错误;
  2. 打开配置stm32f103c8HiXwos/cfg/XuanWuOS.h,将XuanWuOS_CFG_BOARD 的定义改成与工程文件夹名称一致;
  3. 尝试编译一次,打开终端,把路径切换至XuanWuOS/xwbd/stm32fxxxHiXwos, 在终端中执行make命令。

img

修改memory区域

打开stm32f103c8HiXwos/cfg/XuanWuOS.lds,此为gcc的ld连接脚本,可以按照单片机内的资源情况修改。

/* 内部flash的信息 */
flash_mr_origin = 0x08000000;
flash_mr_size = 64k;

/* 内部RAM的信息 */
ocram_mr_origin = 0x20000000;
ocram_mr_size = 20k;

/* 定义固件的起始地址 */
fmw_origin = DEFINED(fmw)? fmw : flash_mr_origin;

/* 定义存储器信息 */
MEMORY {
        /* 内部flash的信息 */
        flash_mr (rx): org = flash_mr_origin, len = flash_mr_size
        /* 内部RAM的信息 */
        ocram_mr (rwx): org = ocram_mr_origin, len = ocram_mr_size

        /* 中断向量表的加载地址(LMA)区域 */
        vctbl_lmr (rx):
                org = fmw_origin,
                len = 1024

        /* 中断向量表的运行地址(VMA)区域 */
        vctbl_vmr (rw):
                org = fmw_origin,
                len = 1024

        /* 镜像文件的信息 */
        image_description_mr (rx):
                org = ORIGIN(vctbl_lmr) + LENGTH(vctbl_lmr),
                len = 64

        /* 代码段(.text)与只读数据段(.rodata) */
        code_mr (rx):
                org = ORIGIN(image_description_mr) + LENGTH(image_description_mr),
                len = flash_mr_size - LENGTH(image_description_mr) - LENGTH(vctbl_lmr)

        /* 数据段(.data)与未初始化的数据段(.bss) */
        data_mr (arw):
                org = data_mr_origin,
                len = 18k

        /* 玄武OS的内核栈 */
        xwos_stk_mr (rw):
                org = ORIGIN(data_mr) + LENGTH(data_mr),
                len = ocram_mr_size - LENGTH(data_mr)
}

/* 引入链接规则 */
INCLUDE soc.lds

ld的基本语法

定义存储器区域

名字 (属性): org = xxx, len = xxx
  • org: 表示定义存储器的起始地址,可以缩写为o
  • len: 表示定义存储器长度,可以缩写为l
  • ORIGIN(x): 表示取存储器x的起始地址
  • LENGTH(x): 表示取存储器x的长度
  • 属性: r表示读,w表示写,a表示可申请,x表示可执行

vctbl_lmr & vctbl_vmr

玄武OS的中断向量表区域,其中LMR表示中断向量的加载地址区域, 也即是中断向量在Flash中的存储位置,VMR表示中断向量的运行地址区域, 也即是上电运行时的中断向量的地址。

  • 如果LMR与VMR都指向Flash,且起始地址(org)与大小(len)完全一致,表示加载地址 就是运行地址,玄武OS在初始化阶段不会对中断向量执行拷贝操作;
  • 如果VMR指向RAM的某个地址,玄武OS会在初始化阶段把Flash中的中断向量表拷贝到 VMR指定的RAM内,并设置ARM的VTOR寄存器;
  • 需要注意ARM的VTOR寄存器低7位(0~6)必须保持为0,因此VMR的起始地址也必须满足 此规则。

image_description_mr

此段中包含镜像文件的一些基本信息,例如起始位置,结尾标志位置等。

code_mr

存放代码和常量的地方。此处让ld自动计算大小,把剩余flash空间全部放在此段。

data_mr

存放全局变量、静态变量的地方。此处分配了17K字节的内存。连接器ld安排完全局变量、 静态变量后的剩余的部分,玄武OS会全部交给默认的内核内存分配器, 用于为动态创建内核对象的API提供底层接口。

xwos_stk_mr

玄武OS内核的栈内存,玄武OS内核处理中断时会使用此内存作为函数的栈。 此处也让ld自动计算大小,把剩余内存全部放在此处。


使用STM32CubeMX生成源码

导入STM32CubeMX工程

已经配置好的工程:XuanWuOS/xwbd/stm32f103c8HiXwos/bm/stm32cube/cubemx/stm32f103c8HiXwos.ioc 可通过STM32CubeMX直接打开。

设置

NVIC设置

  • 设置3个抢占优先级位和1个子优先级位
  • SVC中断设置成最高优先级
  • PendSV中断设置成最低优先级
  • Systick中断设置成最低优先级

img

时钟配置

img

工程设置

img

指定源码生成的目录为 XuanWuOS/xwbd/stm32f103c8HiXwos/bm/stm32cube/cubemx

生成源码

img

集成

stm32cube的源代码使用玄武模块的形式与玄武OS进行集成。 cubemx目录的上一级为stm32cube模块的根目录。

img

cubemx

前文中已经描述过,此为STM32CubeMX生成的代码。

xwmo.mk

此玄武模块的makefile,玄武模块设计思路与Android.mk类似,需要将源码文件、 编译选项、头文件路径等列举在此文件中。 详细可以参考应用手册 —— 构建系统

standard.h

此为顶级头文件,所有源码都需要包含此文件。

mif.c/mif.h

模块接口(Module InterFace),其中包含两个重要的函数: stm32cube_lowlevel_init()stm32cube_init()stm32cube_lowlevel_init()board_lowlevel_init()调用, stm32cube_init()board_init()调用, board_lowlevel_init()board_init()都是玄武OS启动流程中的函数, 详细可参考《应用手册 —— 启动流程》

玄武OS不使用STM32CubeMX生成的启动代码,但需要调用其启动代码中的某些函数 完成对芯片的初始化,这些函数分别被stm32cube_lowlevel_init()stm32cube_init()调用。

xwac

此文件夹的源文件为玄武OS的适配代码。

  1. xwlib/crc32.c

    此源文件为玄武C库中的xwos/lib/crc32.c提供底层接口。

  2. xwos/hook.c

    此源文件提供函数stm32cube_systick_hook(),此函数被玄武OS的systick中断调用, 使得HAL库中的Tick计数器也一起增加。如果没有此函数,HAL库中的延时函数 将不能正常工作。

  3. xwos/vector.c

    中断向量表。

main.c

包含玄武OS的用户应用入口函数:xwos_main(),此函数为玄武OS初始化流程的最后一个 函数,详细可参考《应用手册 —— 启动流程》

编译

将目录切换会stm32f103c8HiXwos,打开stm32f103c8HiXwos/cfg/board.h 增加宏定义。

#define BMCFG_stm32cube  1

此宏为玄武模块stm32cube的编译开关。

如果需要编译Release版本的bin文件,可以在编译时增加选项~D=0,Release编译时会开启编译器的优化选项。

img

产生的bin文件的大小将大大减少。

img


使用STM32CubeIDE进行开发

Eclipse设置

设置代码缩进(参考)

菜单 Window –> Preferences

img

设置文件保存时自动删除行尾空白字符(参考)

菜单 Window –> Preferences

img

XuanWuOS的Code Style配置文件(参考)

通过“右键另存为”下载:

可从菜单 Window –> Preferences –> C/C++ -> Code Style -> Formatter -> Import… 导入。

新建工程

  1. 在IDE的工作目录中建立一个文件夹:stm32f103c8HiXwos;
  2. 将文件 XuanWuOS/xwbd/stm32f103c8HiXwos/bm/stm32cube/cubemx/stm32f103c8HiXwos.ioc 拷贝至这个文件夹中;
  3. XuanWuOS文件夹也拷贝到此文件夹中。

img

选择菜单"File–>New–>STM32 Project from STM32CubeMX .ioc File"

img

STM32CubeMX会自动生成代码:CoreDriversSTM32F103C8TX_FLASH.ld, 这些代码都没有用,可以删除。

文件编码设置

  • 菜单 Project –> Properties –> Resource

img

编译设置

  • 菜单 Project –> Properties
  • Debug和Release两个配置都需要增加:

img

img

环境变量设置

  • 菜单Project –> Properties –> C/C++ Build –> Environment
  • 设置
    • WKSPC: ../../../${ConfigName}
    • ~V: 1
    • ~D: Debug配置为1Release配置为0
  • Debug和Release两个配置都需要增加:

img

img

设置工具链为GNU MCU Eclipse提供的工具链

  • 参考《Ubuntu & Windows 开发环境搭建指南》安装工具;
  • 修改Debug和Release两个配置的PATH环境变量
    • 将包含gnumcu目录的路径放在前面,保证最先被搜索;
    • 删除包含STM32CubeIDE目录的所有路径。

img

头文件路径设置

头文件路径只影响Eclipse中代码的跳转,可打开菜单 Project –> Properties –> C/C++ General –> Paths and Symbols 增加头文件路径。

img

调试

先编译一次工程

img

  • 打开菜单 Run –> Debug Configurations… ,双击 GBD OpenOCD Debugging 建立新的设置;
  • 图中的命令已经在环境变量PATH中,如果无法找命令,则需要写出完整路径。 如果读者参考了之前的指南搭建开发环境,这些命令应该可被找到。

img

img

img

  • 打开菜单 Run –> Debug Configurations… ,双击 STM32 Cortext-M C/C++ Application 建立新的设置;
  • 图中的命令已经在环境变量PATH中,如果无法找命令,则需要写出完整路径。 如果读者参考了之前的指南搭建开发环境,这些命令应该可被找到。

img

img

img

开始调试

img

复位调试

如果调试过程中没有找到复位按钮,可以采用如下方法处理:

  • 在程序入口处设置一个断点;
  • 然后让程序全速运行;
  • 按一下复位按键,程序应该会停在入口的断点处。

使用命令行方式进行开发

编译

编译Release版本

cd  xwbd/stm32f103c8HiXwos
make ~D=0 -j8

编译Debug版本

cd xwbd/stm32f103c8HiXwos
make -j8

查看完整的编译过程

cd xwbd/stm32f103c8HiXwos
make ~V=1 -j8

调试

启动openocd服务

连接好调试器,打开终端,输入下列命令启动openocd

cd xwbd/stm32f103c8HiXwos
make cmdap

启动gdb

擦除Flash

打开另外一个终端,输入下面命令

cd xwbd/stm32f103c8HiXwos
make erase

擦除完成,将进入到gdb的交互终端,可使用命令 q 退出。

烧写Flash
cd xwbd/stm32f103c8HiXwos
make pgm

烧写完成,将进入到gdb的交互终端,可直接开始调试。

直接启动调试
cd xwbd/stm32f103c8HiXwos
make dbg

img

常用gdb命令

mon reset init          # 复位(如果使用SWD方式,需要在执行前按住复位按键,
                        #       然后输入这条命令,敲击回车后再释放复位按键。
                        #       JTAG方式则不需要)
mon reset halt          # 复位并挂起
mon soft_reset_halt     # 软复位(此命令已被废弃,较新的MCU可能不支持)
l path/file.c:n         # 列举源码文件path/file.c的第n行
l func                  # 列举函数func的源码
l                       # 继续列举断点处的剩余源码
b path/file.c:n         # 在path/file.c的第n行设置一个断点
b func                  # 在函数func()入口设置一个断点
i b                     # 列举所有断点信息
del x                   # 删除编号为x的断点
n                       # 单步执行
s                       # 单步执行(和上一条命令等价)
si                      # 指令级别的单步执行
ni                      # 指令级别的单步执行(和上一条命令等价)
c                       # 继续执行,直到遇到断点
mon reg                 # 显示所有寄存器
mon reg x               # 显示寄存器x的内容
disassemble             # 反汇编当前PC指针处的代码
disassemble func        # 反汇编函数func()的代码
disassemble 0xXXXX      # 反汇地址0xXXXXXXXX处的代码
q                       # 退出gdb

附录