加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Arm 2440——Nand flash启动模式详解(LED程序为例)

发布时间:2020-12-15 17:40:13 所属栏目:百科 来源:网络整理
导读:Arm 2440——Nand flash启动模式详解(LED程序为例) 断断续续的研究arm也有2个月了,现在才感觉理解了arm在Nand flash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说,趁着还没有忘记学习过程中的感受,直接进入正题。 大家都知道

Arm 2440——Nand flash启动模式详解(LED程序为例)


断断续续的研究arm也有2个月了,现在才感觉理解了arm在Nand flash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说,趁着还没有忘记学习过程中的感受,直接进入正题。

大家都知道,arm在Nand flash启动模式下启动时系统会将Nand flash中的前4KB代码拷贝到SRAM(也就是Steppingstone中),由SRAM配置中断向量表和完成Nand flash访问的必要初始化,然后将Nand flash中的全部程序代码拷贝到SDRAM中,最后由SRAM跳转到SDRAM,然后程序就正常执行了,这一过程看上去很简单,但是真正理解这一过程还是不简单的,尽管这样,还是想告诉大家仔细理解还是比较容易理解这个过程的。如果您是ADS用户,你省去了很多麻烦,但我不确定你省去的这些麻烦是否值得,这里介绍的是一种麻烦的方式,linux下的led程序。

代码Head.s

[html]? view plain copy

在CODE上查看代码片

派生到我的代码片

  1. .extern?main??
  2. .text??
  3. .global?_start??
  4. _start:??
  5. ????b?reset??
  6. ??
  7. reset:??
  8. ????ldr?sp,=4096??
  9. ????bl?disable_watch_dog??
  10. ????bl?clock_init??
  11. ????bl?memsetup??
  12. ????bl?copy_steppingstone_to_sdram??
  13. ????ldr?pc,=on_sdram??
  14. on_sdram:??
  15. ????msr?cpsr_c,#0xdf??
  16. ????ldr?sp,=0x34000000??
  17. ????ldr?lr,=halt_loop??
  18. halt_loop:??
  19. ????b?halt_loop??

我认为,最需要理解的就是这段代码了。先简单的解释下这段代码。

(1)由于arm执行reset之后pc会被清零,也就是reset中断的中断入口地址,因此,第一条指令就是b reset,跳转到reset中断处理函数。

(2)由于这里硬件配置都是C语言来完成的,而且我们的初始代码比较小,完全不会超出4KB,因此可以在SRAM使用堆栈,故将SP设置为4096,以提供C运行环境

(3)接下来的3个bl分别完成了关闭看门够定时器,配置时钟信号和存储器配置的工作,第四个bl是将SRAM的4KB空间内的代码拷贝到了SDRAM中。

(4)接下来的ldr句将pc赋值为on_sdram的地址,实现了从SRAM到SDRAM的跳转(下面会讲为什么)

(5)on_sdram中切换到了了系统模式然后分配了系统模式堆栈,将链接寄存器设置为halt_loop然后就跳转到了SDRAM中的Main

上面的解释只是大体上说明了代码的意思,但是初学者总会有个疑问就是为什么ldr pc,=on_sdram就实现了从SRAM到SDRAM的跳转呢?我被这个问题困扰了很长时间,到今天才想明白了这个问题,问题的关键就是相对跳转和绝对跳转的问题。为了说明这个问题我先解释一下bl指令跟ldr指令在执行过程中的区别。

B指令是相对跳转指令,B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间),同样的,BL、BX都是相对跳转。

LDR伪指令是将第二操作直接赋值给第一操作数,当执行ldr pc,=Main时是将Main的绝对地址赋值给了PC。

好了,知道这两个指令的区别之后我们来看代码是如何实现的从SRAM到SDRAM的跳转,首先需要指出,2440的开发板有SRAM和SDRAM,SRAM是从地址0x00000000开始的4KB内存空间,SDRAM是从0x30000000开始的64M空间。

