ADSP-TS201——实验IRQ
板上的DSP有两块ADSP Tiger SHARC 201(Tiger,这名字比较生猛),而且据说每个都是双核的,听说主频能达到500MHz,真夸张。
上午看C\C++编译器的文档,发现一个TS101的例子程序,使用了时钟中断和IRQ0,我想这个发现的好,我可以模仿它这个程序自己写一个,增进我对这款DSP的了解。
研究这个程序,首先我了解了在C中定义中断服务程序的方法:
首先编写一个C函数,返回值和参数都是void;
将#pragma interrupt放在这个函数前面,定义这个函数为不可重入的中断服务;
在main中通过__builtin_sysreg_write将这个函数的函数指针放入中断向量表中,例如IRQ0的服务程序为irq0_isr,则:
__builtin_sysreg_write(__IVIRQ0,(int)irq0_isr);
接着我发现了一种叫做flag pin的东西,按我目前的理解是一种可以控制方向(input\output)的管脚。在实验板上这些管脚有的接按钮有的接LED。在TS101中可以通过名为SQCTL的寄存器对它们进行操作,但TS201不是用SQCTL,而是有个专用的寄存器叫做FLAGREG。文档中是这样说明的:
The FLAGREG register is a 32 bit register that controls flag pin direction (input or output) and provides output value controls (1 or 0) for output flag pin.
这个32位寄存器的高16位大概没用,且15~8位也是保留位,无定义;
7~4:FLAGx_OUT——Select output value of flag pins if pin is enabled as an output by its FLAGx_EN bit
4-FLAG0 ... 7-FLAG3
3~0:FLAGx_EN——1=Output 0=Input 0-FLAG0 ... 3-FLAG3
然后又发现,在TS101中可以利用SQCTL设置IRQ的触发方式,电平触发level-sensitive、跳沿触发edge-sensitive,但是在TS201中,这个设置被放在了另外一个寄存器INTCTL中(在AD的文档中此处有一个错误,将INTCTL误为INCTL),定义是这样的:
15~8:保留位
5:TMR1RN Timer 1 run
4:TMR0RN Timer 0 run
3~0:IRQ(3~0)_EDGE 0=edge sensitive 1=level sensitive
其实在程序中我发现两个比较怪异的寄存器,查阅了资料后就很明白了:
SQCTLST:文档中写道:
The SQCTLST bit is an alias used to write to SQCTL.When writting to this address,the data written into SQCTL is the OR of the old register value and the new data written into SQCTLST.A '1' in any bit of the written data sets the corresponding bit in SQCTL,while a '0' in written data does not change the bit value.
E文的说明文一般都是比较简单的,只有文学家和政治家比较让人头疼。SQCTLST就是用来将SQCTL的某些位置1的,利用按位或,我想熟悉Windows编程的人对此并不陌生(熟悉编程的人对此都不会陌生),利用Win32 API操纵窗口的属性时,常常先获取窗口的原本属性,然后利用按位或将某些位置1,以及利用按位与将某些位置0,然后再利用API写入窗口属性。寄存器SQCTLST和SQCTLCL就是为了简化这一操作的。ST就是set,CL就是clear。SQCTLCL用来将某些位清0,使用按位与,就不用多说明了。
在TS201中,像对于flag pin的操作都移到了FLAGREG中,我在头文件defts201.h中发现寄存器FLAGREG也有对应的ST和CL寄存器,操纵能够方便些。
了解了这些,我自己写了一个关于TS201的IRQ0的程序,这个程序模仿了文档中那个TS101的程序,但没有使用时钟中断。程序如下,加了些注释:
- #include<stdio.h>
- #include<builtins.h>
- #include<sysreg.h>
- #include<defts201.h>
- void irq0_isr(void);
- int main( void )
- {
-
- int v;
- //将FLAG2设为输出模式
- __builtin_sysreg_write(__FLAGREGST,FLAGREG_FLAG2_EN);
- //设置IRQ0服务程序
- __builtin_sysreg_write(__IVIRQ0,(int)irq0_isr);
- //设置跳沿触发
- __builtin_sysreg_write(__INTCTL,0);
- //允许外部IRQ0
- v=__builtin_sysreg_read(__IMASKH);
- v|=(1<<INT_IRQ0_P);
- __builtin_sysreg_write(__IMASKH,v);
- //开全局中断使能
- __builtin_sysreg_write(__SQCTLST,SQCTL_GIE);
- while(1);
- return 0;
- }
- #pragma interrupt
- void irq0_isr(void)
- {
- staticint button=0;
- button=!button;
- if(0==button)
- {
- __builtin_sysreg_write(__FLAGREGCL,~FLAGREG_FLAG2_OUT);
- }
- else
- {
- __builtin_sysreg_write(__FLAGREGST,FLAGREG_FLAG2_OUT);
- }
- }
复制代码
在实验板上IRQ0有一个按钮来控制,而FLAG2接了一个LED,虽然没有加按键消抖程序,但按钮还是很听话的:
注意右起第二个LED,可以使用按钮进行亮灭的控制。
|