This commit is contained in:
Donggang Cao 2020-10-30 21:18:20 +08:00
commit ef46906e68
36 changed files with 1941 additions and 1889 deletions

View File

@ -47,6 +47,10 @@ module.exports = {
text: '内核', text: '内核',
link: '/doc/kernel/', link: '/doc/kernel/',
}, },
{
text: '组件',
link: '/doc/component/'
},
{ {
text: '处理器', text: '处理器',
link: '/doc/processor/', link: '/doc/processor/',
@ -68,12 +72,16 @@ module.exports = {
link: '/doc/board/', link: '/doc/board/',
}, },
{ {
text: '应用开发', text: '自研终端',
link: '/doc/appdev/', link: '/doc/selfterminal/'
}, },
{ {
text: '应用框架', text: '应用框架',
link: '/doc/apparch/' link: '/doc/apparch/'
},
{
text: '快速上手',
link: '/doc/appdev/',
} }
] ]
}, },
@ -117,6 +125,10 @@ module.exports = {
title: '内核', title: '内核',
children: getSidebarByCategory('kernel','en') children: getSidebarByCategory('kernel','en')
}, },
{
title: '组件',
children: getSidebarByCategory('component','en')
},
{ {
title: '处理器', title: '处理器',
children: getSidebarByCategory('processor','en') children: getSidebarByCategory('processor','en')
@ -138,14 +150,24 @@ module.exports = {
children: getSidebarByCategory('board','en') children: getSidebarByCategory('board','en')
}, },
{ {
title: '应用开发', title: '自研终端',
children: getSidebarByCategory('appdev','en') children: getSidebarByCategory('selfterminal','en')
}, },
{ {
title: '应用', title: '应用架',
children: getSidebarByCategory('apparch','en') children: getSidebarByCategory('apparch','en')
},
{
title: '快速上手',
children: getSidebarByCategory('appdev','en')
} }
], ],
'/about/': [
['','项目概况'],
['xuos','XiUOS操作系统计划'],
['contact','联系方式'],
['license','开源协议']
]
} }
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 KiB

View File

