花了一个多星期研究了一下dm6437的flash烧写,总结一下:
1 要了解烧写,首先要了解6437的存储器组织
存储器的硬件组织原理可以参看TMSC6000结构原理与硬件设计(北京航天航空大学);具体的存储器的硬件连接可以参照合众达的DEC6437原理图。从原理图可以知道,flash的控制信号线CE/OE/WE都是连接与板子上面的CPLD,如需要控制读写,还要参看flash的datasheet来了解其读写时序,编写CPLD的程序,这里暂且略过,S29AL032D数据线22根,相当于内部有4M*8bit的存储空间(在flash烧写的程序中会有一句
if(FillSize > 0x100000)
{
printf("The OUT file is too big!\n");
}
之所以这里是1M,不是4M,是因为后面调用fread的时候是按照4字节为单位来读取的!),地址线连接于EM_BA0-1(用于bank区分) EM_A0-A19
片选是选择的cs2,因此flash用到的空间是EMIF_CS2 = 0x0x4200 0000,查看存储器映射表(详见TMS320DM6437 Digital Media Processor中table 2-3)
因此,在烧写的程序中基址被定为
#define FLASH_BASE ( EMIF_CS2_BASE )
数据总线与dsp的连接是:EM_D0-7 8位
因此,flash写数据时,指针设置为从FLASH_BASE开始的地方。
2 CCS烧写flash的办法:
a.Ti提供的软件flashburn,需要将.out->rom格式;
b 将编写两个工程:一个主程序工程(即用户应用程序,其中包括二次引导程序),一个搬运程序工程。搬移程序不能使用与主程序的程序空间和中断向量表重合的物理空间,以免覆盖。烧写时,同时打开主程序和搬移程序的PROJECT,先LOAD主程序,再LOAD搬移程序,然后执行搬移程序,烧写OK!
C 用户应用程序(必须包含boot引导程序,否则无法启动)编译生成.out,然后编写烧写程序,在烧写程序中将生成的.out烧写到flash中。
我们将采用第三种办法。网上有人说烧写flash需要修改cmd文件,实际上不用,因为如果自己编程实现的话,只要注意三个地址的区别就可以:一是flash物理地址,文件烧入的地方;二是文件load的地方,也就是程序运行的地址,一般是ram中(当然如果你想直接在flash中跑程序的话,那cmd的确要改);三是在flash烧写或者load启动时将文件读入内存时的一个地址(这个地址实际上是个偏移量,最终操作时是将其与对应的物理地址加起来作为实际的物理地址)
3 cmd中用到的ram
本质上是分为内部ram和外扩的ram,在我们的应用中外部ram是DDR2(0x8000 0000),内部ram分为L1D(数据存储器)、L1P(程序存储器)和L2,查看地址映射表会看到L1D ram、L1Dram/cache、L1Pram/cache、L2 ram/cache的区别。其中包含cache说明可以作为高速缓存用。在6437中,根据寄存器的配置,可以将内部ram的一部分配置成存储器映射ram,也可以配置成高速cache,具体寄存器参见TMS320DM6437 Digital Media Processor table 2-3 Memory map summary中的脚注(1).
Cache的意义在于保留最近读入数据。在开始阶段,cache中是没有数据的,这时如果cpu到cache中来搜索需要的数据,就肯定会有cache的缺失,导致读取外部存储器,并将内容缓存于cache中。后续的操作中若有同样的数据,cpu将优先命中cache,可以有效提高程序的读写速度。新存入cache的数据总是覆盖LRU(least recently use)最近最少使用行,将最少使用的覆盖,以提高cache的命中率。在dsp的程序设计中,cache命中率的提高也是提高效率的一个重要方面。
存储器映射的概念:片内和片外存储器以字节为单位统一编址。在我们的应用中,flash通过emif接口扩展,ddr2通过dm6437专有的ddr2 memory controller来扩展。
EMIF异步扩展存储器接口引脚参看EMIF的手册TMS320DM643x DMP Asynchronous External Memory Interface (EMIF) UG (Rev. A) page9.
DDR2 memory controller 引脚参看对应手册TMS320DM643x DMP DDR2 Memory Controller User's Guide (Rev. B) page11
4 dm6437的启动过程
Dsp上电或复位后,根据设定的dsp自举方式进行引导。引导方式有三种,可以参看SEED-DEC6437用户指南 (Rev.A) page27,SEED-DEC6437 所使用的启动方式是EMIFA ROM FASTBOOT 不采用AIS 模式,即BOOTMODE[3:0] = 1001b, FASTBOOT = 1,AEM[2:0] = 001b。在这种模式下,板卡上电后,先进入地址0x1000 0000(boot rom),
这里有一段出厂时就烧写好的bootloader,这段程序的功能通常是从EMIF CE1端口自动地复制一块数据到地址,实际上就是从flash首地址开始拷贝一段数据出来(具体数据放在什么地方,因为没有boot rom程序参考,因此个人认为是放在应用程序的cmd文件为bootld所指定的1k运行空间,可能是flash,也可能是ram,我自己设置的是ram)
L2ram BOOT_RAM: o = 0x10800000 l = 0x00000400
其实这里是有点疑问的:因为指导书上是这样说的:,先进入地址0x1000 0000,而后直接进入Flash 的首地址0x4200 0000,开始执行烧写在Flash 的程序。我个人认为程序具体在哪里运行应该是看boot rom中一级bootloader将程序拷贝到哪里去了。。。
一般的说法是,一级bootloader复制的数据块大小是有一定限制的,根据芯片不同而不同,许多地方提到的都是1k,有些也提到64k。具体dm6437的手册中应该也会提到,但我没有具体看。当然用1k的程序来实现flash程序的二级搬移应该是够了的。通过二级bootloader就可以实现全部用户程序到cmd指定区域的ram的搬移,搬移完成后,就跳转到c程序的入口。
反正后面的段是按照引导表COPY_TABLE来拷贝到对应的ram区,而COPY_TABLE的内容是在flash烧写时,由烧写程序根据.out文件的内容解析得到的各个段的大小、装载地址及内容而制成的,flash烧写时写入COPY_TABLE的地址就是从0x4200 0000开始后的1k偏移地址0x4200 0400开始。(也许有人会问为何设置在这个地方,因为二级bootloader是在flash开始1k空间,后面才是用户真正的应用程序,你总不能让bootloader自己拷贝自己吧,^_^)
5 boot.asm 和flash烧写程序
好多页,算了,这个在光盘里面都有,原理知道了,自己看看也能明白!
这次调试中遇到一个问题:boot程序中有些寄存器要设置一下,有的boot程序不同,要注意。
6 未解决的问题
;****************************************************************************
;* Copy code sections
;****************************************************************************
mvkl COPY_TABLE, a3 ; load table pointer 加载用户程序代码的起始地址
mvkh COPY_TABLE, a3 ;
ldw *a3++, b1 ; Load entry point 加载用户c语言入口地址
; nop 5
; mvkl 0x80001680, b1 ; load table pointer
; mvkh 0x80001680, b1
copy_section_top:
ldw *a3++, b0 ; byte count 本段加载字节个数size 32bit
ldw *a3++, a4 ; ram start address 本段要被加载到内存中ram起始地址
nop 3
[!b0] b copy_done ; have we copied all sections? 判断是否所有段加载完成
nop 5
copy_loop: ; 循环加载当前段内容
ldb *a3++,b5 ;将flash地址中的数放到B5 8bit
sub b0,1,b0 ; decrement counter 每加载一个,字节数减1
[ b0] b copy_loop ; setup branch if not done 判断加载字节数是否为零
[!b0] b copy_section_top ; 当前段加载成功后转入加载下一段
zero a1 ; 执行完这条指令B5和A4中才有新的数据
[!b0] and 3,a3,a1 ; 什么条件下执行??
stb b5,*a4++ ; 将flash读出到B5中的段内容放到对应的ram地址中,
; 按bit8搬移
[!b0] and -4,a3,a5 ; round address up to next multiple of 4
[ a1] add 4,a5,a3 ; round address up to next multiple of 4
;****************************************************************************
;* Jump to entry point
;****************************************************************************
copy_done:
mvkl 0x00000100, b0 ; set pll_div1 register value
nop 5
copy_done1:
sub b0,1,b0
[ b0] b copy_done1 ; have we copied all sections?
nop 9
b .S2 b1 ;跳转到c入口标签地址 这句还不太懂
nop 9