ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:20.31KB ,
资源ID:26303820      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/26303820.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(ARM无痛苦起步.docx)为本站会员(b****9)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

ARM无痛苦起步.docx

1、ARM无痛苦起步首先看看我们要解决的问题。44B0X片内只有几K CACHE,ROM和RAM都是外接的芯片。我们的程序是要写入FLASH中保存,但执行时是拷到SDRAM中执行的(如在ROM中执行速度会较慢)。要做到这一点需要把程序做成两个分程序:一个是实现你的系统功能的主程序,如果你用嵌入式系统,那就是UCOS和UCLINUX之类的程序,这个程序的代码保存在FLASH中,但执行时会拷到RAM中再执行;一个是引导程序,直接在FLASH中执行,负责把初始化芯片和外设,并把主程序从FLASH中拷到RAM中,然后跳到主程序去执行,对应的概念是UBOOT等常见的引导程序,这个程序会被写入0X0开始的地址

2、,开机后自动执行。那么我们需要解决以下几个问题:1.如何编译和调试主程序2.如何使中断跳到RAM中的中断服务程序执行3.如何把引导程序和主程序写入FLASH中.arm(44b0x)无痛苦起步这两个星期在看arm的资料,在朋友的帮助下弄明白了是怎么回事后,我觉得我原来看的入门资料总有些说的不详细的地方。所以决定写一个文档,总结开始arm开发的入门知识,给后来的朋友参考,也希望得到高手指正我认识上的错误。我的开发板是s3c44b0x的,2m NOR FLASH在bank0,8m sdram在bank6.首先看看我们要解决的问题。有些ARM芯片有内嵌的RAM 和FALSH.这样可以直接在片内运行程序

3、,44B0X片内只有几K CACHE,ROM和RAM都是外接的芯片。我们的程序是要写入FLASH中保存,但执行时是拷到SDRAM中执行的(如在ROM中执行速度会较慢)。要做到这一点需要把程序做成两个分程序:一个是实现你的系统功能的主程序,如果你用嵌入式系统,那就是UCOS和UCLINUX之类的程序,这个程序的代码保存在FLASH中,但执行时会拷到RAM中再执行;一个是引导程序,直接在FLASH中执行,负责把初始化芯片和外设,并把主程序从FLASH中拷到RAM中,然后跳到主程序去执行,对应的概念是UBOOT等常见的引导程序,这个程序会被写入0X0开始的地址,开机后自动执行。那么我们需要解决以下几

4、个问题:1.如何编译和调试主程序2.如何使中断跳到RAM中的中断服务程序执行3.如何把引导程序和主程序写入FLASH中.以下我们来解决这几个问题:1 开始在仿真器中写代码和调试由于主程序会被拷贝到RAM中执行,则我们应该在编译时就把程序定位到RAM中。这里先要说说几个ADS的参数的意义,在ADS的ARM LINKER页有RO,RW两个参数,此外还有一个ZI没有在页中给出,RO是只读代码的起始地址,由这个地址开始存放编译出来的程序指令;RW是程序的读写段的开始,即你程序中的数据存放的开始地址,ZI紧跟在RW区后,ZI区存放的是需要在程序运行时初始化为0的数据。了解这几个链接参数的意义后我们可以设

5、置这几个参数了:对于我的44B0X板8M SDRAM在0XC00_0000.因此在开发时把ADS中的RO BASE的地址指定为0XC00_0000;置于RW,在程序完成前可以预先估计一下程序的体积有多大,需要用到的数据区有多大,避免数据区太小或代码区覆盖掉前面的数据区就是了,我用了0XC10_0000,1M的代码空间,其他作数据区。这样,我们编译出来的程序代码就是在0XC00_0000中,可以直接由仿真器写入RAM中运行仿真运行。此外,在linker-layout页有个object symbol和section的选项,要求你填入映像文件最开始的object文件名和段名,这两个参数在仿真时不填写

