• [技术干货] 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
  • [问题求助] 请问LiteOS源码中没有los_cpup.ph文件吗?
    请问LiteOS的los_cpup.ph文件具体内容是啥?  los_task.c文件宏定义中有如下语句#if (LOSCFG_BASE_CORE_CPUP == YES)#include "los_cpup.ph"但是设置LOSCFG_BASE_CORE_CPUP为YES后,提示找不到los_cpup.ph,源码文件夹也搜不到这个文件。
  • [问题求助] LiteOS Studio没有可能出现Linux版本呢?
        如题,我一般进行编程开发是在Linux环境下进行的,现在的嵌入式开发也没有说非要在Windows下进行开发的,所以作为自由开源引力者的华为在LiteOS的发展下是不是也要给小众开发者一个选择呢?因为在Linux下也可以进行挺多的嵌入式编程开发了,包括arm和stm32等,可能我是要求太多了,但是也是有这方面的诉求,或许技术难度很复杂,可是希望能得到官方的关注,加油!鸿蒙!加油!华为。
  • [问题求助] stm32 移植LiteOS后如何使用IAP?
    stm32 移植LiteOS后如何使用IAP?
  • [问题求助] LiteOS移植到STM32F103C8
    LiteOS\arch\arm\arm-m\src\los_hwi.c(97): warning:  #223-D: function "__get_IPSR" declared implicitlyError: L6218E: Undefined symbol __get_IPSR (referred from los_hwi.o).按照移植步骤执行到最后有错误。