TMS320F28x入门
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录
1.DSP学习步骤 (2)
2.搞明白几个问题 (2)
S6 创建新工程 (3)
A.教程一 (3)
B.教程二 (7)
C.仿真环境构建 (13)
4.TMS320F28x寄存器配置总结 (15)
基本开局初始化 (15)
1.时钟与系统控制 (16)
2.中断控制PIE (21)
3.GPIO (24)
4.ADC (27)
5.增强型脉宽调制器ePWM (29)
6.HRPWM (32)
7.SCI (36)
8.SPI (40)
9.CAN (42)
10.CMD文件 (49)
5.TMS320F28035 DEMO板实验 (51)
1.GPIO 实验 (51)
2.定时器中断实验 (52)
3.PWM占空比调节 (53)
4.ADC实验 (54)
5.SPI实验 (56)
6.SCI实验 (58)
6.经验&教训 (63)
读前须知:
本人在此之前完全没接触过DSP,这是我学习过程中所做的笔
记,直到最后能做些各个模块的一些简单配置实现简单的功能。
希望能给新手一些帮助,与君共勉!
1.DSP学习步骤
1.大体上看一遍书,把大体的知识了解一下。
在学习DSP之前,我觉得应该需要去明白DSP能干什
么,所以你一定要看看DATASHEET,看看DSP的外设和资源,看看你能做啥。
2.就是看例子了,例子是关键,例子里有你学的所有的东西,不建议大家直接拿例程来做试验,因
为那样你MCU的结构没有把握,你把例程跑得再好,那也不是你的东西,一定要自己写,例程只能作为参照,一定要一个字母一个字母地去写程序。
看例程,在自己编写自己需要功能的代码时要看看已有的例程,看看例程里的各种寄存器是怎么配置的,配置时又是怎么实现的,根据看懂的编写自己想要的,然后跑跑自己的程序看和已有的例程有什么异同,是不是自己想要的。
当然,调试环节是最难的一个环节,这个过程中会出现很多意想不到的问题,只能慢慢摸索慢慢前进了.
3.这次你再拿出一本书来看,这次是有针对性的看,比如你做的spi的,你就直接看spi那张,一
边看例子一边看书,这样你就可以把一些重要的寄存器给记住了。
4.把存储器映射结构搞清楚——-—说的具体点就是dsp内到底有那些存储器
5.(ram,rom,flash,etc),这些存储器到底是如何分配的,这个可以参考相关的。
cmd文件的写
法,它定义了存储器映射和输入输出段的位置
6.编译器的堆栈操作,就是中断或是子程序调用时,系统自己的堆栈操作。
7.2407有一个8级硬件堆栈,而2812没有,这个区别比较大,所以在编一边针对堆栈操作的程序
(eg. rtos)时就要特别注意了。
8.中断系统—--—每个mcu的中断系统搞清楚了,会给编程带来很大的便利,所以一定要对所用的
mcu的中断过程了解的清清楚楚。
9.开发环境建立完了要熟悉开发流程,就是说你有一个Idea,怎么把这个 Idea在目标板上实现,
先做什么后做什么,这个一定要想清楚。
开发板,仿真器是必要的,它能带给我们更加直观的感受,有空去TI官网转转,里面东西还是挺多的.另外一个好的程序模板也是很关键的,TI官网上有很多例程,结构严谨并且最大的发挥了CCS的功能,建议先搞懂后再依据此创建自己的模板程序.还有就是芯片的DATASHEET。
得对C熟悉,但会C语言并不能说明你会编程,编程有结构设计的问题,C语言只是工具,看不懂的就好好去想,想通了就发现自己又上了一个台阶;数据结构,合适的数据结构会使自己的程序编写变得结构清楚而且“容易"。
写程序要规范,这会简便很多操作,使编译得以优化,比如相关的文件定义要放在相应的头文件里,全局变量等的定义最好GlobalVariableDefs。
c里,相应的中断程序要放在default_ls中.
2.搞明白几个问题
✓什么是DSP芯片,DSP芯片有什么功能和主要特点
✓如何利用这些功能实现自己的目标,对芯片的基本操作和简单程序的运行
✓如何在DSP上完成操作系统的移植
✓如何在DSP上完成算法的移植和优化
S6 创建新工程
A.教程一
1.首先点击 project —>New CCS Project
2.选择器件和创建工程名
3.找到要用的文件 headers 和 common,是安装 controlSUIT(看截图)复制到新建工程的目录
此时 CCS 会自动将新添的文件加到项目浏览器中
4.编译,然后发现好多错误.。
不能打开头文件,因为还没有将头文件添加到工程里面,项目浏览器只是将文件显示出来了已。
5.右键项目浏览器中的项目名,打开属性
6.选择 dir to include 那个框的加号
7.选择 WorkSpace
8.选择 common 和 headers 的 include,然后 OK,OK,编译,然后更多的错误。
..。
,不过错
误的类型变了,这些错误和内存分配有关,和内存有关的就是 cmd 文件了
9.删除 common 下 cmd 里的所有文件
10.编译,然后还是很多错误,不过一看发现错误和文件重定义有关
看看是哪个文件重定义了11.删除这两个文件,编译
其中可能会碰到一个关于 DSP2803x_Headers_nonBIOS。
cmd(无操作系统)和DSP2803x_Headers_BIOS.cmd(有操作系统)的问题,将 DSP2803x_Headers_BIOS。
cmd 删除即可(我们的是无操作系统).
B.教程二
S6 下载地址:http://www。
/tool/ccstudio
2.F2812 的 C 语言头文件
下载地址:http://www。
ti。
com/lit/zip/sprc097
安装后的文件结构样式如下:
3.新建空的工程
1)点击"Project"—〉”New CCS Project"
2)在 New CCS Project 窗口,按需填写以下内容后按”Finish”完成新建空的工程
新建完成后的工程,结构如下:
点击左上方的编译按钮,应该能够顺利的编译通过,但是会出现一个警告.
4.工程配置-添加系统的头文件
1)在工程名上右击,添加两个文件夹,分别名为 source 和 include。
2)打开"tidcs\c28\DSP281x\v120"文件夹,将"DSP281x_headers\include”中的
所有头文件复制到刚刚新建的 include 目录。
3)打开"tidcs\c28\DSP281x\v120”文件夹,将”DSP281x_common\include"中的
所有头文件复制到刚刚新建的 include 目录(会提示文件已存在,覆盖即可).
此时,工程文件夹的结构如图所示:
4)配置工程
右击工程文件名,选择”Properties"
更改 include 的选项
在新弹出的窗口中选择”Workspace”:
然后选择对应工程的"include”目录:
更改链接选项中的”Base option”:
将 Stack 中填充合适的数值,默认为空(也就是上文中编译的时候出现的警告):完成以上的设置后,编译应该没有任何的错误和警告:
5)额外的设置—-添加 C99 支持:
6)可板上执行的工程配置
根据上文的配置过程,虽然代码能够正常的通过编译,但是却没有任何的实际功能。
这里,以点亮运行灯(即主循环执行过程中,固定间隔点亮的灯)为例,介绍可用的代
码的配置过程。
5.添加必须的头文件代码
在main函数中,添加以下的头文件:
#include "DSP281x_Device。
h"
#include ”DSP281x_Examples。
h”
其中,DSP281x_Device.h 提供了对应的 CPU 寄存器的结构体信息,DSP281x_Examples。
h 主要提供了一个纳秒级的延时函数DELAY_US(A).不过,为了使用此函数,还需要将一个汇编代码文件添加到工程中:
在项目文件名称上右击,选择”Add Files”,打开的窗口中选择
"DSP281x_common\source"文件夹中的”DSP281x_usDelay.asm”.然后手动将 asm 文件拖动到 source目录下。
此时,项目文件夹的组织结构如图,添加必要的源文件:
●添加"DSP281x_headers\source"目录下的"DSP281x_GlobalVariableDefs.c”以指定所有系统结构
体的存储位置。
●添加"DSP281x_common\source"目录下的"DSP281x_SysCtrl.c"以初始化系统的控制选项,包括 PLL,
看门狗,预分频。
●添加"DSP281x_common\source”目录下的"DSP281x_Gpio。
c"以初始化系统的 GPIO 口。
●添加”DSP281x_common\source"目录下的”DSP281x_PieCtrl.c 以初始化 PIE 控制器。
●添加”DSP281x_common\source”目录下的 "DSP281x_PieVect。
c”以初始化 PIE 向量表。
●添加”DSP281x_common\source"目录下的”DSP281x_InitPeripherals。
c”以初始化其他外设。
●添加"DSP281x_common\source"目录下的"DSP281x_DefaultIsr.c”以使用默认的中断函数。
1.添加 cmd 文件
本程序非 TI的 BIOS系统应用,所以需要添加”DSP281x_headers\cmd"目录下的
"DSP281x_Headers_nonBIOS.cmd"。
到此,可以尝试编译工程,应该能够正常的编译通过,且没有任何的警告.目录结构应该如下所示(分别是头文件,源文件和链接文件):
6.第一个可执行程序——点亮 LED 灯
✧编辑 main 函数,将 main 函数修改成如下的内容:
#include ”DSP281x_Device。
h” // 添加必要的头文件
#include ”DSP281x_Examples。
h" // 添加必要的头文件
int main(void)
{
InitSysCtrl();
InitGpio();
DINT;
InitPieCtrl();
IER =0x0000;
IFR =0x0000;
InitPieVectTable();
EINT;
ERTM;
for(;;)
}
main 函数虽然是 int 类型的,但是这里不需要结尾的”return 0;”,否则在编译时会提示一个警告。
编辑”DSP281x_Gpio.c",修改 InitGpio()函数:
void InitGpio(void)
{
EALLOW;// GpioMuxRegs 受到保护,需要EALLOW后才能配置
GpioMuxRegs。
GPAMUX。
bit。
T1PWM_GPIOA6 =0;// 设置为GPIO口
GpioMuxRegs.GPADIR.bit。
GPIOA6 =1;// 配置为输出引脚
EDIS;
}
C.仿真环境构建
在安装完成CCS6。
0和官方学习套件CONTROL SUITE后,并且可以顺利通过编译,这时需要连接上仿真器进一步学习寄存器,在仿真中不断学习基本的操作内容
●购买TL-XDS100V3 / V2 /V1
●由于CCS5 以上的版本都内置了这款驱动,故仅需在创建工程时选择正确的仿真器,并添加
gel文件,如图
●编译成功后点击debug,也就是那个小昆虫,进去后和其他单片机仿真程序类似,如若失败,
请仔细检查端口引脚定义和环境配置
●CCS内置串口助手,可通过其对串口进行监测,以便学习
●CCS可通过仿真查看内部寄存器变量,前提是要知道该变量的地址,可通过在程序中右键选
中变量add watch expression ,
即可在expression中查看相应变量的值得变化
可通过在Tools –》graph—》single time 对一变量查看波形,要设置好对应的Buffer size 和DSP DATA TYPE 。
采样速率选择100Hz 填对地址。
如图设置好即可观察
4.TMS320F28x寄存器配置总结
基本开局初始化
InitSysCtrl();//系统时钟设置
DINT; //禁止所有中断
InitPieCtrl(); //初始化中断向量控制寄存器
IER = 0x0000; //关闭CPU中断
IFR = 0x0000; //清除所有中断标志位
InitPieVectTable();//初始化中断向量表
下面的寄存器受到EALLOW保护:
◆器件仿真寄存器
◆Flash寄存器
◆CSM寄存器
◆PIE向量表
◆系统控制寄存器
◆GPIO MUX寄存器
1.时钟与系统控制
2803x系列DSP有两个内部时钟源(INTOSC1和INTOSC2),可以不需要外部时钟。
同时,也具有PLL时钟模块。
一共有4种时钟源可供选择:
1) INTOSC1(10MHz)
内部时钟源1(INTOSC1),此时钟提供给看门狗块模块,内核和CPU定时器2 。
时钟频率默认为10MHz,可以通过INTOSCnTRIM寄存器修改频率。
2) INTOSC2(10MHz)
功能与INTOSC1是一样的。
3)外部晶体振荡器IntOsc0Sel
使用外部晶体振荡器给芯片提供时钟,晶振连接于X1/X2 脚。
4)外部时钟源
如果不使用外部晶振作为时钟源,可以选择这种模式.时钟从外部时钟源的XCLKIN引脚输入生成.
注意:XCLKIN复用于GPIO19或GPIO38脚。
可以通过XCLK寄存器的XCLKINSEL位选择是GPIO19还是GPIO38作为XCLKIN输入。
CLKCTL(XCLKINOFF)为0时,不使能此
时钟。
如果时钟源不使用或作为GPIO引脚时,用户应该在启动引导时禁用。
A.系统时钟的初始化
在main函数的最初位置初始化DSP,即调用void InitialDSP(void)函数.
void InitSysCtrl(void)
{
EALLOW;
SysCtrlRegs.WDCR= 0x0068; //关看门狗
EDIS;
EALLOW;
SysCtrlRegs。
PCLKCR0。
bit。
ADCENCLK = 1;// 关ADC时钟
(*Device_cal)();
//用于校准内部振荡器和AD C,这个函数在boot ROM的时候,芯片会自动调用。
SysCtrlRegs.PCLKCR0.bit。
ADCENCLK = 0; // 启动ADC时钟
EDIS;
Xtal1scSel ();
//选择内部晶振XTALOSC1作为系统时钟源, 且关闭所有未使用的时钟以节省电源。
InitPll(12,1); //[60 MHz = (10MHz * 12)/2]
InitPeripheralClocks(); //初始化外设时钟
}
void InitPeripheralClocks(void)
{
EALLOW;
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3;// GPIO18 = XCLKOUT
SysCtrlRegs。
LOSPCP。
all = 0x0002; //低速外设时钟(LSPCLK)速率/4
SysCtrlRegs。
XCLK.bit.XCLKOUTDIV=2; // Set XCLKOUT = SYSCLKOUT/1
SysCtrlRegs。
PCLKCR0。
bit.ADCENCLK = 1;// ADC
P1ENCLK = 1;// COMP1
SysCtrlRegs。
PCLKCR3。
P2ENCLK = 1;// COMP2
SysCtrlRegs.PCLKCR3。
bit。
CPUTIMER0ENCLK = 1;// CPU Timer—0
SysCtrlRegs。
PCLKCR3.bit。
CPUTIMER1ENCLK = 1;// CPU Timer—1
SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK = 1; // CPU Timer—2
SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1; // eCAP1
SysCtrlRegs。
PCLKCR1.bit。
EPWM1ENCLK = 1;// EPWM1
SysCtrlRegs.PCLKCR1.bit。
EPWM2ENCLK = 1;// EPWM2
SysCtrlRegs.PCLKCR1。
bit。
EPWM3ENCLK = 1;// EPWM3
SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 1;// EPWM4
SysCtrlRegs.PCLKCR3。
bit。
GPIOINENCLK = 1;// GPIO
SysCtrlRegs.PCLKCR0。
bit。
HRPWMENCLK=1; // HRPWM
SysCtrlRegs。
PCLKCR0.bit。
I2CAENCLK = 1;// I2C
SysCtrlRegs.PCLKCR0。
bit。
SCIAENCLK = 1;// SCI-A
SysCtrlRegs.PCLKCR0.bit。
SPIAENCLK = 1;// SPI-A
SysCtrlRegs.PCLKCR0。
bit。
TBCLKSYNC = 1; // Enable TBCLK within the EPWM
EDIS;
}
B.Cpu定时器设置
定时器定时时间的公式计算
以上寄存器测值在配置函数ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)中设置.形参Timer为第几位定时器,Freq为定时频率,Period为计时周期。
假若Freq为15,Period为1000000,则时间t = 1*15*1000000/150M = 0.1s (系统时钟频率为150M)。
不过这个算式的成立是有条件的,这个条件就是以下两条语句:
Timer-〉RegsAddr-〉TPR.all = 0
Timer->RegsAddr->TPRH.all = 0
上文曾提及,定时器的计数时钟是有预分频寄存器TPRH:TPR决定的。
CpuTimerxRegs.TPR.all = 0,CpuTimerxRegs。
TPRH.all = 0这两句话决定了1个时钟源周期为定时器的时钟周期(即一个SYSCLKOUT,TIMH:TIM减1),若CpuTimerxRegs.TPR。
all = y,CpuTimerxRegs.TPRH.all = 0,则计y+1个时钟周期为定时器的时钟周期.X 表示0,1,2中的任意值(任意定时器)。
因此,真正的定时时间为:
time =TPRH:TPR/SYSCLKOUT*Freq*Peroid。
例如: ConfigCpuTimer(&CpuTimer0, 59, 100 00000);假设系统时钟为60M
定时时间为:60*1M/60M=1s
只有当TPRH:TPR=0时,SYSCLKOUT直接作为TIMH:TIM的时钟周期,
time =Freq*Peroid/SYSCLKOUT。
另外,在定时器配置函数中,
Timer-〉RegsAddr-〉TCR。
bit。
TSS = 1表示停止定时器;
Timer—〉RegsAddr-〉TCR.bit.TRB = 1 表示重装定时器;
Timer—>RegsAddr—〉TCR。
bit。
FREE = 1 表示定时器自由运行;
Timer->RegsAddr->TCR。
bit。
TIE = 1 表示使能定时器中断。
如果要利用定时器产生一定周期的时间中断,别忘了在主函数中设置响应的中断向量。
启动定时器开始运行
o15 TIF定时器中断标志位,进入中断为0,写1清除掉
o14 TIE定时器中断使能位,0禁止定时器中断,1使能
o13~12,9~6 ,0~3 保留-
o11~10 FREE SOFT仿真控制器
o 5 TRB定时器重新装载位,始终未0,写1重新装载PEDH:PRD
o 4 TSS定时器起停控制位0,正在运行,通过向此位写1,停止定时器CpuTimer0Regs。
TCR。
all = 0x4001; //0100 0000 0000 0001设置TSS位为0位
Timer->RegsAddr—〉TCR。
bit。
TSS = 0//表示开始定时器
void InitCpuTimers(void) /***定时器中断设置******/
{
CpuTimer0。
RegsAddr = &CpuTimer0Regs;
CpuTimer0Regs。
PRD。
all = 0xFFFFFFFF;// 将定时器初始化为最大值
// Initialize pre—scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs。
TPR。
all = 0;
CpuTimer0Regs.TPRH.all = 0;
CpuTimer0Regs.TCR。
bit.TSS = 1;// 确保定时器已经停止
CpuTimer0Regs。
TCR.bit.TRB = 1;//重新装在定时器定是周期
CpuTimer0.InterruptCount = 0; //重设中断次数计数器
CpuTimer1.RegsAddr = &CpuTimer1Regs;
CpuTimer2。
RegsAddr = &CpuTimer2Regs;
// Initialize timer period to maximum:
CpuTimer1Regs.PRD。
all = 0xFFFFFFFF;
CpuTimer2Regs。
PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer1Regs.TPR.all = 0;
CpuTimer1Regs。
TPRH。
all = 0;
CpuTimer2Regs.TPR.all = 0;
CpuTimer2Regs。
TPRH.all = 0;
// Make sure timers are stopped:
CpuTimer1Regs.TCR。
bit.TSS = 1;
CpuTimer2Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer1Regs.TCR.bit。
TRB = 1;
CpuTimer2Regs.TCR.bit。
TRB = 1;
// Reset interrupt counters:
CpuTimer1.InterruptCount = 0;
CpuTimer2.InterruptCount = 0;
}
void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period) {
Uint32t emp;
// Initialize timer period:
Timer—>CPUFreqInMHz = Freq;
Timer-〉PeriodInUSec = Period;
temp = (long)(Freq * Period);
Timer-〉RegsAddr->PRD。
all = temp;
// Set pre-scale counter to divide by 1 (SYSCLKOUT):
Timer—>RegsAddr—〉TPR。
all = 0;
Timer->RegsAddr—>TPRH。
all = 0;
// 重设定时器中断控制寄存器
Timer->RegsAddr-〉TCR.bit。
TSS = 1; // 1 = 停定时器, 0 = 开始定时器
Timer—〉RegsAddr->TCR.bit。
TRB = 1;// 1 = 定时器重新装值
Timer->RegsAddr—>TCR。
bit.SOFT = 0;
Timer->RegsAddr->TCR。
bit.FREE = 0; // Timer Free Run Disabled
Timer—〉RegsAddr->TCR.bit。
TIE = 1;// 0 关闭定时器中断 1 打开 Timer-〉RegsAddr—〉TCR。
bit。
TSS = 0; // 0 = 开始定时器
Timer->InterruptCount = 0;// 重设定时器中断次数
}
C.Cpu定时器中断设置
PieVectTable。
TINT0 = &cpu_timer0_isr;//将定时器0的中断服务子函数地址存放到相应的向量地址中,这个函数存在于DSP2802x_DefaultIsr。
c 。
故可以写成
PieVectTable.TINT0=&TINT0_ISR;
在DSP2802x_DefaultIsr.c里边对应填写中断服务函数
关于定时器1和2一定要看懂上边的图,1和2都是直接连哎cpu上未通过PIE,故在使能中断和中断函数中会略有不同
●中断使能
IER |= M_INT1;
IER |= M_INT13;
IER |= M_INT14;
/*PIE级:使能PIE组1中与Timer0对应的中断使能位TINT0,而Timer1和Timer2未经
过PIE模块,直接连到CPU上,由CPU直接应答,无须经过PIE
PieCtrlRegs。
PIEIER1.bit。
INTx7 = 1;//TINT0为PIE组1的第7位
EINT;// 使能全局中断INTM
ERTM; // 使能全局实时中断DBGM
for(;;); //等待中断
一旦中断请求信号送到CPU级,与INTx对应的CPU终端标志寄存器IFR中的相应位将置1,
如果中断使能寄存器IER中的相应位为1,则使全局使能位INTM=0或DBGIER=1(与使用的中
断进程有关)。
CPU相应中断请求:
✓首先自动将IERx、IFRx、EALLOW清0,将INTM置1。
✓从PIE中断向量列表中读取中断服务函数地址,转入中断服务地址开始执行
✓执行完返回
interrupt void cpu_timer0_isr(void)0
{
CpuTimer0.InterruptCount++;
//记录中断次数,中断已经应答,可以从组1中接收更多的中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
2.中断控制PIE
在清除PIEIFR和PIEIER寄存器中的位时应该遵守3个主要规则:
规则1:切勿通过软件来清除PIEIFR的位
当一个写或读—修改-写PIEIFR寄存器操作发生时,引入的中断可能被丢失.要清除一个PIEIFR位,必须服务挂起中断(pending interrupt).如果你想清除PIEIFR位但不执行正常的服务程序,请执行下列操作:
1.置位EALLOW位来允许修改PIE向量表.
2.修改PIE向量表,使外设服务程序的向量指向一个临时的ISR。
这个临时的ISR将只执行
中断返回操作(IRET)。
3.使能中断,让临时ISR服务中断。
4.在临时中断程序执行完后,PIEIFR位将被清除.
5.修改PIE向量表,将外设的服务程序重新映射到合适的服务程序.
6.清除EALLOW位。
规则2:软件划分中断优先级的方法
使用C2833x C/C++头文件和外设示例(文档编号SPRC530)中介绍的方法来操作。
a)使用CPU IER寄存器作为全局优先级,单个PIEIER寄存器作为组优先级。
这时,PIEIER
寄存器只能在一个中断中被修改。
另外,只能修改正在服务的中断所在组的PIEIER。
这个修改在PIEACK位保持其它中断从CPU返回时执行.
b)切勿在服务一个其它组的中断时禁能该组的PIEIER位。
规则3:使用PIEIER禁能中断
如果PIEIER寄存器的位需要在这个上下文环境之外被清除。
应该使用下面2种方法中的一种.第一种方法保存相关的PIE标志寄存器,以便中断不丢失。
第二种方法清除相关的PIE标志寄存器.
方法1:使用PIEIERx寄存器来禁能中断和保存相关的PIEIFRx标志。
为了在保存PIEIFRx寄存器中相关标志的同时清除PIEIERx寄存器中的位,应该执行下列操作:
1。
禁能全局中断(INTM = 1)。
2。
清除PIEIERx.y位来禁能一个给定外设的中断。
可以为同一个组内的一个或多个外设执行该操作。
3. 等待5个周期。
需要这个延时来确保进入CPU的所有中断都在CPU IFR寄存器中标识出来.
4. 清除外设组的CPU IFRx位。
这是一个安全的CPU IFR寄存器操作。
5。
清除外设组的PIEACKx位.
6. 使能全局中断(INTM = 0)。
方法2:使用PIEIERx寄存器来禁能中断和清除相关的PIEIFRx标志.
为了执行一个外设中断的软件复位和清除PIEIFRx寄存器及CPU IFR寄存器中的相关标志,请执行下列操作:
1. 禁能全局中断(INTM = 1)。
2. 置位EALLOW位。
3。
修改PIE向量表,暂时将特定外设中断的向量映射到一个空的中断服务程序(ISR).这个空的ISR只执行中断返回(IRET)。
这是清除单个PIEIFRx。
y位的一种很安全的方法,不会丢失该组内其它外设的任何中断.
4。
在外设寄存器上禁能外设中断.
5。
使能全局中断(INTM = 0).
6. 等待空ISR程序服务所有挂起的外设中断。
7. 禁能全局中断(INTM = 1)。
8. 修改PIE向量表,将外设向量映射回原来的ISR。
9。
清除EALLOW位。
10。
禁能给定外设的PIEIER位。
11。
清除给定外设组的IFR位(这是一个安全的CPU IFR寄存器操作)。
12. 清除PIE组的PIEACK位.
13。
使能全局中断。
图错误!文档中没有指定样式的文字。
错误!未定义书签。
多路复用中断请求流程图
1.PIE组内的任何外设或外部中断产生一个中断。
如果中断在外设模块中被使能,中断请求就被发
送到PIE模块。
2.PIE模块确认PIE组x内的中断(INTx。
y)已经提交一个中断并且相应的PIE中断标志位被锁
存:PIEIFRx。
y = 1。
3.中断请求要从PIE发送到CPU,必须满足条件:
a.相应的使能位必须置位(PIEIERx。
y = 1),并且
b.组的PIEACKx位必须被清除.
4.如果3a和3b的条件都满足,中断请求就被发送到CPU,并且再次置位应答位(PIEACKx = 1)。
PIEACKx位将保持置位,直到你将其清除(表明组的其它中断可以从PIE发送到CPU).
5.置位CPU中断标志位(CPU IFRx = 1),表明CPU级有一个挂起的中断x.
6.如果CPU中断被使能(CPU IER位x = 1,或者DBGIER位x = 1),并且全局中断屏蔽被清除(INTM
= 0),那么CPU将服务INTx。
7.CPU确认中断并执行自动上下文保存,清除IER位,置位INTM以及清除EALLOW。
CPU为
准备服务中断所执行的操作在TMS320C28x DSP CPU和指令集参考指南(文档编号SPRU430)中进行了描述。
8.然后CPU将从PIE中请求合适的向量。
9.对于多路复用的中断,PIE模块使用PIEIERx和PIEIFRx寄存器的当前值来译码应该使用哪个向
量地址。
有两种可能的情形:
a.组内最高优先级中断的向量(该中断在PIEIERx寄存器中被使能,并且在PIEIFRx中标识为
挂起)被提取出来用作跳转地址。
这样,即使在第7步以后有一个更高优先级的已经使能的中
断被标识出来,它也先被服务。
b.如果组内没有标识出来的中断被使能,PIE将用该组内最高优先级中断的向量来响应。
该向
量用作INTx.1的跳转地址。
这个操作对应28x TRAP或INT指令。
注:因为PIEIERx寄存器用来确定哪个向量用作跳转地址,因此在清除PIEIERx寄存器的位时必须十分小心.清除PIEIERx寄存器的位的正确流程如错误!未找到引用源。
节所述。
不遵循该节所描述的步骤可能导致在中断传递到CPU(图错误!文档中没有指定样式的文字。
错误!未定义书签。
中的第5步)后PIEIERx寄存器中出现变化.在这种情况下,PIE的响应就好像执行了一个TRAP或INT指令一样,直到没有其它中断被挂起和使能。
在这里,PIEIFRx.y位被清除,CPU跳转到从PIE中提取出来的中断的向量.
3.GPIO
A.关闭写保护
EALLOW;
B.选择引脚功能
复位时为默认状态
基本的I/O功能外设选择外设选择2 外设选择3 GPAMUX1 (GPAMUX1位=00) (GPAMUX1位=01) (GPAMUX1位=10) (GPAMUX1位=11) 1—0 GPIO0 EPWM1A(O)保留(1)保留(1)
3—2 GPIO1 EPWM1B(O)保留COMP1OUT(O)5—4 GPIO2 EPWM2A(O) 保留保留(1)
7-6 GPIO3 EPWM2B(O) 保留COMP2OUT(O)9—8 GPIO4 EPWM3A(O) 保留保留(1)
11—10 GPIO5 EPWM3B(O) 保留ECAP1(I/O) 13—12 GPIO6 EPWM4A(O)EPWMSYNCI(I)EPWMSYNCO(O)15—14 GPIO7 EPWM4B(O)SCIRXDA(I) 保留
17-16 保留保留保留保留
19-18 保留保留保留保留
21-20 保留保留保留保留
23—22 保留保留保留保留
25—24 GPIO12 TZ1(I) SCITXDA(O) 保留
27—26 保留保留保留保留
29—28 保留保留保留保留
31-30 保留保留保留保留
GPAMUX2 (GPAMUX2位=00)(GPAMUX2位=01) (GPAMUX2位=10) (GPAMUX2位=11)1-0 GPIO16 SPISIMOA(I/O) 保留TZ2(I)
3—2 GPIO17 SPISOMIA(I/O) 保留T Z3(I)
5—4 GPIO18 SPICLKA(I/O) SCITXDA(O)XCLKOUT(O)7—6 GPIO19/XCLKIN SPISTEA(I/O)SCIRXDA(I) ECAP1(I/O)
9-8 保留保留保留保留
GpioCtrlRegs。
GPAMUX1.bit。
GPIO0 = 1; // GPIO0 = PWM1A
例如,通过写GPAMUX[13:12]来控制GPIO6引脚的复用情况。
通过写这两个位,引脚被配置成GPIO6或3种外设功能当中的一个.GPIO6引脚可以配置如下:
GPAMUX1[13:12]位的设置选择的引脚功能
如果GPAMUX1[13:12] = 0,0 引脚配置用作GPIO6
如果GPAMUX1[13:12] = 0,1 引脚配置用作EPWM4A(O)
如果GPAMUX1[13:12] = 1,0 引脚配置用作EPWMSYNCI(I)
如果GPAMUX1[13:12] = 1,1 引脚配置用作EPWMSYNCO(O)
C.使能或禁能内部上拉电阻
位域值描述(1)
31-0 GPIO31-GPIO0
1 配置所选GPIO Port A引脚上的内部上拉电阻。
使能指定引脚上的内部上拉.(GPIO12 –GPIO31的默认状态)禁能指定引脚上的内部上拉。
(GPIO0 – GPIO11的默认状态)
GpioCtrlRegs.GPAPUD。
bit。
GPIO0 = 0;// Enable pullup on GPIO0
D.选择输入鉴定
输入限定功能可以方便地消除噪声中的信号.包含:
●异步输出
●仅与SYSCLKOUT同步
●通过采样窗协定
◆采样周期
◆采样长度
GpioCtrlRegs.GPAQSEL1.bit.GPIO0=0; //与系统时钟同步
默认地,所有输入信号都只与SYSCLKOUT同步。
当信号在3次或6次采样内保持不变时,信号可以通过采样窗口进入DSP内部,采样窗包含的采样周期个数始终比采样次数少1
E.为数字通用I/O选择引脚的方向
如果引脚被配置用作GPIO,在GPADIR、GPBDIR或AIODIR寄存器中指定引脚的方向是输入还是输出。
默认地,所有GPIO引脚都是输入引脚.要将引脚的方向从输入变为输出,首先通过将合适的值写入GPxCLEAR、GPxSET或GPxTOGGLE(或AIOCLEAR、AIOSET或AIOTOGGLE)寄存器把驱动的值装入输出锁存器。
一旦输出锁存器被装载,就可以通过GPxDIR 寄存器来将引脚方向从输入变为输出。
所有引脚的输出锁存器在复位时被清除. GpioDataRegs.GPASET。
bit.GPIO0 = 1; // 产生高电平
GpioCtrlRegs。
GPADIR。
bit。
GPIO0 = 1; // GPIO0 = output
F.选择低功率模式唤醒源
指定哪些引脚(如果存在)能将器件从停机或待机低功率模式唤醒。
在GPIOLPMSEL(不知如何配置)寄存器中指定这些引脚。
G.选择外部中断源
指定XINT1 – XINT3中断的中断源。
你可以指定一个Port A信号作为一个中断的中断源。
中断源在GPIOXINTnSEL寄存器中指定。
中断的极性可以在XINTnCR寄存器中配置注:从写配置寄存器(例如,写GPxMUXn和GPxQSELn)发生到动作有效之间有2个SYSCLKOUT周期的延迟。
void Gpio_Config(void);
{
EALLOW;
GpioCtrlRegs。
GPAMUX1。
bit.GPIO0=0; //设置为数字IO
GpioCtrlRegs。
GPAPUD。
bit。
GPIO0=1;//使能GPIO内部上拉
GpioCtrlRegs。
GPAQSEL1.bit.GPIO0=0;//只与SYSCLKOUT同步,对于外设和GPIO均有效
//GpioCtrlRegs.GPAQSEL1.bit。
GPIO0==3
//(GpioCtrlRegs.GPAQSEL1。
bit。
GPIO0==1 2 //3次采样6次采样
GpioDataRegs。
GPASET.bit.GPIO0=1; //设置为高电平
GpioCtrlRegs。
GPADIR.bit.GPIO0=1 //OUTPUT
GPIOXINT_REG.bit。
GPIOSEL=0x00000;//选择GPIO0作为XINT1/2的输入引脚}
4.ADC
A.ADC上电初始化
ADC的上电顺序如下:
⏹第一步:如果需要外部基准,可通过ADCCTL1寄存器的位3(ADCREFSEL)使能
⏹第二步:通过置位ADCCTL1寄存器中的7—5位(ADCPWDN、ADCBGPWD、ADCREFPWD)将基准、
帶隙和模拟电路一起上电。
通常不支持中间状态
⏹第三步:通过置位ADCCTL1寄存器的位14(ADCENABLE)使能ADC
⏹在执行第一次转换之前,在第二步后面需要1毫秒的延迟
⏹第一步到第三步也可以同时执行.
在ADC掉电时,第二步中的那3个位可以同时清零。
ADC功率电平必须通过软件控制,并且与器件电源模式的状态无关.
注:这种类型的ADC在所有电路上电后需要1ms延迟。
这与之前的那些ADC不同。
void InitAdc(void) //官方例子置位ADCCTL1寄存器中的7—5位
{
extern void DSP28x_usDelay(Uint32 Count);
EALLOW;
SysCtrlRegs。
PCLKCR0。
bit.ADCENCLK = 1; //应该首先设置adcenclk时钟以启用ADC。
(*Device_cal)();
EDIS;
EALLOW;
AdcRegs.ADCCTL1。
bit.ADCBGPWD = 1; // 将带隙电路上电BG
AdcRegs。
ADCCTL1。
bit.ADCREFPWD = 1; //将ADC模拟电路上电
AdcRegs.ADCCTL1.bit。
ADCPWDN = 1;//将基准参考电压上电
AdcRegs。
ADCCTL1。
bit。
ADCENABLE = 1;// Enable ADC
AdcRegs。
ADCCTL1。
bit。
ADCREFSEL = 0;
// ADCREFSEL内部电压选择位,0为使用内部带隙产生参考电压,1为使用外部VREFHI产生参考电压
EDIS;
DELAY_US(ADC_usDELAY); //在ADC转换前必须执行5毫秒的延迟转换须包含DELAY_US.asm文件}
B.初始化AIO
void InitAdcAio()
{
GpioCtrlRegs.AIOMUX1.bit.AIO2 = 2;//Configure AIO2 for A2 (analog input)
}
C.ADC设置
与之前的那些ADC不同,这个ADC不基于序列发生器(sequencer),而是基于SOC.术语SOC是一种配置设置,它定义的是单通道单转换。
该设置包含3个配置:启动转换的触发源、转换通道和采集(采样)窗口尺寸。
每个SOC都可以配置成由许多输入触发器中的其中一个启动.如果需要,几个SOC可以配置成使用同一个通道。
下面就是一些可用的输入触发器:
●软件
●CPU定时器0/1/2中断
●XINT2 SOC
●ePWM1-7 SOCA和SOCB
另外,ADCINT1和ADCINT2可以反馈回来触发另外一次转换。
这种配置由ADCINTSOCSEL1/2寄存器控制。
如果需要连续转换,这种模式将非常有用。
需了解的机制:
✓轮询
✓同步采样,偶数和其后的基数SOC配成一对同时开始采样
✓顺序采样,按照触发顺序进行采样
EALLOW;
AdcRegs.ADCCTL1。
bit。
INTPULSEPOS = 1; //在ADC结果存入寄存器一个周期后
AdcRegs。
INTSEL1N2.bit.INT1E = 1; //使能ADCINT1
AdcRegs。
INTSEL1N2。
bit.INT1CONT = 0;
//0 只有在用户清除ADCINTx标志(在ADCINTFLG寄存器中)之后才能再产生ADCINTx脉冲。
//1 每当产生EOC脉冲时便产生ADCINTx脉冲,与ADCINTx是否被清除无关。
AdcRegs。
INTSEL1N2.bit.INT1SEL = 1; //setup EOC1 to trigger ADCINT1 to fire AdcRegs。
ADCSOC0CTL.bit。
CHSEL = 4; //set SOC0 channel select to ADCINA4
AdcRegs。
ADCSOC1CTL。
bit.CHSEL = 2; //set SOC1 channel select to ADCINA2
AdcRegs。
ADCSOC0CTL.bit.TRIGSEL = 5;
//set SOC0 start trigger on EPWM1A, due to round—robin SOC0 converts first then SOC1 AdcRegs。
ADCSOC1CTL.bit.TRIGSEL = 5;//set SOC1 start trigger on EPWM1A, due to round-robin SOC0 converts first then SOC1
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6;
//set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
AdcRegs.ADCSOC1CTL.bit。
ACQPS = 6;
//set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS plus 1)
EDIS;
D.设置EOC触发信号
EPwm1Regs。
ETSEL。
bit。
SOCAEN = 1; // 在PWM事件触发选择寄存器中使能ADC转换脉冲
EPwm1Regs.ETSEL。
bit。
SOCASEL = 4;//SOCASEL决定何时产生EPWMxSOCA脉冲.增计数CMPA EPwm1Regs.ETPS.bit.SOCAPRD = 1;// Generate pulse on 1st event
EPwm1Regs。
CMPA。
half。
CMPA = 0x0080; // Set compare A value
EPwm1Regs。
TBPRD = 0xFFFF;// Set period for ePWM1
EPwm1Regs.TBCTL.bit。
CTRMODE = 0; // 选择计数方式,增、减、增减
E.开始转换,读取采样结果
interrupt void adc_isr(void)
{
Voltage1[ConversionCount] = AdcResult.ADCRESULT0;
Voltage2[ConversionCount] = AdcResult.ADCRESULT1;
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize for next SOC
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;// Acknowledge interrupt to PIE
return;
}。