2 开发环境简介
APCI5096是北京康拓工业电脑公司自行开发的一款DSP目标板,主要用于对模拟信号量的采样处理。该目标板以TMS320VC32为CPU,同时具有完备的输入/输出功能,可以实现30通道、16位、300KSPS的模拟输入。调试用编译器为TI公司的Code Composer ‘C3x-‘C4x,版本是4.10版。
3 移植过程
3.1 μ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_ CPU.H、OS_ CPU_ C�C、OS_ CPU_ A�ASM。重点是任务堆栈的初始化、任务切换时栈指针的调整。
3.2 OS_ CPU.H
在不同的处理器中有不同的字长,所以必须重新定义一系列数据类型以确保移植的正确性。在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 "); /*置中断使能位*/
3.3 OS_ CPU_ C.C
在OS_ CPU_ C.C文件中主要完成的是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
}
3.4 OS_ CPU_ A.ASM
在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中唯一的与编译器相关的函数,所以在移植后必须利用多次任务切换检查栈指针是否正确调整。
3.5 时钟中断源初始化
μ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定时器的LED控制系统设计,具体要求如下:
(1)给定电源5V,设计供电电路。
(2)给定外部晶振30M,系统时钟工作在150M,给出寄存器如何配置。
(3)利用定时器定时1秒,实现四个LED灯的秒闪。
(4)自主完成发挥功能。
(5)撰写设计报告。
功能说明:
本设计利用F28335DSP芯片来控制模拟基本的LED闪烁,给予系统额定电压来保证系统的正常工作,用中断的方式定时控制LED灯的集体闪烁频率。
设
计
步
骤
设
计
步
骤
设
计
步
骤
设
计
步
骤
设
计
步
骤
步骤一:DSP最小系统分析
1.DSP最小系统
能够用于基本的数字信号处理,运行一些简单的程序。此部分主要包括电源电路、复位电路、时钟电路等。
2.晶振电路
DSP的时钟可以有两种连接方式,即外部振荡器方式和谐振器方式。如果使用内部振荡器,则必须在X1/XCLKIN和X2两个引脚之间连接一个石英晶体。如果采用外部时钟,可将输入时钟信号直接连到X1/CI。KIN引脚上,X2悬空。本设计采用外部晶振,直接选择一个3.3V供电的30MHz晶振实现。系统工作是通过编程选择5倍频的PLL功能,可实现最高工作频率(150MHz)。如图1所示:
图1 晶振电路图
3.复位电路
对于实际的DSP应用系统,特别是产品化的DSP系统,其可靠性是一个不容忽视的问题。由于DSP系统的时钟频率较高,在运行时极有可能发生干扰和被干扰的现象,严重的系统问题可能出现死机现象。为了克服这些情况,除了在软件上做一些保护措施外硬件上必须做相应的处理。硬件上最有效的保护措施是采用具有看门狗(Watchdog)功能的自动复位电路相结合的方式。
TMS320F28335的复位输入引脚XRS为处理器提供了一种硬件初始化的方法,它是一种不可屏蔽的外中断,可在任何时候对TMS320F28335进行复位。本设计采用了简单的RC复位电路,复位电路如图所示2:
图2 复位电路图
4.电源电路
F28335DSP采用了双电源供电机制,以获得更好的电源性能,其工作电压为3.3V和1.8V。其中,1.8V主要为该器件的内部逻辑提供电压,包括CPU和其他所有的外设逻辑。与3.3V供电相比,1.8V供电大大降低功耗。外部接口引脚仍然采用3.3V电压,便于直接与外部低压器件接口,而无需额外的电平变换电路。在本设计里我用TI公司的TPS7301单输出可调电压调节器作为主器件的电源电路,将5V转换为3.3V和1.9V供给DSP,使系统正常工作。电源电路如图3所示:
图3 电源电路图
步骤二:本次设计硬件电路分析
1.定时器中断的实现
为了实现定时器的精确走时功能,系统利用定时器0、PIE模块和CPU中断共同作用产生定时器中断。首先为定时器0设置定时初值,并开启定时器使其计数。当定时器计数器寄存器递减到零时,定时器会产生一个中断TINT并将其传送给PIE外设中断模块,当PIE中的中断时能位PIEIER被时能后,PIE会将这个中断传送给CPU,如果CPU的中断使能位和INTM被使能,则CPU会相应定时器0中断,转而执行定时器0的中断服务子程序。
2.LED显示电路
在定时结束后LED要不停地闪亮,提醒用户定时结束。在本次设计中,将一个发光二极管的输入段与电源相连接,输出与DSP芯片的GPIO4端口相连接,当GPIO端口为低电平时,LED点亮。
步骤三:CMD文件介绍
.text段:存放C程序代码;
.cinit:存放C程序中的变量初值和常量;
.stack:为C程序系统堆栈保留存储空间、用于保存返回地址、函数间的参数传递、存储局部变量和保存中间结果;
.bss:为C程序中的全局和静态变量保留存储空间;
.const:存放C程序中的字符常量、浮点常量和用.const声明的常量;
.sysmem:用于C程序中的malloc、calloc和realloc函数动态分配存储空间;
.far:为C程序中用far声明的全局和静态变量保留空间。
MEMORY用于定义目标存储器的映射,描述了目标系统可以使用的物理存储地址范围及其类型。
PAGE 0 为程序存储空间,起始地址为0x000000包含BEGIN 、BOOT_RSVD、RAMM0 、RAML0、RAML1、ZONE7A 存储区。
PAGE 1为数据存储空间,起始地址为0x000400包含了RAMM1、RAML4、RAML5、RAML6、RAML7、ZONE7B存储区。
SECTIONS用于指示连接器怎样组合输入端,以及如何将输出段定位到存储器中,用于将COFF目标文件中的各个段定位置MEMORY伪指令定义的存储区域。
步骤四:流程图及软件设计
1.系统时钟的详细配置如下
PLLSTS[OSCOFF]=0;
PLLSTS[PLLOFF]=0;
PLLCR[DIV]=1010;
PLLSTS[DIVSEL]=2;
PLLKCR0的ADCENCLK=0。
2.PLL模块的寄存器
锁相环模块的寄存器包括锁相环控制寄存器PLLCR和锁相环状态寄存器PLLSTS,以及外部时钟输出控制寄存器XINTCNF2。其中XINTCNF2用于配置XCLKOUT与SYSCLKOUT的关系。PLLCR和PLLSTS用于振荡器和锁相环模块的配置,以产生CPU时钟输入CLKIN,其位分布如下:
15 40
PLLCR
R-0 R/W-0
15 98
PLLSTS
R-0 R/W-0
7 6 5 4 3 2 1 0
R/W-0 R/W-0 R/W-0 R/W-0R-0R/W-0 R-0 R/W-0
OSCOFF和PLLSTS分别用于振荡器时钟和锁相环时钟的允许;PLLOCKS为锁相环锁定状态标志;MCLKOFF、MCLKCLR、和MCLKSTS用于输入时钟失效检测。
3.流程图
图4 程序流程图
步骤五:系统调试及设计结果分析
按下电源按钮,写入程序,刚开始,4个LED灯全灭,等待一秒钟,4个LED等全亮,如此循环.测试结果成功完课程题目的。效果图如图5所示:
图5 效果图
设
计
小
结
通过这次DSP课程设计,我觉得学到了很多东西。它让我懂得了什么是课程设计,为我们以后的毕业设计打下了一些基础。更重要的是通过这次课程设计,我多少清楚了在以后的工作中我们这个专业能做些什么,也为我们以后的工作积累了一些经验,很有意义。
在本次课程设计过程中出现了一些不该出现的失误。一是不会使用CCS软件,在同学的帮助下使用并编写程序。其二是不能DSP程序烧入试验箱的问题,但是在老师的指导下成功将程序烧入试验箱;之后又遇到DSP程序烧入试验箱后试验箱无反应,同样在老师的帮助下完成实验,并在试验箱上得到想要的实验结果。
通过这次课程报告,使我更深入的掌握了DSP的许多知识,学会了如何让配置寄存器、系统时钟,如何设计电源等等很多知识,不仅复习了以前所学过的知识,而且还接触并学到了很多书本上没有的知识。使我解决问题时更加冷静和熟练,遇到不会知识的积极查阅相关资料,并做好笔记。经过仔细调查确定问题的原因和解决问题的能力有了很大提高。
最后,感谢刘老师的帮忙以及同学之间的相互帮助,使我能顺利完成这次课程设计。
评
分
标
准
(一)系统设计部分(50分,分三档,达不到最低档的小组需重新设计上交)
1.完成规定的全部功能,硬件电路设计正确,程序简洁、可读性、逻辑性强,较好的演示了全部功能。(50分)
2.完成规定的全部功能,硬件电路设计正确,程序较简洁、可读性、逻辑性较强,基本演示了全部功能。(45分)
3.完成规定的部分功能,硬件电路设计无明显错误,程序设计无明显错误,能够完成部分功能的演示。(40分)
(二)设计报告撰写情况(45分)
1.态度认真,报告内容充实、撰写规范。(20分)
2.对所做设计进行了详细的介绍,语言组织精炼,测试数据记录准确。(25分)
(三)发挥部分(5分)
在完成规定功能的基础上,有创新性功能设计个人,获得此项成绩。
总分
任课教师签字
审核人签字
附录:
附录A:实物图
图A
图B
附录B:CMD文件
MEMORY
{
PAGE 0 :
BEGIN : origin = 0x000000, length = 0x000002
BOOT_RSVD : origin = 0x000002, length = 0x00004E
RAMM0 : origin = 0x000050, length = 0x0003B0
RAML0 : origin = 0x008000, length = 0x001000
RAML1 : origin = 0x009000, length = 0x002000
ZONE7A: origin = 0x200000, length = 0x00FC00
CSM_RSVD : origin = 0x33FF80, length = 0x000076
CSM_PWL : origin = 0x33FFF8, length = 0x000008
ADC_CAL : origin = 0x380080, length = 0x000009
RESET : origin = 0x3FFFC0, length = 0x000002
IQTABLES : origin = 0x3FE000, length = 0x000b50
IQTABLES2 : origin = 0x3FEB50, length = 0x00008c
FPUTABLES : origin = 0x3FEBDC, length = 0x0006A0
BOOTROM : origin = 0x3FF27C, length = 0x000D44
PAGE 1 :
RAMM1 : origin = 0x000400, length = 0x000400
RAML4 : origin = 0x00B000, length = 0x002000
RAML5 : origin = 0x00D000, length = 0x001000
RAML6 : origin = 0x00E000, length = 0x001000
RAML7 : origin = 0x00F000, length = 0x001000
ZONE7B: origin = 0x20FC00, length = 0x00040
}
SECTIONS
{
codestart: >BEGIN, PAGE = 0
ramfuncs : >RAML0, PAGE = 0
.text: >RAML1, PAGE = 0
.cinit : >RAML0, PAGE = 0
.pinit : >RAML0, PAGE = 0
.switch : >RAML0, PAGE = 0
.stack : >RAMM1, PAGE = 1
.ebss: >RAML4, PAGE = 1
.econst : >RAML5, PAGE = 1
.esysmem : >RAMM1, PAGE = 1
IQmath : >RAML1, PAGE = 0
IQmathTables : >IQTABLES, PAGE = 0, TYPE = NOLOAD
IQmathTables2: >IQTABLES2, PAGE = 0, TYPE = NOLOAD
FPUmathTables: >FPUTABLES, PAGE = 0, TYPE = NOLOAD
DMARAML4 : >RAML4, PAGE = 1
DMARAML5 : >RAML5, PAGE = 1
DMARAML6 : >RAML6, PAGE = 1
DMARAML7 : >RAML7, PAGE = 1
ZONE7DATA: >ZONE7B,PAGE = 1
.reset : >RESET, PAGE = 0, TYPE = DSECT
csm_rsvd : >CSM_RSVD PAGE = 0, TYPE = DSECT
csmpasswds : >CSM_PWLPAGE = 0, TYPE = DSECT
.adc_cal: load = ADC_CAL, PAGE = 0, TYPE= NOLOAD
}
附录C:源程序
#include"DSP2833x_Device.h"
#include"DSP2833x_Examples.h"
interrupt void zz(void)
#define LED (*(unsignedshort int *)0x180000)
#define SRAM_Base_Adress 0x100000
void main(void)
{
InitSysCtrl()
InitXintf16Gpio()
DINT
InitPieCtrl()
InitPieVectTable()
EALLOW
IER = 0x0000
IFR = 0x0000
PieVectTable.TINT0=&zz
EDIS
InitCpuTimers()
ConfigCpuTimer(&CpuTimer0,150,1000000)
CpuTimer0Regs.TCR.all=0x4001
IER |=M_INT1
PieCtrlRegs.PIEIER1.bit.INTx7=1
EINT
ERTM
LED=0xff
for() }
interrupt void zz(void)
{LED=~LED
PieCtrlRegs.PIEACK.all=PIEACK_GROUP1
}
这几句是将FLASH中的程序COPY到RAM中运行,通常的目的是加快程序的运行速度,通常有两种情况需要这样去 *** 作:1、程序中对基要求比较高的函数,如中断;
2、程序需要对FLASH进行 *** 作,这时就要把程序先复制到RAM中运行然后才能对FLASH *** 作。
RamfuncsLoadStart、RamfuncsLoadEnd、RamfuncsRunStart这三个变量是在CMD文件中创建的,创建方式如下:
LOAD_START(RamfuncsLoadStart),
LOAD_END(RamfuncsLoadEnd),
RUN_START(RamfuncsRunStart),
分别表示了装载函数的首地址,装载函数的结束地址和装载函数的运行地址;
执行完MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart)后,便将FLASH中相关的程序COPY到了RAM中,之后的程序运行时,只要调用FLASH中RamfuncsLoadStart地址开始的相关函数,系统都会自动地指向RAM中相应的函数入口地址运行。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)