无论用ADS编译还是用arm-linux-gcc编译都会将代码链接到0x30000000以后(也就是SDRAM中),ADS用户可以通过查看ADS的工程配置,其中有项配置是RO起始地址是0x30000000,linux用户在链接时需要用-T指定代码的其实地址为0x30000000。

根据编译原理,在链接阶段程序中函数的地址就已经确定了,也就是说函数的实际地址都在0x30000000之后,而程序的入口函数也就是这里的_start的地址就是0x300000000,其他函数都会大于这个数。

但是由于arm上电后系统会将Nand flash的前4KB代码拷贝到SRAM中,也就是_start函数开始的4KB指令将被拷贝到SRAM中执行,根据上例,在0x00000000处执行的指令就是“b reset”,由于b是相对跳转,是在当前pc值的基础上加减某个数而跳转到将要执行的代码处,因此,pc加减该数之后将到达reset函数的位置,故reset函数不能写到4KB之外的空间中,否则arm的启动将会失败,同样的,接下来的几个bl都是执行的相对跳转,所以都相对当前pc进行的跳转,由于Nand flash总共只有64M的空间,所以相对跳转是不可能会跳转到SDRAM的,因为跳转到SDRAM至少要发生0x30000000的跳转,而这个相对位移远远大于64M。

而ldr pc,=Main是将Main函数的实际地址赋值给pc,而Main的实际地址是在0x30000000之后,这样,就从SRAM跳转到了SDRAM。

由于这个过程设计到了硬件格局和编译原理,所以对一般人来讲,理解起来确实比较困难,而且受本人水平限制,很多地方只能说是只可意会不可言传,如果误导了大家请大家谅解。当然如果看到这里还不能理解arm的启动过程可以留言讨论这个问题。下面是相关的其他代码,我附在这里,2440addr.h没有贴出,由于我也是使用arm自带示例程序中的代码,而且代码有四千多行,多数地址是没有用到的。其他的代码如下

代码Init.s

派生到我的代码片

    #include?"2440addr.h"??
  1. void?disable_watch_dog(void);??
  2. void?clock_init(void);??
  3. void?memsetup(void);??
  4. void?copy_steppingstone_to_sdram(void);??
  5. void?inituart(void);??
  6. void?disable_watch_dog(void)??
  7. {??
  8. ????rWTCON?=?0;??
  9. }??
  10. ??
  11. void?clock_init(void)??
  12. {??
  13. ????rCLKDIVN??=?0x03;??
  14. ????/*??
  15. ?????*如果HDIVN非0,CPU的总线模式应该从??
  16. ?????*“fast?bus?mode”变为“asynchronous???
  17. ?????*bus?mode”??
  18. ?????*/??
  19. ????__asm__(??
  20. ????????????"mrc????p15,?0,?r1,?c1,?c0,?0n"??
  21. ????????????"orr????r1,?#0xc0000000n"??
  22. ????????????"mcr????p15,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px"> ???????????);??
  23. ????rMPLLCON?=?(92<<12)|(14)|(2);??
  24. ????//rMPLLCON?=??((0x5c12)|(0x014)|(0x02));??
  25. }??
  26. void?memsetup(void)??
  27. ????volatile?unsigned?long?*p?=?(volatile?unsigned?long?*)0x48000000;??
  28. ????/*?这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值??
  29. ?????*?写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到??
  30. ?????*?SDRAM之前就可以在steppingstone中运行??
  31. ????/*?存储控制器13个寄存器的值?*/??
  32. ????p[0]?=?0x22011110;?????//BWSCON??
  33. ????p[1]?=?0x00000700;?????//BANKCON0??
  34. ????p[2]?=?0x00000700;?????//BANKCON1??
  35. ????p[3]?=?0x00000700;?????//BANKCON2??
  36. ????p[4]?=?0x00000700;?????//BANKCON3????
  37. ????p[5]?=?0x00000700;?????//BANKCON4??
  38. ????p[6]?=?0x00000700;?????//BANKCON5??
  39. ????p[7]?=?0x00018005;?????//BANKCON6??
  40. ????p[8]?=?0x00018005;?????//BANKCON7??
  41. ????/*?REFRESH,??
  42. ?????*?HCLK=12MHz:??0x008C07A3,??
  43. ?????*?HCLK=100MHz:?0x008C04F4??
  44. ?????*/???
  45. ????p[9]??=?0x008C04F4;??
  46. ????p[10]?=?0x000000B1;?????//BANKSIZE??
  47. ????p[11]?=?0x00000030;?????//MRSRB6??
  48. ????p[12]?=?0x00000030;?????//MRSRB7??
  49. void?copy_steppingstone_to_sdram(void)??
  50. ????unsigned?int?*pdwSrc??=?(unsigned?int?*)0;??
  51. ????unsigned?int?*pdwDest?=?(unsigned?int?*)0x30000000;??
  52. ????while?(pdwSrc?<?(unsigned?int?*)4096)??
  53. ????{??
  54. ????????*pdwDest?=?*pdwSrc;??
  55. ????????pdwDest++;??
  56. ????????pdwSrc++;??
  57. ????}??
  58. }??
