<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 設(shè)計應(yīng)用 > 使用ADS1.2進行嵌入式軟件開發(fā)(上)

          使用ADS1.2進行嵌入式軟件開發(fā)(上)

          作者:美國ARM公司 時間:2004-06-18 來源:電子設(shè)計應(yīng)用 收藏
          概述
          嵌入式應(yīng)用程序通常都是在樣機環(huán)境下調(diào)試與開發(fā)的,這種環(huán)境與最終產(chǎn)品之間并不完全相同。因此,在系統(tǒng)調(diào)試階段就考慮應(yīng)用程序在最終目標硬件中的運行情況是非常重要的。
          本文旨在討論如何將一個開發(fā)/調(diào)試環(huán)境下的嵌入式應(yīng)用程序轉(zhuǎn)移到最終獨立運行的目標系統(tǒng)中去,并提到了 ADS1.2開發(fā)工具包的一些功能特性及其在這個過程中所起到的作用。
          使用ADS開發(fā)嵌入式程序時,需要著重考慮以下幾個問題:
          與硬件相關(guān)的C語言庫函數(shù)的使用;
          某些C語言庫函數(shù)使用了調(diào)試環(huán)境中的資源,要把這些使用的資源重定向到目標系統(tǒng)中的硬件上來;
          可執(zhí)行映象文件的存儲器映射必須根據(jù)目標硬件的存儲器分布進行裁剪;
          在主程序執(zhí)行前,嵌入式應(yīng)用程序必須先完成系統(tǒng)的初始化。一個完整的初始化包括用戶的啟動執(zhí)行代碼和ADS中C庫函數(shù)的初始化過程。


          圖1 Semihosting的實現(xiàn)舉例


          圖2 C語言庫函數(shù)結(jié)構(gòu)


          圖3 缺省的存儲器映射


          圖4 連接器布局規(guī)則

          缺省的工程項目設(shè)置
          剛開始一個嵌入式應(yīng)用軟件開發(fā)時,ADS用戶可能并不完全清楚目標硬件的一些參數(shù)指標。比如有關(guān)外設(shè)、存儲器地址分布,甚至處理器類型等一些細節(jié),可能還沒有最終確定。為了在所有這些細節(jié)全部就緒前就能進行軟件開發(fā),ADS工具有一套程序構(gòu)建和調(diào)試的缺省設(shè)置。了解這套缺省的工程項目設(shè)置方法,對于掌握最終的移植步驟非常有好處。
          ADS1.2C語言函數(shù)庫
          Semihosting
          在ADS的C語言函數(shù)庫中,某些ANSIC的功能是由主機的調(diào)試環(huán)境來提供的,這套機制有一個專門術(shù)語叫Semihosting。Semihosting通過一組軟件中斷(SWI)指令來實現(xiàn)。如圖1所示,當一個Semihosting軟中斷被執(zhí)行時,調(diào)試系統(tǒng)先識別這個SWI請求,然后掛起正在運行的程序,調(diào)用Semihosting的服務(wù),完成后再恢復(fù)原來的程序執(zhí)行。因此,主機執(zhí)行的任務(wù)對于程序來說是透明的。
          C語言庫函數(shù)結(jié)構(gòu)
          從概念上來講,C語言庫函數(shù)可以被分成兩部分,一是ANSIC語言規(guī)范本身的一部分,一是只受某一特定ANSIC層次支持的函數(shù),如圖2所示。
          其中一些ANSIC的功能是由主機調(diào)試環(huán)境調(diào)用驅(qū)動程序級的函數(shù)完成的。例如,ADS的庫函數(shù)printf()把輸出信息輸出到調(diào)試器的控制臺窗口,這個功能通過調(diào)用__sys_write()實現(xiàn),__sys_write()執(zhí)行了一個把字符串輸出到主機控制臺的Semihosting軟中斷服務(wù)程序。
          缺省的存儲器映射
          如果用戶在程序編譯時沒有指定映象的存儲器映射分布,ADS將為生成的目標代碼和數(shù)據(jù)分配一個缺省的存儲器映射圖,如圖3所示。
          目標印象被連接至地址0x8000,存儲和執(zhí)行區(qū)域都位于該地址開始的空間。RO(只讀)部分放在前面,接著是RW(讀寫)部分,最后是ZI(零初始化)部分。
          在ZI部分之上緊跟著HEAP,所以HEAP的確切地址要在連接時才能確定。
          STACK的基地址是在應(yīng)用程序啟動時由一個Semihosting操作提供。這項Semihosting操作返回的地址值視不同調(diào)試環(huán)境而定:
          ulator返回配置文件peripherals.ami中的設(shè)置值;缺省為0x08000000。
          Multi-ICE返回的是調(diào)試器內(nèi)部變量$top_of_memory的值;缺省為0x00080000。
          連接器布局規(guī)則
          連接器對代碼和數(shù)據(jù)在存儲器系統(tǒng)中的分配,遵循一套規(guī)則,如圖4所示。
          映象首先按照屬性以RO-RW-ZI的次序進行排列,在同一種屬性里面代碼先于數(shù)據(jù)。然后連接器將輸入段根據(jù)名字的字母順序進行排列,輸入段的名字與匯編代碼里面的塊名字指示一致(在匯編程序中用AREA關(guān)鍵字)。在輸入段中,來自不同對象的代碼和數(shù)據(jù)放置次序與在連接器命令行中指定的對象文件次序一致。
          在需要靈活分配代碼和數(shù)據(jù)放置位置的情況下,建議用戶不要簡單地依靠這些規(guī)則。后面會介紹一種如何控制代碼和數(shù)據(jù)布局的機制Scatterloading。


          圖5 缺省的ADS初始化過程


          圖6 C庫函數(shù)重定向


          圖7 scatter文件語法


          圖8 分散加載的簡單樣例

          啟動應(yīng)用程序
          大多數(shù)嵌入式系統(tǒng)在進入應(yīng)用主程序之前有一個初始化的過程,該過程完成系統(tǒng)的啟動和初始化功能。缺省的ADS初始化過程如圖5所示。
          總體上,初始化過程可以分成兩部分來看:
          _main負責設(shè)置運行映像存儲器映射;
          _rt_entry負責庫函數(shù)的初始化。
          _main完成代碼和數(shù)據(jù)的復(fù)制,并把ZI數(shù)據(jù)區(qū)清零。這一步只有當代碼和數(shù)據(jù)區(qū)在存儲和運行時處于不同的存儲器位置時才有意義。接著_main跳進_rt_entry,進行STACK和HEAP等的初始化。最后_rt_entry跳進應(yīng)用程序的入口main()。當應(yīng)用程序執(zhí)行完時,_rt_entry又將控制權(quán)交還給調(diào)試器。
          函數(shù)main()在ADS中有特殊的意義。當一個程序工程項目中存在main()時,連接器會把_main和_rt_entry中的初始化代碼連接進來;如果沒有main()函數(shù),初始化過程就不會被連接,結(jié)果就會導(dǎo)致一些標準的C庫函數(shù)無效。
          根據(jù)目標環(huán)境裁減C庫函數(shù)
          缺省狀態(tài)下C庫函數(shù)利用Semihotsting機制來實現(xiàn)設(shè)備驅(qū)動的功能。但一個真正的嵌入式系統(tǒng),要使用到具體的外設(shè)或硬件獨立于主機環(huán)境運行。
          C庫函數(shù)重定向
          用戶可以定義自己的C語言庫函數(shù),連接器在連接時自動使用這些新的功能函數(shù)。這個過程叫做重定向C語言庫函數(shù),如圖6所示。
          舉例來說,用戶有一個I/O設(shè)備(如UART)。本來庫函數(shù)fputc()是把字符輸出到調(diào)試器控制窗口中去的,但用戶把輸出設(shè)備改成了UART端口,這樣一來,所有基于fputc()函數(shù)的printf()系列函數(shù)輸出都被重定向到UART端口上去了。
          下面是實現(xiàn)fputc()重定向的一個例子:
          externvoidsendchar(char*ch);
          intfputc(intch,FILE*f)
          {/*e.g.writeacharactertoanUART*/
          chartempch=ch;
          sendchar(&tempch);
          returnch;

          這個例子簡單地將輸入字符重新定向到另一個函數(shù)sendchar(),sendchar()假定是一個另外定義的串口輸出函數(shù)。在這里,fputc()就好像目標硬件和標準C庫函數(shù)之間的一個抽象層。
          在C語言庫函數(shù)中禁用Semihosting
          在一個獨立的嵌入式應(yīng)用程序中,應(yīng)該不存在SemihostingSWI操作。因此,用戶必須確定在所有調(diào)用到的庫函數(shù)中沒有使用Semihosting。為了保證這一點,在程序中可以引進一個符號關(guān)鍵字_use_no_semihosting:
          在C代碼中,使用#prgrama #pragmaimport〈_use_no_semihosting_swi〉
          在匯編程序中,使用IMPORT
          IMPORT_use_no_semihosting_swi
          這樣,當有使用SWI機制的庫函數(shù)被連接時,連接器會進行報錯:
          Error:Symbol_semihosting_swi_guardmultiplydefined
          為了確定具體是哪一個函數(shù),連接時打開-verbose選項。這樣在結(jié)果信息輸出時,該庫函數(shù)上將有一個_I_use_semihosting_swi的標記。
          Loadingmembersys_wxit.ofromc_a_un.1.
          Definition:_sys_exit
          Reference:_I_use_semihosting_swi
          用戶必須要把這些函數(shù)定義成自己的執(zhí)行內(nèi)容。
          有一點需要注意,連接器只能報告庫函數(shù)中被調(diào)用的Semihosting,對用戶自定義函數(shù)中使用的Semihosting則不會報錯。

          根據(jù)目標硬件定制存儲器映射
          分散裝載(Scatlerloading)
          在實際的嵌入式系統(tǒng)中,ADS提供的缺省存儲器映射是不能滿足要求的。用戶的目標硬件通常有多個存儲器設(shè)備位于不同的位置,并且這些存儲器設(shè)備在程序裝載和運行時可能還有不同的配置。
          Scattertoading可以通過一個文本文件來指定一段代碼或數(shù)據(jù)在加載和運行時在存儲器中的不同位置。這個文本文件scatterfile在命令行中由-scatter開關(guān)指定,例如:
          armlink_scatterscat.scffilel.ofile2.0
          在scatterfile中可以為每一個代碼或數(shù)據(jù)區(qū)在裝載和執(zhí)行時指定不同的存儲區(qū)域地址,Scatlertoading的存儲區(qū)塊可以分成二種類型:
          裝載區(qū):當系統(tǒng)啟動或加載時應(yīng)用程序的存放區(qū)。
          執(zhí)行區(qū):系統(tǒng)啟動后,應(yīng)用程序進行執(zhí)行和數(shù)據(jù)訪問的存儲器區(qū)域,系統(tǒng)在實時運行時可以有一個或多個執(zhí)行塊。
          映像中所有的代碼和數(shù)據(jù)都有一個裝載地址和運行地址(二者可能相同也可能不同,視具體情況而定)。在系統(tǒng)啟動時,C函數(shù)庫中的__main初始化代碼會執(zhí)行必要的復(fù)制及清零操作,使應(yīng)用程序的相應(yīng)代碼和數(shù)據(jù)段從裝載狀態(tài)轉(zhuǎn)入執(zhí)行狀態(tài)。
          1.scatter文件語法
          scatter文件是一個簡單的文本文件,包含一些簡單的語法。
          My_Region0x00000x1000
          {
          thecontextofregion
          }
          每個塊由一個頭標題開始定義,頭中至少包含塊的名字和起始地址,另外還有最大長度和其他一些屬性選項。塊定義的內(nèi)容包括在緊接的一對花括號內(nèi),依賴于具體的系統(tǒng)情況。
          一個加載塊必須至少含有一個執(zhí)行塊;實踐中通常有多個執(zhí)行塊。
          一個執(zhí)行塊必須至少含有一個代碼或數(shù)據(jù)段;這些通常來自源文件或庫函數(shù)等的目標文件;通配符號*可以匹配指定屬性項中所有沒有在文件中定義的余下部分。
          2.簡單分散加載樣例
          圖8所示樣例中,只有一個加載塊,包含了所有的代碼和數(shù)據(jù),起始地址為0。這個加載塊一共對應(yīng)兩個執(zhí)行塊。一個包含所有的RO代碼和數(shù)據(jù),執(zhí)行地址與裝載地址相同;同時另一個起始地址為0x10000的執(zhí)行塊,包含所有的RW和ZI數(shù)據(jù)。這樣當系統(tǒng)開始啟動時,從第一個執(zhí)行塊開始運行(執(zhí)行地址等于裝載地址),在執(zhí)行過程中,有一段初始化代碼會把裝載塊中的一部分代碼轉(zhuǎn)移到另外的執(zhí)行塊中。
          下面是這個scatter描述文件,該文件描述了上述存儲器映射方式。
          LOAD_ROM0x4000

          EXE_ROM0x00000x4000;Rootregion

          *〈+RO〉;Allcodeandconstantdata

          RAM0x100000x8000

          *〈+RW,+ZI〉;Allnon-constantdata


          3.在分散文件中放置對象
          在大多數(shù)應(yīng)用中,并不是像前例那樣,簡單地把所有屬性都放在一起,用戶需要控制特定代碼和數(shù)據(jù)段的放置位置。這可以通過在scatter文件中對單個目標文件進行定義實現(xiàn),而不是只簡單地依靠通配符。
          為了覆蓋標準的連接器布局規(guī)則,我們可以使用+FIRST和+LAST分散加載指令。典型的例子是在執(zhí)行塊的開始處放置中斷向量表格:
          LOAD_ROM0x00000x4000

          EXEC_ROM0x00000x4000

          vectors.o〈Vect,+FIRST〉
          *〈+RO〉

          ;moreexecregions...

          在這個scatter文件中,保證了vextors.o中的Vect域被放置于地址0x0000。
          4.RootRegion(根區(qū))
          根區(qū)是一個執(zhí)行塊,它的加載地址與執(zhí)行地址是一致的。每個scatter文件至少有一個根區(qū)。分散加載有一個限制:創(chuàng)建執(zhí)行塊的代碼和數(shù)據(jù)(即完成復(fù)制和清零的代碼和數(shù)據(jù))無法自行復(fù)制到另一個位置。因此,在根區(qū)中必須含有下面的部分:
          _main.o,包含復(fù)制代碼/數(shù)據(jù)的代碼;
          連接器輸出變量$$Table和ZISection$$Table,包含被復(fù)制代碼/數(shù)據(jù)的地址。
          由于上面兩個部分的屬性是只讀的,因此他們被*〈+RO〉通配符語法匹配。如果*〈+RO〉被用在了非根區(qū)中,則在根區(qū)中必須顯式地指明另一個RO區(qū)域。
          下面是一個例子:
          LOAD_ROM0x00000x4000

          EXE_ROM0x00000x4000;rootregion

          _main.o〈+RO〉;copyingcode
          *〈Region$$Tabl0e〉;RO/RWaddressestocopy
          *〈ZISection$$Table〉;ZIaddressestozero

          RAM0x100000x8000

          *〈+RO〉;allotherROsections
          *〈+RW,+ZI〉;allRWandZIsections

          }■(待續(xù))

          在下期中將更詳細介紹利用scatter文件進行存儲器配置的方法,以及系統(tǒng)啟動和初始化的過程和存儲器映射變化關(guān)系。




          關(guān)鍵詞: ARM

          評論


          相關(guān)推薦

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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();