6、也不会影响运行,因为仿真器会自动修改pc指针,但要建立能烧写的映像文件,则一定要填写好,具体填写什么后面分析程序时再讲。2中断问题和所有单片机一样,ARM复位后从地址0X0开始执行,而0X0后是一串默认的中断向量表。对51这样的芯片,我们会直接在这个中断向量表中填入跳转语句,让它跳到指定的ISR处理中断事件。由于我们的主程序是在RAM中执行的,编译时又和引导程序分开,不可能预先知道我们写的ISR具体地址,而预留的中断向量表只够每个中断一个跳转指令,因此我们需要做二次跳转。在内存中建立一个中断向量表,每个中断对应一个字,存放ISR的地址。尔后,对每个中断写一段短的代码,把ISR地址取出,填入PC

7、。而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,boo

8、t的程序非常短,在0xc20_1000开始放主程序。然后把0xc20_0000到0xc40_0000的内容全部拷入rom中(当然在导入文件前这些ram应该先被清空或写入ff.)。让我们来看看相关的代码,具体认识一下该怎么处理前面说的这些问题,还有另外的一些问题。这里使用的代码是在44b0x的application note的第三章中拿出来的,这个文件在网上应该很容易找到。程序的入口在44binit.s汇编文件中,其中一个Init 段是整个程序的入口:AREA Init,CODE,READONLYENTRYb ResetHandler ;for debugb HandlerUndef ;hand

9、lerUndefb HandlerSWI ;SWI interrupt handlerb HandlerPabort ;handlerPAbortb HandlerDabort ;handlerDAbortb . ;handlerReservedb HandlerIRQ关键字ENTRY告诉编译器保留这段代码。从代码看INIT段就是要写入0X0地址的原始中断向量,因此把这个文件编译生成的44BINIT.O和INTT填入上面提到的LAYOUT页对应项中。这样编译器会把该段代码编译到0X0地址。(仿真时你可以试试别填这两个项目,看看ADX中的反汇编代码入口被放到哪里)。这段代码里除了reset句外,

10、有每句都有一个HandlerXXX的标号,这就是前面提到的中断处理程序的入口,它是由前面的一个宏来定义的:MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub sp,sp,#4 ;decrement sp(to store jump address)stmfd sp!,r0USH the work register to stack(lr doest push because it return to original address)ldr r0,=$HandleLabel;load the address of HandleXXX

11、to r0ldr r0,r0 ;load the contents(service routine start address) of HandleXXXstr r0,sp,#4 ;store the contents(ISR) of HandleXXX to stackldmfd sp!,r0,pc OP the work register and pc(jump to ISR)MEND我自己没有写过宏,所以还是看编译出来的代码比较直接:HandlerSWI0x0c000198:e24dd004.M.SUBr13,r13,#40x0c00019c:e92d0001.-.STMFDr13!,r

12、00x0c0001a0:e59f0458X.LDRr0,0xc0006000x0c0001a4:e5900000.LDRr0,r0,#00x0c0001a8:e58d0004.STRr0,r13,#40x0c0001ac:e8bd8001.LDMFDr13!,r0,pc这是ads输出的汇编代码,就是刚才的宏对应swi的一个实例,其中有两句LDRr0,0xc000600LDRr0,r0,#0是把0x0c000600的内容载入r0,再把r0地址的ram单元载入r0.去看看0xc000600的内容,是0X0c7fff08,这是我设定的内存中的中断向量表地址之一,中断向量表的起始地址是0X0c7fff

13、00,因此0X0c7fff08存放的刚好就是swi的isr地址。后面程序就跳到对应的ISR去了。(这段宏程序由于我不熟悉arm的汇编,只看过它怎么执行,实在我不知道中断向量表地址是如何被放入0x0c000600等地址的。希望有高手能再详细解释一下具体的编写,编译方法和原理。)在c程序中,我们需要给每个中断向量定义一个宏:#define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x08)_ISR_STARTADDRESS是起始地址0X0c7fff00,假设ISR是以下函数:void _irq SWI_UserIsr(void)则在系统初始化时用pISR

