# TencentOS tiny定制开发板EVB_AIoT快速入门指南 | Revision | Date | Description | | -------- | --------- | ----------- | | 1.0 | 2021-11-09 | 文档初版 | ## 一. 定制开发板EVB_AIoT硬件简介 ### 1.1 开发板简介 EVB_AIoT是腾讯物联网操作系统TencentOS tiny 团队联合恩智浦半导体、厚德物联网设计的一款高性能AIoT评估板,用于TencentOS tiny 基础内核和AIoT应用功能体验和评估。 开发板如下图所示: ![](image/EVB_AIoT_guide/EVB_AIoT.jpg) ### 1.2 开发板特性 内置TencentOS Tiny开源物联网操作系统 NXP RT1062跨界处理器,最高主频528M 1M RAM 16M SDRAM 64MB qspi flash 128MB spi flash 板载Type-C接口CMSIS DAP仿真器 板载PCIE接口,可扩展4G类物联网模组 板载物联网俱乐部WAN Interface接口,可支持NB-IoT、WiFi、4G cat1、LoRa等模组 板载物联网俱乐部E53 Interface接口,可扩展全系E53传感器; 板载标准24P DVP摄像头接口,可支持最高500万像素摄像头; 板载RGB显示接口,可转换HDMI输出; 板载高性能音频解码芯片,可做语音识别测试; 预留SD卡、用户按键、SPI Flash ## 二. 定制开发板EVB_AIoT软件开发环境准备 ### 2.1 MCUXpresso IDE 介绍 MCUXpresso IDE,是恩智浦公司为开发人员提供的一款基于Eclipse的集成开发环境,可以支持基于ARM Cortex M内核的NXP MCU。MCUXpresso IDE 提供高级编辑、编译和调试功能,并添加了特定于 MCU 的调试视图、代码跟踪和分析、多核调试和集成配置工具,可以帮助开发者基于NXP官方SDK快速搭建MCU软件开发环境。 ### 2.2 MCUXpresso IDE安装 登录NXP官网,下载MCUXpresso IDE软件,下载地址: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-integrated-development-environment-ide:MCUXpresso-IDE?tab=Design_Tools_Tab 这里我下载的版本当前最新的MCUXpresso IDE v11.4.1,本开发教程以该版本为例,双击下载下来的安装文件,按照提示完成安装即可。 安装完成启动软件可以看到如下欢迎界面: ![](image/EVB_AIoT_guide/IDE.png) 然后我们就可以使用IDE了,如图,可以下载安装不同MCU 芯片的官方SDK,可以创建新的项目,可以导入官方SDK的应用案例等。 ### 2.3 NXP RT1060 官方SDK包安装 安装完 MCUXpresso IDE后,我们需要安装开发套件中MCU型号对应的SDK包。 在欢迎界面点击 DownLoad and Install SDKs按钮,或者在项目界面点击按钮,如下图,进入SDK选择界面 ![](image/EVB_AIoT_guide/Install_sdk.png) 进入SDK选择界面后,输入对应的MCU RT1060,开始筛选SDK包,选择对应MCU系列的官方EVK,再点击Install即可完成安装,如下图: ![](image/EVB_AIoT_guide/Install_rt1060_sdk.png) 至此,我们开发板的开发环境已经搭建完毕,可以开始进行代码开发。 ### 2.4 串口调试助手的安装与使用 工具下载: http://www.daxia.com/download/sscom.rar 安装方法:串口调试助手sscom5.13.1是免安装的,解压出压缩包即可直接使用。 ![](./image/EVB_AIoT_guide/development_env_sscom.png) 根据PC和终端之间的连接,选择正确的串行端口。 打开电脑的设备管理器,在端口列表可以看到PC与开发板连接的端口号。 ![](./image/EVB_AIoT_guide/development_env_sscom_port.png) 我这里显示的是COM6,所以要在sscom工具中选择COM6,开发板程序波特率设置为115200,所以我在sscom串口工具中选择115200波特率。 ### 2.5 使用MCUXpresso IDE搭建第一个Hello World 裸机工程 关闭欢迎界面,我们在左下方Create or import a project 选型卡里面选择Import SDK examples ,开始从SDK里面导入Hello World 示例。如下图所示。 ![](image/EVB_AIoT_guide/Import_sdk.png) 进入向导后选择SDK,然后下一步 ![](image/EVB_AIoT_guide/Import_sdk_wizard.png) 在demo apps 里面选择hello world示例,点击完成,即可生成hello World项目 ![](image/EVB_AIoT_guide/Import_sdk_demo.png) ![](image/EVB_AIoT_guide/Install_sdk_hello.png) 生成项目后,可以在工程上右键选择构建项目来完成代码编译,如下图: ![](image/EVB_AIoT_guide/sdk_compile.png) 完成编译后,正确连接 usb typec 到 5V IN 端口,同时注意 SW1 应该拨到 AT MCU 一侧,如下图: ![](image/EVB_AIoT_guide/com_switch_and_typec.png) 接着在工程上右键选择调试方式,再选择CMSIS-DAP(开发板板载了CMSIS DAP调试器)进行工程下载和调试,如下图: ![](image/EVB_AIoT_guide/sdk_debug.png) 使用Type-C USB 连接好电脑,打开sscom串口助手,就可以看到hello world的打印信息,如图: ![](image/EVB_AIoT_guide/sdk_result.png) ## 三. 在EVB_AIoT开发板上移植TencentOS tiny内核 ### 3.1 准备裸机工程 移植TencentOS Tiny内核前,我们先准备一个简单的点灯工程,这里跟前面的步骤一样,我们先使用MCUXpresso IDE 基于RT1060 SDK生成基础工程; ![](image/EVB_AIoT_guide/Port_001.png) ![](image/EVB_AIoT_guide/Port_002.png) 通过SDK 导入 Driver examples-> igpio_led_output 示例工程,如下图: ![](image/EVB_AIoT_guide/Port_003.png) 但是这里sdk默认使用的LED的GPIO端口跟我们开发板上的不一致,我们需要使用 MCUXpresso IDE的 MCUXpresso Config Tools进行引脚配置,查阅开发板原理图,可以发现开发板上的LED接到的是RT1062 MCU的 GPIO_SD_B1_02(M3)脚,这里我们打开MCUXpresso Config Tools-> Open Pins 或者直接点击IDE界面的芯片引脚图标对GPIO进行配置,如图所示: ![](image/EVB_AIoT_guide/Port_004.png) ![](image/EVB_AIoT_guide/Port_005.png) 打开引脚配置后,我们找到左侧的引脚列表,选择GPIO_SD_B1_02(M3)引脚,配置为GPIO3_IO02,如下图 ![](image/EVB_AIoT_guide/Port_006.png) 完成后点击更新源代码,IDE就会将刚才配置好的代码更新到工程,如下图所示: ![](image/EVB_AIoT_guide/Port_007.png) 也可以看到 pin_mux.c文件中GPIO的初始化代码有更新,如下图: ![](image/EVB_AIoT_guide/Port_008.png) 同时,我们修改下工程中board.h文件中LED的GPIO端口和引脚号代码,如下图 ![](image/EVB_AIoT_guide/Port_009.png) 修改完成编译下载到开发板,可以看到开发板上的LED灯闪烁,这样说明我们的基础工程完成了。 ### 3.2 基于裸机工程移植内核 提前在 TencentOS Tiny官方项目仓下载内核代码,下载地址: https://github.com/Tencent/TencentOS-tiny 拷贝如下目录的内核代码到新建的TencentOS-Tiny文件夹备用(请严格按照一下目录拷贝,不需要拷贝多余的) |一级目录 | 二级目录 | 三级目录 | 四级目录 | 五级目录 | 说明 | |---------|---------|---------|---------|---------|---------| | arch | arm | arm-v7m | common | | TencentOS tiny 中断tick相关代码 | | | | | cortex-m7 |gcc |TencentOS Tiny M核调度汇编 GCC | | kernel | core | | | | TencentOS tiny内核源码| | | hal | | | | TencentOS tiny驱动抽象层| | | pm | | | | TencentOS tiny低功耗源码| |TOS_CONFIG| | | | | TencentOS tiny配置头文件,用户自定义,从模板修改过来| 这里只介绍TencentOS tiny的内核移植,所以这里只需要用到 arch、kernel两个目录下的源码。 将全部内核源码复制到工程目录下,如下图: ![](image/EVB_AIoT_guide/Port_010.png) 然后我们在工程界面按F5刷新工程,就可以在源码目录看到TencentOS Tiny的内核源码了,如图所示: ![](image/EVB_AIoT_guide/Port_011.png) 接下来,我们在gpio_led_output.c添加TencentOS Tiny内核初始化和相关任务代码 #### 3.2.1 包含内核头文件 #include "tos_k.h" #### 3.2.2 添加Tick处理函数 SysTick_Handler ,代码如下: ``` void SysTick_Handler(void) { if (tos_knl_is_running()) { tos_knl_irq_enter(); tos_tick_handler(); tos_knl_irq_leave(); } } ``` #### 3.2.3 新建两个测试任务 ``` #define TASK1_STK_SIZE 1024 k_task_t task1; uint8_t task1_stk[TASK1_STK_SIZE]; #define TASK2_STK_SIZE 1024 k_task_t task2; uint8_t task2_stk[TASK2_STK_SIZE]; void task1_entry(void *arg) { while (1) { PRINTF("###I am task1\r\n"); tos_task_delay(2000); } } void task2_entry(void *arg) { while (1) { PRINTF("***I am task2\r\n"); tos_task_delay(1000); } } ``` #### 3.2.4 在main函数后面增加操作系统初始化函数 ``` int main(void) { /* Define the init structure for the output LED pin*/ gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; /* Board pin, clock, debug console init */ BOARD_ConfigMPU(); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); /* Print a note to terminal. */ PRINTF("\r\n GPIO Driver example\r\n"); PRINTF("\r\n Welcome to TencentOS Tiny!\r\n"); /* Init output LED GPIO. */ GPIO_PinInit(EXAMPLE_LED_GPIO, EXAMPLE_LED_GPIO_PIN, &led_config); tos_knl_init(); // TencentOS Tiny kernel initialize tos_task_create(&task1, "task1", task1_entry, NULL, 4, task1_stk, TASK1_STK_SIZE, 0); // Create task1 tos_task_create(&task2, "task2", task2_entry, NULL, 3, task2_stk, TASK2_STK_SIZE, 0);// Create task2 tos_knl_start(); } ``` #### 3.2.5 在工程里面配置TencentOS Tiny 头文件编译目录 如图,需要在IDE里面配置TencentOS Tiny的编译头文件目录,按如图所示配置即可: ![](image/EVB_AIoT_guide/Port_012.png) #### 3.2.6 修改tos_config.h文件 ``` #ifndef _TOS_CONFIG_H_ #define _TOS_CONFIG_H_ #include "board.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 0x2000 // 配置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 128u // 配置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 ``` #### 3.2.7 编译下载测试 编译完成下载到开发板,通过串口助手我们可以看到两个任务交替运行,打印task信息,说明内核移植成功,如下图所示: ![](image/EVB_AIoT_guide/Port_013.png) ## 四. EVB_AIoT开发板上使用TencentOS tiny对接腾讯云IoT Explorer 基于TencentOS Tiny EVB AIoT要完成腾讯云IoT Explorer对接,需要完成两个部分的工作。 一是:腾讯云IoT explorer 上完成项目、产品、设备创建、参数配置 二是:基于TencentOS Tiny完成终端应用开发,向腾讯云上报业务数据。 ### 4.1 云端操作步骤 #### 4.1.1 新建项目 登录[腾讯云物联网开发平台](https://cloud.tencent.com/product/iotexplorer),点击新建项目,填写项目名称和简介: ![](image/EVB_AIoT_guide/cloud_001.png) #### 4.1.2 新建产品 点击项目名称进入到该项目中,点击新建产品: ![](image/EVB_AIoT_guide/cloud_002.png) 产品新建成功后,可在产品列表页查看到: ![](image/EVB_AIoT_guide/cloud_003.png) #### 4.1.3 数据模板 进入产品,点击【物模型】,点击【导入物模型】,导入下面的JSON代码: ```json { "version": "1.0", "properties": [ { "id": "Count", "name": "计数器", "desc": "", "mode": "r", "define": { "type": "int", "min": "0", "max": "9999", "start": "0", "step": "1", "unit": "n" }, "required": false } ], "events": [], "actions": [], "profile": { "ProductId": "JTT7WSTP6T", "CategoryId": "1" } } ``` 导入之后自动根据json文件创建的属性如下: ![](image/EVB_AIoT_guide/cloud_004.png) #### 4.1.4 创建设备 点击【设备调试】,进入后点击【新建设备】,创建真实设备: ![](image/EVB_AIoT_guide/cloud_005.png) 创建成功之后进入设备,查看到产品ID、设备名称、设备秘钥: ![](image/EVB_AIoT_guide/cloud_006.png) ### 4.2 基于TencentOS Tiny AIoT 开发板完成设备侧应用开发 对接腾讯云物联网平台需要使用网络模块,我们开发板上有WAN Interface 可以扩展wifi 4G LoRa等等,这里我们扩展一个esp8266 wifi模块,如下图所示 ![](image/EVB_AIoT_guide/cloud_000.png) 端侧的案例程序可以从微云下载,地址: 链接:https://share.weiyun.com/N299vYzD 密码:wsuwsx 下载完成后解压工程,然后使用 MCUXpresso IDE 导入已有工程,具体操作如下: ![](image/EVB_AIoT_guide/cloud_007.png) ![](image/EVB_AIoT_guide/cloud_008.png) 完成导入后,可以看到对应的工程,如图所示: ![](image/EVB_AIoT_guide/cloud_009.png) 打开工程后进入 < NXP_RT1062_TencentOS_Tiny_AIoT\source\mqttclient_iot_explorer.c> 源文件,根据您的网络环境和云端创建的产品设备信息修改终端参数。 #### 4.2.1 修改WIFI接入信息 找到mqttclient_task函数,修改要接入WIFI的名称和密码(建议使用手机热点,不要有特殊字符): ![](image/EVB_AIoT_guide/cloud_013.png) #### 4.2.2 修改云端对接信息 终端的MQTT客户端需要对应的产品ID、设备ID,密码,我们从云端获取到对应的信息备用,如下图所示: ![](image/EVB_AIoT_guide/cloud_014.png) 获取到云端设备的产品ID、设备名称、设备密钥三元组后,我们使用如下的python脚本来生成mqtt 用户名 密码等信息: python脚本如下,也可以到https://github.com/OpenAtomFoundation/TencentOS-tiny/blob/master/tools/mqtt_config_gen.py 获取。 ``` #!/usr/bin/python # -*- coding: UTF-8 -*- import base64 import hashlib import hmac import random import string import time from string import Template # bind raw_input to input in Python 2 try: input = raw_input except NameError: pass product_id = input("product id:") dev_name = input("device name:") passwd = input("password:") sub = input("subscribe topic:[default:control]") if sub == "": sub = "control" pub = input("publish topic:[default:event]") if pub == "": pub = "event" client_id = product_id + dev_name # expire time: 2^32 - 1 = 4294967295 username = client_id+";21010406;12365;{}".format(4294967295) def hmacsha1(content, passwd): passwd_byte = base64.b64decode(passwd) return hmac.new(passwd_byte, content, digestmod=hashlib.sha1).hexdigest() username = username.encode("utf-8") passwd = passwd.encode("utf-8") sign = hmacsha1(username, passwd) template_header = ('#ifndef TOS_MQTT_CONFIG_H\n' '#define TOS_MQTT_CONFIG_H\n' '\n' '#define MQTT_SERVER_IP "111.230.189.156"\n' '#define MQTT_SERVER_PORT "1883"\n' '#define MQTT_PRODUCT_ID "$product"\n' '#define MQTT_DEV_NAME "$dev"\n' '#define MQTT_CLIENT_ID "$product$dev"\n' '#define MQTT_USR_NAME "$product$dev;21010406;12365;4294967295"\n' '#define MQTT_PASSWORD "$sign;hmacsha1"\n' '#define MQTT_SUBSCRIBE_TOPIC "$product/$dev/$sub"\n' '#define MQTT_PUBLISH_TOPIC "$product/$dev/$pub"\n' '\n' '#define MQTT_SERVER_DOMAIN "$product.iotcloud.tencentdevices.com"\n' '#define MQTT_TOPIC "$product/$dev"\n' '#define MQTT_SUBSCRIBE_TOPIC_DOWN "$thing/down/property/$product/$dev"\n' '#define MQTT_PUBLISH_TOPIC_UP "$thing/up/property/$product/$dev"\n' '\n' '#endif\n' '\n') template_c = ('#ifndef TOS_MQTT_CONFIG_H\n' 'tos_sal_module_parse_domain(MQTT_SERVER_DOMAIN,host_ip,sizeof(host_ip));\n' '\n' 'mqtt_set_port(client, MQTT_SERVER_PORT);\n' 'mqtt_set_host(client, host_ip);\n' 'mqtt_set_client_id(client, MQTT_CLIENT_ID);\n' 'mqtt_set_user_name(client, MQTT_USR_NAME);\n' 'mqtt_set_password(client, MQTT_PASSWORD);\n' 'mqtt_set_clean_session(client, 1);\n' '\n' 'error = mqtt_subscribe(client, MQTT_SUBSCRIBE_TOPIC_DOWN, QOS0, tos_topic_handler);\n' '\n' 'error = mqtt_publish(client, MQTT_PUBLISH_TOPIC_UP, &msg);\n' '\n' '#endif\n' '\n') src_header = Template(template_header) src_c = Template(template_c) d = { 'product':product_id, 'dev':dev_name, 'sign':sign, 'sub':sub, 'pub':pub, 'thing':'$thing' } #do the substitution dst_header = src_header.substitute(d) dst_c = src_c.substitute(d) print("===============Generate mqtt_config.h==================") print(dst_header) with open('mqtt_config.h', 'w') as f: f.write(dst_header) print("===============Generate mqtt_connect_demo.c==================") print(dst_c) with open('mqtt_connect_demo.c', 'w') as f: f.write(dst_c) ``` 运行python脚本,一次输入产品ID、设备名称、设备密钥,就可以生成对用的mqtt信息了,如下图所示: ![](image/EVB_AIoT_guide/cloud_015.png) 然后我们根据生成的mqtt 客户端信息修改mqttclient_task函数,需要修改的内容如下: ![](image/EVB_AIoT_guide/cloud_016.png) 最新版本的mqtt_config_gen.py将同时生成mqtt_config.h、mqtt_connect_demo.c文件,引入mqtt_config.h后,可直接复制mqtt_connect_demo.c中的示例代码,到mqttclient_task函数之中对应的部分。 #### 4.2.3 编译工程 工程上右键,选择构建项目,编译整个工程: ![](image/EVB_AIoT_guide/cloud_017.png) #### 4.2.4 下载程序 工程右键,选择调试方式,进入MCUXpresso IDE LinkServer CMSIS DAP ,下载程序到开发板并进行调试: ![](image/EVB_AIoT_guide/cloud_018.png) #### 4.2.5 使用串口助手查看日志 运行sscom软件,打开电脑上开发板对应的串口,比如我选择COM6,点击【打开串口】: 按下开发板上的复位键,程序开始运行,即可在串口助手中看到系统运行打印的日志: ![](image/EVB_AIoT_guide/cloud_019.png) 从日志中可以看到wifi连接成功,mqtt对接腾讯云物联网平台成功; 同时数据上传成功也会出现如下日志: ![](image/EVB_AIoT_guide/cloud_020.png) ### 4.3 云端平台查看设备数据 回到腾讯云物联网开发平台,可以看到设备状态变为【在线】: ![](image/EVB_AIoT_guide/cloud_010.png) 点击【设备日志】一栏,可以看到设备上报的计数值: ![](image/EVB_AIoT_guide/cloud_011.png) 点击【设备属性】一栏,点击【计数器】后的【查看】,即可看到计数值的历史数据曲线图: ![](image/EVB_AIoT_guide/cloud_012.png) ## 五、腾讯连连小程序操作步骤 ### 5.1 添加家庭 手机端在【微信】搜索【腾讯连连】小程序,首次使用需要进入后点击【我的】->【家庭管理】,添加一个你喜欢的名称即可。 ### 5.2 添加调试设备 返回【首页】,点击右上角“加号”图标: ![](image/EVB_AIoT_guide/app_001.png) 进入后点击右上角扫码图标: ![](image/EVB_AIoT_guide/app_002.png) 在腾讯云物联网开发平台进入【设备调试】,点击对应设备后的【二维码】: ![](image/EVB_AIoT_guide/app_003.png) 腾讯连连扫描此二维码即可成功添加设备,添加成功之后如图: ![](image/EVB_AIoT_guide/app_004.png) 点击此设备即可实时查看数据,并下发控制指令: ![](image/EVB_AIoT_guide/app_005.png) 写在结尾的话:感谢大家使用TencentOS Tiny,本文难免有描述不清晰的地方,如果有任何问题,欢迎加入TencentOS Tiny 的官网QQ技术群进行交流,基于TencentOS Tiny相关的项目合作请邮件联系 supowang@tencent.com ![](./image/EVB_AIoT_guide/TencentOS_Tiny_qq.png)