随着DSP芯片功能的增强,已不再进行单纯的数字信号处理任务,而是作为一种MCU被广泛使用,控制板上各种资源,同时完成采集、计算、控制、通讯等任务。特别是当使用了TCP/IP或其它复杂通讯协议时,没有一个实时多任务 *** 作系统是很难进行任务调度的。μC/OS-II作为一种源码公开的占先式实时多任务 *** 作系统,总是执行处于就绪状态的优先级最高的任务,并支持Semaphore(信号量)、Mailbox(邮箱)、Message Queue(消息队列)等多种常用的进程间通信机制,是大多数高可靠嵌入式设备的首选。
2 开发环境简介
APCI5096是北京康拓工业电脑公司自行开发的一款DSP目标板,主要用于对模拟信号量的采样处理。该目标板以TMS320VC32为CPU,同时具有完备的输入/输出功能,可以实现30通道、16位、300KSPS的模拟输入。调试用编译器为TI公司的Code Composer ‘C3x-‘C4x,版本是410版。
3 移植过程
31 μC/OS-II系统结构
图1说明了μC/OS-II的软硬件体系结构。应用程序软件处于整个系统的顶层,只和μC/OS-II与处理器无关的代码以及μC/OS-II与应用相关的代码关联。这样保证了应用软件的可重用性。
μC/OS-II与处理器无关的代码提供了μC/OS-II的系统服务。利用这些API函数,应用程序可以进行内存管理、任务间的通信以及创建、删除任务等。μC/OS-II与应用相关的代码提供了对μC/OS-II本身的裁减,并可根据实际需要进行任务数、任务栈的大小等设置。
大部分的μC/OS-II代码是使用ANSI C语言书写的,因此μC/OS-II的可移植性较好。尽管如此,仍然需要使用C和汇编语言写一些处理器相关的代码。移植工作需要改写的是与处理器相关的代码,包括三个文件:OS_ CPUH、OS_ CPU_ C�C、OS_ CPU_ A�ASM。重点是任务堆栈的初始化、任务切换时栈指针的调整。
32 OS_ CPUH
在不同的处理器中有不同的字长,所以必须重新定义一系列数据类型以确保移植的正确性。在OS_ CPU�H文件中应完成:数据类型的重新定义、堆栈数据类型的定义、堆栈增长方向的定义、临界区开/关中断的方法、任务切换函数OS_TASK_SW的宏定义。
(1)数据类型的声明:在VC33中所有的整型数据(char、short、int、long)为相同的类型,用32位表示。浮点型数据(float、double)为相同类型,在VC33中用32位单精度浮点数表示。数据类型的重定义:
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U;
typedef signed char INT8S;
typedef float FP32;
typedef double FP64;
(2)VC33栈的数据宽度为32位,采用上面重定义过的数据类型进行定义,确保栈数据类型的一致性。栈的数据类型声明:
typedef INT32U OS_ STK;
(3)μC/OS-II访问代码的临界区时需要先禁止中断,并且在访问完毕后重新允许中断。μC/OS-II利用两个宏来禁止和允许中断,通过状态寄存器的中断使能位开关中断。
cregister unsigned int ST; /*声明CPU内部寄存器*/
#define OS_ ENTER_ CRITICAL() asm(“ANDN 2000H, ST "); /*清中断使能位*/
#define OS_ EXIT_ CRITICAL() asm(“OR 2000H, ST "); /*置中断使能位*/
33 OS_ CPU_ CC
在OS_ CPU_ CC文件中主要完成的是OSTaskStkInit()函数,其余五个函数可以不进行处理。OSTaskStkInit()函数完成任务栈的初始化,使得任务栈的结构看起来如同在任务执行过程中发生过一次中断并将所有寄存器保存到堆栈一样。不同的编译器在函数调用时会有不同的入栈方法,如:参数和返回地址入栈顺序、参数之间入栈的顺序、参数利用寄存器还是堆栈保存等。在具体实现时还需要根据编译器的要求进行调整。
CCS函数调用时堆栈规则为:先将参数从左往右入栈、然后是函数返回地址入栈。依照此规则设计任务栈初始结构如图2。VC33共有28个寄存器,程序中应将寄存器全部入栈,在OSTaskStkInit中实现:
{
OS_ STK *stk; /*定义栈的数据结构*/
opt=opt;
stk=(OS_ STK *)ptos; /*装入栈顶指针*/
*stk=(OS_ STK)pdata; /*参数入栈*/
*++stk=(OS_ STK)task; /*任务返回地址*/
*++stk=(OS_ STK)task; /*中断返回地址*/
*++stk=(OS_ STK)0x2000; /*状态寄存器,开中断*/ 其余CPU寄存器全部入栈,并初始化为0
}
34 OS_ CPU_ AASM
在OS_ CPU_ A�ASM文件中要求用户编写四个简单的汇编语言函数:OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OSTickISR()。这四个函数具有完全相同的公共部分:寄存器入栈和寄存器出栈。只要按照上面设计好的栈结构进行就可以了。注意的是VC33的R0到R7是扩展精度寄存器,具有40位。在入栈和出栈时均需要用两句话完成,如下:
入栈: 出栈:
PUSH R0 POPF R0
PUSHF R0 POP R1
而OSIntCtxSw函数具有特殊部分,该函数用于从中断返回时进行任务切换,由于在调用_ OSIntCtxSw函数前已经发生了中断,中断服务程序已经将CPU寄存器保存到堆栈中了,所以此处不再进行寄存器保存。同时还要进行栈指针的调整,去掉堆栈中一些不需要的内容,然后再将寄存器全部出栈。由于该函数是μC/OS-II中唯一的与编译器相关的函数,所以在移植后必须利用多次任务切换检查栈指针是否正确调整。
35 时钟中断源初始化
μC/OS-II还要求用户提供一个时钟资源,用于实现时间延时和确认超时。根据APCI5096的硬件设置,需要在三个文件中进行时钟资源的设置。
(1)OS_ CPU_ A�ASM:
APCI5096中,已将VC33的定时器1用于测频通道,因此利用未被占用的定时器0产生定时中断。实现方法为在TINT0的中断向量入口处放一跳转指令,跳转到自己写的OSTickISR。
�sect “�TINT0_ vector"
TINT0 br _ OSTickISR
(2)CMD文件
将TINT0跳转到OSTickISR后,还应再指定TINT0的向量入口地址。APCI5096板上的VC33被设置为BootLoader方式,在该方式下TINT0的入口地址固定在0x809FC9。在CMD文件的SECTIONS段指定如下:
�TINT0_ vector:> 0x809FC9
(3)Main�C文件
μC/OS-II要求用户在OSStart()运行后,μC/OS-Ⅱ启动运行的第一个任务中初始化节拍中断。自己编写一个函数TimerInit(),并在第一个任务开始处调用该函数完成定时器0的初始化。函数中TIM0_ XXX代表的是定时器0的三个寄存器的地址,在完成对定时器0的设置后还要打开全局中断和时钟中断。
{
*TIM0_PRD= 0x7530; /*设置周期为1KHZ*/
*TIM0_CNT=0;
*TIM0_CTL=0x2C1; /*启动时钟*/
ST|=0x2000; /*打开中断*/
IE|=0x100; /*打开时钟中断*/
}
4 测试、编写驱动和应用程序
做完以上工作以后,就要测试移植是否成功。最初测试时,可以先运行 *** 作系统本身,调度一些简单的任务和时钟节拍中断任务。主要测试系统本身的正确性,如果调试成功就可以在上面继续开发驱动程序和添加应用程序。
DSP的编程软件是CCS开发平台,编程语言一般是C语言。
CCS有两种工作模式:
1、软件仿真器模式:可与DSP芯片分离,并在PC上模拟DSP指令集和工作机制,主要用于早期算法的实现和调试。
2、硬件在线编程模式:可以在DSP芯片上实时运行,结合硬件开发板的在线编程和调试应用程序。
CCS的开发系统主要由以下组件构成:
1、TMS320C54x集成代码生成工具。
2、CCS集成开发环境。
3、DSP / BIOS实时内核插件及其应用程序接口API。
4、RTDX插件,用于实时数据交换和相应的程序接口API。
5、TI以外的第三方提供的各种应用程序模块插件。
扩展资料:
dsp编程中双重循环、多重循环的优化:
1、将多个循环分成单层循环以减少循环数;
例如,在双循环中,一个周期仅使用一个乘法器。 分成单层环路后,两个乘法器可以使用一个周期,充分利用DSP乘法器资源,运算速度也将提高。
2、循环次数少的放在外层循环,循环次数多的放在内存循环;
3、二维数组的双循环:二维数组的行循环置于外循环,列循环置于内循环;
4、避免在循环内进行乘法和除法运算:将循环内的乘法和除法运算尽可能移至循环外,并用加法代替。
您好,1 首先是接口的预定义
----------------------------------------------
#define LCD_DATA (((volatile Uint16 )0x0070E0)) // GPIOA7-A0对应DB7-DB0
#define RS GpioDataRegsGPBDATbitGPIOB0
#define RW GpioDataRegsGPBDATbitGPIOB1 //别弄错0 1 2
#define EN GpioDataRegsGPBDATbitGPIOB2 // 实际接线要对应
void InitGpio(void)
{
EALLOW;
GpioMuxRegsGPAMUXbitPWM1_GPIOA0 = 0; // 设置为普通GPIO使用
GpioMuxRegsGPADIRbitGPIOA0 = 1; // 设置为输出
GpioMuxRegsGPAMUXbitPWM2_GPIOA1 = 0;
GpioMuxRegsGPADIRbitGPIOA1 = 1;
GpioMuxRegsGPAMUXbitPWM3_GPIOA2 = 0;
GpioMuxRegsGPADIRbitGPIOA2 = 1;
GpioMuxRegsGPAMUXbitPWM4_GPIOA3 = 0;
GpioMuxRegsGPADIRbitGPIOA3 = 1;
GpioMuxRegsGPAMUXbitPWM5_GPIOA4 = 0;
GpioMuxRegsGPADIRbitGPIOA4 = 1;
GpioMuxRegsGPAMUXbitPWM6_GPIOA5 = 0;
GpioMuxRegsGPADIRbitGPIOA5 = 1;
GpioMuxRegsGPAMUXbitT1PWM_GPIOA6 = 0;
GpioMuxRegsGPADIRbitGPIOA6 = 1;
GpioMuxRegsGPAMUXbitT2PWM_GPIOA7 = 0;
GpioMuxRegsGPADIRbitGPIOA7 = 1;
GpioMuxRegsGPBMUXbitPWM7_GPIOB0 = 0;
GpioMuxRegsGPBDIRbitGPIOB0 = 1;
GpioMuxRegsGPBMUXbitPWM8_GPIOB1 = 0;
GpioMuxRegsGPBDIRbitGPIOB1 = 1;
GpioMuxRegsGPBMUXbitPWM9_GPIOB2 = 0;
GpioMuxRegsGPBDIRbitGPIOB2 = 1;
EDIS;
}
----------------------------------------------
一般液晶的控制线是直接对I/O口的位进行 *** 作,数据线是按字进行 *** 作。在这容易出错的是:(1)数据线地址的对应。DSP的GPIO数据地址一般为16位一个地址(F28335有的是32个GPIO一组,给出了一个地址,实际上是有两个地址的,给出的那一个地址是低16位的)。需要注意的是,液晶数据线一般为8位,那么把八位数据送出的时候,实际给的是DSP的16位数据的低八位,所以接线上要接低八位的GPIO;如果接高八位的GPIO,软件上要用下面一行程序进行移位 dat = dat << 8; //左移8位,向高位移动。(2)在进行GPIO初始化和预定义的时候,一般都会复制,但是别忘记改一些0 1 2 3等数,接线上也要一一对应,仔细检查。
2 51程序移植到DSP的时序问题
----------------------------------------------
void Display_Data_All(uchar hz)
{
while(hz != '\0')
{
WriteData12864(hz);
hz++;
delay(20);//2就不够!!!!!!
}
}
----------------------------------------------
由于51单片机的晶振一般为110592MHz,而DSP等控制器的晶振为30MHz,实际执行起来最高有150MHz,而液晶为低速外设,所以移植后可能会不显示,显示乱码等情况。我在调试12864液晶的时候就出现过只显示乱码数字不显示汉字的情况,这不是字库损坏,而是因为写汉字的时间要比写数字的时间长,而程序中延时过短。上面程序中把delay(2)改为delay(20)就解决问题了。
实际上,真正造成影响的是,程序执行过快。它认为显示完一个字之后,又很快进入下一个字的 *** 作;实际上液晶要一定的时间才能写完(见液晶 *** 作时序图),所以写数据的程序中要加长延时。至于RS、RW、EN等控制引脚,延时与否影响不大。
3 240128液晶的调试
240128液晶有busy和int返回信号,实际上不需要接即可。程序中也可以不测忙。。程序中写控制指令两者中间也要加长延时,更不用说写数据之间的延时。
----------------------------------------------
void lcd_regwrite(Uint16 regname,Uint16 regdata) // 写控制指令
{
lcd_regwr(regname);
delay(10); // 加长延时
lcd_regwr(regdata);
}
void lcd_character(uchar cha,int count) // 显示中文或字符
{
int i;
for(i=0;i<count;i++)
{
delay(10); // 加长延时
lcd_datawrite(cha);
++cha;
}
}
例如Y(K) = X(k) +X(k-1)+X(k-2)
int x0, x1, x2;
int y0;
x2 = x1;
x1 = x0;
x0 = input
y0 = x0 + x1 + x2;
bootloader是dsp芯片上固化的一段引导程序,dsp程序在ram上掉电易丢,所以启动时运行bootloader将辅存中的程序调入ram中
至于dsp的框架结构在ti公司有(有点复杂),开发时通常是先在开发板上仿真然后实践,由于dsp一般用于数字信号处理,离不开matlab软件连调。说起来有点复杂,要熟悉dsp开发流程序最简单的方法就是自己动手实践一下,如做个滤波器,频谱分析器等就可以深刻了解了。
ps有点繁琐,自己慢慢体会!
以上就是关于给我一篇完整的dsp程序设计全部的内容,包括:给我一篇完整的dsp程序设计、请问DSP编程软件是什么,,应该用什么编程语言、DSP28335控制12864液晶,读取LCD数据,lcd_read_data程序应该怎么编写等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)