黄桂林 法律:ARM如何读写Flash

来源:百度文库 编辑:九乡新闻网 时间:2024/04/20 18:31:35

1.

我在ARM上裸机。 不使用任何嵌入式操作系统。

我的引导程序把我的程序放在 0x00000000,(这个地方是Flash) 在初始化的时候,我把代码区的所有代码copy到SDRAM里面去。然后跳到SDRAM( 0xc0000000 )里面去运行。此时我能否往 0x00000000及其后的address里面写数据?

2.

不可以,在Flash 中执行的代码不可以改写Flash的内容,你可以在SDRAM中写FLASH的内容。参考bolb和intel strongarm的dm 程序

3.

应该这样说,flash由于本身的技术原因,擦写过程中不能同时读。所以,你不能在运行(读代码)的同时去改写同一个flash芯片中的内容。但你说的跳到sdram中去运行并改写flash应该是可以的。

还有,flash的写操作不同于ram,是需要通过一系列的特定操作才完成的。这个你可以仔细看看flash芯片的手册,不同的芯片可能会有区别。blob中可以找到具体的程序例子参考。

4.

我就是要擦除Flash. 然后写Flash. 我现在是把代码全部copy到SDRAM里面去。然后跳到SDRAM里面去运行。我现在也已经这样做了。 但是我在SDRAM里面运行,而且要写Flash(包括读ID ) 的时候。系统运行就乱了。 可能产生了异常。我不知道这个怎么解决?

5.

如果你确认程序能够正确进入sdram运行了,最可能出问题的就是这段程序中的跳转语句。你的跳转是相对跳转还是绝对跳转?如果是绝对跳转,编译的时候编译器不会知道你以后会把程序挪地方,跳转的目的地址还是在flash中。这样就出错了

6.

Sorry, 前面说错了。是跳到SRAM里面。 不过差不多。

跳转到SRAM里面后,如果不操作Flash. 到目前为止,好像没有什么问题。都能正常运行。 但是只要操作Flash,就会死!

什么是相对跳转?? 什么是绝对跳转??

我用的指令是:

;;这儿是copy_rom_data

bl copy_romdata_to_sram

;; 这儿是跳转到sram 里面去。

ldr pc, =0x600000ac

7.

机器级b和bl指令有一个限制:跳转的范围在当前指令的+/-32Mb范围内。为什么?因为跳转的目的地是以当前的指令为起点的。这就是相对(于当前地址)的跳转。绝对跳转就是直接指定目的地址的跳转,比如你直接给pc赋一个立即数值,就是绝对跳转。你也可以用bx/blx Rm来实现绝对跳转。

我其实对arm指令不熟,你自己琢磨一下吧。我只是说明了一种容易出现的错误,希望对你有帮助。

8.

设置tlb表了么?

在打开mmu之前,把00000000物理地址映射到另外一个地址例如e0000000,然后打开mmu,对e0000000操作,就是对flash操作

9.

没有。 怎么设置TLB表? 能否给我一个sample code ?

10.

操作死机原因可能是:

1.在系统开始时,将Flash ROM 的映射属性设置为uncache和unbuffer.参考Windows CE的Source Code

2.连接时的数据段,代码段的地址是否正确.参考blob

3.数据段和bss段是已经初始化正确.参考blob

4.如果还是失败,初始化代码用Multi ICE 拷贝到 SDRAM中直接调试运行。

注意:

1.最好不要使用ARM 提供的集成开发环境

2.再看一边L7205的参考手册。

3.看原理图

4.看flash rom 的资料,如sst 、amd的源代码

11.

你的中断向量怎么处理的?有没有把中断向量映射到你的SRAM中去?

12.

因为程序运行中我不修改任何中断向量. 我需要映射到SRAM去吗?

----------------

不是说你是否修改中断向量,而是说在你的代码工作过程中会不会产生中断

----------------

我的代码在工作过程中 不产生中断。因为我屏蔽了!

如果产生中断会怎么样?

---------------

如果发生中断,那么cpu会去中断向量表中访问相应的中断向量并执行,而此时你的Flash处于写状态

13.

只要写Flash. 程序就不知道跑到什么地方去了。 我用的是Sharp的Flash. 读厂家的ID 命令是 0x90. 写这个命令时,就发生错误了。表现为程序没有继续运行下去。因为Flash位于0x0000000。

14.

你是否使用L7200或是L7205,如果是请注意,SRAM的大小和你的代码大小

15.

我用的是Cirrus Logic EP7312. 我的代码大小没有超过SRAM的大小不到5K

16.

她的看法跟我一样,你很可能有绝对跳转的指令,使得你的程序运行到中途又跳回到flash中去了。

把你的代码贴出来看看。应该不长吧。

你用了blob吗?

