技术经验分享:DSP2812程序执行过程

简介: 技术经验分享:DSP2812程序执行过程

开始程序,从main()开始运行


Step1:执行语句InitSysCtrl();


初始化系统控制模块:包括PLL, WatchDog, enable Peripheral Control. 这些模块的初始化在DSP281x_SysCtrl.c文件中。


让我们来看看这个初始化系统函数的内容,看看它具体是怎么实现的。


void InitSysCtrl(void)


{


DisableDog();//禁止看门狗


InitPll(0x8);//设置系统时钟=XCLKIN8/2


InitPeripheralClocks(); //设置外设时钟


DINT; // 关闭总中断


IER = 0x0000; // 关闭外设中断


IFR = 0x0000; // 清中断标志


InitPieCtrl(); //初始化PIE控制寄存器


InitPieVectTable(); //使能PIE向量表


}


这个函数中可以看出:


1、禁止看门狗DisableDog();


来看一下禁止看门狗的步骤(这个内容书上应该很多了,这里想要一根线式的抓住DSP编程的脉络,所以在这里赘述一下)。 先是写看门狗控制寄存器SysCtrlRegs.WDCR= 0x0068(要开EALLOW)


来看一下WDCR写0x0068的含义(建议像我一样的初学者也来边查寄存器手册边学习),WDCR是一个16位的寄存器,其中15-8位是保留的。给它写0x0068将这些位进行了设置:


WDFLAG=0:手册上说这一位是看门狗复位状态标志位。如果该位置位,表示一个看门狗复位(WDRST)产生了复位条件。如果为0,则是一个外部器件加电复位条件。


WDDIS=1:使看门狗模块无效。


WDCHK(位5-3)=101:只能写101,写其它值核立即复位。


WDPS(2-0)=000:配置看门狗计数器的时钟。写000(或001)时WDCLK=OSSCCLK/512/1。


2、接着设置系统时钟InitPll(0x8);


同样来看一下设置系统时钟的步骤(这个函数带一个参数)。


让我把这个函数帖在这里


1 void InitPll(Uint16 val)


