2019 年腾讯开源了自己的物联网(internet of thing, IoT) 操作系统 TencentOS tiny,我加入了他们的官方讨论群,关注了很久。最近疫情在家把TencentOS tiny移植到了自己的一块STM32F407的开发板上,移植还算顺利,这里记录一下过程。

需求

腾讯官方移植指南没有具体型号MCU的介绍,网上我只找到了这篇博客 https://juejin.im/post/5da7289d51882553690284a3 介绍了STM32F103的MCU的移植。我自己的开发板STM32F407的,网上没有,有必要记录下来供参考。

开发板介绍

我用的是这个STM32F407VET6 black board开发板,ARM Cortex-M4 内核,相同内核的开发板都可以参考。

STM32F407VET6 black board
STM32F407VET6 black board

具体步骤


创建keil下的裸机工程模板

先找到开发板的前后台系统工程模板,一般买开发板的时候学习资料里就有,也可以在我的github上下载,这是下载链接https://github.com/ZmengXu/STM32ProjectTemplate.git

用Keil软件(也可以在linux或者mac上写个Makefile文件通过arm-none-eabi-gcc来编译,后面我会写个这样的教程)打开工程模板中USER/Template.uvprojx文件, 我用的是Keil μVision5,打开后是这样的

F7编译工程文件,如果下载的是我GitHub上提供的文件,编译是可以直接通过的,并且会自动新建一个OBJ文件夹,并在该文件夹下生成Template.hex的16进制文件。

接下来将Template.hex文件写入STM32F407开发板。我用的是ST-LINK V2 采用SW方式连接开发板,打开魔法棒Options for Target按钮,选Debug, 右侧Use选项打开下拉菜单选ST-Link Debugger,然后点击setting,修改ort选项为SW,连接好开发板插入ST-LINK,这时候右侧SW Device就可以看到电脑找到了刚刚插入的设备。

回到桌面,点击Download,刚刚的16进制文件Template.hex就被写入开发板了。连接上串口,打开串口调试助手,按一下开发板上的复位,调试助手就可以收到这样的输入信息了。

创建新的工程并移植TencentOS tiny

下载TencentOS tiny的源码

去GitHub上https://github.com/Tencent/TencentOS-tiny或者去腾讯工蜂开源仓https://git.code.tencent.com/Tencent_Open_Source/TencentOS-tiny下载。我是在GitHub上下的,参考杰杰的建议后者会快些。

下载下来后有很多子目录,但我们只需要下面几个目录。

一级目录 二级目录 说明
arch arm/arm-v7m TencentOS tiny适配的IP核架构(含M核中断、调度、tick相关代码)
board STM32F407VGT6_discovery/TOS_CONFIG 移植目标芯片的工程文件的配置文件,根据情况选一个最接近自己开发板的
kernel core TencentOS tiny内核源码
pm tiny低功耗模块源码,本次移植暂不使用
osal cmsis_os TencentOS tiny提供的cmsis os 适配

修改工程文件

复制一个模板工程目录,重命名为Demo_MultiTask,在该目录下新建一个文件夹,TencentOS,然后把arm-v7mcorecmsis_os目录复制到TencentOS中。

创建一个TOS_CONFIG子文件夹,并创建一个tos_config.h文件,下面是我用到的,附有腾讯官方解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#ifndef _TOS_CONFIG_H_
#define _TOS_CONFIG_H_

#include "stm32f4xx.h" // 目标芯片头文件,用户需要根据情况更改

#define TOS_CFG_TASK_PRIO_MAX 10u // 配置TencentOS tiny默认支持的最大优先级数量

#define TOS_CFG_ROUND_ROBIN_EN 0u // 配置TencentOS tiny的内核是否开启时间片轮转

#define TOS_CFG_OBJECT_VERIFY_EN 1u // 配置TencentOS tiny是否校验指针合法

#define TOS_CFG_TASK_DYNAMIC_CREATE_EN 1u // TencentOS tiny 动态任务创建功能宏

#define TOS_CFG_EVENT_EN 1u // TencentOS tiny 事件模块功能宏

#define TOS_CFG_MMBLK_EN 1u //配置TencentOS tiny是否开启内存块管理模块

#define TOS_CFG_MMHEAP_EN 1u //配置TencentOS tiny是否开启动态内存模块

#define TOS_CFG_MMHEAP_DEFAULT_POOL_EN 1u // TencentOS tiny 默认动态内存池功能宏

#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE 0x100 // 配置TencentOS tiny默认动态内存池大小

#define TOS_CFG_MUTEX_EN 1u // 配置TencentOS tiny是否开启互斥锁模块

#define TOS_CFG_MESSAGE_QUEUE_EN 1u // 配置TencentOS tiny是否开启消息队列模块

#define TOS_CFG_MAIL_QUEUE_EN 1u // 配置TencentOS tiny是否开启消息邮箱模块

#define TOS_CFG_PRIORITY_MESSAGE_QUEUE_EN 1u // 配置TencentOS tiny是否开启优先级消息队列模块

#define TOS_CFG_PRIORITY_MAIL_QUEUE_EN 1u // 配置TencentOS tiny是否开启优先级消息邮箱模块

