我的开发板是s3c44b0x的, 2m NOR FLASH在bank0,8m sdram在bank6.首要看看咱们要处理的问题。有些ARM芯片有内嵌的RAM 和FALSH.这样能够直接在片内运转程序,44B0X片内只要几K CACHE,ROM和RAM都是外接的芯片。咱们的程序是要写入FLASH中保存,但碑文时是拷到SDRAM中碑文的(如在ROM中碑文速度会较慢)。要做到这一点需求把程序做成两个分程序:一个是完结你的体系功用的主程序,假如你用嵌入式体系,那便是UCOS和UCLINUX之类的程序,这个程序的代码保存在FLASH中,但碑文时会拷到RAM中再碑文;一个是引导程序,直接在FLASH中碑文,担任把初始化芯片和外设,并把主程序从FLASH中拷到 RAM中,然后跳到主程序去碑文,对应的概念是UBOOT等常见的引导程序,这个程序会被写入0X0开端的地址,开机后主动碑文。
那么咱们需求处理以下几个问题:
1.怎样编译和调试主程序
2.怎样使中止跳到RAM中的中止服务程序碑文
3.怎样把引导程序和主程序写入FLASH中.
以下咱们来处理这几个问题:
1 开端在仿真器中写代码和调试
咱们主程序会被拷贝到RAM中碑文,则咱们应该在编译时就把程序定位到RAM中。这儿先要说说几个ADS的参数的含义,在ADS的ARM LINKER页有RO,RW两个参数,此外还有一个ZI没有在页中给出,RO是只读代码的开端地址,由这个地址开端寄存编译出来的程序指令;RW是程序的读写段的开端,即你程序中的数据寄存的开端地址,ZI紧跟在RW区后,ZI区寄存的是需求在程序运转时初始化为0的数据。
了解这几个链接参数的含义后咱们能够设置这几个参数了:关于我的44B0X板8M SDRAM在0XC00_0000.因而在开发时把ADS中的RO BASE的地址指定为0XC00_0000;置于RW,在程序完结前能够预先估量一下程序的体积有多大,需求用到的数据区有多大,防止数据区太小或代码区覆盖掉前面的数据区便是了,我用了0XC10_0000,1M的代码空间,其他作数据区。这样,咱们编译出来的程序代码便是在0XC00_0000中,能够直接由仿真器写入RAM中运转仿真运转。此外,在linker-〉layout页有个object symbol和section的选项,要求你填入映像文件最开端的object文件名和段名,这两个参数在仿真时不填写也不会影响运转,咱们仿真器会主动修正pc指针,但要树立能烧写的映像文件,则一定要填写好,具体填写什么后边剖析程序时再讲。
2中止问题
和一切单片机相同,ARM复位后从地址0X0开端碑文,而0X0后是一串默许的中止向量表。对51这样的芯片,咱们会直接在这个中止向量表中填入跳转查办,让它跳到指定的ISR处理中止事情。咱们咱们的主程序是在RAM中碑文的,编译时又和引导程序分隔,不可能预先知道咱们写的ISR具体地址,而预留的中止向量表只够每个中止一个跳转指令,因而咱们需求做二次跳转。在内存中树立一个中止向量表,每个中止对应一个字,寄存ISR的地址。此后,对每个中止写一段短的代码,把ISR地址取出,填入PC。而0X0后边中止向量的跳转指令,则是跳到这小段程序中。
3烧写flash,ADX中好像有个写入flash的选项,我自己没有具体用过。但传闻用jtag写flash会比较慢。咱们nor flash或nand flash都是能够编程烧写的,即咱们能够写个程序擦写flash,问题是怎样读取编译出来的映像文件。这个也不必忧虑,adx中有个菜单把文件内容写入指定的地址中,把影响文件指定到一个ram地址,然后就用烧写程序把ram的内容拷入rom中便是了。咱们有个boot程序,一个主程序要映射到rom 中.假定我把0xc20_0000开端的2m地址作rom的映像,则把boot程序导入0xc20_0000,boot的程序十分短,在 0xc20_1000开端放主程序。然后把0xc20_0000到0xc40_0000的内容悉数拷入rom中(当然在导入文件前这些ram应该先被清空或写入ff.)。
让咱们来看看相关的代码,具体认识一下该怎样处理前面说的这些问题,还有别的的一些问题。这儿运用的代码是在44b0x的application note的第三章中拿出来的,这个文件在网上应该很简略找到。
程序的进口在44binit.s汇编文件中,其间一个Init 段是整个程序的进口:
AREA Init,CODE,READONLY
ENTRY
b ResetHandler ;for debug
b HandlerUndef ;handlerUndef
b HandlerSWI ;SWI interrupt handler
b HandlerPabort ;handlerPAbort
b HandlerDabort ;handlerDAbort
b . ;handlerReserved
b HandlerIRQ
关键字ENTRY告知编译器保存这段代码。从代码看INIT段便是要写入0X0地址的原始中止向量,因而把这个文件编译生成的44BINIT.O和 INTT填入上面说到的LAYOUT页对应项中。这样编译器会把该段代码编译到0X0地址。(仿真时你能够试试别填这两个项目,看看ADX中的反汇编代码进口被放到哪里)。
这段代码里除了reset句外,有每句都有一个HandlerXXX的标号,这便是前面说到的中止处理程序的进口,它是由前面的一个宏来界说的:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0}
;PUSH the work register to stack(lr doest push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
我自己没有写过宏,所以仍是看编译出来的代码比较直接:
HandlerSWI
0x0c000198: e24dd004 ..M. SUB r13,r13,#4
0x0c00019c: e92d0001 ..-. STMFD r13!,{r0}
0x0c0001a0: e59f0458 X… LDR r0,0xc000600
0x0c0001a4: e5900000 …. LDR r0,[r0,#0]
0x0c0001a8: e58d0004 …. STR r0,[r13,#4]
0x0c0001ac: e8bd8001 …. LDMFD r13!,{r0,pc}
这是ads输出的汇编代码,便是方才的宏对应swi的一个实例,其间有两句
LDR r0,0xc000600
LDR r0,[r0,#0]
是把0x0c000600的内容载入r0,再把r0地址的ram单元载入r0.去看看0xc000600的内容,是0X0c7fff08,这是我设定的内存中的中止向量表地址之一,中止向量表的开端地址是0X0c7fff00,因而0X0c7fff08寄存的刚好便是swi的isr地址。后边程序就跳到对应的ISR去了。(这段宏程序咱们我不熟悉arm的汇编,只看过它怎样碑文,真实我不知道中止向量表地址是怎样被放入0x0c000600等地址的。期望有高手能再具体解说一下具体的编写,编译办法和原理。)
在c程序中,咱们需求给每个中止向量界说一个宏:
#define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x08))
_ISR_STARTADDRESS是开端地址0X0c7fff00,假定ISR是以下函数:
void __irq SWI_UserIsr(void){……………}
则在体系初始化时用pISR_EINT0=(unsigned)SWI_UserIsr;这样的查办把ISR的地址填入中止向量表中,对一切中止作相同的处理,然后开中止,体系就能经过上面的宏把跳到ISR碑文。
44binit.s中还有几段值得留心的代码:以下的代码把rw段的数据拷入ram中,并初始化zi段,即把该段清零:
LDR r0,=|Image$$RO$$Limit|
LDR r1,=|Image$$RW$$Base|
LDR r2,=|Image$$ZI$$Base|
CMP r0,r1
BEQ %F1
0 CMP r1,r3
LDRCC r2,[r0],#4
STRCC r2,[r1],#4
BCC %B0
1 LDR r1,=|Image$$ZI$$Limit|
MOV r2,#0
2 CMP r3,r1
STRCC r2,[r3],#4
BCC %B2
来看反汇编的代码:
0x0c000ae0: e59f0194 …. LDR r0,0xc000c7c
0x0c000ae4: e59f1194 …. LDR r1,0xc000c80
0x0c000ae8: e59f3194 .1.. LDR r3,0xc000c84
0xc000c7c,开端的三个字的内容是:
0x0c000c7c: 0c000e10 …. DCD 201330192
0x0c000c80: 0c200000 .. . DCD 203423744
0x0c000c84: 0c200000 .. . DCD 203423744
0x0c000c88: 0c200004 .. . DCD 203423748
这些反汇编的代码是一个点led的程序的,能够看出我的小程序代码到0x0c000e10就完毕了,0x0c200000是我指定的数据区开端地址。这段程序把|Image$$RO$$Limit| 开端的,长|Image$$ZI$$Base| -|Image$$RW$$Base| 的数据区拷到|Image$$RW$$Base|的对应单元,便是0x0c200000开端的一段ram中。后边还有|Image$$ZI$$ Limit|,在我的代码中是0x0c000c88,内容是0x0c200004.这其实标明我的小程序并没有rw区,只要一个初始为0的变量。
别的还有一段初始化ram操控器的代码:
;****************************************************
;* Set memory control registers
;****************************************************
ldr r0,=SMRDATA
ldmia r0,{r1-r13}
ldr r0,=0x01c80000 ;BWSCON Address
stmia r0,{r1-r13},
咱们44b0x要求13个操控寄存器要一次完结填入,所以先把参数设定在SMRDATA的地址中,一次载入通用寄存器,在一次填入RAM操控寄存器中。 4510的书上介绍调试前需求用SEMEM指令设置这些寄存器,但我自己没有那么做也能够跑的很好,也许是默许现已用了最保存的装备的原因吧!
其他的代码解说比较明晰了,最终摘出我的LED程序和这个小程序的BOOT程序以及烧写程序。这几个程序的project都包含了 44binit.s, option.s, memcfg.s,option.h,44b.h几个从app note中抄来的文件,这儿只列了我自己写的首要c代码。其他这些文件我除了把ram和rom的对应装备改了一下外,都没有改动。我的引导程序编译出来是 3k,led程序也是3k,因而我把他们别离定位在rom的0x0和0x2000处,总共写了8k。
LED程序中的44BINTT.S程序功用和LOAD中的44BINTT.S是重复的,首要是我懒得去修正这些汇编,由着他们占用一点时刻吧!
load程序担任把从0x20000处开端的4k程序(即led程序)拷到ram 0xc000000中,run函数把pc指到0x0c000000,开端碑文led程序:
void (*Run)(void) = (void (*)(void))RAM_ADDR;
void Main(void)
{ INT32U k ;
INT32U *pulSource = (INT32U*)0x2000,;
INT32U *pulDest = (INT32U*)0x0c000000;
rSYSCFG=CACHECFG;
PortInit();
for(k=0;k<2000> *pulDest++ = *pulSource++;
Run();
}
led程序把两个通用io上连的led作不断的亮和灭:
void Main(void)
{ INT32U k ;
//INT16U *ptr;
rSYSCFG=CACHECFG;
PortInit();
while(1)
{
LedDisp(0);
for(k=0;k LedDisp(3);
for(k=0;k }
}
最终是烧写的程序,具体的代码网上高手们写了不少,我仅仅给出最简略的完结。烧写时当程序碑文到清理完0X0C30_0000到0X0C30_4000的 RAM后,让程序中止下来,经过LOAD MEMORY FORM FILE指令把LOAD.BIN导入0X0C30_0000,LED.BIN导入0X0C30_2000中,持续运转程序直到一个LED亮起,烧写就完结了。拔去仿真器后再上电,能够看到两个LED一起亮灭。
#include “option.h”
#include “44b.h”
#include “def.h”
//#include “romdef.h”
//#include “stdio.h”
//#include “stdlib.h”
   #define FLASH_START_ADDR 0X0000
#define FLASH_ADDR_UNLOCK1 0X5555
#define FLASH_ADDR_UNLOCK2 0X2AAA
#define FLASH_DATA_UNLOCK1 0XAAAA
#define FLASH_DATA_UNLOCK2 0X5555
#define FLASH_DATA_WRITE 0XA0A0
#define FLASH_ERASE 0X8080
#define FLASH_ERASE_SECTOR 0X3030
#define FLASH_ERASE_BLOCK 0X5050
#define FLASH_ERASE_CHIP 0X1010
#define FLASH_SID_QUERY 0X9090
#define FLASH_CFI_QUERY 0X9898
#define FLASH_SID_EXIT 0XF0F0
#define FLASH_OP_TIMEOUT 0Xffff
   #define LED_PORTC10 (1 #define LED_PORTC11 (1 #define RAM_ADDR 0xc000000
void (*Run)(void) = (void (*)(void))RAM_ADDR;
void infoFlash(void);
int wait_flash_ready ( INT16U *address, INT16U data );
int writeFlash(INT16U *Address,INT16U Data);
int eraseSector(INT16U* SectorAddr);
int eraseChip(void);
   void PortInit(void);
void LedDisp(int LedStatus);
   //*****************************************
// FLASH WIRTING
//*****************************************
void Main(void)
{ INT32U k ;
INT16U *pdist,*psrc;
rSYSCFG=CACHECFG;
PortInit();
//infoFlash();
eraseChip();
psrc=(INT16U *)0xc300000;
for(k=0;k<0x4000> *psrc++=0x0; //clear ram
psrc=(INT16U *)0xc300000;
pdist=(INT16U *)0x0;
for(k=0;k<0x4000 k ram to> writeFlash(pdist++,*psrc++);
while(1)
{
LedDisp(0);
for(k=0;k LedDisp(2);
for(k=0;k }
}
  
//*****************************************
// init the port
//*****************************************
void PortInit(void)
{
   rPDATC = 0xffff; //All IO is high
rPCONC = 0x0f55ff54;
rPUPC = 0x3000; //PULL UP RESISTOR should be enabled to I/O
}
   //*****************************************
// light led
//*****************************************
void LedDisp(int LedStatus)
{
if((LedStatus&0x01)==0x01)
rPDATC &= (~LED_PORTC10); //LED ON
else
rPDATC |= LED_PORTC10; //LED OFF
if((LedStatus&0x02)==0x02)
rPDATC &=(~LED_PORTC11); //LED ON
else
rPDATC |=LED_PORTC11; //LED OFF
}
   //*****************************************
// show the flash soft id
//*****************************************
void infoFlash()
{
int i,j;
INT16U *pFlash;
*((volatile INT16U *)FLASH_START_ADDR)=FLASH_SID_EXIT;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_SID_QUERY;
for(i=0;i pFlash=FLASH_START_ADDR;
i=0;j=0;
i=(INT16U)*pFlash++;
j=(INT16U)*pFlash;
}
//*****************************************
// erase hold flash
//*****************************************
int eraseChip()
{
*((volatile INT16U *)FLASH_START_ADDR)=FLASH_SID_EXIT;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_ERASE;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_ERASE_CHIP;
if( wait_flash_ready((INT16U *)FLASH_START_ADDR,0xffff) )
return 1;
else return 0;
}
   //*****************************************
// write one falsh word( 16bit)
//*****************************************
int writeFlash(INT16U *Address,INT16U Data)
{ *((volatile INT16U *)FLASH_START_ADDR)=FLASH_SID_EXIT;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_UNLOCK1;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK2)=FLASH_DATA_UNLOCK2;
*((volatile INT16U *)FLASH_START_ADDR+FLASH_ADDR_UNLOCK1)=FLASH_DATA_WRITE;
*Address=Data;
if(wait_flash_ready(Address,Data))
return 1;
else return 0;
}
   //*****************************************
// wait for operation finish
//*****************************************
int wait_flash_ready ( INT16U *address, INT16U data )
{
INT32U tmp;
INT16U *p;
tmp =0xff;
p=address;
while(((*p)&0x8080)!=(data&0x8080))
{tmp–;
if (tmp==0x0)
return 1; // timeout
}
return 0;
}
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/fpga/264286.html