物联网RTOS新贵-TencentOS tiny入门

1 前沿

让我们先简单回顾下物联网(The Internet Of Things)的历史,

1999年,物联网概念第一次被提出;

2009年,“感知中国”的概念被提出,物联网被正式列入国家新兴战略性产业之一;

2013年,Semtech LoRa技术商用;

2016年,NB-IoT R13核心技术标准的冻结,全球运营商有了基于标准化的物联网专有协议,窄带物联网迎来规模商用;

2017年,以NB-IoT、LoRa为代表的「LPWAN」物联网技术异军突起与迅猛发展,LPWAN的技术特性让万物互联场景的实现变成了可能;

2019年,5G商用正式拉开序幕,将为物联网产业的发展搭建一条高速公路.....

同时伴随着十几年互联网技术发展,大数据、云计算、人工智能(机器学习)、IoT通信技术等多种技术的成熟与不断融合,物联网的愿景再一次进化——让万物互联照进现实。

全球权威的信息提供商IHS、IDC、Gartner公司的分析报告都指出到2020年,全球可连接设备数将超过200~300多亿。面对如此海量的连接设备,物联网再一次成为了群雄逐鹿的赛场。同时,面对物联网高度碎片化的特点,各路大佬们纷纷摇旗呐喊,不约而同打造物联网生态。

2016年,HUAWEI CONNECT 大会上,华为正式发布了以IoT联接管理平台为核心的OceanConnect IoT平台。

2017年开始,腾讯云全面布局物联网,为行业客户提供加速物联网+的基础服务,包括:基础云服务、智能化的AI大数据服务,以及物联PaaS服务。

2017年底,华为确定了与IoT紧密相关的新愿景:“把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界”。

2018云栖大会·深圳峰会阿里云总裁胡晓明宣布:阿里巴巴将全面进军物联网领域,IoT是阿里巴巴集团继电商、金融、物流、云计算后新的主赛道。

2018年3月,阿里云发布支持LoRa协议的LinkWAN平台。

2019年7月,腾讯发布一站式物联网开发平台:腾讯云IoT Explorer,或将为物联网应用的爆炸式增长扫除最后一道门槛。

物联网RTOS作为IoT终端侧的基础软件,在一定程度上可以破解物联网下游的碎片化困局,加快下游物联网应用的开发进程,同时海量的物联网应用爆发与普及也会带动芯片\存储等成本持续降低,正如同早些年的IoT WiFi芯片,现在的IoT BLE芯片,规模效应后,单片成本已经快探底,成本承压也会变得不太敏感,进而可进一步释放物联网终端侧的硬件资源瓶颈。各路大佬布局物联网RTOS,卡位数据入口,使得RTOS插上物联网翅膀,在万物互联时代再一次起飞翱翔...

接下来,我们来尝鲜一下物联网RTOS新贵——TencentOS tiny

1.1 IoT RTOS的新贵TencentOS tiny

TencentOS作为IoT RTOS的后起之秀,具备了物联网RTOS几大典型特征:

  • 扩芯片平台
  • 硬实时内核、多任务、IPC通信...
  • 小的FLASH\RAM开销
  • 低功耗
  • 多种联网、上云能力
  • 安全能力
  • 丰富组件

下文学习如何基于MDK与STM32L4实现第一个TencentOS tiny应用程序——串口输出“Hello World”,作为TencentOS tiny入门的第一个里程碑,打开TencentOS tiny知识的大门。

PS:本文代码基于TencentOS tiny 1.0版本(2019.09.18正式对外开源版本)

1.2 内容提要

下文主要内容涉及了TencentOS tiny入门知识、基于MDK的开发环境搭建、TencentOS tiny内核启动过程、main入口与应用层代码入口、helloworld应用示例等。

  • TencentOS tiny入门知识
    • TencentOS tiny系统架构
    • TencentOS tiny源代码目录树
  • 基于MDK的开发环境搭建
  • 基于MDK的TencentOS tiny启动流程
    • TencentOS tiny main函数入口
    • 应用程序入口
  • TencentOS tiny 第一个应用helloworld

2 TencentOS tiny入门知识

2.1 TencentOS tiny系统架构

TencentOS tiny系统架构符合分层架构设计与组件化架构设计原则。TencentOS tiny架构至下(层)而上(层),分别是

  • 2.2 TencentOS tiny文件夹目录树

TencentOS tiny系统架构体现在源代码文件组织结构,如下图所示

image.png

TencentOS tiny源代码一级文件夹目录树


3 开发环境搭建

开发环境主要取决于使用的硬件芯片平台与个人开发习惯。

TencentOS tiny目前主要支持Cortex-M、Risc-V的32位MCU,当前支持BSP里面都提供了KEIL(MDK)示例工程,部分也同时提供了IAR、GCC,对于习惯在Window开发Cortex-M产品的小伙伴会比较熟悉。

针对开发环境,简单对比下国内另外两款非常火的IoT RTOS:

  • RT-Thread4.0.x这块会更完善,提供了基于Python & Scons且无需安装的Env工具,通过简单修改Kconfig与SConscript文件,就可以非常快速生成MDK、IAR工程,工具用熟以后,移植是非常高效的,另外RT-Thread发展历史悠久,积累支持的BSP也非常多。
  • AliOS Things2.1.x同样提供了基于Python & Scons的AOS-Cube工具,可快速生成MDK、IAR工程,但目前支持的BSP尚不太多,还正在完善中。

3.1 基于MDK与STM32L4的开发环境搭建

