• [技术干货] Windows10如何安装LiteOS开发环境-QEMU仿真
    1、下载软件 链接:https://pan.baidu.com/s/1kSgsD-z_fa15Web98bQtCQ  提取码:0asf2、安装软件 请把下载下来的gnumcueclipse解压到任意目录下,即可使用,不需要安装其他任何软件。 双击eclipse目录下eclipse.exe即可运行IDE。3、验证环境配置 1)新建项目LiteOS Eclipse->File->New->C/C++ Project->C Managed Build点击Next,填写Project name, 选择Project type点击Next, 如下图所示配置 要注意修改三个红框的内容点击Next,不更改配置点击Next,不更改配置点击next,确认配置是不是一样,点击Finish完成配置2) 编写代码  在main.cpp中修改main函数,添加打印信息代码int main(int argc, char *argv[])  {      // At this stage the system clock should have already been configured      // at high speed.      // Show the program parameters (passed via semihosting).      // Output is via the semihosting output channel.      trace_dump_args(argc, argv);      // Send a greeting to the trace device (skipped on Release).      trace_puts("Hello ARM World!");      // Send a message to the standard output.      puts("Standard output message.");      // Send a message to the standard error.      fprintf(stderr, "Standard error message.\n");      return 0;  }3)编译  使用快捷键Ctrl+B 可以编译全部代码,成功结果如下图:4)配置qemu 进行模拟 点击 New Launch Configuration选择如下图所示:点击Next,首先确认LiteOS.elf是否正确加载如果加载不正确,请点击Search Project,选择正确的LiteOS.elf点击Debugger 配置Qemu 目标板  Board name :STM32F429I-Discovery  Device name:STM32F429ZI最后点击Finish 完成配置 点击Run按钮进行仿真结果会看到一块板子的画面一闪而过或者会出现防火墙,请点确认就行。 在终端会显示以下信息,说明仿真成功。4、下载LiteOS代码  码云:https://gitee.com/LiteOS/LiteOS Github:https://github.com/LiteOS/LiteOS 5、在LiteOS项目中新建文件夹命名为LiteOS  使用快捷命令Ctrl+N 新建文件夹,选择 C/C++->Floder点击Next,点击LiteOS,在下面输入LiteOS打开LiteOS源码,选择 arch目录和kernel目录 Ctrl+C复制在工程中 点击LiteOS文件夹,Ctrl+V 就复制进来了同样,把源码中targets目录下的STM32F103VET6_NB_GCC/OS_CONFIG文件夹复制进来最后效果如下图:6、配置头文件、源文件  点击LiteOS 工程,使用快捷键Alt+Enter, 打开Properties for LiteOS点击C/C++ General->Paths and Symbols添加下列目录添加源文件,点击 Source Location添加下列文件夹LiteOS/arch LiteOS/kernel排除不需要文件  排除arch目录下的文件以及文件夹排除kernel目录下的文件及文件夹至此添加LiteOS文件完成7、修改代码为了使LiteOS适用STM32F429,需要修改部分代码。1) 修改 ldscripts目录下的 sections.ld 文件添加两行代码:/* 根据target_config.h中给出的memory布局,定义这两个值,用于计算LiteOS可分配内存的起止地址 */  PROVIDE ( _Min_Heap_Size = _Heap_Begin - _ebss ) ;  PROVIDE ( _Min_Stack_Size = __Main_Stack_Size ) ;2) 修改LiteOS/OS_CONFIG/ target_config.h  修改包含的头文件  //#include "stm32f1xx.h"  请把这一行修改成 #include "stm32f4xx.h"  #include "stm32f4xx.h"修改BOARD_SRAM_SIZE_KB 实际开发板RAM为192KB,请设置比开发板RAM小一点 #define BOARD_SRAM_SIZE_KB        191 3) 修改LiteOS/kernel/include/los_config.h  修改位置在文件的末尾  //extern LITE_OS_SEC_TEXT_INIT int main(void);  extern LITE_OS_SEC_TEXT_INIT int main(int argc, char *argv[]);4) 修改src/main.c 包含头文件  #include "los_base.h"修改main函数代码 int main(int argc, char *argv[])   {       // At this stage the system clock should have already been configured       // at high speed.       // Show the program parameters (passed via semihosting).       // Output is via the semihosting output channel.       trace_dump_args(argc, argv);       // Send a greeting to the trace device (skipped on Release).       trace_puts("Hello ARM World!");       // Send a message to the standard output.       puts("Standard output message.");       // Send a message to the standard error.       fprintf(stderr, "Standard error message.\n");              trace_printf("System clock: %u Hz\n", SystemCoreClock);       if (LOS_OK != LOS_KernelInit())        {           return LOS_NOK;       }       trace_printf("Hello, LiteOS!\n");       LOS_Start();       return 0;   }8、编译运行如何编译运行请看上篇文章,本章不再赘述。运行效果如下图所示:输出 Hello LiteOS! 则代表移植成功。
  • [技术干货] LiteOS操作系统中,编译出的程序为什么能打印出当前时间?
    ![](https://img-blog.csdnimg.cn/20200202094937735.png) # 1. 做实验引发的思考 在之前学习LiteOS操作系统时,我发现一个比较有趣的现象: **串口打印的日志中竟然包含着当前时间!并且,我每天做实验时,这个日期都会变化,还能保持和当前时间一致!** 我的好奇心被引发了,系统会不会偷偷配置了RTC,不然它怎么知道现在几点了? 怀揣着问题,我决定要去探索一下。 # 2. 系统打印出的当前时间 LiteOS的日志,不仅能打印出当前日期,还能精确到时分秒: ![](https://img-blog.csdnimg.cn/2020020209065887.png) # 3. 揭晓谜底 其实,这些系统之所以准确的打印出当前时间,和板子硬件没有任何关系,更不会使用的RTC,只是在代码里巧妙的利用了C语言的一个不常用知识点 —— **编译器内置宏定义**。 C语言编译器中内置了一些宏定义,这些内置宏定义可以巧妙地帮我们输出非常有用的调试信息,比如打印时间就用到了下面这两个宏定义: - `__DATE__`:在源文件中**当前的编译日期; - `__TIME__`:在源文件中**当前编译时间; 编写一个简单的C程序测试一下: ```c #include int main(void) { printf("_DATE_ is:%s\r\n", __DATE__); printf("_TIME_ is:%s\r\n", __TIME__); return 0; } ``` 编译运行,测试结果如下: ![](https://img-blog.csdnimg.cn/20200202091734250.png#pic_center) 看看LiteOS的源码实现,是不是也用`__TIME__`和`__DATE__`这两个宏定义实现: ```c static char s_link_mainversion[64]; const char *linkmain_version() { snprintf(s_link_mainversion,64,"V%d.%d.%d AT %s ON %s",CN_LINK_VERSION_MAJOR,\ CN_LINK_VERSION_MINOR,CN_LINK_VERSION_FEATURE,__TIME__,__DATE__); return s_link_mainversion; } ``` **接收更多精彩文章及资源推送,欢迎订阅我的微信公众号:『mculover666』。** ![](https://img-blog.csdnimg.cn/20200202092055136.png)
  • [技术干货] atiny_log | LiteOS 物联网操作系统中的日志打印组件使用分享
    # 1. 为什么使用日志打印组件 在使用LiteOS做项目时,经常使用串口输出调试信息以便于定位问题,查看系统运行情况。 在通常情况下,大多数人都会直接使用 printf 函数输出,但是printf函数只能输出我们编写的信息,无法输出更多的信息来帮助我们定位问题,所以**LiteOS提供了一个atiny_log日志打印组件,基于printf,比printf更有效率**。 # 2. atiny_log组件 atiny_log组件的源码非常简单,只有两个文件: ![](https://img-blog.csdnimg.cn/20200123175030855.png) - `atiny_log.h`:组件定义; - `atiny_log.c`:组件实现; 在使用的时候只需要包含头文件``即可。 atiny_log组件的使用非常简单,两点: - ① 如果你想写printf,请用`ATINY_LOG`替换; - ② 保持第一个参数为日志输出等级,其余参数和printf相同; 日志输出等级支持哪些呢?在`atiny_log.h`文件中已枚举定义: ```c typedef enum { LOG_DEBUG = 0, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_FATAL, LOG_MAX } atiny_log_e; ``` 其中提供了前五种选择,`LOG_MAX`不是日志输出等级。 # 3. atiny_log组件使用示例 编写一个测试文件`atiny_log_test.c`,编写以下内容: ```c #include #include static int atiny_log_test_entry() { /* 设置系统当前日志等级为最低 */ atiny_set_log_level(LOG_DEBUG); /* 开始测试 */ ATINY_LOG(LOG_DEBUG, "This is a LOG_DEBUG Test!\r\n"); ATINY_LOG(LOG_INFO, "This is a LOG_INFO Test!\r\n"); ATINY_LOG(LOG_WARNING, "This is a LOG_WARNING Test!\r\n"); ATINY_LOG(LOG_ERR,"This is a LOG_ERR Test!\r\n"); ATINY_LOG(LOG_FATAL, "This is a LOG_FATAL Test!\r\n"); return 0; } int standard_app_demo_main() { osal_task_create("atiny_log_test",atiny_log_test_entry,NULL,0x400,NULL,12); return 0; } ``` 编译,下载到开发板中,串口输出如下: ![](https://img-blog.csdnimg.cn/202001231759577.png) 可以看到除了正常和使用printf相同的输出之外,还加上了一些日志信息,分别为: - **该条日志的日志等级**; - **当前系统运行时间**; - **该条日志所在的文件以及该行所在位置**; 可以看到,日志输出的行号和实际文件中的行号保持一致,这样一来,**在哪儿出现问题一目了然,非常方便**: ![](https://img-blog.csdnimg.cn/20200123180219612.png#pic_center) ```
  • [技术干货] 漫谈LiteOS-端云互通组件-MQTT开发指南(上)
    端云互通组件-MQTT开发指南(上)摘要:本文介绍使用野火开发板通过Agent Tiny SDK的端云互通组件,使用MQTT协议快速接入华为云平台。通过平台侧、设备侧的开发以及调测过程来了解直接接入物联网平台模式的具体流程,希望对你有所帮助1.介绍SDK简介Agent Tiny是部署在具备广域网能力、对功耗/存储/计算资源有苛刻限制的终端设备上的轻量级互联互通中间件,您只需调用API接口,便可实现设备快速接入到物联网平台以及数据上报和命令接收等功能。Agent Tiny SDK是Huawei Agent Tiny软件开发工具包(Software Development Kit),通过Agent Tiny SDK端云互通组件,简单快速地实现与华为物联网平台安全可靠连接,可以大大减少开发周期,快速构建IoT产品。端云互通组件可以采用MQTT、CoAP和LWM2W协议接入物联网平台。Agent Tiny SDK全景图如图1所示。2. 开发环境2.1硬件需求开发计算机、运行win7及以上操作系统野火开发板STM32F429IG、数据线Jlink下载器、网线、USB转串口2.2软件需求IDE(包括GCC编译器、JDK运行环境、make工具、Jlink驱动、Eclipse)串口工具(QCOM-V1.6)实名认证的华为云账号SDK源码3.接入物联网平台流程根据设备中的接入地址,可以将接入物联网平台分为两种模式:直接接入物联网平台模式通过设备发放服务接入物联网平台模式两种接入方式的对比:直接接入物联网平台示意图通过设备发放服务接入物联网凭条示意图4.直接接入实例下面以野火STM32F429IG开发板通过以太网直接接入物联网平台为例,详细讲述接入流程。总体操作流程参考下图。说明:野火STM32F429IG开发板的详细资料可以从http://www.firebbs.cn/forum.php下载。产品模型参考设备信息参考4.1平台侧开发进入开发中心,根据上图,依次在开发中心中新建项目->新建产品->定义产品模型->注册设备。新建项目选择开发者中心并进入。点击“我的项目”中“+”,创建自己的项目。输入项目信息后点击“确定”。点击“进入项目”。新建产品选择产品开发新建产品,即可跳转到产品模型定义界面。选择自定义产品方式创建产品。补全产品的各类信息,点击“创建”,提示创建成功后点击“确定”,前往产品开发。定义产品模型选择新建服务,开始添加产品的相关特性给产品定义一个属性:batteryLevel,用于设备向平台上报,定义为int型,最大值设置为100,访问模式RWE全部勾选,完成后点击确定;给产品增加一个命令:cmd,设置下发命令属性名称:ioswitch,用于平台向设备发送命令,定义为int型,最大值99。通过上报和下发,构成了我们演示的上行和下行通道。添加完后保存:创建设备创建了产品模型之后,我们需要根据模型创建具体的设备。点击设备管理->添加真实设备,即可进入添加设备界面。进入界面之后,选择我们刚才建立的产品模型“sdk_test_001”,进行设备创建。设备标识(nodeid)是识别该设备的唯一标识符,要求唯一,此处为示范,用户使用时以实际命名为准。此处注意,确认之后自动生成产品设备ID(deviceid)及密钥(password),请记录下设备标识(nodeid)、设备ID(deviceid)及密钥(password),这三个信息主要用于对接华为云时的设备鉴权。创建完毕之后,即可在设备管理中看到刚刚创建的设备,此时设备状态为离线。到此为止,平台侧开发完毕。4.2设备侧开发设备侧开发前准备  下载SDK源码  获取接入信息(进入开发中心的“sdk_test_098”项目中,在“应用 > 对接信息”页面查看“设备接入信息”中的“MQTT接入方式”) 说明:SDK采用的是GCC+MakeFile模式,用户可以根据自己的IDE开发环境灵活适配。修改mk文件集成开发环境搭建好后,修改targets\STM32F429IGTx_FIRE\config.mk    CONFIG_OS_TYPE := "liteos"         CONFIG_ARCH_CPU_TYPE := "armv7-m"     CONFIG_SHELL_ENABLE := y     CONFIG_STIMER_ENABLE := y     CONFIG_DRIVER_ENABLE := y     CONFIG_AT_ENABLE     := y     CONFIG_CJSON_ENABLE := y     CONFIG_TCPIP_ENABLE := y     CONFIG_TCPIP_TYPE := "lwip_socket"     CONFIG_DTLS_ENABLE   := y     CONFIG_DTLS_TYPE     := "mbedtls_cert"     CONFIG_MQTT_ENABLE   := y     CONFIG_MQTT_TYPE     := "paho_mqtt"     CONFIG_OC_MQTT_ENABLE := y     CONFIG_OC_MQTT_TYPE   := "soft"     CONFIG_DEMO_ENABLE := y     CONFIG_DEMO_TYPE   := "oc_tls_mqtt_demo"      ### 产品逻辑 ###修改接入信息参考如下内容,修改demos/oc_tls_mqtt_demo.c    #define DEFAULT_LIFETIME            10         #define DEFAULT_SERVER_IPV4         "49.4.93.24"               //物联网平台MQTT接入地址     #define DEFAULT_SERVER_PORT         "8883"                     //物联网平台MQTT接入端口     #define CN_MQTT_EP_NOTEID           "device_001"               //平台侧新建的设备标识码     #define CN_MQTT_EP_DEVICEID         "c4ef0d27-8ea5-41aa-837f-361cff947601"  //平台侧设备创建成功后提供的设备ID     #define CN_MQTT_EP_PASSWD           "314483483108d92db143"     //平台侧设备创建成功后提供的密钥编译运行修改完成,编译然后debug。4.3调测通过串口工具,可以看到设备已经和物联网平台建立连接。登录开发平台->“sdk_test_098”项目 ->设备管理,可以看到我们的设备已经上线,点击调试产品,可以进入我们平台的设备调试界面。可以看到所创建的设备已经上报的数据输入ioswitch值88,点击“发送”。在串口工具可以看到接收到的命令到此调测完成。博文链接:https://bbs.huaweicloud.com/blogs/143511
  • [技术干货] liteos只开放部分代码??!很多文章介绍说Liteos支持动态加载&分散加载,但实际没发现代码。
    很多文章介绍说Liteos支持动态加载&分散加载,但是看了liteos代码没发现动态加载代码啊!谁知道咋回事!?网上说有这些函数LOS_LdInit初始化动态加载模块LOS_LdDestroy销毁动态加载模块LOS_SoLoad动态加载一个so模块LOS_ObjLoad动态加载一个obj模块LOS_FindSymByName在模块或系统符号表中查找符号地址LOS_ModuleUnload卸载一个模块LOS_PathAdd添加一个相对路径但是这些函数代码 网上哪里能找到呢?
  • [技术干货] 漫谈LiteOS-Huawei_IoT_Link_SDK_OTA 开发指导
    摘要:本文主要介绍Huawei_IoT_Link_SDK_OTA的开发指南,从概述到具体的操作步骤以及后续的编译、适配过程,希望对你有所帮助。1概述在应用升级过程中,无线下载更新(OTA)是一种常用,且方便的升级方式。Liteos采用的OTA升级方案基于LwM2M协议,实现了固件升级(FOTA)和软件升级(SOTA)两种升级方案。用户可根据自己的开发环境选择合适的升级方式。 OTA功能代码结构如下图:2升级文件二进制文件结构如图所示,升级压缩包中二进制文件如下图所示,FOTA与SOTA采用相同的固件格式。 签名校验值:长度256字节,对剩余文件进行hash计算后,并进行sha256加密后得到的签名密文。 二进制信息:预留长度32字节,升级文件是全量升级文件或增量升级文件等信息。 升级文件内容:经压缩后的升级文件,升级文件使用hdiffpatch算法对新、旧镜像进行运算生成的差分包,并使用lzma算法进行压缩。3 存储器接口存储器结构代码位于iot_link/sotrage目录下。存储器结构被划分为两部分,分别定义为存储设备(storage.c)与设备分区(partition.c)。 存储设备定义的是系统中使用的不同类型存储器及接口,如内部flash,spi flash 或 nandflash等,所使用结构体如下:typedef struct {   int id;   char *name;   uint32_t size;     void (*init)();   int (*read)(void *buf, int32_t len, uint32_t offset);   int (*write)(const uint8_t *buf, int32_t len, uint32_t offset);   int (*erase)(uint32_t offset, int32_t len);   int (*erase_write)(const void *buf, int32_t len, uint32_t offset); }storage_device;设备分区定义了用户划分的分区信息,如下所示:typedef struct _partition {   uint8_t dev_id;   char *name;   uint32_t start_addr;   uint32_t size; }storage_partition;设备分区定义了一组外部使用的接口,系统中可以使用这组接口进行相应的读写等操作。int ota_storage_bin_read(int offset, void *buf, int len); int ota_storage_bin_write(int offset, void *msg, int len); int ota_storage_flag_read(ota_flag_t *flag); int ota_storage_flag_write(ota_flag_t *flag);4 OTA管理接口系统中的OTA接口分为三个部分,OTA镜像接口、OTA包管理接口,OTA签名校验接口。4.1 OTA镜像接口OTA镜像接口包括了OTA标志镜像和OTA二进制镜像。其中OTA标志存储了升级版本号、升级文件大小、当前OTA状态及OTA升级结果等信息,其结构如下:#pragma pack(1) typedef struct {     uint8_t  ver[CN_OTA_VERSION_LEN];     uint32_t ver_code;     uint32_t file_size;   ///< the new bin file size     uint32_t blk_size;    ///< the new bin block size     uint32_t blk_num;     ///< the new bin block num     uint32_t blk_cur;     uint32_t file_off;    ///< the current offet to write     uint32_t cur_state;   ///< defined by en_ota_status_t     uint32_t ret_upgrade; ///< the upgrade,filled by the loader     uint32_t updater;     ///< fota or sota     uint32_t crc;         ///< all the ota information computed }ota_flag_t; #pragma pack()在loader和app中维护的同一份OTA标志,APP中会根据下载进度更改cur_state值,在loader中完成升级后会重置cur_state值并填充升级结果到ret_upgrade中,在进入app后将该结果上报至服务器。 外部可调用以下接口进行OTA镜像读写操作:int storage_partition_read(int part_id, uint8_t *buf, uint32_t len, uint32_t offset); int storage_partition_write(int part_id, uint8_t *buf, uint32_t len, uint32_t offset); int storage_partition_erase_write(int part_id, uint8_t *buf, uint32_t len, uint32_t offset); int storage_partition_erase(int part_id, uint32_t offset, uint32_t len);4.2 OTA包管理接口ota_pack实现对接FOTA功能的接口封装。该文件内实现了以下接口:struct pack_storage_device_api_tag_s {      int (*write_software)(pack_storage_device_api_s *thi, uint32_t offset, const uint8_t *buffer, uint32_t len);      int (*write_software_end)(pack_storage_device_api_s *thi, pack_download_result_e result, uint32_t total_len);      int (*active_software)(pack_storage_device_api_s *thi);  };4.3 OTA签名校验接口Ota_checksum实现了升级包签名验证接口。系统中可调用下面接口获取签名校验结果:int ota_pack_get_signature_verify_result(int sign_len, int file_len);若用户使用自己的公私钥对,可在此处更改prv_public_key为对应的公钥key值。5 签名验证OTA升级包签名验证在下载完成后,发送执行升级命令阶段时执行。收到执行命令后,系统首先将调用签名校验接口进行二进制文件签名校验,只有在验签通过后,才会执行后续的升级流程,否则会退出升级流程并上报升级失败到服务器。SOTA在接收到EN_PCP_MSG_EXCUTEUPDATE命令后,位于pcp.c文件中pcp_handle_msg函数。 FOTA流程的签名校验放在了ota_pack_man_software_write_end函数中。6 Loader进入Loader后会在ota_detection函数中读取OTA标志,检测当前OTA状态。若为UPDATING状态,则执行升级,否则跳转至APP。增量升级过程首先会读取升级文件内容并解析出新、旧镜像大小及所使用的压缩插件等信息。随后调用以下接口:hpatch_BOOL patch_decompress_with_cache(const hpatch_TStreamOutput* out_newData,     const hpatch_TStreamInput*  oldData,const hpatch_TStreamInput*  compressedDiff,     hpatch_TDecompress* decompressPlugin,TByte* temp_cache,TByte* temp_cache_end)执行还原差分镜像。 其中接口参数out_newData、oldData、compressedDiff,需要由用户定义并实现对应的镜像读写接口。7 FOTA / SOTAFOTA和SOTA都是基于LwM2M协议实现的升级方案,区别是基于不同的对象。FOTA使用的是协议中定义的固件对象升级方案,基于对象5实现。SOTA使用自定义对象19,并使用了PCP协议作为数据传输协议。因此,在使用SOTA时需要将config.mk中的CONFIG_PCP_ENABLE选项使能并使用oc_lwm2m_ota_demo。8 编译实现OTA功能需要编译Loader镜像和App镜像。需要对编译选项进行修改: Loader和App镜像大小定义在链接脚本中,当定义的镜像空间不足以容纳生成的镜像时,需要适当的调整其大小。Loader和app的链接脚本分别是os_loader.ld和os_loader.ld,在其中更改MEMORY中的FLASH大小,即可调节对应镜像空间。在Makefile文件中,将cfg_seperate_load_mode值改为yes,使编译系统通过链接脚本构建目标文件。  Config.mk中,需要修改以下值:CONFIG_MQTT_ENABLE := n // config中默认使用的时mqtt,需将其关闭  CONFIG_LWM2M_ENABLE := y // 使能lwm2m  CONFIG_LWM2M_TYPE := "wakaama_raw" //选择使用的lwm2m实现类型  CONFIG_OC_LWM2M_ENABLE := y // 使能lwm2m的oc接口  CONFIG_OC_LWM2M_TYPE := "atiny_lwm2m_raw" CONFIG_OTA_ENABLE := y  CONFIG_PCP_ENABLE := y // 若使用SOTA,需使能该选项  CONFIG_DEMO_TYPE := "oc_lwm2m_ota_demo" // 并使用该DEMO进行SOTA功能验证编译loader:在GCC目录下的config.mk文件中,将CONFIG_LOADER_ENABLE和CONFIG_OTA_ENABLE的值改为y,进行loader镜像编译。编译APP:在config.mk文件中,将CONFIG_LOADER_ENABLE值改为n,同时需要使能CONFIG_PCP_ENABLE和CONFIG_OTA_ENABLE选项,进行App镜像编译。9 新平台适配若用户需要在新平台上使用OTA升级功能,需要完成以下工作: 完成存储器的定义。用户需定义所使用的存储器类型接口及分区信息,并使用以下接口将其注册到系统中:int storage_dev_install(storage_device *dev, uint32_t max_num); int storage_partition_init(storage_partition *part, int32_t max_num);  完成OTA镜像接口的定义。用户需定义ota_storage_t中flag镜像与bin镜像的读写接口,并通过下面接口进行注册:int ota_storage_install(const ota_storage_t *device);对于FOTA系统,需要同时适配hal_get_ota_opt函数,填充并返回ota_opt_s的read_flash和write_flash接口。对于loader,需完成ota_detection函数,实现ota状态检查及镜像的升级功能。在config.mk中定义CONFIG_LOADER_ENABLE值为y,进行Loader镜像的编译。将改值改为n,进行APP镜像的编译。在Makefile文件中将cfg_seperate_load_mode赋值为yes,以使用对应的链接脚本来构建对应的执行文件。
  • [技术干货] 使用LiteOS MQTT_AL组件自己搭建的EMQ-X服务器(MQTT服务器)的测试代码分享
    本代码基于MQTT_AL开启成功的前提,使用MQTT_AL提供的API进行连接测试: 测试代码: ```c #include <osal.h> #include <mqtt_al.h> #include <string.h> #define DEFAULT_LIFETIME 60 #define DEFAULT_SERVER_IPV4 "122.51.89.94" #define DEFAULT_SERVER_PORT 1883 #define CN_MQTT_EP_CLIENTID "emqx-test-001" #define CN_MQTT_EP_USERNAME "mculover666" #define CN_MQTT_EP_PASSWD "123456789" static int task_report_msg_entry(void *args) { int ret = -1; void *handle = NULL; mqtt_al_conpara_t config; mqtt_al_string_t str_temp; /* 配置结构体 */ str_temp.data = DEFAULT_SERVER_IPV4; str_temp.len = sizeof(DEFAULT_SERVER_IPV4); config.serveraddr = str_temp; config.serverport = DEFAULT_SERVER_PORT; config.security = en_mqtt_al_security_none; config.version = en_mqtt_al_version_3_1_0; str_temp.data = CN_MQTT_EP_CLIENTID; str_temp.len = sizeof(CN_MQTT_EP_CLIENTID); config.clientid = str_temp; str_temp.data = CN_MQTT_EP_USERNAME; str_temp.len = sizeof(CN_MQTT_EP_USERNAME); config.user = str_temp; str_temp.data = CN_MQTT_EP_PASSWD; str_temp.len = sizeof(CN_MQTT_EP_PASSWD); config.passwd = str_temp; config.cleansession = 1; config.willmsg = NULL; config.keepalivetime = DEFAULT_LIFETIME; config.timeout = 30; /* 配置并连接服务器 */ handle = mqtt_al_connect(&config); if(handle == NULL) { /* 连接出错 */ printf("config error.\r\n"); return -1; } else { /* 进一步检查服务器返回值 */ if(config.conret != cn_mqtt_al_con_code_ok) { /* 服务器返回值出错 */ printf("server return error, conret = %d.\r\n", config.conret); return -1; } else { printf("connect to server success.\r\n"); } } while(1) { printf("config ok.\r\n"); osal_task_sleep(5*1000); } } int standard_app_demo_main() { /* 创建任务 */ osal_task_create("task_reportmsg",task_report_msg_entry,NULL,0x800,NULL,8); return 0; } ``` # 结果 ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202001/10/105653ygqu2ejbcvdq7022.png) ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202001/10/105859ufywymrrpoa9ppyf.png)
  • [问题求助] LiteOS Agent Tiny移植报错
    将LiteOS和Agent Tiny移植到STM32F103过程中报错:.\Objects\Huawei_LiteOS.axf: Error: L6218E: Undefined symbol flag_enable_hwpatch (referred from package_writer.o).追踪函数发现flag_enable_hwpatch 只有定义没有实现,package_writer.c调用flag_enable_hwpatch 导致报错。同样情况在STM32L431的示例工程里不报错,求解。
  • [问题求助] LiteOS移植报错
    参考您“https://bbs.huaweicloud.com/forum/thread-12430-1-1.html”提供的方法进行STM32L431RCT6芯片的LiteOS移植(OS_CONFIG采用的为LiteOS源码中Cloud_STM32L431RxTx_IoTClub内的文件),完成移植后提示两个未定义,曾经尝试将相关引用屏蔽,但会导致更多错误,请问这个问题该怎么解决?如果定义该如何定义呢?求指导,谢谢。
  • [问题求助] LiteOS移植过程中,编译提示:Undefined symbol __los_heap_base (referred from
    在完成LiteOS系统的移植后,通过Keil5进行编译,提示如下错误,经过多次尝试都是这个问题,请问这是什么问题,该如何解决?
  • [问题求助] LiteOS源码没有examples文件夹
    新人学习LiteOS系统移植,通过Huawei LiteOS官网提供的连接下载LiteOS源码,其中没有找到“examples”文件夹,请问怎么获得?
  • [问题求助] LiteOS是全部代码都开源了吗?
    最近在玩LiteOS,看框架和代码总感觉是一个删减版,是我的错觉,还是真的没有全部开源?
  • [技术干货] 基于LiteOS_Lab工程的SW4STM32(AC6)GCC开发环境搭建
    摘要:本文主要基于LiteOS_Lab的开发,在在SW4STM32环境下对于STM32F429IGTx野火开发板的适配工作,希望对你有所帮助。1 环境准备参考网址:https://github.com/LiteOS/LiteOS_Lab/blob/iot_link/doc/Huawei_IoT_Link_SDK_IDE_Eclipse_Guide.md1.1 安装GCC编译器首先需要安装GCC编译器” GNU Arm Embedded Toolchain”,安装完毕务必将添加环境变量“Add path to environment variable”勾选上。 下载地址: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads1.2 安装jdk运行环境安装好jdk后,新建环境变量,并添加path路径。安装后可以windows+R,输入cmd进入terminal,输入java -version,查看版本以及安装成功与否。下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html1.3 安装make工具Make 工具用于build 工程,使用Makefile 编译工程。也可根据需要自行安装所需版本。版本:gnu-mcu-eclipse-build-tools-2.9-20170629-1013-win64-setup.exe下载地址: https://github.com/gnu-mcu-eclipse/windows-build-tools/releases/tag/v2.9-20170629-10131.4 安装Jlink 驱动程序版本:JLink_Windows_V632e.exe  下载地址如下:https://www.segger.com/downloads/jlink/#JLinkSoftwareAndDocumentationPack 1.5 安装Eclipse IDE 环境下载地址: https://github.com/gnu-mcu-eclipse/org.eclipse.epp.packages/releases将下载的eclipse 直接解压即可完成安装。解压后,打开eclipse 目录,如图双击eclipse.exe 即可运行IDE 环境,建议将该应用程序创建桌面快捷方式,这样方便后续直接在桌面打开IDE环境。1.6 安装AC6环境下载最新版本v2.9,即可直接官网https://www.ac6-tools.com/downloads/SW4STM32/install_sw4stm32_win_32bits-v2.9.exe2 获取LiteOS源码下载LiteOS最新源码,并解压到指定文件夹。下载地址:https://github.com/LiteOS/LiteOS_Lab3工程创建与配置31创建工程在软件中,点击File → New → C project,开始创建工程,具体如下所示。图1自定义工程名字,选择创建空项目,以及Ac6 STM32 MCU GCC。图2之后选择开发板,选择对应系列到具体开发板,具体如下所示,可以看到同一系列的一类开发板。图3如果找不到,点击新建开发板。本文使用的是STM32F429IGTx的野火开发板,采用创建新开发板方式。 图4根据需要创建开发板并选择具体的调试接口,本文使用JTAG,注意所选MCU名称。图5接下来点击OK,可以看见开发板的详细信息,包括系列名,以及RAM、ROM的起始地址以及具体大小。图6由于后续将采用LiteOS的启动文件,此处勾选不生成启动文件。图7生成的具体目录情况如下所示,除了Includes文件夹,其余文件夹为空。图83.2 导入LiteOS源码之后在Src文件夹下,新建目录,具体操作如下所示,命名为Huawei_Lab_IoT_link,同时将其链接到LiteOS源码所在文件夹。图9图10图11点击Finish完成创建,打开Src下的Huawei_Lab_IoT_link文件夹,可以看见完整的工程目录。图123.3配置工程之后点击工具栏中Project下的Properties选项,选择C/C++ build,选择修改Build directory,将makefile generation 勾选取消,选择已有的Makefile文件,选择为LiteOS源码下D:\LiteOS\Huawei_IoT_link\LiteOS_Lab-iot_link\targets\STM32F429IGTx_FIRE\GCC文件(上述为我的链接文件路径)。图13 图14图15之后clean项目,然后选择工具栏的project选项中的build project当出现如下所示的内容时,说明make成功。图16图173.4配置调试器 接下来安装调试器,点击工具栏中Help下的Install New SoftWare选项,安装调试器,输入网址http://gnuarmeclipse.sourceforge.net/updates 稍等几秒钟会出现图中所示的调试器,可根据需要选择,本文项目中必选的是Jlink调试器。图18 图19 图20 图21接下来新建Jlink调试器,,进行如图所示的配置,选择debugger选项中添加设备名称为stm32f429IG。勾选Disable auto build。图22图23之后在Executable中选择,所安装的GNU目录项的bin文件夹下的arm-none-eabi-gdb.exe文件。之后在Common选项下选择Shared file。之后编译项目即可。图24
  • [技术干货] 漫谈LiteOS之开发板-LiteOS硬中断移植(基于GD32450i-EVAL)
    10LiteOS硬中断移植摘要:本文是承接漫谈LiteOS之开发板系列第8篇的延伸,前者使用非接管中断方式进行移植,本文是用接管中断方式进行移植,希望对你有所帮助。1 为什么移植?嵌入式设备的芯片型号和外设的差异较大,资源有限。而RTOS无法适配集成所有的驱动,因此会先适配部分开发板,然后通过移植使得适配更多的开发板。可移植性是嵌入式操作系统与普通操作系统的显著区别之一,而所谓移植就是通过一定的代码修改使得该操作系统适配自己的开发板,以使得自己的开发板可以运行一些手头开发板没有配套的编译工程。2 移植的分类移植通常分为系统移植和驱动移植,驱动移植需要依赖具体的外设,本文主要介绍操作系统的移植。采用的主要方案是硬中断接管和不接管中断中的硬中断方式。3 开发环境软件环境:Windows系统、Keil5、J-Link对应驱动;硬件环境:GD32450i-EVAL开发板、J-Link下载器、串口线、数据线;注意:上述环境也可根据自己需求进行修改,如使用IAR、GCC等。4 移植流程4.1 准备工作(1)下载LiteOS源码在github上下载最新的LiteOS源码,地址:https://github.com/LiteOS/LiteOS,下载任意版本皆可,其源码核心一致,我这里使用的是dev-deserted,其工程目录详情如图1所示。                              图1 LiteOS源码工程目录以及对应描述(2)提取LiteOS核心移植文件对LiteOS源码做一个简单的提取便于后续操作的简洁性,当然也可以不提取,新建文件夹命名为LiteOS,将 LiteOS源码中的arch文件、components/cmsis文件、kernel文件、以及targets文件中的示例工程中拷贝两个OS_CONFIG文件,其中一个为接管中断(如Standard_GD32F103C_START工程中的OS_CONFIG文件)一个为非接管中断(如Standard_STM32F103VC_TAIBI工程中的OS_CONFIG文件)。具体如下表1所示。表1 LiteOS核心文件提取一级目录一级目录一级目录描述archarmarm-mM   核中断、调度、tick相关代码commonarm核公用的 cmsis core 接口cmsisLiteOS   提供的 cmsis os接口实现kernelbasecoreLiteOS   基础内核代码文件,包括队列、task   调度、软 timer、时间片等功能OM与错误处理相关的文件IncludeLiteOS   内核内部使用的头文件ipcLiteOS   中 ipc 通讯相关的代码文件,包括事件、信号量、消息队列、互斥锁等memLiteOS   中的内核内存管理的相关代码misc内存对齐功能以及毫秒级休眠   sleep 功能includeLiteOS   开源内核头文件extendedtickless低功耗框架代码OS_CONFIG非接管中断OS_CONFIG_Take接管中断(3)创建裸机工程使用前面的串口示例代码作为裸机工程,当然也可以使用keil自己创建裸机工程,自己创建的裸机工程一定要进行简单的功能测试。将步骤(2)中的LiteOS文件拷贝到裸机工程根目录下,具体如图2所示。图2 LiteOS目录概图4.2 添加内核源码在裸机工程中,添加LiteOS相关文件夹,分别命名为LiteOS/cmsis、LiteOS/arch、LiteOS/kernel、LiteOS/config(可有可无,便于后期操作而已),并分别将cmsis os代码、kernel代码、arch代码、OS_CONFIG文件等添加到对应的文件夹,具体如图3所示。图3 添加工程分组其中需要添加的源码以及对应的文件所在位置具体如下表所示。添加后的文件目录详情,具体如图4所示。图4 添加Lite OS源码4.3 添加头文件添加源码之后,需要添加对应应用的头文件,具体如图5所示。图5 添加头文件4.4 修改target.h文件与非接管中断方式不同,需要对头文件和接管中断方式进行修改。其头文件如图6所示。第43行,需要修改为开发板相对应的系列头文件。图6 target.h头文件修改接管中断方式改为YES,第94行,如下所示#define LOSCFG_PLATFORM_HWI                                 YES4.5 修改启动文件由于LiteOS接管中断方式的中断向量表示系统管理的,因此启动文件需要进行修改。即将los_startup_keil.s文件添加到keil文件夹下,同时将裸机工程中的startup_gd32450.s文件删除,具体如图7所示。图7 修改启动文件4.6 分散加载文件修改首先在编译后生成的文件(E:\GD32450i-EVAL\Project\GD32F450I_TakeOver\MDK-ARM\output) 文件夹下的GD32450I_EVAL.sct文件即为分散加载文件,此处需要根据开发板的RAM以及Flash大小进行一定的修改,二者大小具体如图8所示。图8 查看开发板SRAM大小  sct文件默认下是keil自动生成的,需要使用LiteOS开发中的。sct文件。该文件在LiteOS源码中的targets中的例程中位于MDK_ARM文件夹下,可以拷贝过来之后根据flash以及RAM进行地址的调整。具体使用的设置如图9所示。图9 配置sct文件路径  由于中断向量表示放在运行内存里的,为了避免影响分配内存,需要将代码分散加载到不同的区域中,因此需要对分散加载文件进行修改本文中附件会有该文件。具体修改如图10所示。图10分散加载文件的修改  其中1(0x08000000):表示flash的起始地址。2(0x00100000):表示域大小(Flash大小)对于GD32450i-EVAL开发板其大小为1M。其中3(0x20000000):表示运行时域基地址。4(0x400)表示存储中断向量表的空间大小。其中5(0x20000400):大小为3+4。6(0x0002F800):表示存放数据段的空间大小。其中7(0x20000400):大小为5+6。4.5 注释回调函数代码由于PendSV_Handler以及SysTick_Handler(void)函数在LiteOS源码以及裸机工程中的gd32f4xx_it.c文件中都有定义,因此如果直接编译会出现重定义的错误,如图11所示。此时我们需要将对应gd32f4xx_it.c中代码注释掉或删除即可。图11 运行错误详情5 测试上面已经将移植工作基本完成,后面只需要做一下测试即可,具体包括硬件测试以及LiteOS测试。5.1 硬件启动测试对于测试,首先需要将串口调试好,便于后续的调试,此处我以串口函数以及LED灯进行测试。在使用LiteOS系统之前首先需要将开发板启动起来,具体如下所示。但是需要注意的是初始化的时候不要调用delay函数,因为SysTick_Handler(void)函数被注释掉了,如果调用该函数会导致,程序卡死在delay处。测试的时候一定要注意main函数中要有while循环使其卡停在此处。#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h>   void Hardware_Init(void); void led_init(void); int main() {   Hardware_Init();   printf("\r\n USART printf example: please press the Tamper key \r\n");           while(1){       gd_eval_led_on(LED1);   } }   void Hardware_Init(void) {   led_init();   systick_config();   gd_eval_com_init(EVAL_COM1); }   void led_init(void) {   gd_eval_led_init(LED1); }   int fputc(int ch, FILE *f) {   usart_data_transmit(EVAL_COM1, (uint8_t)ch);   while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));    return ch; }5.2 移植功能测试接下来只需要对Lite OS移植进行测试,对主函数进行修改实现任务的创建于调用即可,主函数具体如下所示。#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h> #include "los_sys.h " #include "los_typedef.h" #include "los_task.ph"    UINT32 g_TskHandle;   void Hardware_Init(void); void led_init(void); UINT32 creat_task1(); UINT32 creat_task2();   int main(){   Hardware_Init();   printf("\r\n USART printf example: please press the Tamper key \r\n");   UINT32 uwRet = 0;   uwRet = LOS_KernelInit();   if (uwRet != LOS_OK){     return LOS_NOK;   }   uwRet = creat_task1();   if (uwRet != LOS_OK){     return LOS_NOK;   }   uwRet = creat_task2();   if (uwRet != LOS_OK){     return LOS_NOK;   }   LOS_Start();   while(1){     gd_eval_led_on(LED1);   } }   void Hardware_Init(void){   led_init();   systick_config();   gd_eval_com_init(EVAL_COM1); }   void led_init(void){   gd_eval_led_init(LED1); }   int fputc(int ch, FILE *f){   usart_data_transmit(EVAL_COM1, (uint8_t)ch);   while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));      return ch; }   void task1(void){   int count = 1;   while(1){     printf("This is task1, count is %d\r\n", count++);     LOS_TaskDelay(1000);   } }   UINT32 creat_task1(){     UINT32 uwRet = LOS_OK;   TSK_INIT_PARAM_S task_init_param;           task_init_param.usTaskPrio = 0;   task_init_param.pcName = "task1";   task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task1;   task_init_param.uwStackSize = 0x200;           uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param);   if(LOS_OK != uwRet){     return uwRet;   }   return uwRet; }   void task2(void){   int count = 1;   while (1){       printf("This is task2,count is %d\r\n",count++);       LOS_TaskDelay(2000);   } } UINT32 creat_task2(){   UINT32 uwRet = LOS_OK;   TSK_INIT_PARAM_S task_init_param;     task_init_param.usTaskPrio = 1;   task_init_param.pcName = "task2";   task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task2;   task_init_param.uwStackSize = 0x200;     uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param);   if(LOS_OK != uwRet){     return uwRet;   }   return uwRet; }运行结果如图12所示,可以看见两个任务在交替打印。移植完成,本例程使用的是非接管中断的方式,如果使用接管中断方式的,需要拷贝结果中断的OS_CONFIG文件,同时对于target.h文件需要额外的修改,同时修改.sct文件(在keil工程下的Objects文件夹下),而不是使用自动生成的.sct文件.图12 Lite OS移植成功运行结果主文博客链接:https://bbs.huaweicloud.com/blogs/124244
  • [技术干货] 漫谈LiteOS之开发板-LiteOS硬中断移植(基于GD32450i-EVAL)
    10LiteOS硬中断移植摘要:本文是承接漫谈LiteOS之开发板系列第8篇的延伸,前者使用非接管中断方式进行移植,本文是用接管中断方式进行移植,希望对你有所帮助。1 为什么移植?嵌入式设备的芯片型号和外设的差异较大,资源有限。而RTOS无法适配集成所有的驱动,因此会先适配部分开发板,然后通过移植使得适配更多的开发板。可移植性是嵌入式操作系统与普通操作系统的显著区别之一,而所谓移植就是通过一定的代码修改使得该操作系统适配自己的开发板,以使得自己的开发板可以运行一些手头开发板没有配套的编译工程。2 移植的分类移植通常分为系统移植和驱动移植,驱动移植需要依赖具体的外设,本文主要介绍操作系统的移植。采用的主要方案是硬中断接管和不接管中断中的硬中断方式。3 开发环境软件环境:Windows系统、Keil5、J-Link对应驱动;硬件环境:GD32450i-EVAL开发板、J-Link下载器、串口线、数据线;注意:上述环境也可根据自己需求进行修改,如使用IAR、GCC等。4 移植流程4.1 准备工作(1)下载LiteOS源码在github上下载最新的LiteOS源码,地址:https://github.com/LiteOS/LiteOS,下载任意版本皆可,其源码核心一致,我这里使用的是dev-deserted,其工程目录详情如图1所示。                              图1 LiteOS源码工程目录以及对应描述(2)提取LiteOS核心移植文件对LiteOS源码做一个简单的提取便于后续操作的简洁性,当然也可以不提取,新建文件夹命名为LiteOS,将 LiteOS源码中的arch文件、components/cmsis文件、kernel文件、以及targets文件中的示例工程中拷贝两个OS_CONFIG文件,其中一个为接管中断(如Standard_GD32F103C_START工程中的OS_CONFIG文件)一个为非接管中断(如Standard_STM32F103VC_TAIBI工程中的OS_CONFIG文件)。具体如下表1所示。表1 LiteOS核心文件提取一级目录一级目录一级目录描述archarmarm-mM   核中断、调度、tick相关代码commonarm核公用的 cmsis core 接口cmsisLiteOS   提供的 cmsis os接口实现kernelbasecoreLiteOS   基础内核代码文件,包括队列、task   调度、软 timer、时间片等功能OM与错误处理相关的文件IncludeLiteOS   内核内部使用的头文件ipcLiteOS   中 ipc 通讯相关的代码文件,包括事件、信号量、消息队列、互斥锁等memLiteOS   中的内核内存管理的相关代码misc内存对齐功能以及毫秒级休眠   sleep 功能includeLiteOS   开源内核头文件extendedtickless低功耗框架代码OS_CONFIG非接管中断OS_CONFIG_Take接管中断(3)创建裸机工程使用前面的串口示例代码作为裸机工程,当然也可以使用keil自己创建裸机工程,自己创建的裸机工程一定要进行简单的功能测试。将步骤(2)中的LiteOS文件拷贝到裸机工程根目录下,具体如图2所示。图2 LiteOS目录概图4.2 添加内核源码在裸机工程中,添加LiteOS相关文件夹,分别命名为LiteOS/cmsis、LiteOS/arch、LiteOS/kernel、LiteOS/config(可有可无,便于后期操作而已),并分别将cmsis os代码、kernel代码、arch代码、OS_CONFIG文件等添加到对应的文件夹,具体如图3所示。图3 添加工程分组其中需要添加的源码以及对应的文件所在位置具体如下表所示。添加后的文件目录详情,具体如图4所示。图4 添加Lite OS源码4.3 添加头文件添加源码之后,需要添加对应应用的头文件,具体如图5所示。图5 添加头文件4.4 修改target.h文件与非接管中断方式不同,需要对头文件和接管中断方式进行修改。其头文件如图6所示。第43行,需要修改为开发板相对应的系列头文件。图6 target.h头文件修改接管中断方式改为YES,第94行,如下所示#define LOSCFG_PLATFORM_HWI                                 YES4.5 修改启动文件由于LiteOS接管中断方式的中断向量表示系统管理的,因此启动文件需要进行修改。即将los_startup_keil.s文件添加到keil文件夹下,同时将裸机工程中的startup_gd32450.s文件删除,具体如图7所示。图7 修改启动文件4.6 分散加载文件修改首先在编译后生成的文件(E:\GD32450i-EVAL\Project\GD32F450I_TakeOver\MDK-ARM\output) 文件夹下的GD32450I_EVAL.sct文件即为分散加载文件,此处需要根据开发板的RAM以及Flash大小进行一定的修改,二者大小具体如图8所示。图8 查看开发板SRAM大小  sct文件默认下是keil自动生成的,需要使用LiteOS开发中的。sct文件。该文件在LiteOS源码中的targets中的例程中位于MDK_ARM文件夹下,可以拷贝过来之后根据flash以及RAM进行地址的调整。具体使用的设置如图9所示。图9 配置sct文件路径  由于中断向量表示放在运行内存里的,为了避免影响分配内存,需要将代码分散加载到不同的区域中,因此需要对分散加载文件进行修改本文中附件会有该文件。具体修改如图10所示。图10分散加载文件的修改  其中1(0x08000000):表示flash的起始地址。2(0x00100000):表示域大小(Flash大小)对于GD32450i-EVAL开发板其大小为1M。其中3(0x20000000):表示运行时域基地址。4(0x400)表示存储中断向量表的空间大小。其中5(0x20000400):大小为3+4。6(0x0002F800):表示存放数据段的空间大小。其中7(0x20000400):大小为5+6。4.5 注释回调函数代码由于PendSV_Handler以及SysTick_Handler(void)函数在LiteOS源码以及裸机工程中的gd32f4xx_it.c文件中都有定义,因此如果直接编译会出现重定义的错误,如图11所示。此时我们需要将对应gd32f4xx_it.c中代码注释掉或删除即可。图11 运行错误详情5 测试上面已经将移植工作基本完成,后面只需要做一下测试即可,具体包括硬件测试以及LiteOS测试。5.1 硬件启动测试对于测试,首先需要将串口调试好,便于后续的调试,此处我以串口函数以及LED灯进行测试。在使用LiteOS系统之前首先需要将开发板启动起来,具体如下所示。但是需要注意的是初始化的时候不要调用delay函数,因为SysTick_Handler(void)函数被注释掉了,如果调用该函数会导致,程序卡死在delay处。测试的时候一定要注意main函数中要有while循环使其卡停在此处。#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h>   void Hardware_Init(void); void led_init(void); int main() {   Hardware_Init();   printf("\r\n USART printf example: please press the Tamper key \r\n");           while(1){       gd_eval_led_on(LED1);   } }   void Hardware_Init(void) {   led_init();   systick_config();   gd_eval_com_init(EVAL_COM1); }   void led_init(void) {   gd_eval_led_init(LED1); }   int fputc(int ch, FILE *f) {   usart_data_transmit(EVAL_COM1, (uint8_t)ch);   while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));    return ch; }5.2 移植功能测试接下来只需要对Lite OS移植进行测试,对主函数进行修改实现任务的创建于调用即可,主函数具体如下所示。#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h> #include "los_sys.h " #include "los_typedef.h" #include "los_task.ph"    UINT32 g_TskHandle;   void Hardware_Init(void); void led_init(void); UINT32 creat_task1(); UINT32 creat_task2();   int main(){   Hardware_Init();   printf("\r\n USART printf example: please press the Tamper key \r\n");   UINT32 uwRet = 0;   uwRet = LOS_KernelInit();   if (uwRet != LOS_OK){     return LOS_NOK;   }   uwRet = creat_task1();   if (uwRet != LOS_OK){     return LOS_NOK;   }   uwRet = creat_task2();   if (uwRet != LOS_OK){     return LOS_NOK;   }   LOS_Start();   while(1){     gd_eval_led_on(LED1);   } }   void Hardware_Init(void){   led_init();   systick_config();   gd_eval_com_init(EVAL_COM1); }   void led_init(void){   gd_eval_led_init(LED1); }   int fputc(int ch, FILE *f){   usart_data_transmit(EVAL_COM1, (uint8_t)ch);   while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE));      return ch; }   void task1(void){   int count = 1;   while(1){     printf("This is task1, count is %d\r\n", count++);     LOS_TaskDelay(1000);   } }   UINT32 creat_task1(){     UINT32 uwRet = LOS_OK;   TSK_INIT_PARAM_S task_init_param;           task_init_param.usTaskPrio = 0;   task_init_param.pcName = "task1";   task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task1;   task_init_param.uwStackSize = 0x200;           uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param);   if(LOS_OK != uwRet){     return uwRet;   }   return uwRet; }   void task2(void){   int count = 1;   while (1){       printf("This is task2,count is %d\r\n",count++);       LOS_TaskDelay(2000);   } } UINT32 creat_task2(){   UINT32 uwRet = LOS_OK;   TSK_INIT_PARAM_S task_init_param;     task_init_param.usTaskPrio = 1;   task_init_param.pcName = "task2";   task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task2;   task_init_param.uwStackSize = 0x200;     uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param);   if(LOS_OK != uwRet){     return uwRet;   }   return uwRet; }运行结果如图12所示,可以看见两个任务在交替打印。移植完成,本例程使用的是非接管中断的方式,如果使用接管中断方式的,需要拷贝结果中断的OS_CONFIG文件,同时对于target.h文件需要额外的修改,同时修改.sct文件(在keil工程下的Objects文件夹下),而不是使用自动生成的.sct文件.图12 Lite OS移植成功运行结果主文博客链接:https://bbs.huaweicloud.com/blogs/124244
总条数:623 到第
上滑加载中