DSPBIOS总结.docx
- 文档编号:6849236
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:35
- 大小:257.05KB
DSPBIOS总结.docx
《DSPBIOS总结.docx》由会员分享,可在线阅读,更多相关《DSPBIOS总结.docx(35页珍藏版)》请在冰豆网上搜索。
DSPBIOS总结
DSP/BISO线程调度
DSP/BIOS使用户的应用程序可以由一个线程集合构筑起来,每一个线程执行一个模块化的功能。
通过允许高优先级的线程抢占低优先级的线程,以及允许阻塞、同步、通信等各种线程间的交互方式,使得多线程的应用程序可以在一个处理器上运行。
DSP/BIOS支持多种不同优先级的线程,每种线程类型都有不同的执行和抢占特性。
这些线程按照优先级从高到低的顺序排列如下:
●硬件中断(HWI),包括CLK函数。
●软件中断(SWI),包括PRD函数。
●任务(TSK)。
●后台线程(IDL)。
在DSP/BIOS中,硬件中断有最高的优先级,然后是软件中断,软件中断可以被高优先权软件中断或硬件中断抢先。
软件中断是不能被阻塞的。
任务的优先权低于软件中断,共有15个任务优先权级别(加上TSK_idle应该16个)。
任务在等待某个资源有效时可以被阻塞。
后台线程idle_loop是优先级最低的线程。
线程优先级如下图表示:
下面具体介绍各种线程。
HWImodule
硬件中断是用来处理应用程序响应外部异步事件时必须执行的关键操作。
在典型的DSP应用中,硬件中断是由片上的外设或者DSP外部的设备触发的。
中断发生后处理器会通过中断向量跳转到相应的ISR地址。
一个中断的跳转由一个DSP/BIOSHWI对象负责,跳转的地址可以是一个用户函数或者是通用的系统HWI调度程序(dispatcher)的入口地址。
硬件中断ISR可以使用汇编语言、C语言或者混合编写。
HWI函数通常使用汇编来提高效率。
如果要完全使用C语言编写,应该使用系统的HWI调度程序,它会在调用用户C函数的前后分别惊醒现场环境保护与恢复。
所有的硬件中断都会一直运行到结束,如果一个硬件中断在其ISR得到运行机会前被多次触发,该ISR也只运行一次。
因此,用户必须尽量和减少HWI执行的代码量。
如果GIE位被使能,一个硬件中断可能被任何其他的被使能的中断抢占。
硬件中断没有优先级的区分;线程调度结果首先取决于该类就绪线程是被使能还是被禁止的。
下图表示了硬件中断的抢占线程以及整个调度过程:
当第一个硬件中断(HWI2)产生时,相应的ISR触发了一个比当前运行的软件中断线程(SWIB)优先级更高的软件中断(SWIA)。
并且当第一个ISR运行时,第二个硬件中断(HWI1)产生。
因为第一个ISR没有屏蔽掉第二个硬件中断,因此产生第二个ISR抢占了第一个ISR。
由于优先级较低的SWI可以被硬件中断异步抢占,因此第一个ISR触发的软件中断在两个硬件中断都执行完毕后才被调度执行。
一、实验目的
熟悉HWI模块在BIOS下的配置,并初步学会自己独立编写程序实现对TIMER的配置和使用。
二、实验任务
1、设置定时器来产生周期性的中断。
在CCS3.1版本的bios下右击CSL-ChipSupportLibrary->TIMER->TimerConfigurationManager选择插入timercfg,根据实验要求配置相应的参数。
(对于ccs3.3版本的bios下没有csl的配置选项,我们需要自己在程序中编写配置指令)
2、设置HWI
在bios下的Scheduling->HWI->HWI_INT15目录,根据实验要求修改HWI_INT15的Properties。
3、建立LOG
在bios下的Instrumentation->LOG目录,新建一个名为trace的LOG。
4、编写main.c
根据以下的程序框架,编写实验程序。
#include
#include
#include
#include
#include
#include
#include"hwilabcfg.h"
staticUint32TimerEventId;
main()
{
/*GetthetimereventID*/
TimerEventId=TIMER_getEventId(hTimer1);
/*Enabletheevent*/
IRQ_enable(TimerEventId);
/*Startthetimer*/
TIMER_start(hTimer1);
}
三、实验过程及内容
在本实验中使用的是CCS3.3,因此,timer的配置需要自己来编写实现,对于HWI的配置如图1和图2所示,
图1、HWI->GENERAL的配置
图2、HWI->GENERAL的配置
实验的源程序如下:
#include
#include
#include
#include
#include
#include
#include"hwilabcfg.h"
staticTIMER_HandlehTimer;
staticUint32TimerEventId;
main()
{
//---------Configurethetimerdevices---------//
TIMER_ConfigMyTimConfig={
0x000002C0,//setthevalueofTimercontrolregister(CTL)
0x00001000,//Setperiod
0x00000000//Startcountvalueatzero
};
//InitialiseCSL
CSL_init();
//OpenTIMER1device,andresetittopower-ondefaultstate
hTimer=TIMER_open(TIMER_DEV1,0);
TIMER_config(hTimer,&MyTimConfig);
//Enablethetimerevents(eventsaredisabledwhileresetting)
IRQ_enable(TimerEventId);
//Startthetimers
TIMER_start(hTimer);
//ObtaintheeventIDforthetimerdevice
TimerEventId=TIMER_getEventId(hTimer);
}
//ISRtoserviceTIMERINT1.
voidtimerHWI(){
LOG_printf(&trace,"HWItimer");
}
SWImodule
软件中断是通过程序中的调用SWI函数而触发的,它提供了一个介于HWI和TSK之间的额外的优先级,用于处理那些时间限制比TSK严格但比HWI宽松的工作。
SWI线程适用于处理发生频率较低的或者实时限制没有硬件中断严格的应用程序作业。
SWI线程都会一直运行直到完成。
SWI使得HWI可以将一些不太关键的处理委托给一个优先级比它低的SWI线程,从而减少CPU在中断服务程序中花费的时间,使得其他的HWI可以得到运行。
当软件中断被触发时,它会在所有等待中的硬件中断都执行完才开始执行。
正在执行的SWI线程在任何时候都可以被硬件中断抢占,并且SWI线程会在硬件中断执行完毕后才恢复执行。
另一方面,SWI总能抢占任务的执行,所有等待中的SWI线程执行完之后具有高优先级的任务才可以开始被调度执行。
要创建一个SWI的配置文件,右键点击DSP/BIOS的Scheduling->SWI然后选择添加,这样会增加一个新的SWI工程,点击右键properties改变属性,写入函数并改变优先级。
KNL_swi是最低级的并且被保留的,用来安排任务。
每一个SWI都有一个邮箱,这个邮箱是个32位的值,来决定是否触发SWI或者作为数值观察SWI函数。
当一个SWI运行时可通过函数SWI_getmbox来查看邮箱。
这个函数在SWI被移除出触发清单之前返回邮箱数值,当SWI运行时邮箱值被锁存,执行后返回初始值。
SWI_getmbox返回的值就是SWI被移除出触发清单之前的邮箱数值。
能够触发软件中断的DSP/BIOSAPI函数有:
1、SWI_andn:
该函数提供的参数的“非”与邮箱值做“与”运算,若邮箱为0,则启动该软件中断;如果一个SWI必须在多个事件都发生之后才触发,就使用SWI_andn来调用;当其他的事件都结束后,都应该调用函数SWI_andn来以互补的位掩模参数来清除SWI邮箱里的值,使其为0触发SWI;
2、SWI_dec:
使邮箱值减1,若邮箱值为0,则启动该软件中断,并恢复邮箱到初始值;如果我们需要同一个事件必须发生多次之后才触发一个SWI,就可以使用该函数;将SWI的邮箱值配置为该时间发生的次数,然后在事件每次发生时调用SWI_dec,直到时间发生了与邮箱值次数相同的时候,即邮箱值为0时,SWI被触发。
3、SWI_post:
启动软件中断;
4、SWI_inc:
启动该软件中断,并对邮箱值加1;如果程序希望SWI在运行前被多次触发的情况下让其多次执行,就可以调用函数SWI_inc;
5、SWI_or:
启动该软件中断,并且邮箱值与该函数提供的参数做“或”运算;通过使用函数SWI_or可以根据触发事件的不同来调用不同的函数;SWI_or使用位掩模值来对触发事件的类型进行编码,可以将该位掩模值作为标志来识别事件并选择不同的函数来执行。
前两个是有条件的触发(邮箱值为0),后三者是无条件的触发。
任务过程目的及结果:
1.熟悉SWI模块及其使用;
2.在PART1中,比较两个SWI在同一优先级的情况下的运行时序,并总结规律;
3.在PART2中,比较两个SWI在不同优先级的情况下的运行时序,结合PART1的结果比较,得出规律;
4.在PART3中,在周期函数的触发作用下,观察时序,比较优先级相同但邮箱值不同的两个SWI的运行情况,并了解函数SWI_dec()的作用和使用方法以及此处邮箱值的变化和作用;
5.在PART4中,创建三个SWI,观察时序图,了解函数SWI_andn()的作用和使用方法以及此处邮箱值的变化和作用;
6.在PART5中,创建三个SWI,观察时序图,了解函数SWI_or()的作用和使用方法以及此处邮箱值的变化和作用。
PART1:
1、实验步骤:
1)创建工程以及DSP/BIOS文件以及将.cmd文件添加入工程;
2)将输入输出改为模拟Simulator;
3)在Instrumentation->LOG添加一个LOG叫做trace;
4)添加两个SWI,如下设置:
SWI0,priority:
1,mailbox:
0,function:
_funSWI0.
SWI1,priority:
1,mailbox:
0,function:
_funSWI1.
5)创建一个main函数并触发SWI0,加入工程;
6)在main函数中写_funSWI0和_funSWI1函数,用LOG_ptintf输出语句;触发SWI用SWI_post;
7)编译连接并通过DSP/BIOS->MessageLog观察。
2、程序代码
#include
#include
#include
#include"swilabcfg.h"
voidmain()
{
LOG_printf(&trace,"mainstarts");
SWI_post(&SWI0);
}
voidfunSWI0()
{
LOG_printf(&trace,"SWI0begins");
SWI_post(&SWI1);
LOG_printf(&trace,"SWI0ends");
}
voidfunSWI1()
{
LOG_printf(&trace,"SWI1begins");
LOG_printf(&trace,"SWI1ends");
}
3、时序图
4、小结
在优先级一致(同为1)的情况下,在main中触发SWI0,之后SWI0启动中断,直到SWI0结束后才由它触发SWI1,再到SWI1结束,都是依次按顺序进行。
PART2:
1、实验步骤
与PART1基本相同,主要的区别是将SWI1的优先级设置为2。
2、实验代码
与PART1相同,只是SWI优先级不同。
3、时序图
4、小结
当优先级不一致时(SWI0为1,SWI1为2),在main中触发SWI0,SWI0开始运行,同时在SWI0中触发SWI1时由于SWI1的优先级高,SWI0被挂起(pending),待SWI1结束后再继续运行SWI0直到结束。
PART3:
1、实验步骤:
1)设置一个周期函数来触发SWI0;SWI1的邮箱值设为1,并且由SWI0来减小,使得SWI1已一半SWI0的速率运行;
2)创建main3.c函数,Scheduling->PRD中添加新的PRD0,改变函数名称为_funPRD0并且周期为1;
3)使得SWI1和SWI0有相同的优先级,SWI1有邮箱值为1;
4)改变主函数使得:
funPRD0触发SWI0;funSWI0减小SWI1的邮箱值;主函数不做任何输出;SWI1输出不变。
2、实验代码
基于PART2程序上修改的程序如下:
voidfunPRD0()
{
SWI_post(&SWI0);
}
voidfunSWI0()
{
LOG_printf(&trace,"SWI0begins");
SWI_dec(&SWI1);
LOG_printf(&trace,"SWI0ends");
}
3、时序图
4、小结
程序中设定了一个1s的周期函数(PRD0)。
在此函数设定后会添加一个PRD_swi,它的中断过程如下:
先开始触发PRD_swi,然后运行PRD0,此时并没有去触发PRD0程序中的SWI0,而是先结束PRD_swi,再去触发SWI0;因为SWI0和SWI1的优先级一致,而且SWI_dec的作用是邮箱值减1,若邮箱值为0,则启动该软件中断;由于之前设置SWI1的邮箱值为1,所以按顺序在SWI0结束后,SWI1的邮箱值减1成为0而触发SWI1,直到其结束。
SWI_dec的作用是邮箱值减1,若邮箱值为0,则启动该软件中断;如果我们需要同一个事件必须发生多次之后才触发一个SWI,就可以使用改函数;将SWI的邮箱值配置为该时间发生的次数,然后在事件每次发生时调用SWI_dec,直到时间发生了与邮箱值次数相同的时候,即邮箱值为0时,SWI被触发。
PART4:
1、实验步骤
1)与PART3基本相同;只是添加一个新的SWI2,设置邮箱值为3,优先级为1;
2)改变MAIN4.C函数使得:
funSWI0函数减少SWI1的邮箱值并清除SWI2的一位;funSWI1清除SWI2的另一位。
2、实验代码
基于PART3的程序修改程序如下:
voidfunPRD0()
{
SWI_post(&SWI0);
}
voidfunSWI0()
{
LOG_printf(&trace,"SWI0begins");
SWI_dec(&SWI1);
SWI_andn(&SWI2,0);
LOG_printf(&trace,"SWI0ends");
}
voidfunSWI1()
{
LOG_printf(&trace,"SWI1begins");
SWI_andn(&SWI2,0);
LOG_printf(&trace,"SWI1ends");
}
3、时序图
4、小结
因为三个SWI的优先级是一致的,所以由PRD0触发SWI0之后,在SWI0运行后中减少了SWI1的邮箱值使SWI1的邮箱值为0成功触发SWI1,同时清除了SWI2中的第一位;SWI1的运行中清除了SWI2的第二位使得SWI2邮箱值为0,成功触发SWI2。
SWI_andn函数的作用是该函数提供的参数的“非”与邮箱值做“与”运算,若邮箱为0,则启动该软件中断;如果一个SWI必须在多个事件都发生之后才触发,就使用SWI_andn来调用;当其他的事件都结束后,都应该调用函数SWI_andn来以互补的位掩模参数来清除SWI邮箱里的值,使其为0触发SWI。
Part5:
1、实验步骤
1)基本与PART3和PART4相同,只是利用函数SWI_or在SWI0或者SWI1运行时触发SWI2:
2)设置SWI2的邮箱值为0,优先级为2;
3)改变main5.c使得:
unSWI0函数减少SWI1的邮箱值并设置SWI2的一位;funSWI1设置SWI2的另一位;
2、实验代码
基于PART4的程序修改程序如下:
voidfunPRD0()
{
SWI_post(&SWI0);
}
voidfunSWI0()
{
LOG_printf(&trace,"SWI0begins");
SWI_dec(&SWI1);
SWI_or(&SWI2,1);
LOG_printf(&trace,"SWI0ends");
}
voidfunSWI1()
{
LOG_printf(&trace,"SWI1begins");
SWI_or(&SWI2,2);
LOG_printf(&trace,"SWI1ends");
}
voidfunSWI2()
{
LOG_printf(&trace,"SWI2begins");
LOG_printf(&trace,"SWI2ends");
}
3、时序图
4、小结
执行PRD_swi后,触发SWI0,在SWI0的执行过程中由于函数SWI_or的作用触发SWI2(优先级为2,最高),SWI0被pending,直到SWI2结束后继续;SWI0结束后触发SWI1(SWI1和SWI2同为1的优先级),在SWI1的执行过程中由于SWI_or的作用再次触发SWI2,待SWI2结束后运行SWI1,直到其结束。
SWI_or是启动该软件中断,并且邮箱值与该函数提供的参数做“或”运算;通过使用函数SWI_or可以根据触发事件的不同来调用不同的函数;SWI_or使用位掩模值来对触发事件的类型进行编码,可以将该位掩模值作为标志来识别事件并选择不同的函数来执行。
IDLEmodule
空闲循环是DSP/BIOS的后台程序,只有没有硬件中断、软件中断和任务运行的时候才会循环运行。
其他的任何线程都可以在任何时候抢占空闲循环。
IDL管理器允许用户配置自定义的IDL函数,在进入空闲循环时这些IDL函数会被执行。
IDL_loop会依照IDL对象创建的顺序调用与每个对象相关联的函数,每次运行一个且当最后一个对象函数运行完后会重新调用第一个IDL函数不断循环。
空闲循环是DSP/BIOS中优先级最低的线程。
目标DSP和主机DSP/BIOS分析工具间的通信通常是在空闲循环中进行的。
这样保证了DSP/BIOS分析工具不会影响应用程序的处理。
默认情况下,空闲循环执行下列IDL对象的函数:
LNK_dataPump:
用来管理主机和DSP处理器之间的实时分析数据(LOG和STS数据)和HST数据的传输。
这通过使用RTDX实现。
RTA_dispatcher:
用于在目标DSP端接收主机实时分析工具的命令,收集目标DSP的监测信息并实时上传给主机PC。
它处在两个主机专用通道的末端,通过LNK_dataPump传输命令和数据。
IDL_cpuload:
使用一个STS对象IDL_busyObj来计算目标DSP的负荷。
它的内容会通过RTA_dispatcher上传给DSP/BIOS分析工具。
任务过程目的及结果:
本实验主要是设置将IDL,SWI,TSK放在一个工程中,看它们的程序调度以及优先级和创建顺序对以上对象函数执行效果的影响。
实验步骤:
●创建工程以及DSP/BIOS文件以及将.cmd文件添加入工程;
●将输入输出改为模拟Simulator;
●在Instrumentation->LOG添加一个LOG叫做trace;
●添加两个SWI,如下设置:
⏹SWI0,priority:
1,mailbox:
0,function:
_swi_yjq.
⏹SWI1,priority:
2,mailbox:
0,function:
_swi_yjq1.
●添加两个TSK,如下设置:
⏹TSK0,priority:
1,function:
_task.
⏹TSK1,priority:
1,function:
_task.
●编译连接并通过DSP/BIOS->MessageLog观察。
程序代码:
#include
#include"l1cfg.h"
#include
#include
voidtask(Argid_arg);
voidswi_yjq(void);
voidswi_yjq1(void);
voididl_trace(void);
voidmain()
{
LOG_printf(&trace,"successful");
}
voididl_trace(void)
{
LOG_printf(&trace,"idling");
SWI_post(&SWI0);
}
voidswi_yjq(void)
{
LOG_printf(&trace,"SWI0");
SWI_post(&SWI1);
}
voidswi_yjq1(void)
{
LOG_printf(&trace,"SWI1");
}
voidtask(Argid_arg)
{
inti;
intid=ArgToInt(id_arg);
for(i=0;i<3;i++)
{
LOG_printf(&trace,"Task%dWorking",id);
TSK_yield();
}
LOG_printf(&trace,"Task%dDONE",id);
}
时序图:
结果:
在IDL中触发了SWI0,SWI0执行后触发SWI1,因为SWI0和SWI1同一优先级,所以按创建顺序执行。
之后因为有TSK等待,所以执行TSK,待TSK执行完后,又回到了IDL,再次触发SWI0,SWI0再次触发SWI1,不断循环,不过不再出现TSK,这是因为软中断由IDL触发,而IDL是不断循环的,所以一直触发SWI0和SWI1。
MBXmodule
MBX模块提供了一整套的职能函数来管理邮箱。
MBX邮箱可以用来传递讯息,从一个任务到另一个任务在同一个处理器上。
一个固定长度的共享邮箱促使了任务间的同步,来确保到来的信息流不会超过系统处理这些信息的能力。
MBX里的邮箱管理不同于SWI中的邮箱结构体。
MBX_create和MBX_delete分别是用来创建和删除邮箱,如下:
MBX_HandleMBX_create(msgsize,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DSPBIOS 总结