@ -1,12 +1,18 @@
const sidebar = { const sidebar = {
'intro': [ 'intro': [
'/doc/intro', '/doc/intro',
], ],
'kernel': [ 'kernel': [
'/doc/kernel/task', '/doc/kernel/task',
'/doc/kernel/mm', '/doc/kernel/mm',
'/doc/kernel/synchron', '/doc/kernel/int',
'/doc/kernel/threadcommunication' '/doc/kernel/tmr'
],
'component': [
'/doc/component/fs',
'/doc/component/drvmodel',
'/doc/component/lib',
'/doc/component/gui'
], ],
'board': [ 'board': [
'/doc/board/aiit-arm32', '/doc/board/aiit-arm32',
@ -42,7 +48,8 @@ const sidebar = {
'/doc/sensor/magneto_sensor', '/doc/sensor/magneto_sensor',
'/doc/sensor/photoelec_sensor', '/doc/sensor/photoelec_sensor',
'/doc/sensor/pressure_sensor', '/doc/sensor/pressure_sensor',
'/doc/sensor/voice_sensor' '/doc/sensor/voice_sensor',
'/doc/sensor/image_sensor'
], ],
'appdev': [ 'appdev': [
'/doc/appdev/env', '/doc/appdev/env',
@ -57,8 +64,12 @@ const sidebar = {
], ],
'processor': [ 'processor': [
'/doc/processor/riscv', '/doc/processor/riscv',
'/doc/processor/riscv_sk', '/doc/processor/arm',
'/doc/processor/riscv_fpga' '/doc/processor/riscv_sfcore'
],
'selfterminal': [
'/doc/selfterminal/aiit-arm',
'/doc/selfterminal/aiit-riscv'
] ]
} }

View File

@ -1,4 +1,4 @@
# 应用开发 # 应用框架
--- ---
@ -6,6 +6,6 @@
* [](/doc/apparch/lian.md) * [](/doc/apparch/lian.md)
* [](/doc/apparch/zhi.md) * [](/doc/apparch/zhi.md)
* [](/doc/apparch/kong.md) * [](/doc/apparch/kong.md)

View File

@ -1 +1,310 @@
# 控 # 控
工业生产中控制逻辑的复杂程度千变万化,往往需要具体行业专业人员完成专门的设计,从而提高了行业的技术壁垒,严重阻碍了工业领域的自动化和智能化升级。
XiUOS应用程序框架中的“控”子框架从“控制需求”本身出发同时面向专业用户和非专业用户通过对“控制需求”本身和复杂的工业控制流程进行深入分析通过软件定义的方式提出以“元控制”为核心的“控”制流程。具体地本设计通过解耦复杂的工业控制流程将工业生产中的各种复制工业控制流程分解为各种类型的“元控制”命令这些“元控制”的命令以软件API的形式交互给用户使用从而屏蔽了以PLC为中心的各种控制器的巨大差异形成了方便易用的接口降低了专业的技术壁垒加速了工业领域的智能化升级。
## 1. XiUOS“控”制框架的关键数据结构定义和解析
```c
struct xs_PlcAbility {
const char name[XS_NAME_MAX]; /* name of the plc ability instance */
enum xs_PlcCtlType type; /* type of control the plcable to excute, such as HSC or PID control */
char address[XS_PLC_ADDRESS_MAX]; /* The address for this function in the plc*/
struct xs_PlcDevice *pdev;/* corresponding plc device */
struct XS_DOUBLE_LINKLIST_NODE link;/* link list node */
};
```
name成员是一个可读的名字用于唯一标识一个xs_PlcAbility结构。
type成员表示该xs_PlcAbility可控制的类型用一个枚举变量表示
```c
enum xs_PLcCtlType {
XS_PLC_CONTROL_TYPE_HSC = 0, /* high-speed counter */
XS_PLC_CONTROL_TYPE_PID , /* proportional,integral,derivative */
XS_PLC_CONTROL_TYPE_PHASING , /* phasing control*/
/* ...... */
XS_PLC_CONTROL_TYPE_END,
};
```
由于plc里控制指令执行都是向数据模块DB写数据,需要知道该函数功能对应的数据块地址这个用address标识。
pdev成员表示该xs_PlcAbility所属的xs_PlcDevice结构其具体定义在下文给出。
最后在系统中不同控制类型的xs_PlcAbility被分别组织成不同的双链表如高速计数器xs_PlcAbility链表、PID控制xs_PlcAbility链表等使用的链表节点即为link成员。
```c
struct xs_PlcDevice {
const char name[XS_NAME_MAX]; /* name of the device */
struct xs_PlcInfo info;/* Plc info, such as vendor name and model name */
struct xs_PlcOps ops;/* filesystem-like APIs for data transferring */
struct xs_PlcInterface interface;/* protocls used for transferring data from program to plc */
structXS_DOUBLE_LINKLIST_NODE link;/* link list node */
};
```
name成员记录PLC设备在系统中的名字用于唯一标识一个xs_PlcDevice结构。
```c
structxs_PlcInfo {
uint32_t ability;
const char *vendor;
const char *product_model;
};
```
info成员记录PLC设备的一些属性信息包括PLC的能力ability、厂家名vendor与型号product_model其中ability用一个位图表示该PLC设备可以控制进行的操作
```c
#define XS_PLC_ABILITY_HSC ((uint32_t)(1 << XS_CONTROL_TYPE_HSC))
#define XS_PLC_ABILITY_PID ((uint32_t)(1 << XS_CONTROL_TYPE_PID))
#define XS_PLC_ABILITY_Phasing ((uint32_t)(1 << XS_CONTROL_TYPE_PHASING))
/* ...... */
```
ps成员包含统一的、类似文件系统的API用于和PLC设备通信进行实际的数据读写和对PLC设备实现控制功能。在使用一个PLC设备前后需要打开open/关闭close该PLC实际为建立和关闭连接read、write分别用与从PLC接收数据与向PLC发送数据ioctl用于向PLC设备发送控制指令
```c
structxs_PlcOps {
int (*open)(struct xs_PlcDevice *pdev);
void (*close)(struct xs_PlcDevice*pdev);
int (*read)(struct xs_PlcDevice*pdev, void *buf, size_tlen);
int (*write)(struct xs_PlcDevice*pdev, constvoid *buf, size_tlen);
int (*ioctl)(struct xs_PlcDevice*pdev, intcmd, void *arg);
};
```
interface成员表示用于与PLC进行通信时所用到的协议
```c
struct xs_PlcInterface {
enum xs_plc_protocol protocol;
enum xs_plc_transport transport;
};
```
xs_plc_protocol和xs_plc_transport是两个枚举类型标识PLC设备和自研的两种终端之间用到的通讯协议其定义如下
```c
enum xs_plc_protocol{
AB-ETH = 0,
ADS/AMS,
BACnet/IP,
DeltaV,
DF1,
EtherNet/IP,
Firmata,
KNXnet/IP,
Modbus,
OPC UA,
S7,
Simulated,
};
enum xs_plc_transport{
TCP = 0,
UDP,
Serial,
Raw Socket,
PCAP Replay,
};
```
:::tip
注意两者间有对应关系而不是随意组合如S7(STEP 7)只能采用TCP协议而Modbus支持tcp/serial/raw socket/pcap replay,可以定义一个函数检查类型:
xs_PlcProtocolCheck(struct xs_PlcDevice*);
:::
最后系统中所有注册过的PLC设备被组织成一个双链表即link成员。
## 2.XiUOS Plc控制框架驱动开发
以HSC高速计数器为例。控制框架针对每个具体的控制类型将xs_PlcAbility进行扩充采用类似面向对象的手段添加其他必要成员
```c
struct xs_PlcAbilityHsc {
struct xs_PlcAbility parent;/* inherit from xs_PlcAbility*/
uint32_t (*write)(struct xs_PlcAbilityHsc *abl, void* param);
void (*read)(struct xs_PlcAbilityHsc *abl, void* param)
};
```
实现xs_PlcOps中的数据通信API具体实现细节取决于PLC型号无法实现的API可以置为NULL
```c
structxs_PlcOpshsc_example_ops = {
.open = hsc_example_open;
.close = hsc_example_close;
.read = hsc_example_read;
.write = hsc_example_write;
.ioctl = hsc_example_ioctl;
};
```
实现xs_PlcAbilityHsc中的write和read接口该接口用于向PLC的HSC模块发送控制参数和读取返回参数。在实现过程中可以使用xs_PlcOps中的接口与plc进行通信。
其中param为一个void类型指针由于要写入的命令参数和要读取的返回参数往往不止一个可以根据不同的控制类型定义不同的数据读写结构体最后使用结构体指针进行强制类型转换即可。例如对于HSC
定义数据写入结构体:
```c
struct hsc_write{
char id[id_max]; /* id_max is to identify the max HSC ctrl instruction of HSC */
int cmd; /* HSC control type *
};
```
其中id用来标识HSC, cmd表示要发送的具体指令具体的指令可以用一个枚举类型来表示
```c
enum HscCmdSubType{
EnHsc = 0; /* enable HSC */
EnCapture; /* enable the function of capturing the inputs */
EnSync; /* enable the function of synchronous inputs */
EnHSCRESET
En_CTRL_UPTODOWN
... ...
};
```
同理,其他的类型
```c
enum PIDcmdSubType{
ENHsc = 0
EN_XS_PLC_CONTROL_TYPE_PID_COMPACT
XS_PLC_CONTROL_TYPE_PID_3STEP /* valve of motor-driven */
... ...
};
enum PHASEcmdSubType{
ENPhase = 0
XS_PLC_CONTROL_TYPE_PHASING_MC_HALT
XS_PLC_CONTROL_TYPE_PHASING_MC_HALT_MOVE_ABSOLUTE
... ...
}
```
定义数据输出结构体:
```c
struct hsc_read{
uint32_t value; /* the main value you want to get, depends on the cmd */
bool done; /* indicate whether the SFB has been done */
bool busy; /* indicate whether the function is busy */
bool error; /* indicate whether there is error */
};
```
value是指定返回的变量值与结构体hsc_write发送的指令cmd类型有关down/busy/error是一些状态指示位。
如我们要使用write函数向PLC发送HSC类型的控制指令
```c
struct hsc_write write_example;
```
struct xs_PlcAbilityHsc hsc_example进行必要的初始化后用强制类型转换作为参数传递给write函数
```c
hsc_example ->write(&hsc_example,(struct hsc_write*)&write_example);
```
最后将plc设备添加到plc框架。分别填充xs_PlcDevice与对应物理量的xs_PlcAbility结构高速计数器即为xs_PlcAbilityHsc)并依次使用xs_PlcDeviceRegister和xs_PlcAbilityRegister函数将其注册到plc框架
```c
int xs_PlcDeviceRegister (struct xs_PlcDeviceRegister *pdev);
int xs_PlcAbilityRegister (struct xs_PlcAbilityRegister *abl);
extern struct xs_PlcOps plc_example_ops;
extern uint32_t plc_example_write(struct xs_PlcAbilityHsc *abl, void *param);
extern void plc_example_read(struct xs_PlcAbilityHsc *abl, void *param);
/* declare xs_PlcDevice and xs_PlcAbilityHsc objects */
struct xs_PlcDevice hsc_example_pdev;
struct xs_PlcAbilityHsc hsc_example_abl;
void register_example_plc()
{
/* initialize and register the xs_PlcDevice object */
memset(&hsc_example_pdev, 0, sizeof(xs_PlcDevice));
hsc_example_pdev.name = "plc1";
hsc_example_pdev.info.ability |= XS_PLC_ABILITY_HSC;
hsc_example_pdev.info.vendor = "Siemens";
hsc_example_pdev.info.product_model = "yyy";
hsc_example_pdev.ops = &hsc_example_ops;
hsc_example_pdev.interface.xs_plc_protocol = S7;
hsc_example_pdev.interface.xs_plc_transport = TCP;
xs_PlcDeviceRegister(&hsc_example_pdev);
/* initialize and register the xs_PlcAbility of hsc object */
memset(&hsc_example_abl, 0, sizeof(xs_PlcAbilityHsc));
hsc_example_abl.parent.name = "hsc_1";
hsc_example_abl.parent.type = XS_PLC_TYPE_HSC;
hsc_example_abl.parent.pdev = &hsc_example_pdev;
hsc_example_abl.read = hsc_example_read;
hsc_example_abl.write = hsc_example_write;
xs_PlcAbilityRegister((struct xs_PlcAbility *)&hsc_example_abl);
/* initialize and register otherxs_PlcAbilityobject */
memset(&other_example_abl, 0, sizeof(xs_PlcAbilityOther));
... ...
}
```
## 3. XiUOS Plc控制框架的使用示例
PLC控制应用开发者使用PLC控制框架提供的API操作PLCPLC的API可以分为通用API与控制类型特有API。通用API用于PLC的获取、打开与关闭控制类型特有API用于不同种类PLC的不同控制指令。以具有HSC高速计时器功能的PLC为例
```c
/* generic API: find a plcability instance by its name */
struct xs_PlcAbility *xs_PlcAbilityFind(const char *name);
/* generic API: open/close a plc ability instance */
int xs_PlcAbilityOpen(struct xs_PlcAbility *abl);
void xs_PlcAbilityClose(struct xs_PlcAbility *abl);
/* HSC API: send control parameter to PLC and read HSC condition*/
uint32_t xs_PlcHscWrite(struct xs_PlcAbilityHsc *abl, void *param);
void xs_PlcHscRead(struct xs_PlcAbilityHsc *abl, void *param);
```
在发送命令和获取数据前需要先获取并打开要使用的PLCPLC打开后可以随时对PLC发送指令和对其数据进行读取使用完毕后须关闭PLC。完整的使用过程示例如下
```c
int main(int argc, char *argv[])
{
int ret;
structxs_PlcAbility *abl;
structxs_PlcAbilityHsc *hsc_abl;
/* get the Plc hsc ability instance */
abl = xs_PlcAbilityFind("hsc_1");
XS_ASSERT(abl->type == XS_PLC_CONTROL_TYPE_HSC);
/* open the Plc hscability instance */
hsc_abl = (struct xs_PlcAbilityHsc*)abl;
ret = xs_PlcAbilityOpen(abl);
XS_ASSERT(ret == XS_EOK);
/* initialize the write and read data structure */
structhsc_write write1={
.id = "xxx";
.cmd = EnHsc;
};
struct hsc_read read1;
/* send control param to the HSC, just for demonstration */
xs_PlcHscWrite(hsc_abl,write1);
/* read data from hsc, just for demonstration */
xs_PlcHscRead(hsc_abl,read1);
if(!read1.error)
xs_kprintf("Read data from PLC HSC is \n", read1.value);
else
xs_kprintf("Read data from PLC HSC wrong!\n")
xs_PlcAbilityClose(abl);
return 0;
}
```

View File

@ -1 +1,15 @@
# 智 # 知 - 智能框架
## 基本框架
工厂中不仅有气压、温度等环境数据还有很多图像、声音等数据比如工业设备仪表盘、厂房工人分布等这些数据也需要检测并处理。传统方案使用嵌入式终端采集、云端处理的架构。而当前越来越多的硬件厂商开始将一部分AI算力下沉到嵌入式终端上比如 ST 推出的针对 STM 平台的神经网络加速库 STM32 Cube.AIARM 即将发布的针对嵌入式场景的 Ethos-U55 神经网络处理器,以及 勘智 K210 平台嵌入了一颗卷积网络加速器 KPU。本系统提供了在嵌入式节点端做轻量级AI处理的应用框架可以在 Arm Cortex-M 或者 有神经网络加速器的平台(比如 勘智 K210运行。对于复杂的 AI 应用,可以选择完全在 边缘或者云侧处理,也可以选择在 节点端做简单预处理,在 边缘或者云侧做后续的处理。基本结构如下:
![智能框架架构](/images/framework-ai-arch.png)
端侧智能运行框架中,目前在 STM32 平台上支持 TensorFlow Lite for Microcontroller勘智K210 上支持 KPU ModelCV算子目前暂不支持。模型库中有一些已经训练好的模型可以直接使用比如人物检测模型仪表盘识别模型等。
## 端侧 Framework 的使用说明
在 STM32 平台,本系统提供 TensorFlow Lite for Microcontroller 框架,关于 TF Lite for MCU 的使用,可以参照 [TF Lite for MCU 官方教程](https://www.tensorflow.org/lite/microcontrollers) ,详细说明后续补充。
在 勘智 K210 平台,本系统提供 KPU Model 的框架,详细使用可以参考 [勘智官方说明](https://s3.cn-north-1.amazonaws.com.cn/dl.kendryte.com/documents/kendryte_standalone_programming_guide_v0.3.0.pdf) 的 “神经网络处理器KPU”章节详细说明后续补充。

View File

@ -1,4 +1,4 @@
# 应用开发 # 快速上手
--- ---

View File

@ -0,0 +1,11 @@
# 应用开发
---
* [文件系统](/doc/component/fs.md)
* [驱动模型](/doc/component/drvmodel.md)
* [第三方库](/doc/component/lib.md)
* [GUI图形库](/doc/component/gui.md)

View File

@ -0,0 +1 @@
# 驱动模型

1
docs/doc/component/fs.md Normal file
View File

@ -0,0 +1 @@
# 文件系统

View File

@ -0,0 +1 @@
# GUI引擎

View File

@ -0,0 +1 @@
# 第三方库

View File

@ -4,7 +4,7 @@
- [西门子](/doc/controller/ximenzi.md) - [西门子](/doc/controller/ximenzi.md)
- [线程管理](/doc/controller/shinaide.md) - [施耐德](/doc/controller/shinaide.md)
- [资源管理](/doc/controller/sanling.md) - [三菱](/doc/controller/sanling.md)

338
docs/doc/ipc.md Normal file
View File

@ -0,0 +1,338 @@
# 任务通信
XiUOS提供多种任务间通信机制包括消息队列、信号量、互斥量与事件集。
## 消息队列
消息队列message queue提供可供多个任务读或写的消息缓冲区其中消息指固定长度的任意数据块。消息队列的容量有限。当消息队列满时向消息队列写入的任务会被挂起当消息队列空时从消息队列读取的任务会被挂起。
### 消息队列结构定义
```c
struct xs_MsgQueue
{
xs_uint16 id;
void *msg_buf;
xs_uint16 index;
xs_uint16 num_msgs;
xs_uint16 each_len;
xs_uint16 max_msgs;
XS_DOUBLE_LINKLIST send_pend_list;
XS_DOUBLE_LINKLIST recv_pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 消息队列ID用于唯一标识一个消息队列 |
| msg_buf | 用于存储消息的缓冲区的首地址 |
| index | 当前缓冲区中第一个消息的序号 |
| num_msgs | 当前缓冲区中的消息数量 |
| each_len | 每条消息的大小,单位为字节 |
| max_msgs | 缓冲区中最多能存放的消息数量 |
| send_pend_list | 被挂起的发送任务链表 |
| recv_pend_list | 被挂起的接收任务链表 |
| link | 系统中所有消息队列构成的链表 |
### 消息队列函数接口
```c
xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_len, xs_uint16 max_msgs);
```
该函数用于创建一个消息队列。创建成功后新的消息队列会被加入内核的消息队列管理链表并返回该消息队列的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| msg_len | 每条消息的长度,单位为字节 |
| max_msgs | 缓冲区中最多存放的消息数量 |
```c
void xs_UserMsgQueueDelete(xs_uint16 id);
```
该函数用于删除一个已创建的消息队列。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的消息队列ID |
```c
xs_int32 xs_UserMsgQueueSend(xs_uint16 id, const void *msg, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于向消息队列发送一个消息。若消息发送成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 目标消息队列ID |
| msg | 消息数据首地址 |
| size | 消息长度 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueRecv(xs_uint16 id, void *buf, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于从消息队列接收一个消息。若消息接收成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| buf | 用于接收消息数据的缓冲区 |
| size | 缓冲区大小 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueReinit(xs_uint16 id);
```
该函数用于将一个消息队列复位。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
## 信号量
信号量semaphore具有一个给定的初值。任务可以获取或释放一个信号量。当任务获取信号量时信号量的值递减释放信号量时值递增。当信号量值递减至0时后续尝试获取信号量的任务会被挂起。每当一个已获取信号量的任务释放信号量时内核会从信号量挂起队列上唤醒一个任务。信号量可以用于实现任务间的同步与互斥。
### 信号量结构定义
```c
struct xs_Semaphore
{
xs_uint16 id;
xs_uint16 value;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 信号量ID用于唯一标识一个信号量 |
| value | 信号量的当前值 |
| pend_link | 挂起任务链表 |
| link | 系统中所有信号量构成的链表 |
### 信号量函数接口
```c
xs_int32 xs_UserSemaphoreCreate(xs_uint16 val);
```
该函数用于创建一个信号量。创建成功后新的信号量会被加入内核的信号量管理链表并返回该信号量的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| val | 信号量的初值|
```c
void xs_UserSemaphoreDelete(xs_uint16 id);
```
该函数用于删除一个已创建的信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的信号量的ID |
```c
xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个信号量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的信号量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id);
```
该函数用于释放一个信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的信号量的ID |
```c
xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val);
```
该函数用于将一个信号量的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| val | 重置的信号量的值 |
## 互斥量
互斥量mutex可以视作一个初值为1的信号量同样有获取和释放操作。互斥量一般用于任务间的互斥。
### 互斥量结构定义
struct xs_Mutex
{
xs_uint16 id;
xs_uint8 origin_prio;
xs_uint8 recursive_cnt;
struct task_descriptor *holder;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
| 成员 | 描述 |
| --- | --- |
| id | 互斥量ID用于唯一标识一个互斥量 |
| origin_prio | 持有互斥量的任务的原优先级,用于避免优先级反转 |
| recursive_cnt | 持有互斥量的任务获取互斥量的次数,用于实现递归锁 |
| holder | 持有互斥量的任务 |
| pend_list | 挂起任务链表 |
| link | 系统中所有互斥量构成的链表 |
### 互斥量函数接口
```c
xs_int32 xs_UserMutexCreate(void);
```
该函数用于创建一个互斥量。创建成功后新的互斥量会被加入内核的互斥量管理链表并返回该互斥量的IDID默认范围0-255可配置。
```c
void xs_UserMutexDelete(xs_uint16 id);
```
该函数用于删除一个已创建的互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的互斥量的ID |
```c
xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个互斥量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的互斥量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMutexAbandon(xs_uint16 id);
```
该函数用于释放一个互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的互斥量的ID |
## 事件集
事件集event set允许用户定义一个事件集合集合中的每个事件都可以被任务触发或等待。任务可以同时等待多个事件此时等待触发的条件可以配置为AND或者OR当等待触发条件配置为AND时只有所有被等待的事件均被触发才视作等待结束当等待触发条件配置为OR时任意一个被等待的事件触发即视作等待结束。使用事件集可以实现多对多的任务间同步与互斥。
### 事件集结构定义
```c
#define XS_EVENT_AND (1 << 29)
#define XS_EVENT_OR (1 << 30)
#define XS_EVENT_AUTOCLEAN (1 << 31)
#define XS_EVENTS(x) (1 << x)
struct xs_event
{
xs_uint16 id;
xs_uint32 trigge_way;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 事件集ID用于唯一标识一个事件集 |
| trigge_way | 高3位用于记录事件集属性等待触发条件、是否自动清空低29位用于表示至多29个事件 |
| pend_list | 等待任务链表 |
| link | 系统中所有事件集构成的链表 |
### 事件集函数接口
```c
xs_int32 xs_UserEventCreate(xs_uint32 options);
```
该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN。创建成功后新的事件集会被加入内核的事件集管理链表并返回该事件集的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
void xs_UserEventDelete(xs_uint16 id);
```
该函数用于删除一个已创建的事件集。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的事件集的ID |
```c
xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events);
```
该函数用于触发事件集中的一组事件。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲触发的事件其中被置1的位标识被触发的事件 ,可以使用XS_EVENTS宏按位或发送事件类型|
```c
xs_int32 xs_UserEventProcess(xs_uint16 id, xs_uint32 events, xs_ticks_x wait_time);
```
该函数用于等待事件集中的一组事件。若等待成功则返回XS_EOK此时若XS_EVENT_AUTOCLEAN被打开则事件集中所有已触发事件会被清空若等待失败超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲等待的事件其中被置1的位标识被等待的事件可以使用XS_EVENTS宏按位或接收事件类型|
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options);
```
该函数用于配置事件集中的一种事件类型。若等配置成功则返回XS_EOKoptions参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
xs_int32 xs_UserEventReinit(xs_uint16 id);
```
该函数用于将一个事件的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |

View File

@ -2,11 +2,10 @@
--- ---
- [任务管理](/doc/kernel/task.md)
- [内存管理](/doc/kernel/mm.md) - [内存管理](/doc/kernel/mm.md)
- [线程管理](/doc/kernel/task.md) - [中断机制](/doc/kernel/int.md)
- [资源管理](/doc/kernel/synchron.md)
- [线程间通信](/doc/kernel/threadcommunication.md)
- [节拍机制](/doc/kernel/tmr.md)

98
docs/doc/kernel/int.md Normal file
View File

@ -0,0 +1,98 @@
# 中断机制
## 简介
中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
中断的触发一般是由外设或者CPU内部产生由中断控制器进行处理再通知到CPU进行中断响应过程其要点如下
•外设或者CPU内部产生的这个中断来源称为中断源
•CPU响应中断转入到的新的处理程序称为中断服务程序
•中断处理完成后,处理器需要恢复之前的现场,简称“恢复现场”;
•当多个中断源请求中断的时候需要通过优先级区分中断便于CPU进行中断的处理
•低优先级可以被高优先级打断,这个过程称之为中断嵌套;
•中断可以被屏蔽;
•所有的中断源都有一个编号,称为“中断号”;
•每一个中断号通过中断向量表与中断服务程序一一对应,中断向量表保存的是所有的中断服务程序的入口地址,该入口地址被称之为中断向量;
## 中断机制
## RISC-V架构的中断和异常
### 概述
从广义上来说,中断和异常属于一个概念;对于处理器而言,通常只区分为同步异常和异步异常。
同步异常:同步异常是指由于执行程序或者试图执行指令而产生的异常;例如,非法指令访问;
异步异常:最常见的异步异常是外部中断,例如外设触发一个外部中断。
### 异常处理机制
• 进入异常时RISC-V架构规定(以机器模式为例)
1、当前的程序执行流停止执行直接跳转到CSR寄存器的mtvec定义的PC地址执行
2、硬件同时更新下列几个CSR寄存器(具体情况可参考RISC-V架构介绍)
• mcause(Machine Cause Register):机器模式异常原因寄存器
• mepc(Machine Exception Program Register):机器模式异常PC寄存器
• mtval(Machine Trap Value Register):机器模式异常值寄存器
• mstatus(Machine Status Register):机器模式状态寄存器
mstatus寄存器的Exception Code域标识是何种异常或者何种中断。定义如下图表格所示
• 退出异常时需要从异常服务程序中退出并返回主程序。RISC-V架构定义了一组专门的退出异常指令MRET、SRET、URET分别
对应机器模式、监督模式、用户模式的退出。
以MRET为例当处理器执行MRET指令后硬件行为如下
1、当前程序执行流程停止执行跳转到mepc的地址运行
2、更新mstatus状态寄存器(具体情况可参考RISC-V架构介绍)
### 中断类型
RISC-V 架构定义的中断类型分为 4 种。
• 外部中断External Interrupt 指来自处理器核外部的中断例如GPIO、UART等产生的中断。
• 计时器中断Timer Interrupt :计时器中断是指来自计时器的中断。
• 软件中断Software Interrupt :软件中断是指来自软件自己触发的中断。
• 调试中断Debug Interrupt专用于实现调试器Debugger
### 中断控制器
1、CLINT 模块生成计时器中断和软件中断
CLINT 的全称为处理器核局部中断控制器Core Local Interrupts Controller主要用于产生计时器中断Timer Interrupt和软件中断Software Interrupt
2、PLIC 管理多个外部中断
PLIC 全称为平台级别中断控制器Platform Level Interrupt Controller它是 RISC-V架构标准定义的系统中断控制器主要用于多个外部中断源的优先级仲裁。
RISC-V中断控制器如下图所示
### 中断处理流程
#### 中断服务程序
每一个中断源对应一个中断号,每一个中断号又通过中断向量表和中断服务程序进行关联。当中断产生后,通过中断向量表
跳转到中断服务程序的入口地址进行执行。如下图所示:
#### 中断处理流程
CPU响应中断并进行处理通常经历以下过程保存当前线程的栈信息、跳转中断服务程序运行、恢复被打断的线程栈继续运行。
如下图所示:
### 中断函数接口
```c
xs_int32 xs_RegisterHwIrq(xs_uint32 irq, void * handler, void *arg, char *name);
```
该函数用于
```c
xs_int32 xs_FreeHwIrq();
```
```c
xs_int32 xs_DisableHwIrq();
```
```c
xs_int32 xs_EnableHwIrq();
```
## 使用场景
/* 底层的中断控制器操作函数*/
xs_int32 xs_DisableHwPlicIrq() ///< RISCV平台级别中断控制器中断关闭接口控制片上外设中断
xs_int32 xs_EnableHwPlicIrq() ///< RISCV平台级别中断控制器中断使能接口控制片上外设中断
xs_int32 xs_DisableHwClintIrq()///< RISCV局部中断控制器中断关闭接口控制片上定时器中断和软件中断
xs_int32 xs_EnableHwClintIrq() ///< RISCV局部中断控制器中断使能接口控制片上定时器中断和软件中断
xs_int32 xs_DisableGloableIrq()

338
docs/doc/kernel/ipc.md Normal file
View File

@ -0,0 +1,338 @@
# 任务通信
XiUOS提供多种任务间通信机制包括消息队列、信号量、互斥量与事件集。
## 消息队列
消息队列message queue提供可供多个任务读或写的消息缓冲区其中消息指固定长度的任意数据块。消息队列的容量有限。当消息队列满时向消息队列写入的任务会被挂起当消息队列空时从消息队列读取的任务会被挂起。
### 消息队列结构定义
```c
struct xs_MsgQueue
{
xs_uint16 id;
void *msg_buf;
xs_uint16 index;
xs_uint16 num_msgs;
xs_uint16 each_len;
xs_uint16 max_msgs;
XS_DOUBLE_LINKLIST send_pend_list;
XS_DOUBLE_LINKLIST recv_pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 消息队列ID用于唯一标识一个消息队列 |
| msg_buf | 用于存储消息的缓冲区的首地址 |
| index | 当前缓冲区中第一个消息的序号 |
| num_msgs | 当前缓冲区中的消息数量 |
| each_len | 每条消息的大小,单位为字节 |
| max_msgs | 缓冲区中最多能存放的消息数量 |
| send_pend_list | 被挂起的发送任务链表 |
| recv_pend_list | 被挂起的接收任务链表 |
| link | 系统中所有消息队列构成的链表 |
### 消息队列函数接口
```c
xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_len, xs_uint16 max_msgs);
```
该函数用于创建一个消息队列。创建成功后新的消息队列会被加入内核的消息队列管理链表并返回该消息队列的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| msg_len | 每条消息的长度,单位为字节 |
| max_msgs | 缓冲区中最多存放的消息数量 |
```c
void xs_UserMsgQueueDelete(xs_uint16 id);
```
该函数用于删除一个已创建的消息队列。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的消息队列ID |
```c
xs_int32 xs_UserMsgQueueSend(xs_uint16 id, const void *msg, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于向消息队列发送一个消息。若消息发送成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 目标消息队列ID |
| msg | 消息数据首地址 |
| size | 消息长度 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueRecv(xs_uint16 id, void *buf, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于从消息队列接收一个消息。若消息接收成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| buf | 用于接收消息数据的缓冲区 |
| size | 缓冲区大小 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueReinit(xs_uint16 id);
```
该函数用于将一个消息队列复位。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
## 信号量
信号量semaphore具有一个给定的初值。任务可以获取或释放一个信号量。当任务获取信号量时信号量的值递减释放信号量时值递增。当信号量值递减至0时后续尝试获取信号量的任务会被挂起。每当一个已获取信号量的任务释放信号量时内核会从信号量挂起队列上唤醒一个任务。信号量可以用于实现任务间的同步与互斥。
### 信号量结构定义
```c
struct xs_Semaphore
{
xs_uint16 id;
xs_uint16 value;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 信号量ID用于唯一标识一个信号量 |
| value | 信号量的当前值 |
| pend_link | 挂起任务链表 |
| link | 系统中所有信号量构成的链表 |
### 信号量函数接口
```c
xs_int32 xs_UserSemaphoreCreate(xs_uint16 val);
```
该函数用于创建一个信号量。创建成功后新的信号量会被加入内核的信号量管理链表并返回该信号量的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| val | 信号量的初值|
```c
void xs_UserSemaphoreDelete(xs_uint16 id);
```
该函数用于删除一个已创建的信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的信号量的ID |
```c
xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个信号量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的信号量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id);
```
该函数用于释放一个信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的信号量的ID |
```c
xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val);
```
该函数用于将一个信号量的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| val | 重置的信号量的值 |
## 互斥量
互斥量mutex可以视作一个初值为1的信号量同样有获取和释放操作。互斥量一般用于任务间的互斥。
### 互斥量结构定义
struct xs_Mutex
{
xs_uint16 id;
xs_uint8 origin_prio;
xs_uint8 recursive_cnt;
struct task_descriptor *holder;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
| 成员 | 描述 |
| --- | --- |
| id | 互斥量ID用于唯一标识一个互斥量 |
| origin_prio | 持有互斥量的任务的原优先级,用于避免优先级反转 |
| recursive_cnt | 持有互斥量的任务获取互斥量的次数,用于实现递归锁 |
| holder | 持有互斥量的任务 |
| pend_list | 挂起任务链表 |
| link | 系统中所有互斥量构成的链表 |
### 互斥量函数接口
```c
xs_int32 xs_UserMutexCreate(void);
```
该函数用于创建一个互斥量。创建成功后新的互斥量会被加入内核的互斥量管理链表并返回该互斥量的IDID默认范围0-255可配置。
```c
void xs_UserMutexDelete(xs_uint16 id);
```
该函数用于删除一个已创建的互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的互斥量的ID |
```c
xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个互斥量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的互斥量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMutexAbandon(xs_uint16 id);
```
该函数用于释放一个互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的互斥量的ID |
## 事件集
事件集event set允许用户定义一个事件集合集合中的每个事件都可以被任务触发或等待。任务可以同时等待多个事件此时等待触发的条件可以配置为AND或者OR当等待触发条件配置为AND时只有所有被等待的事件均被触发才视作等待结束当等待触发条件配置为OR时任意一个被等待的事件触发即视作等待结束。使用事件集可以实现多对多的任务间同步与互斥。
### 事件集结构定义
```c
#define XS_EVENT_AND (1 << 29)
#define XS_EVENT_OR (1 << 30)
#define XS_EVENT_AUTOCLEAN (1 << 31)
#define XS_EVENTS(x) (1 << x)
struct xs_event
{
xs_uint16 id;
xs_uint32 trigge_way;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 事件集ID用于唯一标识一个事件集 |
| trigge_way | 高3位用于记录事件集属性等待触发条件、是否自动清空低29位用于表示至多29个事件 |
| pend_list | 等待任务链表 |
| link | 系统中所有事件集构成的链表 |
### 事件集函数接口
```c
xs_int32 xs_UserEventCreate(xs_uint32 options);
```
该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN。创建成功后新的事件集会被加入内核的事件集管理链表并返回该事件集的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
void xs_UserEventDelete(xs_uint16 id);
```
该函数用于删除一个已创建的事件集。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的事件集的ID |
```c
xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events);
```
该函数用于触发事件集中的一组事件。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲触发的事件其中被置1的位标识被触发的事件 ,可以使用XS_EVENTS宏按位或发送事件类型|
```c
xs_int32 xs_UserEventProcess(xs_uint16 id, xs_uint32 events, xs_ticks_x wait_time);
```
该函数用于等待事件集中的一组事件。若等待成功则返回XS_EOK此时若XS_EVENT_AUTOCLEAN被打开则事件集中所有已触发事件会被清空若等待失败超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲等待的事件其中被置1的位标识被等待的事件可以使用XS_EVENTS宏按位或接收事件类型|
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options);
```
该函数用于配置事件集中的一种事件类型。若等配置成功则返回XS_EOKoptions参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
xs_int32 xs_UserEventReinit(xs_uint16 id);
```
该函数用于将一个事件的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |

View File

@ -1 +0,0 @@
# 资源管理

540
docs/doc/kernel/task.md Executable file → Normal file
View File

@ -1 +1,539 @@
# 线程管理 # 任务
* [任务管理](#management)
* [任务状态](#state)
* [任务调度](#sched)
* [任务结构定义](#struct)
* [任务函数接口](#api)
* [任务通信](#communication)
* [消息队列](#msg_quque)
* [信号量](#sem)
* [互斥量](#mutex)
* [事件集](#event)
* [使用场景](#situation)
<span id="management"></span>
## 任务管理
任务task是XiUOS中处理器使用权分配的最小单位。每个任务有自己的程序栈与寄存器上下文在多处理器平台上可以互不干扰地同时运行但单个处理器上任意时刻只能有一个任务在运行。用户可以使用XiUOS提供的接口创建任意数量的任务。内核会对系统中的所有任务按照一定策略抢占式优先级或先来先服务进行调度以最大限度地利用处理器资源。用户可以使用XiUOS提供的接口创建任意数量的任务。
<span id="state"></span>
### 任务状态
系统中的任务在任意时刻都处于就绪ready、运行running、阻塞/挂起suspend、退出quit四种状态之一。状态之间的变化关系如下图所示。
![task_status](task_status.png)
任务在创建完成后会进入就绪状态并被加入就绪队列等待内核调度。当任务被调度开始运行时,任务会进入运行状态。若任务在运行过程中被更高优先级的任务抢占,则被强占的任务会回到就绪队列并再次进入就绪状态。当任务在运行过程中申请资源失败时,任务会被挂起并进入挂起状态,并在所申请资源能够被满足时回到就绪状态。当任务执行完成,即从入口函数返回时,会进入终止状态,并由内核回收其相关资源。
<span id="sched"></span>
### 任务调度
任务调度即从系统就绪队列中按一定策略选择任务使其进入运行状态的过程。XiUOS支持以下调度方式
* 抢占式优先级调度:在创建任务时可以指定任务的优先级,内核总是选取就绪队列中优先级最高的任务。当新创建的任务优先级高于正在运行的任务的优先级时,当前运行的任务会被抢占。若就绪队列中最高优先级任务有多个,则这些任务会按时间片轮转交替运行。
* 先来先服务FIFO调度任务按照被创建的顺序依次被执行。当一个任务运行完成后系统才会让下一个任务开始运行。
* 时间片轮转RR调度任务按照分配的时间片执行时间片结束调度一个新的就绪任务执行当前任务重新就绪等待下一次的调度。
<span id="struct"></span>
### 任务结构定义
每个任务在内核中由一个task_descriptor结构表示二者一一对应。
```c
struct task_descriptor
{
void *stack_pointer;
struct dync_sched_member dync_sched_member_x;
struct t_baseinfo t_baseinfo_x;
#ifdef XS_USING_SMP
struct smp_info smp_info_x;
#endif
#if defined(XS_USING_EVENT)
xs_uint32 event_ctrl1:3;
xs_uint32 event_ctrl2:29;
#endif
xs_err_t error;
XS_DOUBLE_LINKLIST link;
};
```
其中stack_pointer成员表示该任务的栈的起始地址dync_sched_member_x成员包含与任务调度相关的信息t_baseinfo_x包含任务的基本信息smp_info_x包含与多处理器相关的信息event_ctrl1/event_ctrl2用于实现事件集机制见任务间通信部分文档error为任务调用内核接口时最近的错误码link用于将系统中的所有任务组织成一个双链表。各复合成员的详细定义如下
```c
struct task_baseinfo {
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 origin_prio;
};
```
struct task_baseinfo结构记录了任务的基本属性包括任务的名称name、入口函数和参数func_entry、func_param、栈大小stack_size、优先级origin_prio
```c
struct dync_sched_member {
xs_uint8 stat;
xs_uint8 advance_cnt;
xs_uint8 cur_prio;
xs_ubase origin_timeslice;
xs_ubase rest_timeslice;
#ifdef XS_USING_TASK_ISOLATION
xs_uint8 isolation_flag;
void *isolation;
#endif
union {
XS_DOUBLE_LINKLIST sched_link;
XS_AVL sched_avl;
}
XS_DOUBLE_LINKLIST pend_link;
xs_Timer_t task_timer;
};
#define XS_SUSPEND ((1) << (0))
#define XS_READY ((1) << (1))
#define XS_RUNNING ((1) << (2))
#define XS_QUIT ((1) << (3))
```
struct dync_sched_member结构的成员用于记录与调度相关的信息。stat表示任务的当前状态可以为挂起XS_SUSPEND、就绪XS_READY、运行XS_RUNNING或退出XS_QUIT。advance_cnt表示在配置成短作业预先调度时优先处理的时间片周期个数。cur_prio表示任务当前的优先级为防止出现优先级反转该优先级可以高于任务创建时配置的优先级。origin_timeslice表示在时间片轮转调度中该任务每次运行的时间片。地址空间隔离信息isolation_flag变量和指针isolation。sched_link、sched_avl构成的联合体为就绪队列节点XiUOS中就绪队列可以配置为双链表sched_link或AVL树sched_avl。pend_link为任务挂起时使用的等待队列节点。task_timer用于任务睡眠的计时。
```c
struct smp_info {
xs_uint8 combined_coreid;
xs_uint8 runing_coreid;
};
```
struct smp_info结构包含多处理器相关的信息其成员分别表示该任务绑定的CPU ID与正在运行的CPU ID。
<span id="api"></span>
### 任务函数接口
```c
struct xs_utask
{
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 prio;
};
typedef struct xs_utask struct xs_utask;
struct task_descriptor* xs_UserTaskCreate(xs_utask_x task);
```
该函数用于用户态创建一个任务。任务的各个属性由一个struct xs_utask结构表示包括任务的名称、入口函数及参数、栈大小和优先级在调用该函数时需要传入该结构的实例用于配置任务。任务创建成功后内核会为其分配指定大小的栈及其他结构如struct task_descriptor结构并返回任务描述符指针。
| 参数 | 描述 |
| --- | --- |
| task | 任务配置属性 |
```c
xs_int32 xs_UserTaskDelete(struct task_descriptor task);
```
该函数用于删除一个任务强制使其进入退出状态。若删除成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task| 待删除的任务描述符 |
```c
xs_int32 xs_UserTaskCoreCombine(struct task_descriptor task, xs_uint8 coreid);
```
该函数用于将任务绑定至指定的处理器上。若绑定成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task_id | 待绑定的任务描述符 |
| coreid | 带绑定的处理器ID |
```c
xs_int32 xs_UserTaskCoreUncombine(struct task_descriptor task);
```
该函数用于解除任务与处理器的绑定。若解除成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task | 待解除绑定的任务描述符 |
```c
xs_int32 xs_UserTaskDelay(xs_ticks_x ticks);
```
该函数用于将当前任务挂起一定时间单位为tick。挂起时间结束后任务会进入就绪状态可以继续被调度。
| 参数 | 描述 |
| --- | --- |
| ticks | 任务挂起时间单位为tick |
```c
struct task_descriptor* xs_UserTaskSearch(char *name)
```
该函数用于从任务名称获取任务描述符。
| 参数 | 描述 |
| --- | --- |
| name | 任务名称 |
<span id="communication"></span>
## 任务通信
XiUOS提供多种任务间通信机制包括消息队列、信号量、互斥量与事件集。
<span id="msg_quque"></span>
### 消息队列
消息队列message queue提供可供多个任务读或写的消息缓冲区其中消息指固定长度的任意数据块。消息队列的容量有限。当消息队列满时向消息队列写入的任务会被挂起当消息队列空时从消息队列读取的任务会被挂起。
#### 消息队列结构定义
```c
struct xs_MsgQueue
{
xs_uint16 id;
void *msg_buf;
xs_uint16 index;
xs_uint16 num_msgs;
xs_uint16 each_len;
xs_uint16 max_msgs;
XS_DOUBLE_LINKLIST send_pend_list;
XS_DOUBLE_LINKLIST recv_pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 消息队列ID用于唯一标识一个消息队列 |
| msg_buf | 用于存储消息的缓冲区的首地址 |
| index | 当前缓冲区中第一个消息的序号 |
| num_msgs | 当前缓冲区中的消息数量 |
| each_len | 每条消息的大小,单位为字节 |
| max_msgs | 缓冲区中最多能存放的消息数量 |
| send_pend_list | 被挂起的发送任务链表 |
| recv_pend_list | 被挂起的接收任务链表 |
| link | 系统中所有消息队列构成的链表 |
#### 消息队列函数接口
```c
xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_len, xs_uint16 max_msgs);
```
该函数用于创建一个消息队列。创建成功后新的消息队列会被加入内核的消息队列管理链表并返回该消息队列的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| msg_len | 每条消息的长度,单位为字节 |
| max_msgs | 缓冲区中最多存放的消息数量 |
```c
void xs_UserMsgQueueDelete(xs_uint16 id);
```
该函数用于删除一个已创建的消息队列。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的消息队列ID |
```c
xs_int32 xs_UserMsgQueueSend(xs_uint16 id, const void *msg, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于向消息队列发送一个消息。若消息发送成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 目标消息队列ID |
| msg | 消息数据首地址 |
| size | 消息长度 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueRecv(xs_uint16 id, void *buf, xs_uint16 size, xs_ticks_x wait_time);
```
该函数用于从消息队列接收一个消息。若消息接收成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| buf | 用于接收消息数据的缓冲区 |
| size | 缓冲区大小 |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMsgQueueReinit(xs_uint16 id);
```
该函数用于将一个消息队列复位。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
<span id="sem"></span>
### 信号量
信号量semaphore具有一个给定的初值。任务可以获取或释放一个信号量。当任务获取信号量时信号量的值递减释放信号量时值递增。当信号量值递减至0时后续尝试获取信号量的任务会被挂起。每当一个已获取信号量的任务释放信号量时内核会从信号量挂起队列上唤醒一个任务。信号量可以用于实现任务间的同步与互斥。
#### 信号量结构定义
```c
struct xs_Semaphore
{
xs_uint16 id;
xs_uint16 value;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 信号量ID用于唯一标识一个信号量 |
| value | 信号量的当前值 |
| pend_link | 挂起任务链表 |
| link | 系统中所有信号量构成的链表 |
#### 信号量函数接口
```c
xs_int32 xs_UserSemaphoreCreate(xs_uint16 val);
```
该函数用于创建一个信号量。创建成功后新的信号量会被加入内核的信号量管理链表并返回该信号量的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| val | 信号量的初值|
```c
void xs_UserSemaphoreDelete(xs_uint16 id);
```
该函数用于删除一个已创建的信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的信号量的ID |
```c
xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个信号量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的信号量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id);
```
该函数用于释放一个信号量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的信号量的ID |
```c
xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val);
```
该函数用于将一个信号量的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
| val | 重置的信号量的值 |
<span id="mutex"></span>
### 互斥量
互斥量mutex可以视作一个初值为1的信号量同样有获取和释放操作。互斥量一般用于任务间的互斥。
#### 互斥量结构定义
struct xs_Mutex
{
xs_uint16 id;
xs_uint8 origin_prio;
xs_uint8 recursive_cnt;
struct task_descriptor *holder;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
| 成员 | 描述 |
| --- | --- |
| id | 互斥量ID用于唯一标识一个互斥量 |
| origin_prio | 持有互斥量的任务的原优先级,用于避免优先级反转 |
| recursive_cnt | 持有互斥量的任务获取互斥量的次数,用于实现递归锁 |
| holder | 持有互斥量的任务 |
| pend_list | 挂起任务链表 |
| link | 系统中所有互斥量构成的链表 |
#### 互斥量函数接口
```c
xs_int32 xs_UserMutexCreate(void);
```
该函数用于创建一个互斥量。创建成功后新的互斥量会被加入内核的互斥量管理链表并返回该互斥量的IDID默认范围0-255可配置。
```c
void xs_UserMutexDelete(xs_uint16 id);
```
该函数用于删除一个已创建的互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的互斥量的ID |
```c
xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time);
```
该函数用于获取一个互斥量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 欲获取的互斥量的ID |
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserMutexAbandon(xs_uint16 id);
```
该函数用于释放一个互斥量。
| 参数 | 描述 |
| --- | --- |
| id | 待释放的互斥量的ID |
<span id="event"></span>
### 事件集
事件集event set允许用户定义一个事件集合集合中的每个事件都可以被任务触发或等待。任务可以同时等待多个事件此时等待触发的条件可以配置为AND或者OR当等待触发条件配置为AND时只有所有被等待的事件均被触发才视作等待结束当等待触发条件配置为OR时任意一个被等待的事件触发即视作等待结束。使用事件集可以实现多对多的任务间同步与互斥。
#### 事件集结构定义
```c
#define XS_EVENT_AND (1 << 29)
#define XS_EVENT_OR (1 << 30)
#define XS_EVENT_AUTOCLEAN (1 << 31)
#define XS_EVENTS(x) (1 << x)
struct xs_event
{
xs_uint16 id;
xs_uint32 trigge_way;
XS_DOUBLE_LINKLIST pend_list;
XS_DOUBLE_LINKLIST link;
};
```
| 成员 | 描述 |
| --- | --- |
| id | 事件集ID用于唯一标识一个事件集 |
| trigge_way | 高3位用于记录事件集属性等待触发条件、是否自动清空低29位用于表示至多29个事件 |
| pend_list | 等待任务链表 |
| link | 系统中所有事件集构成的链表 |
#### 事件集函数接口
```c
xs_int32 xs_UserEventCreate(xs_uint32 options);
```
该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN。创建成功后新的事件集会被加入内核的事件集管理链表并返回该事件集的IDID默认范围0-255可配置。
| 参数 | 描述 |
| --- | --- |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
void xs_UserEventDele##
该函数用于删除一个已创建的事件集。
| 参数 | 描述 |
| --- | --- |
| id | 待删除的事件集的ID |
```c
xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events);
```
该函数用于触发事件集中的一组事件。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲触发的事件其中被置1的位标识被触发的事件 ,可以使用XS_EVENTS宏按位或发送事件类型|
```c
xs_int32 xs_UserEventProcess(xs_uint16 id, xs_uint32 events, xs_ticks_x wait_time);
```
该函数用于等待事件集中的一组事件。若等待成功则返回XS_EOK此时若XS_EVENT_AUTOCLEAN被打开则事件集中所有已触发事件会被清空若等待失败超时则返回-XS_ETIMEOUT。
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| events | 欲等待的事件其中被置1的位标识被等待的事件可以使用XS_EVENTS宏按位或接收事件类型|
| wait_time | 等待时间上限单位ticks若为0则不等待 |
```c
xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options);
```
该函数用于配置事件集中的一种事件类型。若等配置成功则返回XS_EOKoptions参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN
| 参数 | 描述 |
| --- | --- |
| id | 事件集ID |
| options | 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN |
```c
xs_int32 xs_UserEventReinit(xs_uint16 id);
```
该函数用于将一个事件的值进行重置。
| 参数 | 描述 |
| --- | --- |
| id | 来源消息队列ID |
<span id="situation"></span>
## 使用场景
* 在多处理器设备上,多个任务可以并行运行,从而提高处理器的利用率。
* 在一些中断驱动的应用中,如果中断需要处理的工作过于复杂,则可以创建一个任务专门用于处理相关工作,从而改善中断延迟。

View File

@ -1,179 +0,0 @@
# 线程间通信
XiUOS 的线程间通信使用管道和消息队列进行通信。下面将分别介绍。
## 消息队列
### 消息队列的工作机制
消息队列能够接收线程或中断产生的不固定长度的消息,并储存到自己的内存空间中。其他线程可以从消息队列中读取相应的消息。当消息队列为空时,挂起读取线程,当有新的消息到达时,唤醒读取线程进行读取。
### 结构体定义和函数接口
#### 结构体定义
```C
struct xs_MessageQueue
{
char name[XS_NAME_MAX];
xs_uint8 style;
xs_uint8 sign;
xs_list_t link;
xs_list_t pend_list;
void *msg_buf;
xs_uint16 size;
xs_uint16 max_msgs;
xs_uint16 index;
void *mq_listhead;
void *mq_listtail;
void *mq_free;
xs_list_t pend_sender_thread;
};
typedef struct xs_MessageQueue *xs_messagequeue_t;
```
| 参数 | 描述 |
| ------ | ------ |
| name | 消息队列名称 |
| style | 线程等待的方式可以取FIFO或PRIO |
| sign | 标记消息队列的创建方式,静态创建或动态创建 |
| link | 消息队列存放的列表 |
| pend_list | 线程等待队列 |
| msg_buf | 存放消息的缓存区 |
| size | 缓存区大小 |
| max_msgs | 一条消息的最大长度 |
| index | 当前消息数 |
| mq_listhead | 消息链表头 |
| mq_listtail | 消息链表尾 |
| mq_free | 空闲消息链表 |
| pend_sender_thread | 发送线程的挂起等待队列 |
#### 函数接口
```C
xs_err_t xs_InitMessageQueue(xs_messagequeue_t mq,
const char *name,
void *msgpool,
xs_size_t msg_size,
xs_size_t pool_size,
xs_uint8 flag)
```
该函数用于初始化一个静态消息队列,并将它加入消息队列管理列表中。创建成功后返回`XS_OK`。</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| name | 消息队列名称 |
| msgpool | 指向存放消息的内存空间的指针 |
| msg_size | 一条消息的最大长度 |
| pool_size | 存放消息的内存区大小 |
| flag | 消息队列采用的等待方式可取FIFO或PRIO |
</br>
```C
xs_err_t xs_DetachMessageQueue(xs_messagequeue_t mq)
```
该函数用于将一个静态消息队列从消息队列管理列表中移除。移除成功则返回`XS_OK`。</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
</br>
```C
xs_messagequeue_t xs_CreateMessageQueue(const char *name,
xs_size_t msg_size,
xs_size_t max_msgs,
xs_uint8 flag)
```
该函数用于动态创建一个消息队列,并将消息队列加入消息队列管理列表。</br>
| 参数 | 描述 |
| ------ | ------ |
| name | 消息队列名称 |
| msg_size | 缓冲区的大小 |
| max_msgs | 一条消息的最大长度 |
| flag | 消息队列采用的等待方式可取FIFO或PRIO |
</br>
```C
xs_err_t xs_DeleteMessageQueue(xs_messagequeue_t mq)
```
该函数用于将由`xs_CreateMessageQueue`创建的消息队列从消息队列管理列表中删除。</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
</br>
```C
xs_err_t xs_MessageQueueSendwait(xs_messagequeue_t mq,
const void *buffer,
xs_size_t size,
xs_int32 timeout)
```
发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部,成功则返回`XS_EOK`。如果消息长度大于最大长度,则返回`XS_ERROR`。如果消息队列满了,则根据超时时间设定进行等待,超时则返回`-XS_EFULL`。</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| buffer | 消息内容 |
| size | 消息大小 |
| timeout | 超时时间 |
</br>
```C
xs_err_t xs_MessageQueueSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size)
```
该函数是timeout为0的`xs_MessageQueueSendwait`。
</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| buffer | 消息内容 |
| size | 消息大小 |
</br>
```C
xs_err_t xs_MessageQueueUrgentSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size)
```
发送紧急消息和发送普通消息的区别是:当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| buffer | 消息内容 |
| size | 消息大小 |
</br>
```C
xs_err_t xs_MessageQueueReceive(xs_messagequeue_t mq,
void *buffer,
xs_size_t size,
xs_int32 timeout)
```
当队列中有消息时,接收消息。队列中没有消息时,根据超时时间设定进行等待。接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。成功收到消息返回`XS_EOK`,超时返回`XS_ETIMEOUT`。接收消息失败返回`-XS_ERROR`。
</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| buffer | 消息内容 |
| size | 消息大小 |
| timeout | 超时时间 |
</br>
```C
xs_err_t xs_CmdControlMessageQueue(xs_messagequeue_t mq, int cmd, void *arg)
```
该函数用于获取或设置消息队列的其他属性。目前当cmd == XS_LINKLIST_CMD_RESET时重新初始化消息队列。
</br>
| 参数 | 描述 |
| ------ | ------ |
| mq | 消息队列对象指针 |
| cmd | 需要执行的命令 |
| arg | 命令的参数 |
</br>
## 管道

1
docs/doc/kernel/tmr.md Normal file
View File

@ -0,0 +1 @@
# 节拍机制

View File

@ -1,10 +1,10 @@
# 控制 # 处理
--- ---
- [西门子](/doc/processor/riscv.md) - [RISC-V](/doc/processor/riscv.md)
- [线程管理](/doc/processor/riscv_sk.md) - [ARM](/doc/processor/arm.md)
- [资源管理](/doc/processor/riscv_fpga.md) - [RISC-V软核](/doc/processor/riscv_sfcore.md)

View File

@ -0,0 +1 @@
# ARM

View File

@ -1 +1 @@
# 三菱 # RISC-V

View File

@ -1 +0,0 @@
# 西门子

View File

@ -0,0 +1 @@
# RISC-V 软核

View File

@ -1 +0,0 @@
# 施耐德

View File

@ -0,0 +1,8 @@
# 自研终端
---
* [aiit_arm](/doc/selfterminal/aiit-arm.md)
* [aiit_riscv](/doc/selfterminal/aiit-riscv.md)

View File

@ -0,0 +1 @@
# aiit-arm

View File

@ -0,0 +1 @@
# aiit-riscv

View File

@ -18,3 +18,5 @@
- [声音传感器](/doc/sensor/voice_sensor.md) - [声音传感器](/doc/sensor/voice_sensor.md)
- [图像传感器](/doc/sensor/image_sensor.md)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
# 图像传感器
## 传感器介绍
| 传感器信号 | 传感器说明 | 驱动支持 | 传感器外形 |
| --- | --- | --- | --- |
| OV7670 | 最大支持 40x48030万像素不支持 JPEG 输出,不支持自动对焦 | 已支持 | ![ov7670](/images/sensor-ov7670.png) |
| OV2640 | 最大支持 1600x1200200万像素支持 JPEG 输出,不支持自动对焦 | 待支持 | ![ov7670](/images/sensor-ov2640.png) |
## 使用说明
本系统支持 dev fscamera 设备会在 /dev 下面注册。
相关数据结构:
```c
enum CameraOutputFormat {
RGB565,
JPEG,
};
struct CameraInfo {
int width;
int height;
CameraOutputFormat format;
};
```
基本使用说明:
```c
// open camera device
int fd = open(“/dev/cam1”);
// get camera info
struct CameraInfo cam_info;
int ret = ioctl(fd, GET_INFO, &cam_info);
// read camera data to buf
void *buf = malloc(cam_info.width * cam_info.height * 2); // assume the format is RGB565
int ret = read(fd, buf, size);
```

174
docs/doc/task.md Normal file
View File

@ -0,0 +1,174 @@
# 任务管理
任务task是XiUOS中处理器使用权分配的最小单位。每个任务有自己的程序栈与寄存器上下文在多处理器平台上可以互不干扰地同时运行但单个处理器上任意时刻只能有一个任务在运行。用户可以使用XiUOS提供的接口创建任意数量的任务。内核会对系统中的所有任务按照一定策略抢占式优先级或先来先服务进行调度以最大限度地利用处理器资源。用户可以使用XiUOS提供的接口创建任意数量的任务。
## 任务状态
系统中的任务在任意时刻都处于就绪ready、运行running、阻塞/挂起suspend、退出quit四种状态之一。状态之间的变化关系如下图所示。
![task_status](task_status.png)
任务在创建完成后会进入就绪状态并被加入就绪队列等待内核调度。当任务被调度开始运行时,任务会进入运行状态。若任务在运行过程中被更高优先级的任务抢占,则被强占的任务会回到就绪队列并再次进入就绪状态。当任务在运行过程中申请资源失败时,任务会被挂起并进入挂起状态,并在所申请资源能够被满足时回到就绪状态。当任务执行完成,即从入口函数返回时,会进入终止状态,并由内核回收其相关资源。
## 任务调度
任务调度即从系统就绪队列中按一定策略选择任务使其进入运行状态的过程。XiUOS支持以下调度方式
* 抢占式优先级调度:在创建任务时可以指定任务的优先级,内核总是选取就绪队列中优先级最高的任务。当新创建的任务优先级高于正在运行的任务的优先级时,当前运行的任务会被抢占。若就绪队列中最高优先级任务有多个,则这些任务会按时间片轮转交替运行。
* 先来先服务FIFO调度任务按照被创建的顺序依次被执行。当一个任务运行完成后系统才会让下一个任务开始运行。
* 时间片轮转RR调度任务按照分配的时间片执行时间片结束调度一个新的就绪任务执行当前任务重新就绪等待下一次的调度。
## 任务结构定义
每个任务在内核中由一个task_descriptor结构表示二者一一对应。
```c
struct task_descriptor
{
void *stack_pointer;
struct dync_sched_member dync_sched_member_x;
struct t_baseinfo t_baseinfo_x;
#ifdef XS_USING_SMP
struct smp_info smp_info_x;
#endif
#if defined(XS_USING_EVENT)
xs_uint32 event_ctrl1:3;
xs_uint32 event_ctrl2:29;
#endif
xs_err_t error;
XS_DOUBLE_LINKLIST link;
};
```
其中stack_pointer成员表示该任务的栈的起始地址dync_sched_member_x成员包含与任务调度相关的信息t_baseinfo_x包含任务的基本信息smp_info_x包含与多处理器相关的信息event_ctrl1/event_ctrl2用于实现事件集机制见任务间通信部分文档error为任务调用内核接口时最近的错误码link用于将系统中的所有任务组织成一个双链表。各复合成员的详细定义如下
```c
struct task_baseinfo {
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 origin_prio;
};
```
struct task_baseinfo结构记录了任务的基本属性包括任务的名称name、入口函数和参数func_entry、func_param、栈大小stack_size、优先级origin_prio
```c
struct dync_sched_member {
xs_uint8 stat;
xs_uint8 advance_cnt;
xs_uint8 cur_prio;
xs_ubase origin_timeslice;
xs_ubase rest_timeslice;
#ifdef XS_USING_TASK_ISOLATION
xs_uint8 isolation_flag;
void *isolation;
#endif
union {
XS_DOUBLE_LINKLIST sched_link;
XS_AVL sched_avl;
}
XS_DOUBLE_LINKLIST pend_link;
xs_Timer_t task_timer;
};
#define XS_SUSPEND ((1) << (0))
#define XS_READY ((1) << (1))
#define XS_RUNNING ((1) << (2))
#define XS_QUIT ((1) << (3))
```
struct dync_sched_member结构的成员用于记录与调度相关的信息。stat表示任务的当前状态可以为挂起XS_SUSPEND、就绪XS_READY、运行XS_RUNNING或退出XS_QUIT。advance_cnt表示在配置成短作业预先调度时优先处理的时间片周期个数。cur_prio表示任务当前的优先级为防止出现优先级反转该优先级可以高于任务创建时配置的优先级。origin_timeslice表示在时间片轮转调度中该任务每次运行的时间片。地址空间隔离信息isolation_flag变量和指针isolation。sched_link、sched_avl构成的联合体为就绪队列节点XiUOS中就绪队列可以配置为双链表sched_link或AVL树sched_avl。pend_link为任务挂起时使用的等待队列节点。task_timer用于任务睡眠的计时。
```c
struct smp_info {
xs_uint8 combined_coreid;
xs_uint8 runing_coreid;
};
```
struct smp_info结构包含多处理器相关的信息其成员分别表示该任务绑定的CPU ID与正在运行的CPU ID。
## 任务函数接口
```c
struct xs_utask
{
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 prio;
};
typedef struct xs_utask struct xs_utask;
struct task_descriptor* xs_UserTaskCreate(xs_utask_x task);
```
该函数用于用户态创建一个任务。任务的各个属性由一个struct xs_utask结构表示包括任务的名称、入口函数及参数、栈大小和优先级在调用该函数时需要传入该结构的实例用于配置任务。任务创建成功后内核会为其分配指定大小的栈及其他结构如struct task_descriptor结构并返回任务描述符指针。
| 参数 | 描述 |
| --- | --- |
| task | 任务配置属性 |
```c
xs_int32 xs_UserTaskDelete(struct task_descriptor task);
```
该函数用于删除一个任务强制使其进入退出状态。若删除成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task| 待删除的任务描述符 |
```c
xs_int32 xs_UserTaskCoreCombine(struct task_descriptor task, xs_uint8 coreid);
```
该函数用于将任务绑定至指定的处理器上。若绑定成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task_id | 待绑定的任务描述符 |
| coreid | 带绑定的处理器ID |
```c
xs_int32 xs_UserTaskCoreUncombine(struct task_descriptor task);
```
该函数用于解除任务与处理器的绑定。若解除成功则返回XS_EOK若失败则返回-XS_ERROR。
| 参数 | 描述 |
| --- | --- |
| task | 待解除绑定的任务描述符 |
```c
xs_int32 xs_UserTaskDelay(xs_ticks_x ticks);
```
该函数用于将当前任务挂起一定时间单位为tick。挂起时间结束后任务会进入就绪状态可以继续被调度。
| 参数 | 描述 |
| --- | --- |
| ticks | 任务挂起时间单位为tick |
```c
struct task_descriptor* xs_UserTaskSearch(char *name)
```
该函数用于从任务名称获取任务描述符。
| 参数 | 描述 |
| --- | --- |
| name | 任务名称 |
## 使用场景
* 在多处理器设备上,多个任务可以并行运行,从而提高处理器的利用率。
* 在一些中断驱动的应用中,如果中断需要处理的工作过于复杂,则可以创建一个任务专门用于处理相关工作,从而改善中断延迟。