#define TOS_CFG_TIMER_EN 1u // 配置TencentOS tiny是否开启软件定时器模块

#define TOS_CFG_PWR_MGR_EN 0u // 配置TencentOS tiny是否开启外设电源管理模块

#define TOS_CFG_TICKLESS_EN 0u // 配置Tickless 低功耗模块开关

#define TOS_CFG_SEM_EN 1u // 配置TencentOS tiny是否开启信号量模块

#define TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN 1u // 配置TencentOS tiny是否开启任务栈深度检测

#define TOS_CFG_FAULT_BACKTRACE_EN 0u // 配置TencentOS tiny是否开启异常栈回溯功能

#define TOS_CFG_IDLE_TASK_STK_SIZE 1512 // 配置TencentOS tiny空闲任务栈大小

#define TOS_CFG_CPU_TICK_PER_SECOND 1000u // 配置TencentOS tiny的tick频率

#define TOS_CFG_CPU_CLOCK (SystemCoreClock) // 配置TencentOS tiny CPU频率

#define TOS_CFG_TIMER_AS_PROC 1u // 配置是否将TIMER配置成函数模式

#endif

添加.c和.s文件到工程中

打开USER/Template.uvprojx文件,依次添加arch平台代码和内核源码。具体地

点击File Extensions新建工程分组tos/arch。点击右侧的Add Files添加TencentOS\arm-v7m\cortex-m4\common里的tos_cpu.c文件和TencentOS\arm-v7m\cortex-m4\armcc里的port_c.cport_c.S。同样新建工程分组和tos/kernel。添加TencentOS\kernel\core里的所有.c文件。另外,pm是内核中的低功耗组件,基础移植的时候可以不添加。

添加TencentOS tiny头文件目录

打开魔法棒Options for Target按钮,选C/C++, 右侧Use选项打开下拉菜
点击添加的头文件目录如下:

1
2
3
4
5
..\TencentOS\arm-v7m\common\include
..\TencentOS\arm-v7m\cortex-m4\armcc
..\TencentOS\core\include
..\TencentOS\cmsis_os
..\TencentOS\TOS-CONFIG

//在C/C++界面上一定要勾上c99,否则编译的时候出underfined reference 的错误(好像不是这个原因,是我忘了添加tos_cpu.c文件了,不需要)

修改部分代码

修改SYSTEM/USART/usart.c第29行,_sys_exit(int x) 改为 void _sys_exit(int x)

修改stm32f4xx_it.c

  1. 包含#include "tos_k.h" 头文件
  2. 注释掉PendSV_Handler函数
  3. SysTick_Handler函数中添加TencentOS tiny的调度处理函数
    修改后stm32f4xx_it.c长这样
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include "stm32f4xx_it.h"
    #include "tos_k.h"
    ...
    /**
    * @brief This function handles PendSVC exception.
    * @param None
    * @retval None
    */
    //void PendSV_Handler(void)
    //{
    //}

    /**
    * @brief This function handles SysTick Handler.
    * @param None
    * @retval None
    */
    void SysTick_Handler(void)
    {
    if (tos_knl_is_running())
    {
    tos_knl_irq_enter();
    tos_tick_handler();
    tos_knl_irq_leave();
    }
    }
    ...

编写main.c

这里参考官方测试代码,原链接在这里 https://github.com/Tencent/TencentOS-tiny/blob/master/doc/10.Porting_Manual_for_KEIL.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "sys.h"
#include "delay.h"
#include "usart.h"

#include "tos_k.h"
#include "cmsis_os.h"

//task1
#define TASK1_STK_SIZE 256
void task1(void *pdata);
osThreadDef(task1, osPriorityNormal, 1, TASK1_STK_SIZE);

//task2
#define TASK2_STK_SIZE 256
void task2(void *pdata);
osThreadDef(task2, osPriorityNormal, 1, TASK2_STK_SIZE);

void task1(void *pdata)
{
int count = 1;
while(1)
{
printf("\r\nHello world!\r\n###This is task1 ,count is %d \r\n", count++);
osDelay(2000);
}
}
void task2(void *pdata)
{
int count = 1;
while(1)
{
printf("\r\nHello TencentOS !\r\n***This is task2 ,count is %d \r\n", count++);
osDelay(1000);
}
}

int main(void)
{
uart_init(115200); //bps 115200
printf("Welcome to TencentOS tiny\r\n");

osKernelInitialize(); //TOS Tiny kernel initialize
osThreadCreate(osThread(task1), NULL);// Create task1
osThreadCreate(osThread(task2), NULL);// Create task2
osKernelStart();//Start TOS Tiny
}

编译并测试

编译和下载与模板例子模板例子一样,F7编译工程文件,没有错误的话连接ST-LINK V2和开发板,点击Download下载程序到开发板。

找一个USB转串口连接上电脑和开发板的UART1端口,记得TX-RX,RX-TX交替连接。打开串口调试助手,选择波特率115200,然后复位开发板,就可以收到上面的信息了。task1和task2交替打印,就说明TencentOS-tiny的任务调度功能实现了,移植成功。

下载链接

我放在github上了https://github.com/ZmengXu/STM32ProjectTemplate.git。如果访问不了,可以发邮件找我要。