在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM無(wú)痛苦起步(S3C44B0X)

            ARM無(wú)痛苦起步(S3C44B0X)

            作者: 時(shí)間:2016-11-20 來(lái)源:網(wǎng)絡(luò) 收藏
            arm(44b0x)無(wú)痛苦起步

              這兩個(gè)星期在看arm的資料,在朋友的幫助下弄明白了是怎么回事后,我覺(jué)得我原來(lái)看的入門(mén)資料總有些說(shuō)的不詳細(xì)的地方。所以決定寫(xiě)一個(gè)文檔,總結(jié)開(kāi)始arm開(kāi)發(fā)的入門(mén)知識(shí),給后來(lái)的朋友參考,也希望得到高手指正我認(rèn)識(shí)上的錯(cuò)誤。我的開(kāi)發(fā)板是s3c44b0x的,2m NOR FLASH在bank0,8m sdram在bank6.
              首先看看我們要解決的問(wèn)題。有些ARM芯片有內(nèi)嵌的RAM 和FALSH.這樣可以直接在片內(nèi)運(yùn)行程序,44B0X片內(nèi)只有幾K CACHE,ROM和RAM都是外接的芯片。我們的程序是要寫(xiě)入FLASH中保存,但執(zhí)行時(shí)是拷到SDRAM中執(zhí)行的(如在ROM中執(zhí)行速度會(huì)較慢)。要做到這一點(diǎn)需要把程序做成兩個(gè)分程序:一個(gè)是實(shí)現(xiàn)你的系統(tǒng)功能的主程序,如果你用嵌入式系統(tǒng),那就是UCOS和UCLINUX之類的程序,這個(gè)程序的代碼保存在FLASH中,但執(zhí)行時(shí)會(huì)拷到RAM中再執(zhí)行;一個(gè)是引導(dǎo)程序,直接在FLASH中執(zhí)行,負(fù)責(zé)把初始化芯片和外設(shè),并把主程序從FLASH中拷到RAM中,然后跳到主程序去執(zhí)行,對(duì)應(yīng)的概念是UBOOT等常見(jiàn)的引導(dǎo)程序,這個(gè)程序會(huì)被寫(xiě)入0X0開(kāi)始的地址,開(kāi)機(jī)后自動(dòng)執(zhí)行。
              那么我們需要解決以下幾個(gè)問(wèn)題:
              1.如何編譯和調(diào)試主程序
              2.如何使中斷跳到RAM中的中斷服務(wù)程序執(zhí)行
              3.如何把引導(dǎo)程序和主程序?qū)懭隖LASH中.
            以下我們來(lái)解決這幾個(gè)問(wèn)題:
              1 開(kāi)始在仿真器中寫(xiě)代碼和調(diào)試
              由于主程序會(huì)被拷貝到RAM中執(zhí)行,則我們應(yīng)該在編譯時(shí)就把程序定位到RAM中。這里先要說(shuō)說(shuō)幾個(gè)ADS的參數(shù)的意義,在ADS的ARM LINKER頁(yè)有RO,RW兩個(gè)參數(shù),此外還有一個(gè)ZI沒(méi)有在頁(yè)中給出,RO是只讀代碼的起始地址,由這個(gè)地址開(kāi)始存放編譯出來(lái)的程序指令;RW是程序的讀寫(xiě)段的開(kāi)始,即你程序中的數(shù)據(jù)存放的開(kāi)始地址,ZI緊跟在RW區(qū)后,ZI區(qū)存放的是需要在程序運(yùn)行時(shí)初始化為0的數(shù)據(jù)。
            了解這幾個(gè)鏈接參數(shù)的意義后我們可以設(shè)置這幾個(gè)參數(shù)了:對(duì)于我的44B0X板8M SDRAM在0XC00_0000.因此在開(kāi)發(fā)時(shí)把ADS中的RO BASE的地址指定為0XC00_0000;置于RW,在程序完成前可以預(yù)先估計(jì)一下程序的體積有多大,需要用到的數(shù)據(jù)區(qū)有多大,避免數(shù)據(jù)區(qū)太小或代碼區(qū)覆蓋掉前面的數(shù)據(jù)區(qū)就是了,我用了0XC10_0000,1M的代碼空間,其他作數(shù)據(jù)區(qū)。這樣,我們編譯出來(lái)的程序代碼就是在0XC00_0000中,可以直接由仿真器寫(xiě)入RAM中運(yùn)行仿真運(yùn)行。此外,在linker-〉layout頁(yè)有個(gè)object symbol和section的選項(xiàng),要求你填入映像文件最開(kāi)始的object文件名和段名,這兩個(gè)參數(shù)在仿真時(shí)不填寫(xiě)也不會(huì)影響運(yùn)行,因?yàn)榉抡嫫鲿?huì)自動(dòng)修改pc指針,但要建立能燒寫(xiě)的映像文件,則一定要填寫(xiě)好,具體填寫(xiě)什么后面分析程序時(shí)再講。
              2中斷問(wèn)題
              和所有單片機(jī)一樣,ARM復(fù)位后從地址0X0開(kāi)始執(zhí)行,而0X0后是一串默認(rèn)的中斷向量表。對(duì)51這樣的芯片,我們會(huì)直接在這個(gè)中斷向量表中填入跳轉(zhuǎn)語(yǔ)句,讓它跳到指定的ISR處理中斷事件。由于我們的主程序是在RAM中執(zhí)行的,編譯時(shí)又和引導(dǎo)程序分開(kāi),不可能預(yù)先知道我們寫(xiě)的ISR具體地址,而預(yù)留的中斷向量表只夠每個(gè)中斷一個(gè)跳轉(zhuǎn)指令,因此我們需要做二次跳轉(zhuǎn)。在內(nèi)存中建立一個(gè)中斷向量表,每個(gè)中斷對(duì)應(yīng)一個(gè)字,存放ISR的地址。爾后,對(duì)每個(gè)中斷寫(xiě)一段短的代碼,把ISR地址取出,填入PC。而0X0后面中斷向量的跳轉(zhuǎn)指令,則是跳到這小段程序中。
              3燒寫(xiě)flash,ADX中似乎有個(gè)寫(xiě)入flash的選項(xiàng),我自己沒(méi)有具體用過(guò)。但聽(tīng)說(shuō)用jtag寫(xiě)flash會(huì)比較慢。由于nor flash或nand flash都是可以編程燒寫(xiě)的,即我們可以寫(xiě)個(gè)程序擦寫(xiě)flash,問(wèn)題是如何讀取編譯出來(lái)的映像文件。這個(gè)也不用擔(dān)心,adx中有個(gè)菜單把文件內(nèi)容寫(xiě)入指定的地址中,把影響文件指定到一個(gè)ram地址,然后就用燒寫(xiě)程序把ram的內(nèi)容拷入rom中就是了。我們有個(gè)boot程序,一個(gè)主程序要映射到rom中.假設(shè)我把0xc20_0000開(kāi)始的2m地址作rom的映像,則把boot程序?qū)?xc20_0000,boot的程序非常短,在0xc20_1000開(kāi)始放主程序。然后把0xc20_0000到0xc40_0000的內(nèi)容全部拷入rom中(當(dāng)然在導(dǎo)入文件前這些ram應(yīng)該先被清空或?qū)懭雈f.)。
              讓我們來(lái)看看相關(guān)的代碼,具體認(rèn)識(shí)一下該怎么處理前面說(shuō)的這些問(wèn)題,還有另外的一些問(wèn)題。這里使用的代碼是在44b0x的application note的第三章中拿出來(lái)的,這個(gè)文件在網(wǎng)上應(yīng)該很容易找到。
              程序的入口在44binit.s匯編文件中,其中一個(gè)Init 段是整個(gè)程序的入口:
            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
            關(guān)鍵字ENTRY告訴編譯器保留這段代碼。從代碼看INIT段就是要寫(xiě)入0X0地址的原始中斷向量,因此把這個(gè)文件編譯生成的44BINIT.O和INTT填入上面提到的LAYOUT頁(yè)對(duì)應(yīng)項(xiàng)中。這樣編譯器會(huì)把該段代碼編譯到0X0地址。(仿真時(shí)你可以試試別填這兩個(gè)項(xiàng)目,看看ADX中的反匯編代碼入口被放到哪里)。
            這段代碼里除了reset句外,有每句都有一個(gè)HandlerXXX的標(biāo)號(hào),這就是前面提到的中斷處理程序的入口,它是由前面的一個(gè)宏來(lái)定義的:
            MACRO
            $HandlerLabel HANDLER $HandleLabel
            $HandlerLabel
            sub sp,sp,#4 ;decrement sp(to store jump address)
            stmfd sp!,{r0}
            USH 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} OP the work register and pc(jump to ISR)
            MEND
              我自己沒(méi)有寫(xiě)過(guò)宏,所以還是看編譯出來(lái)的代碼比較直接:
              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輸出的匯編代碼,就是剛才的宏對(duì)應(yīng)swi的一個(gè)實(shí)例,其中有兩句
              LDR   r0,0xc000600
              LDR   r0,[r0,#0]
            是把0x0c000600的內(nèi)容載入r0,再把r0地址的ram單元載入r0.去看看0xc000600的內(nèi)容,是0X0c7fff08,這是我設(shè)定的內(nèi)存中的中斷向量表地址之一,中斷向量表的起始地址是0X0c7fff00,因此0X0c7fff08存放的剛好就是swi的isr地址。后面程序就跳到對(duì)應(yīng)的ISR去了。(這段宏程序由于我不熟悉arm的匯編,只看過(guò)它怎么執(zhí)行,實(shí)在我不知道中斷向量表地址是如何被放入0x0c000600等地址的。希望有高手能再詳細(xì)解釋一下具體的編寫(xiě),編譯方法和原理。)
            在c程序中,我們需要給每個(gè)中斷向量定義一個(gè)宏:
              #define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x08))
            _ISR_STARTADDRESS是起始地址0X0c7fff00,假設(shè)ISR是以下函數(shù):
            void __irq SWI_UserIsr(void){……………}
            則在系統(tǒng)初始化時(shí)用pISR_EINT0=(unsigned)SWI_UserIsr;這樣的語(yǔ)句把ISR的地址填入中斷向量表中,對(duì)所有中斷作同樣的處理,然后開(kāi)中斷,系統(tǒng)就能經(jīng)過(guò)上面的宏把跳到ISR執(zhí)行。
              44binit.s中還有幾段值得留意的代碼:以下的代碼把rw段的數(shù)據(jù)拷入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
            來(lái)看反匯編的代碼:
              0x0c000ae0:  e59f0194  ....  LDR   r0,0xc000c7c
              0x0c000ae4:  e59f1194  ....  LDR   r1,0xc000c80
              0x0c000ae8:  e59f3194  .1..  LDR   r3,0xc000c84
            0xc000c7c,開(kāi)始的三個(gè)字的內(nèi)容是:    
              0x0c000c7c:  0c000e10  ....  DCD  201330192
              0x0c000c80:  0c200000  .. .  DCD  203423744
              0x0c000c84:  0c200000  .. .  DCD  203423744
              0x0c000c88:  0c200004  .. .  DCD  203423748
            這些反匯編的代碼是一個(gè)點(diǎn)led的程序的,可以看出我的小程序代碼到0x0c000e10就結(jié)束了,0x0c200000是我指定的數(shù)據(jù)區(qū)起始地址。這段程序把|Image$$RO$$Limit| 開(kāi)始的,長(zhǎng)|Image$$ZI$$Base| -|Image$$RW$$Base| 的數(shù)據(jù)區(qū)拷到|Image$$RW$$Base|的對(duì)應(yīng)單元,就是0x0c200000開(kāi)始的一段ram中。后面還有|Image$$ZI$$Limit|,在我的代碼中是0x0c000c88,內(nèi)容是0x0c200004.這其實(shí)表明我的小程序并沒(méi)有rw區(qū),只有一個(gè)初始為0的變量。
              另外還有一段初始化ram控制器的代碼:
              ;****************************************************
              ;*  Set memory control registers          
              ;****************************************************
              ldr    r0,=SMRDATA
              ldmia  r0,{r1-r13}
              ldr    r0,=0x01c80000 ;BWSCON Address
              stmia  r0,{r1-r13},
            由于44b0x要求13個(gè)控制寄存器要一次完成填入,所以先把參數(shù)設(shè)定在SMRDATA的地址中,一次載入通用寄存器,在一次填入RAM控制寄存器中。4510的書(shū)上介紹調(diào)試前需要用SEMEM命令設(shè)置這些寄存器,但我自己沒(méi)有那么做也可以跑的很好,也許是默認(rèn)已經(jīng)用了最保守的配置的原因吧!
              其余的代碼解釋比較清晰了,最后摘出我的LED程序和這個(gè)小程序的BOOT程序以及燒寫(xiě)程序。這幾個(gè)程序的project都包括了44binit.s, option.s, memcfg.s,option.h,44b.h幾個(gè)從app note中抄來(lái)的文件,這里只列了我自己寫(xiě)的主要c代碼。其他這些文件我除了把ram和rom的對(duì)應(yīng)配置改了一下外,都沒(méi)有改動(dòng)。我的引導(dǎo)程序編譯出來(lái)是3k,led程序也是3k,因此我把他們分別定位在rom的0x0和0x2000處,一共寫(xiě)了8k。
            LED程序中的44BINTT.S程序功能和LOAD中的44BINTT.S是重復(fù)的,主要是我懶得去修改這些匯編,由著他們占用一點(diǎn)時(shí)間吧!
              load程序負(fù)責(zé)把從0x20000處開(kāi)始的4k程序(即led程序)拷到ram 0xc000000中,run函數(shù)把pc指到0x0c000000,開(kāi)始執(zhí)行l(wèi)ed程序:
            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程序把兩個(gè)通用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     }
            }
            最后是燒寫(xiě)的程序,詳細(xì)的代碼網(wǎng)上高手們寫(xiě)了不少,我只是給出最簡(jiǎn)單的實(shí)現(xiàn)。燒寫(xiě)時(shí)當(dāng)程序執(zhí)行到清理完0X0C30_0000到0X0C30_4000的RAM后,讓程序中斷下來(lái),通過(guò)LOAD MEMORY FORM FILE命令把LOAD.BIN導(dǎo)入0X0C30_0000,LED.BIN導(dǎo)入0X0C30_2000中,繼續(xù)運(yùn)行程序直到一個(gè)LED亮起,燒寫(xiě)就完成了。拔去仿真器后再上電,可以看到兩個(gè)LED同時(shí)亮滅。
            #i nclude "option.h"
            #i nclude "44b.h"
            #i nclude "def.h"
            //#i nclude "romdef.h"
            //#i nclude "stdio.h"
            //#i nclude "stdlib.h"

            本文引用地址:http://www.biyoush.com/article/201611/318874.htm

            #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="/blog/(INT16U" *)0xc300000;
              for(k=0;k<0x4000>   *psrc++=0x0; //clear ram
              psrc="/blog/(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;
            }



            關(guān)鍵詞: ARMS3C44B0

            評(píng)論


            技術(shù)專區(qū)

            關(guān)閉