【原创】初始化并开始运行MQX
0赞MQX 开始于_mqx()函数,该函数以 MQX 初始化结构为参数。基于这一结构中的参数,MQX完成如下任务:
(1).载入并初始化 MQX 经常使用的数据,包括默认内存池,就绪队列,中断堆栈和任务栈;
(2).初始化硬件(如芯片选择);
(3).开启定时器;
(4).设置默认的时间片值;
(5).生成空闲任务,当没有其它任务就绪时将被激活;
(6).生成由任务模板列表定义为自启动的任务;
(7).开始调度多任务。
1.MQX初始化结构
MQX 初始化结构中定义应用程序和目标硬件的参数如下:
typedef struct mqx_initialization_struct
{
_mqx_uint PROCESSOR_NUMBER;
pointer START_OF_KERNEL_MEMORY;
pointer END_OF_KERNEL_MEMORY;
_mqx_uint INTERRUPT_STACK_SIZE;
TASK_TEMPLATE_STRUCT_PTR TASK_TEMPLATE_LIST;
_mqx_uint MQX_HARDWARE_INTERRUPT_LEVEL_MAX;
_mqx_uint MAX_MSGPOOLS;
_mqx_uint MAX_MSGQS;
char _PTR_ IO_CHANNEL;
char _PTR_ IO_OPEN_MODE;
_mqx_uint RESERVED[2];
} MQX_INITIALIZATION_STRUCT, _PTR_ MQX_INITIALIZATION_STRUCT_PTR;
如需查看每个域的描述,参见 MQX的手册。
1.1 默认MQX初始化结构
你可以为 MQX 初始化结构定义自己的初始值,或者使用由每个 BSP 提供的默认值。该默认值被称为 MQX_init_struct 而且保存在相应的 BSP 目录下的 mqx_init.c 文件中。该文件已经被编译并连接到 MQX。
注意:对于任务相关的调试工具来说,MQX 初始化结构必须命名为 MQX_init_struct。
本章中的例子将使用如下 MQX_init_struct:
MQX_INITIALIZATION_STRUCT MQX_init_struct =
{
/* PROCESSOR_NUMBER */ BSP_DEFAULT_PROCESSOR_NUMBER,
/* START_OF_KERNEL_MEMORY */ BSP_DEFAULT_START_OF_KERNEL_MEMORY,
/* END_OF_KERNEL_MEMORY */ BSP_DEFAULT_END_OF_KERNEL_MEMORY,
/* INTERRUPT_STACK_SIZE */ BSP_DEFAULT_INTERRUPT_STACK_SIZE,
/* TASK_TEMPLATE_LIST */ (pointer)MQX_template_list,
/* MQX_HARDWARE_INTERRUPT_LEVEL_MAX*/
BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX,
/* MAX_MSGPOOLS */ BSP_DEFAULT_MAX_MSGPOOLS,
/* MAX_MSGQS */ BSP_DEFAULT_MAX_MSGQS,
/* IO_CHANNEL */ BSP_DEFAULT_IO_CHANNEL,
/* IO_OPEN_MODE */ BSP_DEFAULT_IO_OPEN_MODE
};
注:初始化 RESERVED 域的元素值为 0
1.2 任务模板列表
任务模板列表(TASK_TEMPLATE_STRUCT)定义了一组初始化模板,基于该模板可以在处理器上生成任务。
初始化时,MQX 生成每个任务的一个实例,任务模板将其定义为一个自启动任务。同样,当应用程序运行时,它能按任务模板生成其它任务,该模板由任务模板定义或应用程序动态定义。任务模板队列的结尾是一个填入全 0 的任务模板。
typedef struct task_template_struct
{
_mqx_uint TASK_TEMPLATE_INDEX;
void _CODE_PTR_ TASK_ADDRESS)(uint_32);
_mem_size TASK_STACKSIZE;
_mqx_uint TASK_PRIORITY;
char _PTR_ TASK_NAME;
_mqx_uint TASK_ATTRIBUTES;
uint_32 CREATION_PARAMETER;
_mqx_uint DEFAULT_TIME_SLICE;
} TASK_TEMPLATE_STRUCT, _PTR_ TASK_TEMPLATE_STRUCT_PTR;
如需查看每个域的描述,请参见 MQX 手册。
1.2.1 指定任务优先级
注意:如果指定某个任务优先级为 0,则该任务运行时屏蔽了所有中断。当你在任务模板列表中指定任务优先级,请注意:
MQX 为每个优先级生成一个就绪队列直至最低的优先级(最大的数值)
当一个应用程序运行时,它不能生成一个优先级低于任务模板列表中的最低优先级(较大的数值)的任务。
1.2.2 指定任务属性
你可以为一个任务指定如下属性的任意组合:
(1).自启动——当 MQX 开始运行时,它生成任务的一个实例;
(2).DSP——MQX 保存 DSP 协处理器寄存器作为任务现场的一部分;
(3).浮点——MQX 保存浮点寄存器作为任务现场的一部分;
(4).时间片——MQX 为任务使用轮循调度(默认是 FIFO 调度)。
1.2.3 默认任务模板列表
你可以初始化自己的任务模板列表,也可以使用默认的列表 MQX_template_list。
1.2.4 举例:一个任务模板列表
TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
{ MAIN_TASK, world_task, 0x2000, 5, "world_task",
MQX_AUTO_START_TASK, 0L, 0},
{ HELLO, hello_task, 0x2000, 5, "hello_task",
MQX_TIME_SLICE_TASK, 0L, 100},
{ FLOAT, float_task, 0x2000, 5, "Float_task",
MQX_AUTO_START_TASK | MQX_FLOATING_POINT_TASK, 0L, 0},
{ 0, 0, 0, 0, 0, 0, 0L, 0 }
};
在这个例子中,world_task 是一个自启动任务,因此在初始化时 MQX 生成一个参数为 0 的任务实例。应用程序定义任务模板索引(MAIN_TASK)。该任务优先级为 5。World_task()函数是任务的入口,栈的大小是 0x2000 个寻址单元。
任务 hello_task 是一个时间片任务,如果使用默认的实时编译配置选项,其时间片数值为 100毫秒。
Float_task 任务既是一个浮点任务,也是一个自启动任务。
1.2.5 实例:创建一个自启动任务
创建一个简单任务,其功能为输出“Hello World”并终止,程序编写如下:
/* hello.c */
#include
#include
/* Task IDs */
#define HELLO_TASK 5
extern void hello_task(uint_32);
TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
{ HELLO_TASK, hello_task, 500, 5, "hello",
MQX_AUTO_START_TASK, 0L, 0},
{ 0, 0, 0, 0, 0,
0, 0L, 0}
};
void hello_task(uint_32 initial_data)
{
printf("\n Hello World \n");
_mqx_exit(0);
}
1.2.5.1 编译程序并连接到MQX
(1).进入如下目录:mqx\examples\hello
(2).参考 MQX 发布版本的说明文档,获得创建和运行程序的指令。
(3).按照说明文档的指令运行该应用程序。
在输出设备上将会有如下显示:
Hello World