17.

中途跳转到Flash中去了??? 但是如果我把读Flash ID这段代码注释掉. 程序运行很正常阿!? 看看我这段代码:

下面这段是初始化中的程序片断:

。。。。。。。。。。

IMPORT Move_Program

BL Move_Program

ldr pc, =0x600000b8 ; 跳到C的入口处。

.........................

下面一段代码是读Flahs的ID的函数:

void CheckFlash(void)

{

unsigned long* addr = (unsigned long*)0x00000000;

unsigned long MID;

unsigned long DeviceID;

*addr = 0x00900090;

MID = *addr;

if( MID == 0x00B0000B )

{

//display Manufacture ID

}

addr+=2;

DeviceID = *addr;

if( DeviceID == 0x00D000D0 )

{

// display "Device ID"

}

}

下面的代码是复制程序到 SRAM.

void Move_Program(void)

{

unsigned long* rom_adr=(unsigned long*)0x00000000;

unsigned long* ram_adr=(unsigned long*)0x60000000;

int i;

int rom_size;

rom_size = (int)(rom_data_base-0x00000000);

for( i=0; i

{

*ram_adr++ = *rom_adr++;

}

}

18.

BL Move_Program

這句可是要返回到flash中的

--------------

这条指令( BL Move_Program ) 当然回到Flash. 他的下条指令 : ldr pc, =0x600000b8 才是真正转到SRAM里面去执行。

-------------

19.

你在进入c代码后到读flash之前都做了那些事?

另外你可以试试能不能从flash中直接读数据?

20.

在读flash前,我做了LCD的初始化和相关的测试。 另外我可以直接读flash中的数据(包括程序代码等等)。

21.

MID = *addr;

if( MID == 0x00B0000B )

{

//display Manufacture ID

}

上面这段能显示出来吗?(应该可以吧)

addr+=2;

这里,地址+2,好象不对吧,你的可是32位数据总线啊

DeviceID = *addr;

if( DeviceID == 0x00D000D0 )

{

// display "Device ID"

}

}

我想这里就飞了吧

给你一段读的代码

WRITE_FLASH(0x00000000,0x00980098);

OffSet=0x10<<2;

ReadData=READ_FLASH(0x0+OffSet);

//属性Q

OffSet=0x11<<2;

ReadData=READ_FLASH(0x0+OffSet);

//属性“R“

OffSet=0x12<<2;

ReadData=READ_FLASH(0x0+OffSet);

//属性"Y“

22.

MID = *addr;

if( MID == 0x00B000B0 )

{

//display Manufacture ID

}

到这儿根本无法显示!!

下面这个你说得对。

可以改成 : addr++; addr++;

23.

你用的什么编译器?

unsigned long是多少位的?

还有,你确定你的CPU的MID是0x00B000B0?

最后,你用什么显示ID的,最好用串口,如果是LCD的话,

可能是显示语句造成的错误

---------------------------

我用ARM SDT 2.50.

unsigned long 是32Bit. unsigned int 也是 32Bit.

不是CPU 的MID. 是Flash的 Manufacture ID . 我确信 它是:

0x00B000B0

我用LCD显示ID. 显示驱动是我自己写的。能正常显示。

24.

把check_flash的汇编代码贴出来。c程序里面看不出具体有了什么跳转方式。

举个例子:(用的是伪代码)

jump 0x00000300

这样一句语句不管你把它拷贝到哪里,他都一定会执行到0x300这个地址去的.如果你的程序中有这样的跳转,因为编译的时候编译器不知道你会把它拷贝到别的地方,必然填充的是当前程序段内的地址.而这个地址不会随着你的代码的搬移而改变.那么执行到这一句的时候就又跳回去了.

代码本身是没错的,错就错在它是不可移动的.

25.

我的Check_flash本来就是用C写的。 因为我只是想简单测试一下在我把ROM CODE搬到SRAM区后,能否操作Flash.

所以就那么简单。

我想在编译连接阶段不会把具体的段地此也放在最后的代码中。它总是在运行的时候把所在段的地址和它相加就是了。如果真的像你所说,那么我前面的代码(在操作Flash之前)一定不能运行。但是实际情况正像我所料。我的LCD能工作。我的蜂鸣器能响。我的LED能闪烁。

26.

你还是没有懂我的意思.

只要你的sram中能运行程序,它就可以写flash.

如果不能,一定是你的程序出了问题.最常见的就是真正的"自己写自己".因为编程时,flash的状态不是普通的读状态,所以处理器读不到程序代码,当然就出错了.

如果你做的都是对的,那么为什么会出错呢?

你说过,你是在没有操作系统的裸机上运行的,那么你的代码一定不是一个可执行程序,而是真正的机器代码段.除了程序自己,没有人会帮他设置什么运行时的段地址的.

