这两个都是DSP/BIOS中的,先大概介绍一下
tsk:
task,任务.在Scheduling中,其优先级高于IDL(背景程序),低于SWI(软中断)和HWI(硬中断).可以被软硬中断打断,也可以被其它事件阻塞(blocked),顺便说一下,SWI和HWI是不能阻塞的.(阻塞和中断的不同,见我的另外一篇文章:CCS的一些问题)
tsk和swi和hwi类似,可以调用一个函数,还可以传递多达8个参数,不同的tsk可以有15个优先级,执行任务的顺序相当于一个优先队列,如果一个tsk被阻塞,会自动将这个tsk放到同优先级tsk的后面,等待条件满足的时候执行.
tsk有个重要的函数TSK_yield,当一个tsk调用这个函数的时候,会将自己挂起(pend),将控制权交给接下来的一个tsk,让他执行.
查看不同的tsk的状态,可以选择"DSP/BIOS -> Kernel/Object View ",在出现的窗口左边点击tsk,就可以在右边看到所有tsk的状态(ready:准备好,running:运行中,blocked:被阻塞,terminal:结束)
------------------------------------------------------------------------------
mbx:
mailbox,邮箱.在Synchronization中.一般作为不同的任务(tsk)之间传递数据.
mbx有两个属性,
Size:这里面可以存放的单个数据的大小,比如想在这里面存放int类型的数值,那么Size就设为4.
Length:里面最多能存放多少个大小为Size的数据,如果设为2,那么就能存放2个.
主要函数:
MBX_pend:
语法:
status = MBX_pend(mbx, msg, timeout);
参数:
MBX_Handle mbx; /* 句柄*/
Ptr msg; /* 用以保存读取出来的数据的地址*/
Uns timeout; /* 超时时间*/
返回值:
Bool status; /* 如果成功,返回TRUE if successful,如果timeout设定的时间内没有读取到数据,则返回 FALSE*/
描述:
如果mbx不为空,将复制其中的第一个数据到msg指定的地址并且返回TRUE.如果为空,这个任务将被挂起,直到MBX_post函数被调用或者timeout设置的时间到.
如果timeout的值是SYS_FOREVER,那这个任务将一直挂起,直到MBX_post函数被调用,如果timeout的值是0,那么将立即返回FALSE.
MBX_post:
语法:
status = MBX_post(mbx, msg, timeout);
参数:
MBX_Handle mbx; /* 句柄*/
Ptr msg; /* 存放写入数据的地址*/
Uns timeout; /*等待时间,如果超过此时间仍然不能写入,返回FALSE*/
返回值:
Bool status; /* 成功写入返回TRUE,超时返回FALSE */
描述:
MBX_post 检查mbx中是否有空闲的位置,如果有,则将msg的内容写入mbx.同时将下一个MBX_post任务(如果有的话)设为ready状态.
如果mbx已经满了,而且timeout等于SYS_FOREVER,这个任务将被挂起,等待MBX_pend函数被调用.如果timeout等于0,那么立即返回FALSE.如果timeout是不为0的数,这个任务将等待这么长的时间,如果还是没有MBX_pend函数被调用,则返回FALSE.
A task switch occurs when calling MBX_post if a higher priority task is made ready to run, or if there are no free message slots and timeout is not 0.
这两个东西还有不少可以测试的地方,比如tsk的优先队列是怎么排的,调用TSK_yield后排到什么地方,mbx未放满是不是能读取,未读完是不是能放入,pend和post的Timeout值有什么用,这些等下次有空研究的时候补充.
===================================================
在调试TI的一个例程tsktest(位置:X:\CCStudio_v3.1\tutorial\sim64xx\tsktest,其中的sim64xx根据你使用的DSP类型而定)的时候,花了不少时间,才终于理解了这里面任务调度的顺序.
程序中有一个mbx,能放2个8B的数据,有4个tsk,1个是读mbx,3个写mbx,这三个写mbx的tsk调用的是同一个函数,不过为了区分,调用的时候传递了一个不同的参数.程序运行的结果这里就不写了.
我经过改变mbx的length和write函数的循环写入次数后,可以确定mbx有自己的一个任务队列,当mbx满的时候,post过来的tsk会被blocked,但是这个post的动作已经是放在mbx的任务队列中,等到mbx被读空的时候,会自动开始这个post动作.如果在这个post动作后面还排着其它的动作,那么会接着执行后面的动作.
举个现实中的例子,假设有ABC三队人在排队买票,每队3人,分别叫A1A2A3B1B2B3C1C2C3.他们在售票大厅外面的广场排队,售票大厅有一个门,要进大厅的人,必须在门前排成一队,然后才能进去.从各自的队伍排到门口的队伍,按照ABC的顺序,门口的队伍每队只能有一人.大厅里面有2个窗口在卖票,如果两个窗口都有人在买,那么后面的人只能排在门口,不能进大厅.只有当在两个窗口买票的人都离开后,排在后面的前两个人才能进大厅.进入大厅的人,如果自己的队伍还有人,必须通知下一个人过来排队.
那么看一下买票和排队的顺序.
一开始A1A2到门口,大厅空,
两人进去,通知A3过来排队
A3到门口,里面满了,在门口排队,
A队已经一人在门外,就轮到B队了
B1到门口排队,排在A3后面,B组结束,
轮到C队,C1排到B1后面,C队结束.
现在开始第一轮卖票,
A1A2买完走人,大门可以进人,
A3进大厅,因为A队没人了,不用通知,
接着B1进入大厅,顺便通知B队的B2过来排队,B2只能排在C1后面.
大厅又满,禁止进人,
开始卖票,
A3B1买完走人.大门开,
C1进门,通知C2过来排队,C2排在B2后面,
B2进门,通知B3来排队,B3排在C2后边.
大厅满,
开始卖票,
C1B2买完走人.大厅空,门开,
C2进,通知C3,C3排在B3后边,
B3进大厅,B队没人,不用通知,
大厅满,
开始卖票,
C2B3买完走人,大厅空,门开
,C3进,后边没人,不用通知,
由于所有队都排完,大厅虽然没满,也开始卖票,
C3买完走人.
卖票的人等了一会,发现没人来买了,就关门回家了.
买票的顺序就是A1A2 A3B1 C1B2 C2B3 C3
再和tsk和mbx类比,三个tsk就是ABC三条队伍,每次要post一个数据,就是来门口排队,而门口的队伍就是mbx的任务队列,只有mbx中的内容被读完,才会依次启动任务队列中的任务