14、_EINT0=(unsigned)SWI_UserIsr;这样的语句把ISR的地址填入中断向量表中,对所有中断作同样的处理,然后开中断,系统就能经过上面的宏把跳到ISR执行。44binit.s中还有几段值得留意的代码:以下的代码把rw段的数据拷入ram中,并初始化zi段,即把该段清零:LDRr0,=|Image$RO$Limit|LDRr1,=|Image$RW$Base|LDRr2,=|Image$ZI$Base|CMPr0,r1BEQ%F10 CMPr1,r3LDRCCr2,r0,#4STRCCr2,r1,#4BCC%B01 LDRr1,=|Image$ZI$Limit|MOV r2,#0

15、2 CMPr3,r1STRCCr2,r3,#4BCC%B2来看反汇编的代码:0x0c000ae0:e59f0194.LDRr0,0xc000c7c0x0c000ae4:e59f1194.LDRr1,0xc000c800x0c000ae8:e59f3194.1.LDRr3,0xc000c840xc000c7c,开始的三个字的内容是:0x0c000c7c:0c000e10.DCD2013301920x0c000c80:0c200000. .DCD2034237440x0c000c84:0c200000. .DCD2034237440x0c000c88:0c200004. .DCD203423748

16、这些反汇编的代码是一个点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 contr

17、ol registers;*ldrr0,=SMRDATAldmia r0,r1-r13ldrr0,=0x01c80000;BWSCON Addressstmia r0,r1-r13,由于44b0x要求13个控制寄存器要一次完成填入,所以先把参数设定在SMRDATA的地址中,一次载入通用寄存器,在一次填入RAM控制寄存器中。4510的书上介绍调试前需要用SEMEM命令设置这些寄存器,但我自己没有那么做也可以跑的很好,也许是默认已经用了最保守的配置的原因吧!其余的代码解释比较清晰了,最后摘出我的LED程序和这个小程序的BOOT程序以及烧写程序。这几个程序的project都包括了44binit.s,

18、 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,开始

19、执行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 *pulDest+ = *pulSource+;Run();led程序把两个通用io上连的led作不断的亮和灭:void Main(void)INT32U k ;/INT16U *ptr;rSYSCFG=CACHECFG

20、;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同时亮灭。i nclude option.hi nclude 44b.hi ncl

21、ude def.h/i nclude romdef.h/i nclude stdio.h/i nclude stdlib.h#define FLASH_START_ADDR0X0000#define FLASH_ADDR_UNLOCK10X5555#define FLASH_ADDR_UNLOCK20X2AAA#define FLASH_DATA_UNLOCK10XAAAA#define FLASH_DATA_UNLOCK20X5555#define FLASH_DATA_WRITE0XA0A0#define FLASH_ERASE 0X8080#define FLASH_ERASE_SECT

22、OR0X3030#define FLASH_ERASE_BLOCK 0X5050#define FLASH_ERASE_CHIP0X1010#define FLASH_SID_QUERY 0X9090#define FLASH_CFI_QUERY 0X9898#define FLASH_SID_EXIT0XF0F0#define FLASH_OP_TIMEOUT0Xffff#define LED_PORTC10 (1 #define LED_PORTC11(1 #define RAM_ADDR 0xc000000void (*Run)(void) = (void (*)(void)RAM_AD

23、DR;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=CAC

24、HECFG;PortInit();/infoFlash();eraseChip();palt=深圳单片机交流网 src=/blog/(INT16U *)0xc300000;for(k=0;k*psrc+=0x0; /clear rampalt=深圳单片机交流网 src=/blog/(INT16U *)0xc300000;pdist=(INT16U *)0x0;for(k=0;k writeFlash(pdist+,*psrc+);while(1)LedDisp(0);for(k=0;k LedDisp(2);for(k=0;k /*/init the port/*void PortInit(v

25、oid)rPDATC = 0xffff;/All IO is highrPCONC = 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 ONelserPDATC |= LED_PORTC10;/LED OFFif(LedStatus&0x02)=0x02)rPDATC &=(LED_PORTC11);/LED ONelser

26、PDATC |=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;*

27、(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)=FLA

28、SH_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

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1