data/attach/1907/r1u6v8mu58bewj0zwg196b9bpbph41vr.jpgdata/attach/1907/p8au8mp3brkrv1qi0orr9fhrwg8hr3z9.jpg
序:
最近在调试TMS320C6722的Parallel Flash启动,大约调了两周左右(中间因为找不出错误原因,断了几天),最后调试成功。关于DSP的资料,网上多是关于2812和28335等C2000系列。关于C6000系列,C6713较多一些。所以在这里将C6722的调试过程以及中间遇到的一些问题写下来,希望能够为调试C6722的朋友们提供些帮助。
首先,说下我这里的配置:DSP主芯片为TMS320C6722, FLASH为:SST39VF6401,4M
16
因为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的4M
2=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指令,最好在之间加入几条空指令。
文章有些长,希望能给遇到相同问题的读者提供一些经验。