查看下 TencentOS tiny\board 是否有与目标主芯片相似的示例工程

  1. 如果是已有相似平台的话,直接拷贝该示例工程作为项目原型,然后根据实际硬件,重新配置,移植也会相对简单高效。比如本文平台目标芯片为STM32L476VGT6,STM32同系列芯片可以共用相同底层代码,因此这里直接修改TencentOS tiny\board\NUCLEO_STM32L476RG
  2. 如果没有的话,需要参考官方移植文档,具体可如“6 参考”章节相关内容。

4 基于MDK的TOS内核启动流程

在嵌入式系统(MCU)中,启动文件(比如startup_stm32l476xx.s)是芯片上电最先运行的一段程序,是整个系统软件非常关键的部分,如果启动文件出现错误,则整个系统就跑不起来。

4.1 MCU的启动过程

MCU上电后,启动文件会自动进行一些MCU芯片底层的初始化,构建程序运行必要的环境,包括:

  • 堆栈空间定义与初始化
    • 变量初始化
    • 申请与定义中断向量表
    • 定义复位中断函数(Reset_Handler)
  • 用SystemInit()函数来初始化系统的各种时钟、向量表偏移,然后调用(跳转到)__main()函数
    • __main()调用库函数初始化堆栈
  • 其他中断异常服务函数定义(弱[WEAK]申明)

通常,芯片原厂都提供了MDK对应内核芯片(比如ST STM32L4xx...)启动文件,启动文件由汇编程序编写,一般命名为startup_xxx.s,xxx为支持的芯片型号,比如startup_stm32l476xx.s。

image.png

基于MDK开发,一般可直接使用芯片原厂提供的启动文件,不需要涉及启动文件的修改。

4.2 内核启动过程

通过“4.1 MCU的启动过程”完成了MCU从系统上电开始运行到系统进入应用程序主代码(main函数)的准备工作。接下来便是TencentOS tiny内核启动。

下文结合TencentOS tiny与board\NUCLEO_STM32L476RG的开发板示例进行说明。

4.2.1 TencentOS tiny的main程序入口

TencentOS tiny的main()函数主要完成以下工作:

  1. board_init()板级初始化,初始化系统时钟(system clock)、相关外设初始化(TencentOS tiny目前没有提供设备驱动框架,因此这块跟裸机开发一样,直接使用STM32CubeMX生成代码)
  2. 调用osKernelInitialize,调用内核相关初始化操作,用户根据实际项目通过board\NUCLEO_STM32L476RG\TOS_CONFIG\tos_config.h相关宏定制内核服务等
    1. 在这里面会创建系统IDLE任务
  3. 调用osThreadCreate,创建一个application_entry任务,在application_entry()任务中会开始执行应用层代码。application_entry()默认采用__weak弱定义,用户重新自定义实现application_entry()即可.
  4. 最后调用osKernelStart,启动系统调度

TencentOS tiny内核启动流程,如下所示:

从TencentOS tiny实际代码看看:

1. main()函数所处的位置位于硬件平台的BSP文件夹中,比如\board\NUCLEO_STM32L476RG\main.c。

int main(void)
{
    board_init();
    printf("Welcome to TencentOS tiny\r\n");
    osKernelInitialize(); // TOS Tiny kernel initialize
    osThreadCreate(osThread(application_entry), NULL); // Create TOS Tiny task
    osKernelStart(); // Start TOS Tiny
}

2. board\LR_STM32L476RG\BSP\Src\mcu_init.c定义了硬件平台的系统时钟、GPIO、串口等MCU外设初始化

void board_init(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
}

4.2.2 应用程序入口

TencentOS tiny默认通过弱定义的application_entry()任务作为应用层代码的入口,用户根据实际项目重新自定义application_entry(),并添加应用层代码。

应用层参考代码放在example目录下,在application_entry()函数中实现应用代码,如“5章节” Hello Word示例应用。

__weak void application_entry(void *arg)
{
    while (1) {
        printf("This is a demo task,please use your task entry!\r\n");
        tos_task_delay(1000);
    }
}

5 第一个应用 HelloWorld

TencentOS tiny的hello world应用程序放在TencentOS-tiny\examples\hello_world\hello_world.c

#define TASK1_STK_SIZE    512
void task1(void *arg);
osThreadDef(task1, osPriorityNormal, 1, TASK1_STK_SIZE);

#define TASK2_STK_SIZE    512
void task2(void *arg);
osThreadDef(task2, osPriorityNormal, 1, TASK2_STK_SIZE);

// 每2s钟printf hello world
void task1(void *arg)
{
    int count = 1;
    while (1) {
        printf("###This is task1,Hello World %d\r\n", count++);
        osDelay(2000);
    }
}

// 每1s钟printf hello world
void task2(void *arg)
{
    int count = 1;
    while (1) {
#if TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN > 0u
        k_err_t rc;
        int depth;

        rc = tos_task_stack_draught_depth(K_NULL, &depth);
        printf("%d  %d\n", rc, depth);
#endif

        printf("***This is task2,Hello World %d\r\n", count++);
        osDelay(1000);
    }
}

// 重新定义application_entry,将自动取代已有__week修饰的application_entry
void application_entry(void *arg)
{
    osThreadCreate(osThread(task1), NULL); // Create task1
    osThreadCreate(osThread(task2), NULL); // Create task2
}

使用Doxygen生成的函数调用关系,可以比较清楚看到函数之间的调用逻辑,如下图所示

                                                             application_entry系统调用图

                                                                application_entry系统调用图(局部放大)

                         image.png

                                                         task1函数调用图 

                             image.png

                                                         task2函数调用图

通过Jlink等下载到STM32L4硬件板子上,并运行,实际效果如下:

                                           image.png

                                                   串口Hello World示例

6 参考

猜你喜欢

转载自blog.csdn.net/nich2009/article/details/101094512