2 {


3 volatile Uint16 iVol;


4


5 if (SysCtrlRegs.PLLCR.bit.DIV != val)


6 {


7


8 EALLOW;


9 SysCtrlRegs.PLLCR.bit.DIV = val;


10 EDIS;


11


12 for(iVol= 0; iVol[span style="color: rgba(128, 0, 128, 1)">4096; iVol++);


13 }


14 }


InitPll(0x8)


意思是说将PLLCR写0x8。通过查寄存器表,PLLCR的15-4位是保留的。将3-0位写1000的意思是CLKIN=(OSCCLK8.0)/2。


程序里for(iVol= 0; iVol<4096; iVol++);语句的意思是PLL的设置须要一定的时间,这里写这句来确保PLL顺利启动。


3、设置外设时钟InitPeripheralClocks();首先设置分频时钟


SysCtrlRegs.HISPCP.all = 0x0001;//设置高速时钟 2分频


SysCtrlRegs.LOSPCP.all = 0x0002;//设置低速时钟 4分频


然后设置外设时钟PCLKCR,PCLKCR的15位是保留的,按位定义将EVAENCLK EVBENCLK,SCIAENCLK,SCIBENCLK,MCBSPENCLK,SPIENCLK,ECANENCLK,ADCENCLK位全部置1,表示使能这些外设时钟,这些外设有的用的是高速时钟,有的用的是低速时钟。


4、关闭总中断。


5、关闭外设中断。


6、清中断标志。


7、初始化PIE控制寄存器InitPieCtrl();


void InitPieCtrl(void)


{


DINT; //禁止CPU级中断


PieCtrlRegs.PIECRTL.bit.ENPIE = 0;//屏蔽PIE中断向量表


//清除所有PIEIER寄存器


PieCtrlRegs.PIEIER1.all = 0;


PieCtrlRegs.PIEIER2.all = 0;


PieCtrlRegs.PIEIER3.all = 0;


PieCtrlRegs.PIEIER4.all = 0;


PieCtrlRegs.PIEIER5.all = 0;


PieCtrlRegs.PIEIER6.all = 0;


PieCtrlRegs.PIEIER7.all = 0;


PieCtrlRegs.PIEIER8.all = 0;


PieCtrlRegs.PIEIER9.all = 0;


PieCtrlRegs.PIEIER10.all = 0;


PieCtrlRegs.PIEIER11.all = 0;


PieCtrlRegs.PIEIER12.all = 0;


// 清除所有PIEIFR寄存器


PieCtrlRegs.PIEIFR1.all = 0;


PieCtrlRegs.PIEIFR2.all = 0;


PieCtrlRegs.PIEIFR3.all = 0;


PieCtrlRegs.PIEIFR4.all = 0;


PieCtrlRegs.PIEIFR5.all = 0;


PieCtrlRegs.PIEIFR6.all = 0;


PieCtrlRegs.PIEIFR7.all = 0;


PieCtrlRegs.PIEIFR8.all = 0;


PieCtrlRegs.PIEIFR9.all = 0;


PieCtrlRegs.PIEIFR10.all = 0;


PieCtrlRegs.PIEIFR11.all = 0;


PieCtrlRegs.PIEIFR12.all = 0;


}


ENPIE这PIE中断扩展寄存器里的PIECTRL(中断控制寄存器)里的最后一位,它的意思是从PIE块中取回向量使能。该位置0,PIE无效。


总之,4,5,6,7步貌似就是关闭一切中断(外部中断,CPU中断,PIE中断),清除一切中断标志。这样做的目的应该就是使系统初始化到一种已知的状态。便于我们以后操作。


8、使能PIE向量表InitPieVectTable();


void InitPieVectTable(void)


{


int16 i;


Uint32 Source = (void ) &PieVectTableInit;


Uint32 Dest = (void ) &PieVectTable;


EALLOW;


for(i=0; i < 128; i++)


Dest++ = Source++;


EDIS;


// 使能中断向量表


PieCtrlRegs.PIECRTL.bit.ENPIE = 1;


}


值得注意的是,如果DSP芯片复位,在没有初始化PIE前,换句话说还没有将ENPIE设为1时,使用的是BROM向量。因此,在DSP复位和程序引导完成之后,用户必须对PIE向量表进行初始化,然后由应用程序使能PIE向量表,这样CPU响应中断时,就从PIE中断向量表中所指出的位置上取出中断向量,即取出中断服务子程序的地址。


这就是这两条语句的意思。


Uint32 Source = (void ) &PieVectTableInit;


Uint32 Dest = (void ) &PieVectTable;


中断向量表的地址是2*16位的,也就是32位地址。


----初始化系统模块就是这些内容。


Step2:初始化GPIO。设置GPIO到它的默认状态只须要一条语句(函数)InitGpio();本例跳过这个设置,因为用不到GPIO作为实时I/O口。


而只须要用到它的多功能引脚GPAMUX和GPBMUX作为PWM输出引脚(将GPAMUX和GPBMUX都写0x00FF即可,受EALLOW保护)。


Step3:清除所有中断并初始化PIE向量表。这个过程怎么来来回回两次了,不知道这个函数写的是不是有问题,明天再看。


Step4:执行init_eva(),init_evb()函数,也就是输出PWM波。


void init_eva()


{


// EVA Configure T1PWM, T2PWM, PWM1-PWM6


// Initalize the timers


// Initalize EVA Timer1


EvaRegs.T1PR = 0xFFFF; // Timer1 period


EvaRegs.T1CMPR = 0x3C00; // Timer1 compare


EvaRegs.T1CNT = 0x0000; // Timer1 counter


// TMODE = continuous up/down


// Timer enable


// Timer compare enable


EvaRegs.T1CON.all = 0x1042;


// Initalize EVA Timer2


EvaRegs.T2PR = 0x0FFF; // Timer2 period


EvaRegs.T2CMPR = 0x03C0; // Timer2 compare


EvaRegs.T2CNT = 0x0000; // Timer2 counter


// TMODE = continuous up/down


// Timer enable


// Timer compare enable


EvaRegs.T2CON.all = 0x1042;


// Setup T1PWM and T2PWM


// Drive T1/T2 PWM by compare logic


EvaRegs.GPTCONA.bit.TCMPOE = 1;


// Polarity of GP Timer 1 Compare = Active low


EvaRegs.GPTCONA.bit.T1PIN = 1;


// Polarity of GP Timer 2 Compare = Active high


EvaRegs.GPTCONA.bit.T2PIN = 2;


// Enable compare for PWM1-PWM6


EvaRegs.CMPR1 = 0x0C00;


EvaRegs.CMPR2 = 0x3C00;


EvaRegs.CMPR3 = 0xFC00;


// Compare action control. Action that takes place


// on a cmpare event


// output pin 1 CMPR1 - active high


// output pin 2 CMPR1 - active low


// output pin 3 CMPR2 - active high


// output pin 4 CMPR2 - active low


// output pin 5 CMPR3 - active high


// output pin 6 CMPR3 - active low


EvaRegs.ACTRA.all = 0x0666;


EvaRegs.DBTCONA.all = 0x0000; // Disable deadband


EvaRegs.COMCONA.all = 0xA600;


}


1、T1PR定时器1周期寄存器写初值0xFFFF;T1CMPR定时器1计数的比较值设有0x03C0;T1CNT定时器1当前计数值设为0x0000;这三步称为初始化EVA Timer1。


2、通用定时器1控制寄存器T1CON=0//代码效果参考:http://www.jhylw.com.cn/300429349.html

x1042:将TMODE1、T2SWT1、TECMPR这三位置为1。

其中TMODE1~TMODE0=10,表示计数器工作在连续增模式。T2SWT1写1表示使用T1CON的使能位。TECMPR写1使能定时器1的比较操作。


3、接着初始化EVA的Timer2,然后设置T2CON=0x1042,注意,Timer2使用的是T1CON的使能位。


4、EvaRegs.GPTCONA.bit.TCMPOE = 1;使能定时器比较输出。T1PIN = 1定时器1比较输出低有效,T2PIN定时器2比较输出高有效。


5、使能PWM1~PWM6,三条语句:


EvaRegs.CMPR1 = 0x0C00;


EvaRegs.CMPR2 = 0x3C00;


EvaRegs.CMPR3 = 0xFC00;


——没查到这三个寄存器赋值的意思 - -!


6、EvaRegs.ACTRA.all = 0x0666;设置比较输出引脚6,4,2低有效,5,3,1高有效。


DBTCONA死区定时器控制寄存器写0x0000,不使能死区控制。


COMCONA比较控制寄存器A写0xA600,使能比较操作,14~13位写01表示当T3CNT=0或T3CNT=T3PR(下溢或周期匹配)时,比较器寄存器CMPRx重载。12位为0,表示禁止空间向量PWM模式。


11~10位01,当T3CNT=0或T3CNT=T3PR(即下溢或周期匹配)时控制寄存器重载。9位设为1,全比较输出,PWM1~6由相应的比较逻辑驱动。


——init_evb()与init_eva()的设置步骤相同。


总结:

相关文章
|
3月前
|
Linux C语言
【Linux系统编程】基础指令(二)(上)
【Linux系统编程】基础指令(二)
|
3月前
|
Linux
【Linux系统编程】基础指令(二)(下)
【Linux系统编程】基础指令(二)
|
3月前
|
存储 Unix Linux
【Linux系统编程】基础指令(三)
【Linux系统编程】基础指令(三)
|
3月前
|
Linux
【Linux系统编程】基础指令(一)(下)
【Linux系统编程】基础指令(一)
|
3月前
|
人工智能 Unix Linux
【Linux系统编程】基础指令(一)(上)
【Linux系统编程】基础指令(一)
|
3月前
|
存储
【51单片机】初学者必读的一文【探究定时计数器与中断系统是如何配合起来的?】(9)
【51单片机】初学者必读的一文【探究定时计数器与中断系统是如何配合起来的?】(9)
麒麟系统开发笔记(十一):在国产麒麟系统上使用gdb定位崩溃异常方法流程进阶定位代码行数及专项测试Demo
上一篇,通过研究,可以定位到函数,本篇进一步优化,没有行数,程序较为复杂的时候,就无法定位,所以进一步定位。   本篇做了qBreakpad的研究,但是没有成功,过程也还是填出来,后来突然注意到gdb出现行数的方法,并通过了几轮测试以及实战,确实可以定位到行数,所以为了大家方便,把国企麒麟上的Qt崩溃方法分享出来。   本篇文章比较长,就不分篇了,同时还做了专项测试。
麒麟系统开发笔记(十一):在国产麒麟系统上使用gdb定位崩溃异常方法流程进阶定位代码行数及专项测试Demo
|
存储 安全 程序员
鲲鹏开发重点––ARM CPU的推测执行
MMU,内存管理单元,顾名思义就是用于管理内存的部件,这是CPU内部模块名,需要操作系统来进行空间配置和管理,所以,有时提到的MMU并不完全指硬件部分,也包括软件部分。其作用就是完成VA虚拟地址到PA物理地址的转换,页面大小管理,同时配置地址空间的访问属性,包括Normal(乱序访问)和Device(定序访问)进行区分,cache写回,cache写透,关闭cache等等,配置地址空间的访问权限。
459 0
鲲鹏开发重点––ARM CPU的推测执行
嵌入式开发学习之--中断应用概览
嵌入式开发学习之--中断应用概览
嵌入式开发学习之--中断应用概览
|
监控 C语言 Perl
西门子S7-1200编程实例,基本位逻辑指令如何使用?
今天我们来介绍一下西门子S7-1200基本位逻辑指令,通过一个简单的起保停控制实例来学习基本位逻辑指令如何使用。
西门子S7-1200编程实例,基本位逻辑指令如何使用?