README.md
1@page helloworld_demo helloworld_demo
2# 1. 案例简介
3helloworld_demo是我们提供的最简化的运行实例,该app从字面上来看功能也比较简单,即完成**hello world!**的关键字符输出,以表明系统初始化完成并能够正常输出。但是虽然功能看似简单单一,该app能够运行成功,即代码内核小系统以及基本的打印输出功能即正常运行。
4其完成的主要功能包括:
5- 系统板级初始化
6- 内核基础组件初始化
7- application_start用户入口
8- 串口打印输出
9- 循环睡眠打印
10该示例的运行依赖下述基本功能完成对接:
11- uart串口
12- 内核的任务和中断运行正常
13- 系统tick定时器正常运行
14即helloworld_demo这个示例运行,代码系统的**任务调度**、**tick调度**以及**串口打印功能**已经OK。
15
16# 2. 基础知识
17## 2.1 基础目录结构
18
19```sh
20.
21├── helloworld.c # 该solution核心打印输出代码,入口**application_start**
22├── k_app_config.h # 内核组件的配置开关,优先级低于**k_config.h**
23├── maintask.c # 系统主任务入口处理,入口**aos_maintask**
24├── Makefile # aos make编译时入口
25├── package.yaml # 编译系统配置文件
26└── SConstruct # Makefile => Scon => aostools
27```
28
29## 2.2 基本规范
30solution统一以**aos_maintask**作为入口函数,从具体单板的C入口main函数开始,通过创建一个主任务来执行,即aos_maintask是系统主任务的入口函数:
31```c
32static void aos_main_task_entry(void)
33{
34 ......
35 aos_maintask();
36}
37
38/* main一般为单板的C程序入口 */
39int main(void)
40{
41 ......
42 krhino_task_dyn_create(&g_main_task, "main_task", 0, OS_MAIN_TASK_PRI, 0, OS_MAIN_TASK_STACK, (task_entry_t)aos_main_task_entry, 1);
43
44 while (1) {
45 krhino_task_sleep(100);
46 }
47}
48```
49aos_maintask内实现包括板级初始化**board_init**、基础组件初始化**aos_components_init**、以及app入口**application_start**
50```c
51/* For user config
52 kinit.argc = 0;
53 kinit.argv = NULL;
54 kinit.cli_enable = 1;
55*/
56static kinit_t kinit = {0, NULL, 1};
57
58void board_init(void)
59{
60 board_tick_init(); // tick板级初始化,实现在具体board目录内
61 board_stduart_init(); // uart串口初始化,实现在具体board目录内
62 board_dma_init(); // 如果使用dma相关初始化,没有置空
63 board_gpio_init(); // gpio的时钟等初始化,没有可置空
64}
65
66void aos_maintask(void* arg)
67{
68 board_init();
69 board_kinit_init(&kinit); // 给系统参数赋值,可使用默认值
70 aos_components_init(&kinit); // 系统基础组件的初始化
71
72#ifndef AOS_BINS
73 application_start(kinit.argc, kinit.argv); // app的实际实现入口
74#endif
75}
76
77```
78其中为了统一不同单板的板级初始化,新增单板需要统一支持board_init内各板级模块初始化,如果没有相关函数可以实现为空;
79对于helloworld功能比较简单,一般需要tick和uart的初始化即可;而对于复杂的app,即需要初始化的模块则按照实际情况来增加,对应实现在具体board中添加,如:
80```c
81void board_stduart_init(void)
82void board_tick_init(void)
83void board_flash_init(void)
84void board_network_init(void)
85void board_gpio_init(void)
86void board_wdg_init(void)
87void board_ota_init(void)
88void board_dma_init(void)
89```
90对于aos_components_init,其完成了一些基础组件如vfs、cli、kv等基础中间件的初始化,并通过组件宏开关,一旦相应该基础组件模块被加入编译,则aos_components_init即进行相关模块的初始化。
91application_start是实际solution的实现,即app的统一入口。
92
93## 2.3 基本运行流程
94
95<div align=left display=flex>
96 <img src="https://img.alicdn.com/imgextra/i3/O1CN01hHWuKH1gO2oeDXMtR_!!6000000004131-2-tps-399-302.png" style="max-width:90%;" />
97</div>
98
99# 3. 物料清单
100
101## 3.1 HaaS100 硬件
102
103[HaaS100 硬件简介](https://help.aliyun.com/document_detail/184426.html)
104
105<div align=left display=flex>
106 <img src="https://img.alicdn.com/imgextra/i4/O1CN01XxD6Xo217CB3FZnEU_!!6000000006937-2-tps-746-497.png" style="max-width:90%;" />
107</div>
108
109# 4. 案例实现
110
111## 4.1 硬件连接
112该案例只需要连接电源线以及串口线,如下图所示:
113
114<div align=left display=flex>
115 <img src="https://img.alicdn.com/imgextra/i2/O1CN01S9jkJw1dihpqURQH4_!!6000000003770-0-tps-1280-960.jpg" style="max-width:90%;" />
116</div>
117
118## 4.2 软件实现
119application_start实际app入口内实现较简单,主要包括:
120- 基本的串口打印
121- while循环睡眠1S打印计数
122代码如下:
123```c
124int application_start(int argc, char *argv[])
125{
126 int count = 0;
127
128 printf("nano entry here!\r\n");
129
130 while(1) {
131 printf("hello world! count %d \r\n", count++);
132 aos_msleep(1000);
133 };
134}
135```
136其中系统能够正常打印代表uart功能正常;能够循环1S打印代表tick中断以及任务切换功能正常。
137
138## 4.3 编译下载
139### 编译
140```sh
141cd solutions/helloworld_demo && aos make
142```
143其中具体单板还需要先配置环境:
144```sh
145aos make helloworld_demo@haas100 -c config
146```
147
148### 烧录镜像命令:
149```sh
150aos burn
151```
152
153烧写步骤可以参考 [HaaS100快速开始](https://help.aliyun.com/document_detail/184184.html?spm=a2c4g.11186623.6.642.717c6489icKeP3)
154
155## 4.4 串口输出效果
156```sh
157 Welcome to AliOS Things
158nano entry here!
159hello world! count 0
160hello world! count 1
161hello world! count 2
162hello world! count 3
163hello world! count 4
164hello world! count 5
165hello world! count 6
166```
167
168# 5 添加新组件
169helloworld_demo作为一个基础组件,其本身依赖的组件相对较少,主要包括内核基础代码、cli以及单板和mcu相关的组件。
170用户可以基于此solution作为参考,来开发属于自己的app。
171如期望在helloworld_demo中增加ramfs文件系统的组件功能,操作步骤如下:
172
173## 5.1 yaml增加组件
174- 在helloworld_demo的yaml文件中添加组件依赖ramfs。由于需要使用标准vfs接口,因此还需要加上vfs组件。
175```sh
176depends:
177 - ramfs: master
178 - vfs: master
179```
180至于ramfs本身依赖的组件,则在ramfs自身的yaml中需要添加完全。
181
182- 在helloworld_demo的app入口helloworld.c中添加ramfs头文件引用以及初始化函数调用,
183如下图,先注册一个根目录为**/test**的ramfs:
184
185<div align=left display=flex>
186 <img src="https://img.alicdn.com/imgextra/i3/O1CN01yyLyVL1mbgIjh55DK_!!6000000004973-2-tps-660-404.png" style="max-width:90%;" />
187</div>
188
189- 添加功能调用
190示例:
191```c
192 #include <fcntl.h>
193 #include <sys/types.h>
194 #include <unistd.h>
195 #include "ramfs.h"
196
197 int fd;
198 int ret;
199 char teststring = "1234";
200 char readbuf[10];
201
202 ramfs_register("/test");
203 fd = open("/test/file1", O_RDWR);
204 if(fd < 0){
205 printf("ramfs open fail!\r\n");
206 return fd;
207 }
208 ret = write(fd, teststring, 5);
209 if(ret < 0){
210 printf("ramfs write fail!\r\n");
211 return ret;
212 }
213 lseek(fd, 0, SEEK_SET);
214 ret = read(fd, readbuf, 5);
215 if(ret < 0){
216 printf("ramfs read fail!\r\n");
217 return ret;
218 }
219 if(strncmp(readbuf, teststring, 5)){
220 printf("ramfs test fail! readbuf:%s\r\n",readbuf);
221 }else{
222 printf("ramfs test success!\r\n");
223 }
224 ramfs_unregister("/test");
225```
226由于使用了标准文件系统的O_RDWR相关定义,需要包含#include "fcntl.h"
227
228- 编译、运行
229
230```sh
231aos make helloworld_demo@haas100 -c config
232aos make
233```
234运行效果:
235
236```sh
237 Welcome to AliOS Things
238nano entry here!
239ramfs test success!
240hello world! count 0
241hello world! count 1
242hello world! count 2
243hello world! count 3
244```
245
246# 6. 总结
247helloworld_demo虽然代码较少,但是其完成了一个最小系统需要的基本功能,包括:内核启动、任务切换、tick中断,以及串口输出。一般作为单板移植的基本solution来参考对接;
248同时,还可以此solution为基础,开始添加用户需要的其他组件,并定制修改自身需要的APP。
249