1. 本次使用三兄弟的XDS28335开发板,研究一下XINTF操作SRAM的代码。哈弗结构,奇怪,DSP28335是哈弗结构,那么数据和程序空间应该独立的,为啥书上说采用统一的寻址方式?估计只是读写数据和程序的方法一样的意思。
2. 看下原理图部分,有地址线XA0-XA18,数据线XD0-XD15,XWEn是写信号(低电平有效),XRDn是读信号(低电平有效),F_CSn是片选信号(低电平有效)。
3. 看下芯片的XINTF章节介绍,最近TI把C2000系列划到MCU部分了,搞的找不到,Learn more(了解更多)。下图是DSP28335的内部地址空间,有3个区域,据说CCS可以通过仿真器直接访问XINTF连接的外部存储器,有点厉害。可以看下图的3个区域的地址空间,这里有个问题没明白,区域0的外部地址范围是0X00000-0X00FFF,如果要对区域0的第一个存储单元进行操作,需要将0X00000送到地址线,并将片选信号XZCS0拉低,这没问题,可是下面的0X0000 4000是什么地址?哎,好像明白了,0X0000 4000是DSP28335的内部地址,0X00000-0X00FFF是信号的地址,意思是程序里面写0X0000 4000这个地址,然后硬件上会把XZCS0拉低,XA(19:0)的值是0X00000,这个就是统一寻址的意思吧。本次SRAM用的是区域6。
4. 看下配置流程
5. 时钟的配置
6. 测试下代码,导入工程\SXD_C28335\SXD28335_PRO_1_V2\Example_2833xCodeRunFromXintf,第一个问题下面是什么意思?百度了一下利用#pragma CODE_SECTION指令可以将程序从Flash搬到RAM中运行,从而提高程序执行速率,该方法需要完成以下四步。
第一步,利用#pragma CODE_SECTION指令关联程序和SECTIONS;主函数的一开始用#pragma CODE_SECTION 将中断函数 cpu_timer0_isr 和cpu_timer1_isr 指定到片外 SRAM 空间。
// These two functions will be loaded into SARAM and copied to
// XINTF zone 6 for execution
#pragma CODE_SECTION(cpu_timer0_isr,"xintffuncs");
#pragma CODE_SECTION(cpu_timer1_isr,"xintffuncs");
第二步,为链接创建相关变量;
extern Uint16 XintffuncsLoadStart;
extern Uint16 XintffuncsLoadEnd;
extern Uint16 XintffuncsRunStart;
extern Uint16 XintffuncsLoadSize;
第三步,复制时间关键代码以及Flash设置代码到RAM;这个不懂,有什么用途?
memcpy(&XintffuncsRunStart, &XintffuncsLoadStart, (Uint32)&XintffuncsLoadSize);
第四步,修改CMD文件。这段程序的作用是将程序加载到片内 RAML1 空间中,运行时搬移到片外 ZONE6去 执 行 。 _XintffuncsLoadStart 为 变量加载的起始地址 、_XintffuncsLoadEnd 变量加载的结束地址、_XintffuncsRunStart 运行的起始地址、_XintffuncsLoadSize 加载代码的大小。这四个变量都是 CCS 自己算的(怎么算出来的,问题点?)。第一次接触这个机制,感觉很懵逼。把2个函数放到外部SRAM,那拷贝的时候怎么知道这个两个函数原来的地址和大小?理清思路,一个函数cpu_timer0_isr放到一个空间xintffuncs,这个空间配置如下(CMD文件只是配置地址空间而已):下面CMD文件只是为了生成4个变量给memcopy使用吗?
SECTIONS
{
/* Setup for "boot to SARAM" mode:
The codestart section (found in DSP28_CodeStartBranch.asm)
re-directs execution to the start of user code. */
codestart : > BEGIN, PAGE = 0
ramfuncs : > RAML0, PAGE = 0
.text : > RAML1, PAGE = 0
.cinit : > RAML0, PAGE = 0
.pinit : > RAML0, PAGE = 0
.switch : > RAML0, PAGE = 0
xintffuncs : LOAD = RAML1,
RUN = ZONE6,
LOAD_START(_XintffuncsLoadStart),
LOAD_END(_XintffuncsLoadEnd),
RUN_START(_XintffuncsRunStart),
LOAD_SIZE(_XintffuncsLoadSize),
PAGE = 0
}
看下ZONE6的区域,既然4个变量是CCS自动算的。那么memcopy是什么用途?拷贝的是什么?是2个定时中断函数吗?指定到片外SRAM和可拷贝到片外SRAM的区别是什么?
RAML1 : origin = 0x009000, length = 0x001000 ZONE6 : origin = 0x180000, length = 0x001000
看下这几个变量的定义,不过依然不太懂
00009741 _XintffuncsLoadEnd
00000029 _XintffuncsLoadSize
00009718 _XintffuncsLoadStart
00180000 _XintffuncsRunStart
7. 看下代码部分,关注关键点,是不是初始化区域6的SRAM之后,就可以把这两个中断函数复制到这个SRAM里面的意思?
// Initialize XINTF Zone 7
init_zone6(); //首先要初始化访问 zone6 空间的时序
// Copy non-time critical code to XINTF
// This includes the following ISR functions: cpu_timer0_isr(), cpu_timer1_isr()
// The XintffuncsLoadStart, XintffuncsLoadEnd, and XintffuncsRunStart
// symbols are created by the linker. Refer to the F28335_ram_xintf.cmd file.
memcpy(&XintffuncsRunStart, &XintffuncsLoadStart, (Uint32)&XintffuncsLoadSize);
8. 本次例程有3个定时器中断函数,估计是2个拷贝到区域6的SRAM里面运行,一个在DSP28335的内部SRAM里面运行。
__interrupt void cpu_timer0_isr(void)
{
CpuTimer0.InterruptCount++;
// Acknowledge this interrupt to receive more interrupts from group 1
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
__interrupt void cpu_timer1_isr(void)
{
CpuTimer1.InterruptCount++;
// The CPU acknowledges the interrupt.
EDIS;
}
__interrupt void cpu_timer2_isr(void)
{ EALLOW;
CpuTimer2.InterruptCount++;
// The CPU acknowledges the interrupt.
EDIS;
}
9. 看下XINTF的配置函数
void init_zone6(void)
{
// Make sure the XINTF clock is enabled
EALLOW;
SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1;
EDIS;
// Configure the GPIO for XINTF with a 16-bit data bus
// This function is in DSP2833x_Xintf.c
InitXintf16Gpio();
EALLOW;
// All Zones---------------------------------
// Timing for all zones based on XTIMCLK = SYSCLKOUT
XintfRegs.XINTCNF2.bit.XTIMCLK = 0;
// Buffer up to 3 writes
XintfRegs.XINTCNF2.bit.WRBUFF = 3;
// XCLKOUT is enabled
XintfRegs.XINTCNF2.bit.CLKOFF = 0;
// XCLKOUT = XTIMCLK
XintfRegs.XINTCNF2.bit.CLKMODE = 0;
// Disable XHOLD to prevent XINTF bus from going into high impedance state
// whenever TZ3 signal goes low. This occurs because TZ3 on GPIO14 is
// shared with HOLD of XINTF
XintfRegs.XINTCNF2.bit.HOLD = 1;
// Zone 7------------------------------------
// When using ready, ACTIVE must be 1 or greater
// Lead must always be 1 or greater
// Zone write timing
XintfRegs.XTIMING6.bit.XWRLEAD = 1;
XintfRegs.XTIMING6.bit.XWRACTIVE = 2;
XintfRegs.XTIMING6.bit.XWRTRAIL = 1;
// Zone read timing
XintfRegs.XTIMING6.bit.XRDLEAD = 1;
XintfRegs.XTIMING6.bit.XRDACTIVE = 3;
XintfRegs.XTIMING6.bit.XRDTRAIL = 0;
// don't double all Zone read/write lead/active/trail timing
XintfRegs.XTIMING6.bit.X2TIMING = 0;
// Zone will not sample XREADY signal
XintfRegs.XTIMING6.bit.USEREADY = 0;
XintfRegs.XTIMING6.bit.READYMODE = 0;
// 1,1 = x16 data bus
// 0,1 = x32 data bus
// other values are reserved
XintfRegs.XTIMING6.bit.XSIZE = 3;
EDIS;
//Force a pipeline flush to ensure that the write to
//the last register configured occurs before returning.
__asm(" RPT #7 || NOP");
}
10. 运行ccxml目标配置文件,启动,连接目标开发板,加载程序,
11. 首先将用于中断计数的 CpuTimer0.InterruptCount、CpuTimer1.InterruptCount 和 CpuTimer2.InterruptCount 添加到观察窗口中。并设置窗口为连续刷新。开始全速运行,可以看到这三个计数器会累加计数。我是全部加载到观察窗口了。
12. 看下内存空间,也可以通过View->Memory Browser查看cpu_timer0_isr 和cpu_timer1_isr 所在空间的地址。刚开始我选的Data,所以没找个这个函数,原来还有3个选项。切换到Program空间,找到函数。
13. DONE,飞翔吧,上一个妹子的照片