//第一章 EMIF的控制
//07.09.06 昨天发工资了。
//sdram.prj 向sdram中写数再读数,之后灯闪烁。
//csl库: csl.h / csl_irq.h / csl_chip.h / csl_emifa.h
1.烧写Flash
改动想要学习烧写flash,于是把程序改成闪烁。
while(1)
{
for(i=0 ; i < 0x100000 ; i++)
{
for(j=0;j<40;j++)
{
汇编table指令什么意思asm(" Nop ");
}
}
* LED = (~(* LED))&0x03;
}
A)直接写到内部RAM中去
通过Load Program就行了,不过要注意的是,在线修改程序后,一定要把正在运行着的程序停掉之后重新Load Program,那个ReLoad Program好像不太好
使。另外,板子上的复位键是用来复位板子的,复位之后,Ram中的程序还是以
前那个,于重新下载没有任何帮助。
在程序运行阶段,不要对板子突然停电,这样的话,又要重新启动CCS;也不要在板子停电之后运行程序,不然程序铁定死在那里。
B)烧写到flash中去。
B1)使用FlashBurn
参见文档《烧写步骤》。
z经验:1.flashBurn装不上很有可能是因为以前CCS3.1没有删干净,如果那样,只好重装系统。
2.最后一步program memory如果报错,那么reset一下就可以下载了,不用download
fbtc,也不用erase memory,不过作了也没什么影响。
z在烧写过程中有三个文件需要自己编写,分别是:
d , Boot.asm , d 在编译源程序时,Cmd文件用来分配rom和ram空间,告诉链接程序怎样计算地址和分配空间。Cmd文件由三部分组成:
1.输入/输出定义:这一部分,可以通过ccs的“”菜单设置-l xx.lib 连接系统文件xx.lib
(rtsxx.lib包括ANSI C标准库、系统启动程序c int00、允许C访问特殊指令的函数和宏)(cslxx.lib)包括使用CSL库编程时的链接。在ccs文件夹下,大端加e。
-o xx.out 最终生成的二进制文件命名为xx.out
-m xx.map 生成映射文件xx.map
-stack 0xyyy 系统堆栈为yyy字
-c 初始化rom
Xx.obj 链接目标文件
2.MEMORY命令:描述系统实际的硬件资源
MEMORY
{
PAGE 0:
name 0 [attr] : origin = constant, length = constant
PAGE n:
name n [attr] : origin = constant, length = constant
}
通常PAGE 0 对应rom;PAGE 1对应ram。PAGE 里包含的区间名字与其后面的参数反映了该区间的起始地址和长度。
name:存储空间名称
attr:存储空间属性:只读R,只写W,可包含可执行代码X,可以被初始化I。
orgin:用来定义存储空间的起始地址
Lenth:用来定义存储空间的长度
3.SECTION命令:描述“段”如何定位
SECTIONS
{
.SectionName > DistributeName PAGE Number
}
系统保留的段名参见相关书籍。
本例在boot.asm中声明.boot_load段,在d文件中将其放到了boot区内。在C源程序中,可以利用两个伪函数,将程序中声明的变量或函数放到数据/程序空间内。 #pragma CODE_SECTION(symbol."section name") 程序空间
#pragma DATA_SECTION(symbol,"section name") 数据空间
此外,配置DSP空间时,注意寄存器PMST中MP/MC,OVLY,DROM位。
在使用hex6x命令将.out文件转换成16位.hex文件时,xx.cmd文件用作格式转换命令文件。转换后的十六进制格式文件即是引导表的内容,引导表包含并行引导的标识、程序执行的入口地址、程序存放的目的地址、用户程序及用户程序块长度。
具体格式参见spru186.pdf第11章
注意:1.注意器件接口、存储器接口和ROM接口三者关系同目标文件数量对应。
2.使用SECTION命令指定需要转换的段,需要启动时载入的段。
3.image模式产生连续的储存区域。
4.建立引导表步骤:P255
Bootorg 指明boot table的地址。Bootsection指明boot routine的起始地址。Boot
table是数据搬移表,而boot routine是引导程序,被用作引导dsp启动,当该程
序执行完毕,程序跳转到-e指明的地址开始执行,若没有-e说明,程序跳转到
coff定义的程序入口(boot table中)。如果MP/MC=1;则程序不自举,直接从0ff80h
开始执行。
Boot.asm文件:
驻留在地址0处,程序从此处开始执行,作用为搬移代码和数据。C6x系列的dsp内部驻有自引导程序,会将flash rom中1k内容搬移到片内0地址开始的内存空间。
如果代码、数据大于1k,那么就需要在这1k程序中将代码段和数据段复制到内存中运行。
Boot.asm采用汇编编写,汇编语句格式:
label: || [cond] instruction .unit operand ;comment
label:代码或变量地址
[cond]:条件寄存器
instruction:助记符(mnemonic);伪指令(directive)
.unit:功能单元(可选)
operand:寄存器;常量;指针。
;comment:注释
简要分析boot.asm文件:
.title "Flash bootup utility for seed-dec6416"
.option D,T
.
length 102
.width 140
COPY_TABLE .equ 0x64000400
//使用.equ,使COPY_TABLE=0x64000400 ;在d文件中可以看出,
//这个地址正是boot table的首地址。
.sect ".boot_load" //声明boot_load段,以下代码嵌入该段中
.global _boot //声明_boot符号,该符号可以在其他模块中被引用。
_boot: zero B1 //将B1清零,B1为内置寄存器。
_myloop: nop 5 //执行5次空操作,避免流水线冲突。
_myloopend: nop
mvkl COPY_TABLE, a3 //将COPY_TABLE的值赋给A3内置寄存器
mvkh COPY_TABLE, a3 //汇编语言不区分大小写
ldw *a3++, b1 //将引导表指示的程序入口地址给B1
//地址以字节为单位,故a3实际是加4
copy_section_top: //引导表结构参见spru186p,P254
ldw *a3++, b0 //第一段数据个数,以byte为单位
ldw *a3++, a4 //第一段数据目标地址
nop 3
[!b0] b copy_done //如果数目为全零,跳转到结束
nop 5 //转移指令有5周期延迟,故之后的5个语句都会进入流水线
//相继执行,如果不想执行,nop 5 。
copy_loop:
ldb *a3++,b5 //将8位数据放入b5
sub b0,1,b0 //待拷贝数据量减一
[ b0] b copy_loop //如果该段还有字段未拷贝,则继续拷贝
[!b0] b copy_section_top //该段转移完毕,跳转转移下一段
zero a1 //a1清零
[!b0] and 3,a3,a1 //该段转移完毕,将a3低两位赋给a1
stb b5,*a4++ //将b5的低八位放入a4
[!b0] and -4,a3,a5 //该段转移完毕,将a3的低2位置0赋给a5.
[ a1] add 4,a5,a3 //本句只有b0=0时方能执行,将a5加4赋给a3
//后几句的意思连起来就是当开始一个新段时,如果a3低2位不为零,则将低2位清零进位,//即:引导表中段的起始位置是以32位(w)计算的。(此为猜测,待考,正确率80%)copy_done:
b .S2 b1 //跳到程序入口
nop 5
2.外部地址空间分配
EMIF分为四个CE空间,各自地址可以在datasheet查到。所以分派好储存器地址就可以不要管CE管脚的逻辑了,dsp会自动设置。CE空间通过几个寄存器进行配置,详情参见文档和程序。
3.中断声明
Vector.asm文件声明了中断向量,以后会对中断作单独的讨论,这里不再赘述。只是要注意带参数宏的声明方法。
4.EMIF控制寄存器配置
A)程序代码分析
本程序基于CSL库建立,使用大量头文件和API函数,具体问题还木有搞清楚,留待以后吧。
a)EMIFA_Config:自定义的一个包含12个32位数值的结构,其中的数值对应
了EMIF控制寄存器对应的12个需要配置的寄存器的值。使用EMIFA_config
(*EMIFA_Config)进行对寄存器的配置。
b)EMIFA_config(*EMIFA_Config)函数:指定首地址和各个寄存器的偏移量,
然后将参数值对应地付给各个寄存器。
符号“\”为行连接符,表示下一行的内容同上一行是同一行的。
“#”为宏转义符,将之后参数转义为字符串。
“##”为宏合并符,将之后参数与之前的字符连接起来形成新的参数。
Volatile关键字:
提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没
有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的
值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
c)EMIFA_Config内部函数,均是调用CSL-API函数,对每一位移位与掩码。
d)伪指令 #pragma
pragma就是为了让编译器编译出的C或C++程序与机器硬件和操作系统保持完全兼容而定义的宏扩展,#pragma是和特定编译器相关的。
e)主函数中调用了很多中断函数IRQ_***(),尽快本CSL的书来看看。参见
文档TMS320C6000 CSL API Reference Guide.Pdf.
B)EMIF相关寄存器说明和配置方法。
本例中,SDRAM使用了EMIFA的CE0空间,对应地址0x80000000-0x8fffffff,Flash使用EMIFB的CE1空间,对应地址为0x64000000-0x641fffff。
代码中寄存器配置为GBLCTL; CE0~3CTL;SDCTL;SDTIM;SDEXT;
CESEC0~3。对照程序,发现CSL编程有很大方便。详情参考emif.pdf/P135。
5.LED灯的使用
通过EMIFB的CE0空间外接CPLD译码控制。
SDRAM程序的分析就到此为止。对SDRAM来说,这仅仅是些皮毛,比如SDRAM的
各种方式,如自举刷新,时钟设置等等都没有深入的涉及。这些只有等到真正自己做板子的
时候才会有动力去钻研了。
对DSP的学习,那更是万里长征的第一步,欲知后事如何,且看第二章,中断。
万恶的ccs居然不支持中文路径,再一次鄙视。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论