没有绝对跳转的程序是可以移动的,有绝对跳转的程序是不可移动的.

27.

你的意思是怀疑我的程序是否真的在SRAM里面运行? 还是怀疑我的Check_Flash有问题?

1)。 在Flash里面运行程序和在SRAM运行程序的速度是有很大差别的。 可以从运行的情况可以看出来。这点基本可以确定程序真的在SRAM运行。(否则也无法逾越这条指令:

ldr pc, =0x600000b8 )

2)。Check_Flash 真的有问题吗? 我真的是用C写的。

我再检查他编译以后的汇编代码看看。

28.

那,下面就是用armcc 编译产生的asm代码。

====================================

CheckFlash

MOV a2,#0x90

ADD a2,a2,#0x900000

MOV a1,#0

STR a2,[a1,#0]

MOV a2,#0

ADD a3,pc,#L000198-.-8

B LCDDrawStr

L000198

DCB "Unkn"

DCB "ow F"

DCB "LASH"

DCB " DEV"

DCB "ICE\0"

===================================

注意。我把检查设备ID的那部分注释掉了。

从这个代码看,好像也没有问题。 你说呢?

29.

CheckFlash

MOV a2,#0x90

ADD a2,a2,#0x900000

MOV a1,#0

STR a2,[a1,#0]

如果在flash中执行,那么这一句之后,程序代码就读不到了,也就是程序飞掉了.

MOV a2,#0

ADD a3,pc,#L000198-.-8

B LCDDrawStr

L000198

DCB "Unkn"

DCB "ow F"

DCB "LASH"

DCB " DEV"

DCB "ICE\0"

如果你的LCD显示是正常的.你试试在这段程序开头的地方把PC的值显示出来,看看是不是在flash中运行.

30.

MID = *addr;

if( MID == 0x00B000B0 )

{

你在这里用串口先显示一下PC的值,看他是在Flash还是

sdram里面,最好然后延时一会,看看效果

//display Manufacture ID

我怀疑调用你的显示函数时候,回到Flash里面去了,如果可以,

在你的显示函数里面,也从串口输出PC的值,看看是在flash

还是sdram里面

}

31.

我不知道你的编译器,不过象gcc的,c的函数名通常在汇编中看到的是加前缀_的c函数名. 象Move_Program的c函数,在汇编中是看不到的。在gcc中是在Move_Program前加asmlinkage。

32.

我调试过,我用LCD显示出PC. 请看:

在这个语句"*addr = 0x00900090" 之前, PC都正常。显示结果为SRAM里面的地址(0x60000278), 但是如果一执行这个语句之后,PC 无法显示出来了(就是我调用了显示函数,但没有显示)。但是好像又能跑!因为LED在闪烁。(注意在这条语句之后,我加了LED 闪烁功能,以证明程序在跑 ) 很奇怪。

33.

那就是你的显示函数有问题啦,不是程序跑飞了。

你再仔细查查看具体的错误出现在什么位置上吧。

你不是有指示灯吗,在显示函数的入口处加入PC的检查代码,看看PC是在什么范围,比如,在sram就熄灭指示灯,在flash中就点亮指示灯。

34.

谢谢各位! 我明白了。 哈哈~~~~~~~

原来是那些全局变量(字库)的地址还没有变。怪不得,在我写0x00000000之前,程序仍然访问的是Flash里面的ROM DATA. 然后在写0x00000000后, 此时Flash的读写状态发生变化,可是程序仍然要访问Flash里面的ROM DATA. 这个时候问题就出来了。因为这个时候Flash可能无法正确读出ROM DATA. 所以LCD Driver无法正确拿到字库,因此无法正确显示。因此可能作如下修改就可以拉:

LCD Driver在使用绝对地址(就是 0x60000000 + 偏移 )

但是这样的话如果全局变量很多的话,或者有静态变量的话,就非常麻烦了。 有什么办法解决吗??

有劳各位了。 真的非常感谢各位。 给了很多提示和启发。

再次谢谢。 :-)

35.

但是这样的话如果全局变量很多的话,或者有静态变量的话,就非常麻烦了。 有什么办法解决吗??

可以用PIC,也就是动态连接库使用的技术,我记得ppcboot用这种方法实现从Flash搬到RAM后,只要作简单的修补(Fixup),就可以在RAM中执行。

更简单的方法是把全局变量放到一个结构中,程序移动后调整结构指针就可以了。

36.

1.尽量用局部变量。

2.改写ld的参数(一般在makefile中,或者有一个单独的ldscript),把代码的起始地址改成你将要把它复制过去的那个sram中的地址。

37.

OK. Very good.

我测试过了。可以改 -ro-base xxxxxx。

成功。

谢谢。