DSP

TMS320C6722的Parallel Flash启动

2019-07-13 17:50发布

data/attach/1907/r1u6v8mu58bewj0zwg196b9bpbph41vr.jpgdata/attach/1907/p8au8mp3brkrv1qi0orr9fhrwg8hr3z9.jpg 序:       最近在调试TMS320C6722的Parallel Flash启动,大约调了两周左右(中间因为找不出错误原因,断了几天),最后调试成功。关于DSP的资料,网上多是关于2812和28335等C2000系列。关于C6000系列,C6713较多一些。所以在这里将C6722的调试过程以及中间遇到的一些问题写下来,希望能够为调试C6722的朋友们提供些帮助。         首先,说下我这里的配置:DSP主芯片为TMS320C6722, FLASH为:SST39VF6401,4M16         因为6722的EMIF地址线只有14根(EM_BA0、EM_BA1、EM_A0~A11),所以要想要想寻址更多的内容,需要6722的GPIO来扩展。在这里,用的是McASP0 AXR的0~4和10~13总共9根GPIO。总共23根地址线,能够寻址2^23=8M,与flash的4M2=8M相对应。因为flash的每个内存单元为16位,而DSP得每个内存单元为8位,所以要将6722的EM_BA1连接flash的最低位地址线A0。         如果绕不过来,可以参考一下这个链接:http://wenku.baidu.com/link?url=55Z5UcY8VwCYmbtGqej6jOQruMbJC39yqY-C2uJoYJcQQQdFKVCm48W-DNCIaZxREzBdxflDcS54UX_BDHPYWNp_n_VDkRtIZDWqqgaCtHG     虽然不是嵌入式的内容,但道理是相通的。 一、简述6722的启动过程         上电后,从0x0000 0000开始运行,CFGPIN0和CFGPIN1两个寄存器会在的上升沿捕获相关引脚的状态(高电位为1,低电位为0),跟启动模式有关的引脚有四个,SPI0的SIMO、SOMI、CLK以及UHPI_HCS,因为6722没有UHPI模块,所以对于6722来说跟启动模式有关的引脚有3个。虽然6722没有UHPI模块,在仿真器状态下查看6722的寄存器,UHPI_HCS始终为1。                                参考文献:SPRS370E,  P16~18         检测到dsp的启动模式后,在Parallel Flash模式下,它会读取flash的第一个字节的最低两位(这个地方是672x与其它系列不同的地方),也就是0x9000 0000的内容,来确定是8位模式还是16位模式(8位8位的copy,还是16位16位的copy),然后将flash前1k的数据copy到dsp内存以0x1000 0000为起始地址的地方。到这个地方为止,都是DSP自己运作的,不需要人工介入,这段程序是出厂时就固化到6722的ROM里的。接下来就需要人工介入了。copy到dsp内存的1K数据,除了第一个字(32位)外,剩余的代码就是用户自己编写的二次bootloader。ROM copy  1k数据到dsp内存的过程为一次bootloader。然后二次bootloader的作用就是将用户代码从flash0x9000 0400的位置copy到内存RAM里0x1000 0400的位置。                            参考文献:SPRAA69D,P5 二、二次bootloader         接下来就是写二次bootloader。因为运行二次bootloader时,c语言环境还没建立起来,所以必须用汇编来写。         内容包含下面几部分:1.配置PLLC;2.配置EMIF;3.copy代码,从0x9000 0400到0x1000 0400;4.跳转到_c_int00         附上二次bootloder代码:          ;*************environment:TMS320C6722********* ;*************time:2016/08/07***************** ;*************author:LXD_BUAA********************** .title "flash boot" ;address of the generated boot table user_size .equ 0x00003468 ;refer to the .map file user_ld_start .equ 0x90000400 ;the start location of user's codes loaded in flash user_rn_start .equ 0x10000400 ;the start location of user's codes run in ram CFGBRIDGE .equ 0x40000024 ;Controls Reset Of The Bridge BR2. Must Assert RESET After PLL Changed & Must Release Before dMAX/UHPI Acesse PLLCSR .equ 0x41000100 ;PLL Control/status Register Address PLLM .equ 0x41000110 ;PLL Multiplier Control Register Address PLLDIV0 .equ 0x41000114 ;PLL Controller Divider0 Register Address PLLDIV1 .equ 0x41000118 ;PLL Controller Divider1 Register Address PLLDIV2 .equ 0x4100011C ;PLL Controller Divider2 Register Address PLLDIV3 .equ 0x41000120 ;PLL Controller Divider3 Register Address PLLCMD .equ 0x41000138 ;PLL Control Command Register Address PLLSTAT .equ 0x4100013C ;PLL Controller Status Register Address ALNCTL .equ 0x41000140 ;PLL Clock Align Control Register Address A1CR .equ 0xF0000010 ;The Register Accouting For EMIF FLASH Device MCASP0_PFUNC .equ 0x44000010 ;Pin function register MCASP0_PDIR .equ 0x44000014 ;Pin direction register MCASP0_PDOUT .equ 0x44000018 ;Pin data output register MCASP0_PDSET .equ 0x4400001C ;To change a pin from 0 to 1 if corresponding pin is configured as GPIO MCASP0_PDCLR .equ 0x44000020 ;To change a pin from 1 to 0 if corresponding pin is configured as GPIO .sect ".boot_load" .global _boot .ref _c_int00 _boot: ;***********************part1:pllc configuration***************** ;SYSCLK1(CPU) = 200MHz, SYSCLK2(Pheriperal) = 100MH,SYSCLK3(EMIF)=100MHz,OSCIN=25MHz ;INITIAL PLL MVKL .S1 PLLCSR , A5 ;SECTION: Disable PLL MVKH .S1 PLLCSR , A5 ;A5->PLLCSR || MVKL .S2 00000040H , B6 ; MVKH .S2 00000040H , B6 ;B6 = 000000040H STW .D1 B6 , *A5 ;PLLEN=0, OSCPWRDN=0, PLLRST=0, PLLPWRDN=0, STABLE=1(Read-Only Bit) NOP 4 ;Wait For 4 Cycles MVKL .S2 00000048H , B6 ;SECTION: Reset PLL MVKH .S2 00000048H , B6 ;B6 = 000000048H STW .D1 B6 , *A5 ;PLLRST=1, PLLEN=0, OSCPWRDN=0, PLLPWRDN=0, STABLE=1(Read-Only Bit) NOP 4 MVKL .S1 PLLDIV0 , A5 ;SECTION: Program Divider0 & PLLM MVKH .S1 PLLDIV0 , A5 ;A5->PLLDIV0 || MVKL .S2 PLLM , B5 ; MVKH .S2 PLLM , B5 ;B5->PLLM || MVKL .S1 00008001H , A6 ; MVKH .S1 00008001H , A6 ;A6 = 00008001H XXXXXXXXXXXXXXXXXX || MVKL .S2 00000010H , B6 ; MVKH .S2 00000010H , B6 ;B6 = 00000004H XXXXXXXXXXXXXXXXXX STW .D1 A6 , *A5 ;Write PLLDIV0, Enable DIV0 & DIV0_OUT = CLKIN/2 || STW .D2 B6 , *B5 ;Write PLLM, PLL_OUT = CLKIN*8 = 200 MHz NOP 4 MVKL .S1 PLLSTAT , A4 ;SECTION: Check The Status Of GO Operation MVKH .S1 PLLSTAT , A4 ;A4->PLLSTAT $1: LDW .D1 *A4 , A1 ;A1 = PLLSTAT NOP 4 [A1] B .S1 $1 ;GOSTATE = 1, Then Wait For The Complement Of GO Operation NOP 5 MVKL .S1 PLLDIV1 , A5 ;SECTION: Program Divider1 , 2, 3 & ALN1~3 MVKH .S1 PLLDIV1 , A5 ;A5->PLLDIV1 || MVKL .S2 PLLDIV2 , B5 ; MVKH .S2 PLLDIV2 , B5 ;B5->PLLDIV2 || MVKL .S1 00008000H , A6 ; MVKH .S1 00008000H , A6 ;A6 = 00008000H XXXXXXXXXXXXXXXXXXXXXXXXXX || MVKL .S2 00008001H , B6 ; MVKH .S2 00008001H , B6 ;B6 = 00008001H STW .D1 A6 , *A5 ;Write PLLDIV1, Enable DIV1 & SYSCLK1 = 200MHz || STW .D2 B6 , *B5 ;Write PLLDIV2, Enable DIV2 & SYSCLK2 = 100MH NOP 4 MVKL .S1 PLLDIV3 , A5 ; MVKH .S1 PLLDIV3 , A5 ;A5->PLLDIV3 || MVKL .S2 ALNCTL , B5 ; MVKH .S2 ALNCTL , B5 ;B5->ALNCTL || MVKL .S1 00008001H , A6 ; MVKH .S1 00008001H , A6 ;A6 = 00008001H || MVKL .S2 00000007H , B6 ; MVKH .S2 00000007H , B6 ;B6 = 00000007H STW .D1 A6 , *A5 ;Write PLLDIV3, Enable DIV3 & SYSCLK3 = 100MHz || STW .D2 B6 , *B5 ;Write ALNCTL, Set ALN1~3 NOP 4 MVKL .S1 PLLCMD , A5 ;SECTION: Initialize PLL GO Operation MVKH .S1 PLLCMD , A5 ;A5->PLLCMD || MVKL .S2 00000001H , B6 ; MVKH .S2 00000001H , B6 ;B6 = 000000001H STW .D1 B6 , *A5 ;GOSET = 1 NOP 4 MVKL .S1 PLLSTAT , A4 ;SECTION: Check The Status Of GO Operation MVKH .S1 PLLSTAT , A4 ;A4->PLLSTAT $2: LDW .D1 *A4 , A1 ;A1 = PLLSTAT NOP 4 [A1] B .S1 $2 ;GOSTATE = 1, Then Wait For The Complement Of GO Operation NOP 5 MVKL .S1 0000000AH , A1 ;SECTION: Wait For Reset Time (It is Supposed To Be More than 125nS) MVKH .S1 0000000AH , A1 ;A1 = 10 $3: [A1] B .S1 $3 ;As PLL is Bypassed, Right Now System Clock Cycle is 40 ns. 10*5*40ns = 2us [A1] SUB .L1 A1 , 1 , A1 ;A1-- NOP 4 MVKL .S1 PLLCSR , A5 ;SECTION: Retrive From Reset Of PLL MVKH .S1 PLLCSR , A5 ;A5->PLLCSR || MVKL .S2 00000040H , B6 ; MVKH .S2 00000040H , B6 ;B6 = 000000040H STW .D1 B6 , *A5 ;PLLRST=0, PLLEN=0, OSCPWRDN=0, PLLPWRDN=0, STABLE=1(Read-Only Bit) NOP 4 MVKL .S1 0002710AH , A1 ;SECTION: Wait For Lock Time Before Setting (It is Supposed To Be More than 187.5uS) MVKH .S1 0002710AH , A1 ;A1 = 10000 NOP 4 $4: [A1] B .S1 $4 ;As PLL is Bypassed, Right Now System Clock Cycle is 40 ns. 10000*5*50ns = 2.5 ms [A1] SUB .L1 A1 , 1 , A1 ;A1-- NOP 4 MVKL .S1 PLLCSR , A5 ;SECTION: Enable PLL, Initialization Of PLL Is Done MVKH .S1 PLLCSR , A5 ;A5->PLLCSR || MVKL .S2 00000041H , B6 ; MVKH .S2 00000041H , B6 ;B6 = 000000040H STW .D1 B6 , *A5 ;PLLEN=1, PLLRST=0, OSCPWRDN=0, PLLPWRDN=0, STABLE=1(Read-Only Bit) NOP 4 MVKL .S1 CFGBRIDGE , A5 ;SECTION: Reset BR2 As PLL Has Been Changed. Ref. TMS320C672x Datasheet Tb.3-1 P30 MVKH .S1 CFGBRIDGE , A5 ;A5->CFGBRIDGE || MVKL .S2 00000001H , B6 ; MVKH .S2 00000001H , B6 ;B6 = 000000001H STW .D1 B6 , *A5 ;CPSRST = 1 , Assert BR2 RESET NOP 4 ;***********************part1 end******************************** ;***********************part2:emif configuration***************** ;Initialize EMIF For Flash Access,including configuring the high-address pins which are connected to flash MVKL .S1 A1CR , A5 ; MVKH .S1 A1CR , A5 ;A5->A1CR, The Register Accouting For EMIF FLASH Device MVKL .S1 845224ADH , A6 ; MVKH .S1 845224ADH , A6 ;A6 = 845224ADH STW .D1 A6 , *A5 ;A1CR = 845224ADH NOP 4 MVKL .S1 MCASP0_PDIR , A5 ; MVKH .S1 MCASP0_PDIR , A5 ;A5->PDIR For AXR0 || MVKL .S2 MCASP0_PFUNC , B5 ; MVKH .S2 MCASP0_PFUNC , B5 ;B5->PFUNC ZERO .L1 A6 ;A6 = 0 || MVKL .S2 00003C1FH , B6 ; MVKH .S2 00003C1FH , B6 ;B6 = 00003C1FH STW .D1 A6 , *A5 ;PDIR = 0 , ALL AXR0 PINS ARE INITIALIZED AS INPUT PINS STW .D2 B6 , *B5 ;PFUNC = 00003C1FH , ARX0[0..4 , 10..13] ARE SET AS GPIO PUPURSE NOP 4 MVKL .S1 MCASP0_PDOUT , A5 ; MVKH .S1 MCASP0_PDOUT , A5 ;A5->PDOUT For AXR0 || MVKL .S2 MCASP0_PDIR , B5 ; MVKH .S2 MCASP0_PDIR , B5 ;B5->PDIR STW .D1 A6 , *A5 ;PDOUT = 0 STW .D2 B6 , *B5 ;PDIR = 00003C1FH, ACTIVATE OUTPUT FUNCTION ON PIN ARX0[0..4 , 10..13] NOP 4 ;prepare for the part3 || MVKL .S1 MCASP0_PDSET , A3 ; MVKH .S1 MCASP0_PDSET , A3 ;A3->PDSET || MVKL .S2 MCASP0_PDCLR , B3 ; MVKH .S2 MCASP0_PDCLR , B3 ;B3->PDCLR || MVKL .S1 0007C000H , A6 ; MVKH .S1 0007C000H , A6 ;A6= 0007C000H || MVKL .S2 00780000H , B6 ; MVKH .S2 00780000H , B6 ;B6= 00780000H ;***********************part2 end*********************************** ;***********************part3:copy codes from flash to ram******* MVKL .S1 user_ld_start , A4 MVKH .S1 user_ld_start , A4 ;A4->user_ld_start || MVKL .S2 user_size , B1 MVKH .S2 user_size , B1 ;A5->user_size ;B1 = Length Of user's codes Counting In Bytes || MVKL .S1 user_rn_start , A5 MVKH .S1 user_rn_start , A5 ;A5->user_rn_start $5: AND .L1 A4 , A6 , A7 ;A7.Bit14~18 = A4.Bit14~18, A7.Bitx(x!=14~18) = 0 || AND .L2X B6 , A4 , B7 ;B7.Bit19~22 = A4.Bit19~22, B7.Bitx(x!=19~22) = 0 SHRU .S1 A7 , 0EH , A7 ;A7>>14 || SHRU .S2 B7 , 09H , B7 ;B7>>9 OR .L1X A7 , B7 , A7 ;A7.Bit0~4 = A4.Bit14~18, A7.Bit10~13 = A4.Bit19~22, other bits of A7 are 0 NOT .L2X A7 , B7 ;B7 = !A7 || STW .D1 A7 , *A3 ;PDSET = A7 STW .D2 B7 , *B3 ;PDCLR = B7, These Two Instructions Acomplish The Updating Of The Upper Address LDHU .D1 *A4++ , A8 ; SUBAH .D2 B1 , 1 , B1 ;B1 -= 2 [B1] B .S2 $5 ;Copy is not Completed NOP 4 STH .D1 A8 , *A5++ ;Move Code From FLASH TO RAM NOP 4 ;***********************part3 end**************************************** ;***********************part4:run to the _c_init00 to initialise c environment MVKL .S2 _c_int00,B0 MVKH .S2 _c_int00,B0 B .S2 B0 NOP 5 ;***********************part4 end*****************************************         调试过程中有几个需要注意的地方:         1.配置PLLC时要严格遵守TI的官方手册:SPRU879A         2.对于EMIF的配置,只需配置A1CR寄存器,但是相关值的计算要查看EMIF文档和所选用flash文档AC characteristics部分         3.由于flash的高位地址与6722的GPIO相连,然而dsp并不知道你选了那个GPIO来寻址flash的高位地址,所以在每次访问flash时,都要先对GPIO引脚进行配置,也就是相应的引脚置0还是1。                    二次bootloader对GPIO进行配置就是这一小段代码          4.对于二次bootloader一开始的变量user_size:先不加二次bootloader这个.asm文件,在ccs中编译工程,然后查看.map文件查看编译之后所占用内存的大小,此值为字节数。然后user_size就等于这个值。当用户程序发生变化时,对于二次bootloader这个.asm文件需要改的也就是这个值。在工程里加入这个.asm文件,再编译工程。还有二次bootloader中的“  .sect ".boot_load"  ”要在.cmd文件中体现出来,附上.cmd文件截图:                   看到BOOT_RAM部分了吧,这一内存块只存放二次bootloader。  三、FLASH驱动程序         做完上面的工作我们就可以把程序下载到flash了,不过在这之前你要先确定flash擦除、读写都没问题。下载的方法我是参考的下面这篇博客:         http://blog.csdn.net/xiahouzuoxin/article/details/22621933         也就是,连上仿真器,把程序下载到芯片里,通过ccs保存相应地址的机器码,将bootloader程序以及用户程序分别保存到两个数组里,然后通过flash驱动程序下载到flash中。这个过程上面的那个博客写的很清楚,这里就不赘述了。         下面附上自己的flash驱动程序:           #include "boot.h" #include "user.h" #define FLASH_UL1 0xAA #define FLASH_UL2 0x55 #define FLASH_UL3 0x80 #define FLASH_UL4 0xAA #define FLASH_UL5 0x55 #define FLASH_PROGRAM 0xA0 #define McASP0PFUNC 0x0004 #define McASP0PDIR 0x0005 #define McASP0PDOUT 0x0006 #define McASP0PDIN 0x0007 #define McASP0PDSET 0x0007 #define McASP0PDCLR 0x0008 #define PLLCSR 0x0000 #define PLLM 0x0004 #define PLLDIV0 0x0005 #define PLLDIV1 0x0006 #define PLLDIV2 0x0007 #define PLLDIV3 0x0008 #define PLLCMD 0x000E #define PLLSTAT 0x000F #define ALNCTL 0x0010 volatile Uint16 *FLASH_5555 = (volatile Uint16 *)(0x90000000+(0x5555<<1)); volatile Uint16 *FLASH_2AAA = (volatile Uint16 *)(0x90000000+(0x2AAA<<1)); volatile unsigned int * EMIF_A1CR = (unsigned int *) 0xF0000010; volatile unsigned int * McASP0_ptr = (unsigned int *) 0x44000000; volatile unsigned int * pll_ptr = (unsigned int *) 0x41000100; volatile unsigned int * brideg_ptr = (unsigned int *) 0x40000024; Uint32 count; Uint32 read_data; void main ( void ) { pll_configuration(); printf (" Pllc configuration PASSED "); //********************************************************************* //configure the EMIF register EMIF_A1CR[0x0000]=0x845224AD; printf(" EMIF register configure OK "); //configure GPIOs McASP0_ptr[McASP0PDIR]=0x00000000;//default as input McASP0_ptr[McASP0PFUNC]=0x00003C1F;//GPIO function McASP0_ptr[McASP0PDOUT]=0x00000000;//desired output vaule,default 0 McASP0_ptr[McASP0PDIR]=0x00003C1F;//change to output after desired vaule is configured in PDOUT //erase flash memory Flash_Erase(0x90000000,0x10); printf(" Erase Flash OK"); //write flash memory Flash_Writes(0x90000000,0x0001);//16-bit parallel flash Flash_Writes(0x90000002,0x0000);//16-bit parallel flash printf(" Write Flash 16-bit parallel flash OK"); //Flash_Writem(0x90000004,0x10000000,0x120); //write second bootloader into the flash Flash_Writem_test(0x90000004,(Uint16 *)boot,0x1FE); //write second bootloader into the flash printf(" Write second bootloader into flash OK"); //Flash_Writem(0x90000400,0x10000400,0x1A34);//write user's codes to flash Flash_Writem_test(0x90000400,(Uint16 *)user,0x1A34);//write user's codes to flash printf(" Write user's codes into flash OK"); while(1) { } //********************************************************************** } /*flash erase function*/ Uint32 Flash_Erase(Uint32 addr,Uint16 type) { Uint32 j=1; Uint32 temp1=0x0007C000; Uint32 temp2=0x00780000; Uint32 temp3; Uint32 temp4; Uint32 temp5; temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555 = FLASH_UL1; //first temp3=0x90000000+(0x2AAA<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_2AAA = FLASH_UL2; //second temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555 = FLASH_UL3; //third temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555 = FLASH_UL4; //forth temp3=0x90000000+(0x2AAA<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_2AAA = FLASH_UL5; //fifth switch(type) { case 0x50 : break; case 0x30 : break; case 0x10: temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555=type; while((*FLASH_5555&0x80)!=0x80); break; default: break; } return(j); } /*write a single data*/ void Flash_Writes(Uint32 addr,Uint16 data) { Uint32 j=0; Uint32 temp1=0x0007C000; Uint32 temp2=0x00780000; Uint32 temp3; Uint32 temp4; Uint32 temp5; temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555 = FLASH_UL1; //first temp3=0x90000000+(0x2AAA<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_2AAA = FLASH_UL2; //second temp3=0x90000000+(0x5555<<1); temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *FLASH_5555 = FLASH_PROGRAM; //third temp3=addr; temp4=temp3&temp1; temp5=temp3&temp2; temp4=temp4>>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; *(Uint16 *)addr = data ; j=0; while(j<255) j++; //delay while(*(Uint16 *)addr != data); } /*write the certain length data*/ void Flash_Writem_test(Uint32 addr,Uint16 *ptr,Uint32 length) { Uint32 i; for(i=0;i>14; temp5=temp5>>9; temp4=temp4|temp5; temp5=~temp4; McASP0_ptr[McASP0PDSET]=temp4; McASP0_ptr[McASP0PDCLR]=temp5; return(*(Uint16*)addr); } /*read a certain length data*/ void Flash_Readm(Uint32 addr,Uint16 *ptr,Uint32 length) { Uint32 i; for(i=0;i            还记得前面说过每次访问flash时都要确定连接flash高位地址线的GPIO要确定好是置0还是1,驱动程序里已经体现出来了,自己看吧。         还要啰嗦句,第一部分说过ROM里的启动程序要先读取flash里第一个字节的最低两位来执行8位模式或是16位模式,所以要在0x9000 0000的位置写入0x0000 0001(我选的是16位)。在上面的驱动程序里,在0x9000 0000的位置写入0x0000 0001,然后将二次bootlader写在0x9000 0004起始位置处。虽然手册里没指定第一个字的最低两位之外的30位到底是写1还是0,我试过都写1,然后连上仿真器使其从0地址开始运行,模拟硬件启动,然后会发现,PC指针会卡在ROM启动程序里的一个死循环里。所以,写0x0000 0001,不要写0xFFFF FFFD。经验教训,读者也可以自己尝试一下,经历下折磨,能明白好多东西。         注意:要想在c程序里引用“NOP”指令,应该写为 asm("  NOP   4"),而不是asm("NOP   4")。第一个里NOP前面有空格,如果不添加空格,编译器会报错(单纯的NOP不会报错,“NOP   n”会报错)。
PS:         1.要想看看硬件如何启动,可以连上仿真器,让PC指针指向0x0000 0000,然后单步运行,看看其是如何工作的         2.保存程序的机器码时(我用的是CCS5.5),将程序下载到dsp中后,菜单栏会出现tool选项,tool->save memory,然后将机器码保存到.dat文档中         3.之前调试时,有个错误一直没找出来。后来发现由于这个错误,PC指针卡在了二次bootloader里的一个死循环里。我写二次bootloader后,先在仿真器环境下确保这段程序没问题之后,才往下做的,后来发现问题出在了二次bootloader的这个地方:                  看到第三行的“NOP   4” 了吧,之前我是没加的,然后仿真运行没问题,生成机器码,copy进flash之后,上电运行就变成了这样:                  看到指针指向的那一行了吧,应该是跳转到指针的下一行,但是每次他都跳转到指针所在行,致使A1始终为2,A1不为零时就跳转,所以就进入了一个无限死循环,出不来了。后来加上了第三行的“NOP   4” ,就好了。教训:MVK指令后若有跳转B指令,最好在之间加入几条空指令。
文章有些长,希望能给遇到相同问题的读者提供一些经验。