让DSP从FLASH启动——step bystep
TI的资料上的说明如下: 对于C6416,片上的Bootloader工具只能将1 KB的代码搬入内部RAM。通常情况下,用户应用程序的大小都会超过这个限制。所以,需要在外部Flash的前1 KB范围内预先存放一小段程序,待片上Bootloader工具把此段代码搬移入内部并开始执行后,由这段代码实现将Flash中剩余的用户应用程序搬移入内部RAM中。此段代码可以被称作一个简单的二级Bootloader。[1] 由于执行二级Bootloader时C的运行环境还未建立起来,所以必须用汇编语言编写。如果你不会写汇编程序,这段代码可以从网上下。TI发布的标准bootloader是对存储格式有要求的,即引导表格式。C64XX的引导表格式如下:
以下是对应的bootloader汇编代码,笔者在官方版本上稍作了修改,不妨使用。 ;boot.asm .title? "Flash bootup utility for c6416" ??????????? .option D,T ??????????? .length 102 ??????????? .width? 140 ? COPY_TABLE? .equ???0x64000400 EMIF_BASE?? .equ???0x01A80000 ? ??????????? .sect ".boot_load" ??????????? .global _boot ? _boot:????? ;************************************************************************ ;* Debug Loop-? Comment out B for Normal Operation ;************************************************************************ ??????????? zero B1 _myloop:? ; [!B1] B _myloop? ??????????? nop?5 _myloopend:nop ? ;************************************************************************ ;* ConfigureEMIF ;************************************************************************ ?????????? ;CONFIG THE EMIFB_GBLCTL ??????? MVKL????? 0x01A80000,A4 ????? ||MVKL????? 0x000120BC,B4 ??????? MVKH????? 0x01A80000,A4 ????? ||MVKH????? 0x000120BC,B4 ??????? STW?????? B4???????,*A4 ??????? ??????? ;CONFIG THE EMIFB_CE1CTL ??????? ??????? MVKL????? 0x01A80004,A4 ????? ||MVKL????? 0x1171C109,B4 ??????? MVKH????? 0x01A80004,A4 ????? ||MVKH????? 0x1171C109,*A4 ??????? nop 4 ? ;**************************************************************************** ;* Copy codesections ;**************************************************************************** ??????? mvkl?COPY_TABLE,a3?? ; load tablepointer ??????? mvkh?COPY_TABLE,a3 ? ??????? ldw??*a3++,b1??????? ; Load entrypoint ? copy_section_top: ??????? ldw??*a3++,b0??????? ; byte count ??????? ldw??*a3++,a4??????? ; ram startaddress ??????? nop??3 ? ?[!b0]? bcopy_done??????????? ; have we copied allsections? ??????? nop??5 ? copy_loop: ??????? ldb??*a3++,b5 ??????? sub??b0,1,b0????????? ; decrementcounter ?[ b0]?b???? copy_loop??????? ; setup branch if not done ?[!b0]?b???? copy_section_top ??????? zero?a1 ?[!b0]?and?? 3,a3,a1 ??????? stb??b5,*a4++ ?[!b0]?and?? -4,a5???????? ; round address up to next multiple of4 ?[ a1]?add?? 4,a5,a3????????? ; round address up to next multipleof 4 ? ;**************************************************************************** ;* Jump toentry point ;**************************************************************************** copy_done: ??????? b???.S2 b1 ??????? nop??5 ? 再说说如何烧写flash。[2] 把代码等写入Flash的办法大体上可分为以下几种: ①使用通用烧写器写入。 ②使用CCS中自带的FlashBurn工具。 ③用户自己编写烧写Flash的程序,由DSP将内存映像写入Flash。 其中,使用通用烧写器烧写需要将内存映像转换为二进制或十六进制格式的文件,而且要求Flash器件是可插拔封装的。这将导致器件的体积较大,给用户的设计带来不便。 使用TI公司提供的FlashBurn工具的好处在于使用较为直观。FlashBurn工具提供的图形界面可以方便地对Flash执行擦除、编程和查看内容等操作。但这种力法需要FlashBurn工具运行时下载一个.out镜像(FBTC,FlashBurn Target Component)到DSP系统中,然后由上位PC机通过仿真器发送消息(指令和数据)给下位DSP,具体对Flash的操作由FBTC执行。FlashBurn工具不能识别.out文件,只接受. hex的十六进制文件,因此,需要将.out文件转换为.hex文件。这个转换的工具就是TI公司提供的Hex6x.exe工具。转换过程的同时,需要一个cmd文件指定作为输入的.out文件,输出的.hex文件的格式,板上Flash芯片的类型和大小,需要写入Flash中的COFF段名等。 使用用户自己编写的烧写Flash的程序较为灵活,避免了文件格式转换的繁琐。不过,此方法要求用户对自己使用的Flash芯片较为熟悉。在此仅对这种方法具体介绍。 先把用户应用程序(包含二级Bootloader)编译生成的.out文件装载到目标DSP系统的RAM中,再把烧写Flash的工程编译生成的.out文件装载到目标DSP系统RAM的另一地址范围,执行Flash烧写程序,完成对Flash的烧写。这个办法要注意避免两次装载可能产生的地址覆盖,防止第2次装载修改了应该写入Flash的第1次装载的内容。 具体方法是:如果你使用DSP/BIOS,可以修改烧写程序的.cdb文件中的system ->MEM->ISRAM,右键-〉属性,使base=0x00080000,len=0x00020000 (6416的内部RAM是1M,要根据你的CPU内部RAM改写)。这样生成的.cmd文件就会把烧写程序放到0x00080000开始的内存中去。同样方法将应用程序限制在0x00000400~0x00080000的范围(前边1k留给bootloader)。不过这样做有一个缺点,就是后边0x00020000的内存被浪费了,所以你可以写成0x00000400 ~0x00100000的范围,只要应用程序没用到后面的0x00020000,就不会产生抵制覆盖。如果你没用DSP/BIOS,那你一定自己写了.cmd文件,直接改.cmd文件的SECTIONS,将程序个段放入自己想放的位置,就不用我多说了吧。 .out文件遵守COFF(公共目标文件格式)格式。一个COFF段就是占据一段连续存储空间的程序或数据块。COFF段分为3种类型:代码段、初始化数据段和未初始化数据段。 对于EMIF加载方式,需要加载的镜像由代码段(如.vectors和.text等)和初始化数据段(如.cinit,.const,.switch,.data等)构成。所有未初始化的数据段(如.bss等)都不需要烧入到Flash中。各位可以参考边以后生成的.map文件(在Debug文件夹),通常看起来像这样: >>Linked Mon Aug 10 14:45:30 2009 OUTPUT FILENAME:?? <./Debug/my_timer.out> ENTRY POINTSYMBOL: "_c_int00"? address:00001060 SECTIONALLOCATION MAP ? ?output????????????????????????????????? attributes/ section?? page???origin????? length?????? input sections --------? ----?----------? ----------?? ---------------- frt??????? 0???00000400??? 00000000???? UNINITIALIZED .prd?????? 0???00000400??? 00000000???? UNINITIALIZED .sysregs?? 0???00000400??? 00000000???? UNINITIALIZED …… .cinit???? 0???00001120??? 00000b24???? ????????????????? 00001120??? 0000033c????my_timercfg.obj (.cinit) ????????????????? 0000145c??? 00000004????--HOLE-- [fill = 0] …… 通常包含以下内容:程序入口点ENTRY POINT,就是程序开始的位置;段名称,对应的起始地址、长度、初始化状态。凡是后边是UNINITIALIZED的,都不用写入FLASH中,以免占地方,FLASH烧写很慢,少烧点是点。 如果想减少代码量以下有几点建议: 1、???????尽量使用DSP 提供的API函数,而不用标准库函数。我曾在代码中用printf函数,结果代码量很大,删掉就少了很多。 2、???????可以删除RTDX的监测和追踪,具体方法是:打开.cdb文件->system->Global Setting->右键property->删掉Enable Real Time Analysis和Enable All TRC Trace Event Classes。 3、???????尽量不用DSP/BIOS,能省了很多废话。 如果不介意烧写时间长,可以用最简单粗暴的方法:将整个程序作为一个段,烧写进FLASH,存储器并不真正区分这些代码到底属于哪个段。少些代码可以如下: #include<stdio.h> #include<std.h> #include<log.h> #include<csl.h> #include<csl_irq.h> #include<csl_chip.h> #include <csl_emifb.h> #include"flash.h" #include"section.h" #include"flashbootcfg.h" ? unsignedchar* boot_addr = (unsigned char*)0x0;???? //0x64000000; void main() { ????? unsigned int i; ????? //NMI使能 ????? IRQ_nmiEnable(); ????? //开总中断 ????? IRQ_globalEnable(); ????? //整片擦除 //?? reset_fls(); ????? printf( "Erasing flashchip..."); ????? erase_chip(); ????? printf( "???? OKn"); ????? printf( "writingbootloader..."); ????? //在地址0x64000000处写BOOT ????? for(i = 0; i < BOOT_SECTION_SIZE; i++) ????? { ?????????? flash_writes(boot_addr++,*(( char*)(BOOT_SECTION_ADDRESS+i))); ????? } ????? printf( "???? OKn"); ????? printf( "writing entrypoint..."); ????? //在地址0x64000400处写ENTRY_POINT 小端模式 ????? boot_addr=(unsigned char *)0x400; ?? flash_writes(boot_addr++,(char)ENTRY_POINT); ????? flash_writes(boot_addr++,(char)(ENTRY_POINT>>8)); ????? flash_writes(boot_addr++,(char)(ENTRY_POINT>>16)); ????? flash_writes(boot_addr++,(char)(ENTRY_POINT>>24)); ????? printf( "???? OKn"); ????? printf( "writing programsection..."); ????? //应用程序段长度 ????? flash_writes(boot_addr++,(char)PROGRAM_SIZE); ????? flash_writes(boot_addr++,(char)(PROGRAM_SIZE>>8)); ????? flash_writes(boot_addr++,(char)(PROGRAM_SIZE>>16)); ????? flash_writes(boot_addr++,(char)(PROGRAM_SIZE>>24)); ????? //应用程序段在RAM中的地址 ????? flash_writes(boot_addr++,(char)PROGRAM_ADDRESS); ????? flash_writes(boot_addr++,(char)(PROGRAM_ADDRESS>>8)); ????? flash_writes(boot_addr++,(char)(PROGRAM_ADDRESS>>16)); ????? flash_writes(boot_addr++,(char)(PROGRAM_ADDRESS>>24)); ????? //应用程序的数据 ????? for(i = 0; i < PROGRAM_SIZE; i++) ????? { ?????????? flash_writes(boot_addr++,*(( char*)(PROGRAM_ADDRESS+i))); ????? }??? ????? printf( "???? OKn"); ????? printf( "writing tableend...n"); ????? //table end ????? for(i = 0; i < 3; i++) ????? { ?????????? flash_writes(boot_addr++,(unsignedchar)TABLE_END); ?????????? flash_writes(boot_addr++,(unsignedchar)(TABLE_END>>8)); ?????????? flash_writes(boot_addr++,(unsignedchar)(TABLE_END>>16)); ?????????? flash_writes(boot_addr++,(unsignedchar)(TABLE_END>>24)); ????? } ????? printf( "flash program isover!n"); ????? //boot(); ????? return; } //flash.c #include<csl_emifb.h> #include<csl_gpio.h> #include"flash.h" ? structERASE_CHIP ec={ ????? {0xaaa,0x555,0xaaa,0xaaa}, ????? {0xaa,0x55,0x80,0xaa,0x10} ????? }; structERASE_SECT? es={ ????? {0xaaa,0x80000},0x30} ????? };? structWRITE_FLS wf={ ????? {0xaaa,0xa0,0} }; ? intout_range(unsigned char * addr) { ????? if ((unsignedint)addr<FLS_BASE||(unsigned int)addr>FLS_MAX) ????? { ?????????? return 1; ????? } ????? else ????? { ?????????? return 0; ????? } } ? voidreset_fls() { ????? *(unsigned char *)FLS_BASE=0xf0; } ? charflash_reads(unsigned char * addr) { ????? addr+=FLS_BASE; ????? if(out_range(addr)) ????? { ?????????? return -1; ????? } ????? else ????? { ?????????? return *addr; ????? } } ? intflash_readm(unsigned char * from,unsigned char * to,const int size) { ????? int i; ????? for(i=0; i<size; i++) ????? { ?????????? *(to+i)=flash_reads(from+i); ????? } ????? return i; } ? interase_chip() { ????? int i; //?? struct ERASE_CHIP ec; ????? for(i=0; i<6; i++) ????? { ?????????? *(volatile unsigned char*)(FLS_BASE+ec.addr[i]) =ec.data[i]; ????? } ????? while((*(volatile unsigned char*)(FLS_BASE+0xaaa) & 0x80) != 0x80); ????? for(i=0;i<CHIP_SIZE;i+=1000) ????? { ?????????? while(*(volatile unsigned char*)(FLS_BASE+i)!=0xff); ????? } ????? reset_fls(); ????? return 0; } ? interase_sect(unsigned char * page) { ????? int i; ? ????? page+=FLS_BASE; ????? es.addr[5]=(unsigned int)page; ????? if (out_range(page)) ????? { ?????????? return -1; ????? } ????? for (i=0; i<6; i++) ????? { ?????????? *(char*)(FLS_BASE+es.addr[i])=es.data[i]; ????? } ????? while((*(unsigned char *)page & 0x80)!= 0x80); ????? return 0; } ? intflash_writes(unsigned char * addr,const char what) { ????? int i=0; ????? ????? wf.addr[3]=(unsigned int)addr; ????? wf.data[3]=what; ????? for (i=0;i<4;i++) ?????????? { ???????????????? *(char*)(wf.addr[i]+FLS_BASE)=wf.data[i]; ?????????? } ? ????? while(*( char *)(FLS_BASE+addr) != what); ????? return 1; } ? intflash_writem(const unsigned char *from,unsigned char *to,const int size) { ????? int i; ????? if(out_range(FLS_BASE+to) ||out_range(FLS_BASE+to+size)) ????? { ?????????? return 0; ????? }??? ????? for ( i=0; i<size; i++) ????? { ?????????? flash_writes(to+i,*(from+i)); ????? } ????? return i; } ? unsigned char* judge_sector(unsigned char * addr) { ????? unsigned char * sector; ????? sector=addr-(unsigned int)addr%0x20000; ????? return sector; } 再将前文给出的bootloader代码一并加入到烧写程序的工程中。 其中定义了一些符号,BOOT_SECTION_ADDRESS和BOOT_SECTION_SIZE表示.bootload段的起始地址和大小,在烧写程序的.map文件中查找;ENTRY_POINT,PROGRAM_SIZE,PROGRAM_ADDRESS在应用程序里查找。前文已述,PROGRAM_ADDRESS可以是一个初始化段的开始地址,PROGRAM_SIZE用最后一个初始化段结束地址减去一个初始化段的起始地址。这些定义看起来像这样: //section.h #define???? ENTRY_POINT?????? 0x00001060 /*? boot段的长度和RAM中地址设定???? */ #defineBOOT_SECTION_SIZE??? 0x000000a0??? #defineBOOT_SECTION_ADDRESS? 0x000926e0 /*? program段的长度和RAM中地址设定???? */ #definePROGRAM_SIZE? 0x0000750C #definePROGRAM_ADDRESS???? 0x000008f4 //flash.h #defineFLS_BASE ??? 0x64000000?? //BCE1:0x64000000~0x67ffffff #defineFLS_MAX?????? 0x640fffff //addr space 20bits #defineFLS_MID?????? 0x64080000 #defineCHIP_SIZE??? 0x80000?? #defineSECT_SIZE?? 0x20000 ? structERASE_CHIP { ????? const unsigned int addr[6]; ????? const char data[6]; };// ? structERASE_SECT { ????? unsigned int addr[6]; ????? const char data[6]; };// //alias ERASE_SECT.addr[5]sect_addr; ? structWRITE_FLS { ????? unsigned int addr[4]; ????? char data[4]; }; ? intout_range(unsigned char * addr); voidreset_fls(); charflash_reads(unsigned char * addr); intflash_readm(unsigned char * from,const int size); interase_chip(); interase_sect(unsigned char * page); intflash_writes(unsigned char * addr,const char what); intflash_writem(const unsigned char *from,const int size); unsigned char* judge_sector(unsigned char * addr); 你也可以将boot.asm放在应用程序中,然后专门为这段程序指定一个段地址,原理是一样的,只不过我们试过,这里不推荐。 将应用程序和烧写程序下载到RAM后,运行烧写程序,这个过程很慢,耐心等。烧写完成后关掉DSP电源,再重新启动,加载速度也不快,行不行等5分钟就知道了。 [1] 本文参考过网上一些资料,但能保证我的方法是对的。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |