您的位置 首页 数字

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

断断续续的研究arm也有2个月了,现在才感觉理解了arm在Nandflash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说

时断时续的研讨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

  1. .externmain
  2. .text
  3. .global_start
  4. _start:
  5. breset
  6. reset:
  7. ldrsp,=4096
  8. bldisable_watch_dog
  9. blclock_init
  10. blmemsetup
  11. blcopy_steppingstone_to_sdram
  12. ldrpc,=on_sdram
  13. on_sdram:
  14. msrcpsr_c,#0xdf
  15. ldrsp,=0x34000000
  16. ldrlr,=halt_loop
  17. ldrpc,=Main
  18. halt_loop:
  19. bhalt_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

  1. #include”2440addr.h”
  2. voiddisable_watch_dog(void);
  3. voidclock_init(void);
  4. voidmemsetup(void);
  5. voidcopy_steppingstone_to_sdram(void);
  6. voidinituart(void);
  7. voiddisable_watch_dog(void)
  8. {
  9. rWTCON=0;
  10. }
  11. voidclock_init(void)
  12. {
  13. rCLKDIVN=0x03;
  14. /*
  15. *假如HDIVN非0,CPU的总线形式应该从
  16. *“fastbusmode”变为“asynchronous
  17. *busmode”
  18. */
  19. __asm__(
  20. “mrcp15,0,r1,c1,c0,0”
  21. “orrr1,r1,#0xc0000000”
  22. “mcrp15,0,r1,c1,c0,0”
  23. );
  24. rMPLLCON=(92<<12)|(1<<4)|(2);
  25. //rMPLLCON=((0x5c<<12)|(0x01<<4)|(0x02));
  26. }
  27. voidmemsetup(void)
  28. {
  29. volatileunsignedlong*p=(volatileunsignedlong*)0x48000000;
  30. /*这个函数之所以这样赋值,而不是像前面的试验(比方mmu试验)那样将装备值
  31. *写在数组中,是因为要生成”方位无关的代码”,使得这个函数能够在被复制到
  32. *SDRAM之前就能够在steppingstone中运转
  33. */
  34. /*存储控制器13个寄存器的值*/
  35. p[0]=0x22011110;//BWSCON
  36. p[1]=0x00000700;//BANKCON0
  37. p[2]=0x00000700;//BANKCON1
  38. p[3]=0x00000700;//BANKCON2
  39. p[4]=0x00000700;//BANKCON3
  40. p[5]=0x00000700;//BANKCON4
  41. p[6]=0x00000700;//BANKCON5
  42. p[7]=0x00018005;//BANKCON6
  43. p[8]=0x00018005;//BANKCON7
  44. /*REFRESH,
  45. *HCLK=12MHz:0x008C07A3,
  46. *HCLK=100MHz:0x008C04F4
  47. */
  48. p[9]=0x008C04F4;
  49. p[10]=0x000000B1;//BANKSIZE
  50. p[11]=0x00000030;//MRSRB6
  51. p[12]=0x00000030;//MRSRB7
  52. }
  53. voidcopy_steppingstone_to_sdram(void)
  54. {
  55. unsignedint*pdwSrc=(unsignedint*)0;
  56. unsignedint*pdwDest=(unsignedint*)0x30000000;
  57. while(pdwSrc<(unsignedint*)4096)
  58. {
  59. *pdwDest=*pdwSrc;
  60. pdwDest++;
  61. pdwSrc++;
  62. }
  63. }

留意:因为咱们的代码比较小,远小于4KB,因而arm发动时主动复制到SRAM中的4KB代码包括咱们的悉数代码,因而copy操作我是将stepingstone中的4KB代码复制到了SDRAM中,在实践使用中代码大都是超越4KB,因而copy函数应该是将Nand flash中的悉数代码复制到SDRAM,这样才干成功运转ARM。

代码Main.c:

  1. #include”2440addr.h”
  2. voidDelay(inti)
  3. {
  4. intm,n,p;
  5. for(m=0;m!=i;++m)
  6. {
  7. for(n=0;n!=255;++n)
  8. {
  9. for(p=0;p!=255;++p)
  10. ;
  11. }
  12. }
  13. }
  14. voidMain()
  15. {
  16. intcount;
  17. intleds[4]={0x1c0,0x1a0,0x160,0xe0};
  18. rGPBCON=0x00155555;
  19. rGPBUP=rGPBUP&0xFF00;
  20. while(1)
  21. {
  22. for(count=0;count!=4;++count)
  23. {
  24. rGPBDAT=leds[count];
  25. if(count%2)
  26. rGPBDAT+=1;
  27. Delay(2);
  28. }
  29. }
  30. }

链接文件led.lds如下:

  1. SECTIONS
  2. {
  3. .=0x30000000;
  4. .text:{*(.text)}
  5. .rodataALIGN(4):{*(.rodata)}
  6. .dataALIGN(4):{*(.data)}
  7. .bssALIGN(4):{*(.bss)*(COMMON)}
  8. }

makefile如下:

  1. objects:=Head.oInit.oMain.o
  2. led.bin:$(objects)
  3. arm-linux-ld-Tled.lds-nostdlib-oled_elf$^
  4. arm-linux-objcopy-Obinary-Sled_elf$@
  5. arm-linux-objdump-D-marmled_elf>led.dis
  6. %.o:%.c
  7. arm-linux-gcc-Wall-O2-c-o$@$<
  8. %.o:%.s
  9. arm-linux-gcc-Wall-O2-c-o$@$<;
  10. .PYTHON:clean
  11. clean:
  12. rm-fled.binled_elfled.dis*.o

如上除了2440addr.h之外就都全了,别的需求指出的是2440addr.h中引用了Option.h,为了简化代码,能够将这句能够注释掉,在咱们这段代码中彻底用不到该文件相关功用。不然需求自行修正makefile文件完结Option.h相关的编译和链接作业。

好了,又浪费了咱们这么长的时刻,这儿就不多说了,有什么问题求高手指出来。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/shuzi/256225.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部