注意:由于我们的代码比较小,远小于4KB,因此arm启动时自动拷贝到SRAM中的4KB代码包含我们的全部代码,因此copy操作我是将stepingstone中的4KB代码拷贝到了SDRAM中,在实际应用中代码多数是超过4KB,因此copy函数应该是将Nand flash中的全部代码拷贝到SDRAM,这样才能成功运行ARM。

代码Main.c:

派生到我的代码片

    void?Delay(int?i)??
  1. ????int?m,n,p;??
  2. ????for(m?=?0;?m?!=?i;?++?m)??
  3. ????{??
  4. ????????for(n?=?0;?n?!=?255;?++?n)??
  5. ????????{??
  6. ????????????for(p?=?0;?p?!=?255;?++?p)??
  7. ????????????????;??
  8. ????????}??
  9. ????}??
  10. void?Main()??
  11. ????int?count;??
  12. ????int?leds[4]?=?{0x1c0,?0x1a0,?0x160,?0xe0};??
  13. ????rGPBCON=0x00155555;??
  14. ????rGPBUP=rGPBUP&0xFF00;??
  15. ????while(1)??
  16. ????????for(count?=?0;?count?!=?4;?++?count)??
  17. ????????????rGPBDAT=leds[count];??
  18. ????????????if(count%2)??
  19. ????????????????rGPBDAT+=1;??
  20. ????????????Delay(2);??
  21. }??

链接文件led.lds如下:

派生到我的代码片

    SECTIONS??
  1. ????.?=?0x30000000;??
  2. ????.text?:?{*(.text)}??
  3. ????.rodata?ALIGN(4)?:?{*(.rodata)}??
  4. ????.data?ALIGN(4)?:?{*(.data)}??
  5. ????.bss?ALIGN(4)?:?{*(.bss)?*(COMMON)}??
  6. }??

makefile如下:

派生到我的代码片

    objects:=Head.o?Init.o?Main.o??
  1. led.bin?:?$(objects)??
  2. ????arm-linux-ld?-Tled.lds?-nostdlib?-o?led_elf?$^??
  3. ????arm-linux-objcopy?-O?binary?-S?led_elf?$@??
  4. ????arm-linux-objdump?-D?-m?arm?led_elf?>?led.dis??
  5. %.o:%.c??
  6. ????arm-linux-gcc?-Wall?-O2?-c?-o?$@?$<??
  7. %.o:%.s??
  8. <;??
  9. .PYTHON:clean??
  10. clean:??
  11. ????rm?-f?led.bin?led_elf?led.dis?*.o??

如上除了2440addr.h之外就都全了,另外需要指出的是2440addr.h中引用了Option.h,为了简化代码,可以将这句可以注释掉,在我们这段代码中完全用不到该文件相关功能。否则需要自行修改makefile文件完成Option.h相关的编译和链接工作。

好了,又浪费了大家这么长的时间,这里就不多说了,有什么问题求高手指出来。


参考链接:

http://blog.163.com/lyj_666888/blog/static/1200519172010420111534621/

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读