色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          ARM 的分散加載

          作者: 時(shí)間:2016-11-09 來(lái)源:網(wǎng)絡(luò) 收藏
          對(duì)于剛學(xué)習(xí)ARM的人來(lái)說(shuō),如果分析它的啟動(dòng)代碼,往往不明白下面幾個(gè)變量的含義:|Image$$RO$$Limit|、|Image$$RW$$Base|、|Image$$ZI$$Base|。

          首先申明我使用的調(diào)試軟件為ADS1.2,當(dāng)我們把程序編寫(xiě)好以后,就要進(jìn)行編譯和鏈接了,在ADS1.2中選擇MAKE按鈕,會(huì)出現(xiàn)一個(gè)Errors and Warnings的對(duì)話(huà)框,在該欄中顯示編譯和鏈接的結(jié)果,如果沒(méi)有錯(cuò)誤,在文件的最后應(yīng)該能看到Image component sizes,后面緊跟的依次是Code,RO Data,RW Data,ZI Data,Debug各個(gè)項(xiàng)目的字節(jié)數(shù),最后會(huì)有他們的一個(gè)統(tǒng)計(jì)數(shù)據(jù):

          本文引用地址:http://cafeforensic.com/article/201611/317890.htm

          Code 163632,RO Data 20939,RW Data 53,ZI Data 17028

          Tatal RO size (Code+ RO Data) 184571 (180.25kB)

          Tatal RW size(RW Data+ ZI Data) 17081(16.68 kB)

          Tatal ROM size(Code+ RO Data+ RW Data) 184624(180.30 kB)

          后面的字節(jié)數(shù)是根據(jù)用戶(hù)不同的程序而來(lái)的,下面就以上面的數(shù)據(jù)為例來(lái)介紹那幾個(gè)變量的計(jì)算。

          在ADS的Debug Settings中有一欄是Linker/ARM Linker,在output選項(xiàng)中有一個(gè)RO base選項(xiàng),下面應(yīng)該有一個(gè)地址,我這里是0x0c100000,后面的RW base地址是0x0c200000,然后在Options選項(xiàng)中有Image entry point,是一個(gè)初始程序的入口地址,我這里是0x0c100000。

          有了上面這些信息我們就可以完全知道這幾個(gè)變量是怎么來(lái)的了:

          |Image$$RO$$Base| = Image entry point = 0x0c100000;表示程序代碼存放的起始地址

          |Image$$RO$$Limit|=程序代碼起始地址+代碼長(zhǎng)度+1=0x0c100000+Tatal RO size+1

          = 0x0c100000 + 184571 + 1 = 0x0c100000 +0x2D0FB + 1

          = 0x0c12d0fc

          |Image$$RW$$Base| = 0x0c200000;由RW base地址指定

          |Image$$RW$$Limit| =|Image$$RW$$Base|+ RW Data 53 = 0x0c200000+0x37(4的倍數(shù),0到55,共56個(gè)單元)

          =0x0c200037

          |Image$$ZI$$Base| = |Image$$RW$$Limit| + 1 =0x0c200038

          |Image$$ZI$$Limit| = |Image$$ZI$$Base| + ZI Data 17028

          =0x0c200038 + 0x4284

          =0x0c2042bc

          也可以由此計(jì)算:

          |Image$$ZI$$Limit| = |Image$$RW$$Base| +TatalRWsize(RWData+ZIData) 17081

          =0x0c200000+0x42b9+3(要滿(mǎn)足4的倍數(shù))

          =0x0c2042bc

          原文地址http://blog.csdn.net/yyt7529/archive/2009/06/05/4245604.aspx

          簡(jiǎn)單應(yīng)用時(shí)可以不寫(xiě).scf文件。而在"Output"頁(yè)中選擇"Simple".然后填寫(xiě)"RO Base"和"RW Base"的起始地址。在"Lay Out"頁(yè)中,填寫(xiě)Object/Symble: Startup.o, Section: Start.編寫(xiě)啟動(dòng)文件:Startup.s.

          在"Option"頁(yè)里的"Image Entry Point"填入起始地址。

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

          Scatter-Load Description File的結(jié)構(gòu):

          ".scf"文件中的"+RW"對(duì)應(yīng)".s"源文件中的"READWRITE".

          ".scf"文件中的"+ZI"對(duì)應(yīng)".s"源文件中的"NOINIT".

          ".scf"文件中的"+RO"對(duì)應(yīng)".s"源文件中的"READONLY".

          在".s"源文件中有:

          AREA area_name CODE/DATA,READONLY/NOINIT/READWRITE

          END

          ".scf"的例子

          內(nèi)容 注解

          ROM_LOAD 0x80000000

          {?。籒ame of Load Region, Start Address for Load Region and Maximum size of Load Region(省略了)

           ROM_EXEC 0x80000000 0x20000

          {;片外存儲(chǔ)區(qū),從0x80000000開(kāi)始,最多0x20000字節(jié)。

           Startup.o(Vector,+First);Startup模塊的Vector段放在最前面。注1

           *(+RO);其他所有模塊中的所有代碼和只讀的數(shù)據(jù)放在這里。

           } 

           IRAM 0x40000000 0x00004000

          {;片內(nèi)RAM區(qū),從0x40000000開(kāi)始,最多0x4000字節(jié)

           Startup.o(MyStacks,+first);指定Startup.o中MyStacks放在最前面。

           Startup.o(+RW,+ZI);Startup.o中的其他+RW/+ZI段。注1

           os_cpu_a.o(+RW,+ZI) 

           } 

           STACKS 0x40004000 UNINIT

          {;片內(nèi)16K RAM的頂端,存放不需要被"C library"初始化的段。

           Stack.o(+ZI)注2

           } 

           ERAM 0x80040000

          { 

           *(+RW,+ZI) 

           } 

           HEAP +0 UNINIT

          {;"+0"表示接著上一段"ERAM"的結(jié)尾,繼續(xù)安排存儲(chǔ)區(qū)。

           Heap.o(+ZI)注3

           } 

          }  

          下面是在scf文件中引用過(guò)的源文件示意:"Startup.s"

          code 32

          area Vectors,CODE,READONLY

          entry

          ...

          end注1:在"Startup.o"里面會(huì)生成名為"Vectors"的段,段的屬性為"READONLY"

          "Stack.s"

          area Stacks, DATA, NOINIT

          export StackUsr

          StackUsr SPACE 1

          end注2:在"Stack.o"里面會(huì)生成名為"Stacks"的段,段的屬性為"NOINIT",該屬性對(duì)應(yīng)scf文件中的"+ZI".該段不需要初始化或者可以被初始化為"0".

          "Heap.s"

          area Heap,DATA,NOINIT

          export bottom_of_heap

          bottom_of_heap SPACE 1

          end注3: "Heap.o"里面名為"Heap"的段。

          在Scatter文件中最好每一個(gè)Region都加一個(gè)Maximum參數(shù),這樣當(dāng)編譯時(shí)如果實(shí)際使用的空間大于Maximum Size,會(huì)有Error:16220E: Excution region xxx size (xxx bytes) exceeds limit (xx bytes)。如果地址有重復(fù),會(huì)有Error: 16221E: Excution region xxx overlaps with excution region xxx。前一個(gè)Region的首地址+ Maximum >后一個(gè)Region的首地址時(shí)不一定有Error。只有當(dāng)一分配的內(nèi)存出現(xiàn)覆蓋時(shí)才會(huì)有Error。

          Region的"UNINIT"之類(lèi)的參數(shù)要放在"Maximum size"參數(shù)之前。

          在一個(gè)Region中,RAM的分配不是按照羅列的順序來(lái)的。要想讓匯編中使用的變量有固定的位置,可以把所有匯編文件產(chǎn)生的".o"放在同一個(gè)Region中。如:

          IRAM1 0x40000000

          {

          startup.o(+RW,+ZI)

          ASMSourceCode1.o(+RW,+ZI)

          ASMSourceCode2.o(+RW,+ZI)

          }

          IRAM2 +0

          {

          CSourceCode1.o(+RW,+ZI)

          CSourceCode2.o(+RW,+ZI)

          }

          這樣,所有匯編中定義的變量地址就相對(duì)集中了。

          如果只有一個(gè)匯編文件如startup.s,也可以這樣:

          IRAM 0x40002000 0x1000

          {

          startup.o (Mystack,+first)

          *(+RW,+ZI)

          }

          用一個(gè)"+first"強(qiáng)行將startup.s中的Mystack放在0x40002000位置。

          在"Edit -> DebugRel Settings...->ARM Linker"中選中"Image map"。編譯后在Error & Warnings窗口會(huì)顯示出詳細(xì)的內(nèi)存分配情況。如果在"List file name"中指定一個(gè)輸出文件名,該祥單會(huì)直接存在制定文件中以供多次研究。

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

          關(guān)于JTAG接口:

          P1.20/TRACESYNC應(yīng)該加上拉電阻以禁止TRACE功能。PINSEL2一定要在程序開(kāi)始時(shí)初始化一下。LPC2210

          JTAG

           1,2/VDD3.3V 

          P1.31/nTRST, input 3/nTRST, output EasyJTAG中有上拉電阻。

          P1.28/TDI, input 5/TDI, output EasyJTAG中有上拉電阻。

          P1.30/TMS, input 7/TMS,output EasyJTAG中有上拉電阻。

          P1.29/TCK, input/output 9/TCK, input/output EasyJTAG中有上拉電阻。

          P1.26/RTCK, input 11/RTCK, output P1.26外接下拉電阻。

          P1.26有內(nèi)部上拉電阻,故測(cè)量時(shí)該引腳會(huì)呈現(xiàn)高電平。但是在復(fù)位時(shí),它的上拉電阻不起作用,只有外部的下拉電阻起作用,P1.26 = 0V,所以上電后PINSEL2的D3~D0會(huì)是0x04(B0100),JTAG有效。

          若將P1.26接到3.3V再?gòu)?fù)位,此時(shí)PINSEL2的D3~D0將會(huì)是0x00,JTAG無(wú)效。

          P1.27/TDO, output 13/TDO, input EasyJTAG中有上拉電阻。

          nRESET, input 15/nRST, output EasyJTAG中有上拉電阻。

           4,6,8,10,12,14,16,18,20/GND 

           17,19/NC 

          G18控制板采用LPC2114,每次運(yùn)行Axd都不會(huì)正確調(diào)入程序。原因如下:

          有一次是因?yàn)橐呀?jīng)有一個(gè)Axd在運(yùn)行了,打開(kāi)第二個(gè)Axd,當(dāng)然不會(huì)正確調(diào)入程序。

          還有一次是重新編譯了一下,就好了。

          以上兩次都不奇怪,奇怪的是下面幾次:

          在"Config Target -> Config -> Easy JTag Setup"隨便點(diǎn)兩下"Halt Mode"中的選項(xiàng),然后一路點(diǎn)擊"OK",會(huì)出現(xiàn)"Reload the last Image?",點(diǎn)擊"Yes"。有時(shí)會(huì)有正確的程序被調(diào)入,但有時(shí)候不成功。要檢驗(yàn)是不是已經(jīng)成功調(diào)入了,只要按下"Ctrl-D"顯示Disassembly窗口,即可看到芯片中的程序是否正確。

          在"Option -> Config Interface -> Session File -> Session file Options"中選擇"Reload Images",之后每次啟動(dòng)Axd都會(huì)提示"The processor ARM_1 already has image(s) loaded. Continue the operation will replace the currently loaded images(s).... Do you wish to continue?"選擇"Yes",有時(shí)候也可以成功調(diào)入程序。

          當(dāng)然,在"Easy JTag Setup -> Aux Option"中要選中"Erase Flash when need".

          固化的程序中有禁止JTag調(diào)試端口的語(yǔ)句(操作PINSEL2的語(yǔ)句),連不上時(shí)用LPC2000 Flash Utility擦除了Flash。偶爾可行。

          注意使用LPC2000 Flash Utility時(shí)要先將電路復(fù)位,再點(diǎn)"OK".

          當(dāng)然最根本的解決辦法是將計(jì)算機(jī)并口設(shè)置為"EPP"模式。其他地方都按照"Default"就可以了。

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

          有效用戶(hù)代碼:

          ARM把“向量表所有32位數(shù)據(jù)累加和為0”作為有效用戶(hù)代碼的條件,只適用于使用片內(nèi)程序存儲(chǔ)器的時(shí)候,片外程序存儲(chǔ)器無(wú)此限制。

          C語(yǔ)言程序通常需要一段用于初始化的匯編代碼,通常存儲(chǔ)為"Startup.s",它實(shí)現(xiàn)的任務(wù)通常是:

          1、做好中斷向量表

          2、初始化外部總線(xiàn)控制器/堆棧/目標(biāo)板基本模塊。

          3、給庫(kù)函數(shù)使用的"__user_inital_stackheap"。

          4、除數(shù)為零時(shí)的死循環(huán)"__rt_div0: B __rt_div0"。

          5、支持加密功能的語(yǔ)句。

          6、定義堆??臻g:AREA MyStacks, DATA,NOINIT,ALIGN = 2

          要定義棧的起始地址:IrqStackSpace SPACE ...

          和棧的頭部:StackIrq DCD IrqStackSpace + Length*4。因?yàn)闂J窍蛳律L(zhǎng)的。

          與目標(biāo)板有關(guān)的初始化程序可以放在一個(gè)名為"Target.c"的文件里。

          1、定義中斷處理入口:void IRQ_Exception(void), void FIQ_Exception(void), void Timer0_Exception(void)。

          2、向量中斷控制器初始化。

          3、remap,系統(tǒng)時(shí)鐘,實(shí)時(shí)時(shí)鐘,存儲(chǔ)器加速。

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

          C語(yǔ)言中的延時(shí):

          __asm{

          nop;

          nop;}

          即可。

          關(guān)注C編譯器:"=="的優(yōu)先級(jí)確實(shí)比"&"的高,所以,凡牽扯到邏輯的東西,用"()"確認(rèn)優(yōu)先級(jí),以避免出現(xiàn)低級(jí)錯(cuò)誤。

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

          對(duì)定時(shí)器的操作:

          void Timer0Init(uint8 VICSlot, uint32 fdiv)

          {

          T0PR = 0; //Prescaling = 0

          T0PC = 0; //Prescalar Counter

          T0TC = 0; //T0 Counter

          T0MR0 = Fpclk / fdiv; //計(jì)數(shù)周期

          T0MCR = 0x03; //計(jì)數(shù)達(dá)到T0MR0則置位中斷,計(jì)數(shù)器復(fù)位并繼續(xù)運(yùn)行。

          T0CCR = 0x00; //不用捕獲模式

          T0TR = 0xffffffff; //清中斷

          T0TCR = 0x01; //運(yùn)行

          if(VICSlot <= 15){

          *((uint32*)(&VICVectAddr0 + VICSlot)) = (uint32)Timer0_Exception;

          *((uint32*)(&VICVectCntl0 + VICSlot)) = 0x20 | 0x04;

          VICIntEnable = 1 << 0x04;

          }

          }

          注意:

          1、"*((uint32*)(&VICVectAddr0 + VICSlot)) = ..."中,&VICVectAddr0作為基址,VICSlot作為偏移量。由于前面已經(jīng)有(uint32*)聲明這是一個(gè)指向uint32的指針,故偏移量每變化一個(gè)數(shù)字代表地址變化了4個(gè)字節(jié),在基址與偏移量相加的時(shí)候,系統(tǒng)自動(dòng)將VICSlot乘以4。如果程序中寫(xiě)成"... + 4 * VICSlot"就錯(cuò)了。

          2、一定要用"Fpclk / fdiv"設(shè)置,以延時(shí)1/fdiv秒。該參數(shù)不可以以u(píng)S為單位。若"Fpclk * us / 1000000"在計(jì)算中會(huì)乘法溢出,不易避免,又無(wú)警告,故不可用。

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

          對(duì)I2C占空比的設(shè)置:

          I2SCLH = (Fpclk / fi2c + 1) / 2;

          I2SCLL = (Fpclk / fi2c) / 2;

          妙哉!無(wú)論"Fpclk / fi2c"是奇是偶,單方面的"Fpclk / fi2c + 1"使得I2C總周期"Fpclk / fi2c = I2SCLH + I2SCLL"在方法上沒(méi)有誤差。

          I2C必須工作在中斷模式。因?yàn)椋?When the "SI" flag is reset, no serial interrupt is requested, and there is no stretching of the serial clock on the SCL line."

          I2C的資料在http://www.semiconductors.philips.com/acrobat/various/8xC552_562OVERVIEW_2.pdf.

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

          宏的應(yīng)用:

          在片內(nèi)外設(shè)如I2C,UART,T0,T1,SPI的設(shè)置過(guò)程中,都需要根據(jù)Fpclk計(jì)算出一些設(shè)定值。我討厭用ARM做除法,所以就用宏來(lái)實(shí)現(xiàn),除法在編譯時(shí)就可以完成。

          首先,所有片內(nèi)外設(shè)的初始化程序都名為:"void _xxxInit();"。之所以在正式函數(shù)名之前加一個(gè)"_",是為了與宏區(qū)別開(kāi),不至于誤寫(xiě)函數(shù)。因?yàn)楹甑拿峙c函數(shù)名相同,只是全部大寫(xiě),并且前面沒(méi)有"_"。如:

          #define TIMER0INIT(VICSlot,ms) _Timer0Init(VICSlot,Fpclk/100*ms/10);

          void _Timer0Init(uint8 VICSlot,uint32 ClockCycle);

          在函數(shù)中,直接"T0MR0 = ClockCycle"即可。

          注意宏里面的表達(dá)式,不可寫(xiě)成"Fpclk*ms/1000",因?yàn)槿绻@樣寫(xiě),當(dāng)mS太大時(shí),比如mS=1000, Fpclk*mS=(11059200/4)*1000=0xA4CB8000,算到這一步,編譯器認(rèn)為是溢出(它把計(jì)算結(jié)果看作是有符號(hào)數(shù)),只要有溢出的警告出現(xiàn),設(shè)置就不正確。

          也不可以先做除法,以防止吃掉精度,使計(jì)算結(jié)果為"0"而令定時(shí)器死掉。

          總之,既要保證計(jì)算精度,又不可以出現(xiàn)溢出警告。

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

          關(guān)于C編譯器使用的堆棧設(shè)置:

          1、在Startup.s中有一句:

          MSR CPSR_C,#0x5f//系統(tǒng)模式

          LDR SP, =UsrStack //用戶(hù)棧

          2、在Scatter文件中,有

          STACKS 0x40004000 UNINT

          {

          UsrStack.o(+ZI)

          }

          3、在UsrStack.s中有

          AREA Stacks, DATA, NOINT

          EXPORT UsrStack

          UsrStack SPACE 1

          END

          定義一個(gè)UsrStack,大小都無(wú)所謂,把它放在可用物理內(nèi)存的最頂端。C編譯器在編譯子程序調(diào)用時(shí),會(huì)將要保護(hù)的寄存器壓棧,如:

          stmfd r13!,{r3-r7,r14}

          其中,r13的別名是SP。

          這是一個(gè)滿(mǎn)遞減堆棧。即SP指向的單元內(nèi)的數(shù)據(jù)是有效的,入棧時(shí)先減SP再存數(shù)據(jù)。



          關(guān)鍵詞: ARM分散加

          評(píng)論


          技術(shù)專(zhuān)區(qū)

          關(guān)閉