日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

S3c2410軟件調(diào)試總結(jié)之我見

 昵稱7715138 2011-09-18

S3c2410軟件調(diào)試總結(jié)  

      這部分介紹下ADS下如何生成可以運(yùn)行的ROM鏡像文件,我們知道當(dāng)程序下載到flash中運(yùn)行的時(shí)候,對(duì)于RW、ZI數(shù)據(jù)就存在著兩個(gè)環(huán)境,一個(gè)load 環(huán)境,一個(gè)是exec環(huán)境,有時(shí)候由于速度的需要RO數(shù)據(jù)也要重新加載,那么對(duì)RO數(shù)據(jù)也是有兩個(gè)環(huán)境。編譯器產(chǎn)生ROM鏡像文件時(shí)候,這三塊數(shù)據(jù)的存放依次為RO、RW、ZI,并且地址空間時(shí)連續(xù)的。但是到了運(yùn)行的時(shí)候,RW數(shù)據(jù)必須被拷貝到SDRAM(SRAM)中以支持讀寫,這就是我們所謂的運(yùn)行環(huán)境。那么就要有一段代碼去完成這個(gè)任務(wù),在本章中我們介紹如何生成這段代碼。
      玩過(guò)2410的朋友都知道2410初始化代碼中有一段搬運(yùn)RW和ZI初始化的代碼,沒(méi)錯(cuò),它確實(shí)能夠在一定程度上完成上面所說(shuō)的任務(wù),只要我們?cè)谏啥M(jìn)制可執(zhí)行代碼的時(shí)候在編譯器鏈接項(xiàng)的地方填寫正確的 RO&RW地址,(比如RO =&nbsp0,&nbspRW =&nbsp0x30000000), 那么將程序下到 &nbspNOR&nbspflash的零地址并從nor&nbspflash啟動(dòng),啟動(dòng)代碼會(huì)將RW&ZI數(shù)據(jù)弄到 0x30000000,程序就能跑起來(lái)了。
      但是各位有沒(méi)有想過(guò),怎么把RO代碼弄到SDRAM中(有時(shí)候這是必須的,比方后面我將提到用nor&nbspflash的bootloader燒寫nor&nbspflash)?如果直接設(shè)RO=0x30000000,那么這段代碼下載到0地址肯定跑不起來(lái),除非是ROPI,這個(gè)要求就高了。這里我們有必要從介紹ADS中規(guī)定的C語(yǔ)言入口開始,ADS中從初始化匯編代碼跳到main函數(shù)有兩種方式,main和__main:
1,在__main入口的模式下,匯編代碼的指令為& nbspb&nbsp__main, 編譯器在跳轉(zhuǎn)到main之前還要作一系列的工作,這其中就包括對(duì)運(yùn)行環(huán)境的初始化,在< ADS&nbspCOMPILE&nbspGUIDE>中提到:&nbspcopies&nbspnonroot (RO&RW)&nbspexecution&nbspregions&nbspfrom&nbspload&nbspaddr&nbspto&nbspexec&nbspaddr,&nbspand&nbspZeros& nbspZI&nbspregion. 借助編譯器,我們就可以定義更為復(fù)雜的運(yùn)行環(huán)境,這里要用到scatter文件(.scf),比如我們要的目標(biāo)運(yùn)行環(huán)境是:將啟動(dòng)代碼以外的所有代碼都 拷貝到SDRAM的初始地址中運(yùn)行,比且把RW段設(shè)在0x30800000,那么對(duì)應(yīng)的scf文件如下:
FLASH&nbsp0x0&nbsp0x200000
{
EXEC1&nbsp0x0&nbsp0x200000
{
2410init.o(Init, +First)
__main.o(+RO) &nbspcopy&nbspcode
* (Region$$Table) &nbspRO/RW&nbspaddresses&nbspto&nbspcopy
* (ZISection$$Table) &nbspZI&nbspaddresses&nbspto&nbspzero
}
EXEC2&nbsp0x30000000&nbsp0x00800000
{
*(+RO)
}
SDRAM&nbsp0x30800000&nbsp0x00800000
{
*(+RW,+ZI)
}
}
;Sections&nbspnamed&nbspRegion$$Table&nbspand&nbspZISection$$Table&nbspwhich&nbspcontain&nbspthe&nbspaddresse
s&nbspof&nbspthe&nbspcode/data&nbspto&nbspbe&nbspcopied.

當(dāng)然,在這種模式下,有些入口函數(shù)必須自己重定義,比如__user_initial_stackheap,具體參見ADS文檔。
2, &nbspmain入口模式即簡(jiǎn)單的跳轉(zhuǎn),這里起始不用“main”這個(gè)名字也無(wú)所謂。那么編譯器不會(huì)作任何的初始化,所有運(yùn)行環(huán)境的建立都要 * 我們自己,這就是大家看到的那段搬運(yùn)代碼存在的理由。但是它實(shí)現(xiàn)一些簡(jiǎn)單的運(yùn)行環(huán)境是可取的,如果用scf定義的復(fù)雜環(huán)境,雖然我 相信是可以做到的,但是可能會(huì)比較麻煩。我還沒(méi)深究。
      另外,這里提一下semihost,因?yàn)槲覀冊(cè)诳碅DS的東西的時(shí)候經(jīng)常出現(xiàn)這個(gè)詞,我也一直受其困擾。這里我簡(jiǎn)單說(shuō)一下自己的見解,semihost 僅僅是一種調(diào)試手段,它的機(jī)理就是利用MULTI_IDE等工具捕捉目標(biāo)環(huán)境運(yùn)行過(guò)程中產(chǎn)生的值為0x123456的SWI中斷,然后向上位機(jī)的ADS 軟件發(fā)送對(duì)應(yīng)的調(diào)試信息。對(duì)于我們最后的應(yīng)用代碼來(lái)說(shuō),都是nonsemihost類型的。如果我們?cè)谡{(diào)試中使用semihost,那么只要在最后重定義&nbspADS中的一些使用到的庫(kù)函數(shù)(比如fputc),代碼就可以從 semihost向nonsemihost的類型轉(zhuǎn)變。不過(guò)到目前為止,我還沒(méi)體會(huì)到semihost的威力。


2410啟動(dòng)代碼分析
   這一章主要對(duì)目前廣泛流行的2410啟動(dòng)代碼進(jìn)行分析:S3C2410的初始化代碼主要涉及到對(duì)系統(tǒng)主要模塊的配置、運(yùn)行環(huán)境的建立、系統(tǒng)時(shí)鐘、MMU等模塊的配置,下面按執(zhí)行順序依次都各個(gè)部分進(jìn)行分析:

程序入口:(ResetHandler)
在程序一開始,首先進(jìn)行的一些操作主要保證初始化程序能夠順利的運(yùn)行, 因此主要包括關(guān)閉WDT、中斷,配置鎖相環(huán)等。配置memory接口memory接口是確保數(shù)據(jù)訪問(wèn)正確的基本保障,此處主要配置SFR寄存器中0x48000000開始的memory接口寄存器組, 確保每個(gè)bank的位寬、訪問(wèn)類型(waitable)以及時(shí)序參數(shù)正確。如果沒(méi)有特別的要求,一般來(lái)說(shuō)時(shí)序參數(shù)使用默認(rèn)值即可。

初始化堆棧
ARM有6種運(yùn)行模式,必須為每一種模式提供獨(dú)立的堆??臻g,在堆棧設(shè)置之前是不能進(jìn)行C函數(shù)的調(diào)用的。ARM的堆棧模式 是從高地址遞減的,我的所有代碼統(tǒng)一將堆棧的首地址設(shè)在0x33ff8000處,往低依次為FIQ、IRQ、Abort、Undef、SVC,其中VC和User模式不予區(qū)分。堆棧大小一般可在頭文件或者當(dāng)前文件中修改。

運(yùn)行空間的初始化
這段代碼主要完成兩個(gè)功能,一是將RW數(shù)據(jù)搬運(yùn)到RW空間(我們生成ROM鏡像時(shí),RW數(shù)據(jù)是跟在RO數(shù)據(jù)之后的),二是 初始化ZI數(shù)據(jù)段。當(dāng)然,這段代碼存在的前提是代碼的運(yùn)行環(huán)境只是標(biāo)準(zhǔn)的兩段式:一段RO空間和一段RW空間;并且在C程序
入口時(shí)沒(méi)有調(diào)用編譯器的鏈接庫(kù)(__main)。后者已經(jīng)提供相應(yīng)的功能,并且支持更加復(fù)雜的運(yùn)行環(huán)境定義(使用SCF文件),
(關(guān)于這一點(diǎn),我在介紹ADS中C代碼的啟動(dòng)模式時(shí)已經(jīng)詳細(xì)介紹)。

__rt_lib_init
在ADS1.2的環(huán)境中,如果在C入口沒(méi)有調(diào)用編譯器的鏈接庫(kù)(__main),那么在C程序一開始要調(diào)用該函數(shù)以初始化運(yùn)行時(shí)的函數(shù)庫(kù),以保證對(duì)ADS提供的某些庫(kù)函數(shù)能夠正常調(diào)用。從這個(gè)函數(shù)開始,我們已經(jīng)在C語(yǔ)言環(huán)境下了。

MMU初始化
2410的MMU支持1級(jí)&2級(jí)地址映射,在我們目前大部分應(yīng)用中均采用1級(jí)section模式的地址映射,一個(gè)section的大小為1M,也就是說(shuō)從邏輯地址到物理地址的轉(zhuǎn)變是這樣的一個(gè)過(guò)程:
一個(gè)32位的地址,高12位決定了該地址在頁(yè)表中的index,這個(gè)index的內(nèi)容決定了該邏輯section對(duì)應(yīng)的物理section; 低20位決定了該地址在section中的偏移(index)。
因此從0x0~0xffffffff的地址空間總共可以分成0x1000(4K)個(gè)section,頁(yè)表中每項(xiàng)的大小為32個(gè)bit,因此頁(yè)表的大小為0x4000(16K)。在我的代碼中所有程序的頁(yè)表統(tǒng)一存放在地址0x33ff8000。
每個(gè)頁(yè)表項(xiàng)的內(nèi)容如下:

bit:&nbsp31&nbsp20&nbsp19&nbsp12&nbsp11&nbsp10&nbsp9&nbsp8&nbsp5&nbsp4&nbsp3&nbsp2&nbsp1&nbsp0
content: &nbspSection對(duì)應(yīng)的物理地址&nbspNULL&nbspAP&nbsp0& nbspDomain&nbsp1&nbspC&nbspB&nbsp1&nbsp0

最低兩位(10)是section分頁(yè)的標(biāo)識(shí)。
AP:Access&nbspPermission,區(qū)分只讀、讀寫、SVC&其它模式。
Domain:每個(gè)section都屬于某個(gè)Domain,一個(gè)有16個(gè)Domain,每個(gè)Domain的屬性由CP15的R3寄存器控制。 在我得所有程序中,都只包含兩個(gè)Domain,一個(gè)是SFR地址以下(包括SFR)的空間,可訪問(wèn); 另一個(gè)是SFR以上的空間,不可訪問(wèn)。C、B:這兩位決定了該section的cache&write&nbspbuffer屬性,這與該段的用途(RO&nbspor&nbspRW)有密切關(guān)系。不同的用途要做不同的設(shè)置。

C&nbspB 具體含義
0&nbsp0 無(wú)cache,無(wú)寫緩沖,任何對(duì)memory的讀寫都反映到ASB總線上。

對(duì)&nbspmemory 的操作過(guò)程中CPU需要等待。
0&nbsp1 無(wú)cache,有寫緩沖,讀操作直接反映到ASB總線上。寫操作CPU將數(shù)據(jù)寫入 到寫緩沖后繼續(xù)運(yùn)行,由寫緩沖進(jìn)行ASB操作。1&nbsp0 有cache,寫通模式,讀操作首先考慮cache&nbsphit;寫操作時(shí)直接將數(shù)據(jù)寫入
寫緩沖,如果同時(shí)出現(xiàn)cache&nbsphit,那么也更新cache。1&nbsp1 有cache,寫回模式,讀操作首先考慮cache&nbsphit;寫操作也首先考慮cache,

如果hit,則只修改cache,并將cache對(duì)應(yīng)半行的dirty比特置位;如果miss,則寫入寫緩沖,觸發(fā)ASB總線操作。

在我的程序中內(nèi)存空間的分配統(tǒng)一采用了文末的MEMORY圖。雖然MMU只是使用了邏輯地址到物理地址的linear&nbsptransfer (值不改變),但是由于MMU能夠引入cache&write&nbspbuffer,因此系統(tǒng)性能有很大的提高!

配置時(shí)鐘比、重新設(shè)置PLL
2410內(nèi)部有三個(gè)時(shí)鐘:FCLK、HCLK、PCLK,分別供CPU、AHB總線和APB總線使用,為了降低功耗,一般都選擇周期比為1:2:4的合理配置。 同時(shí)將PLL配置為運(yùn)行環(huán)境時(shí)鐘,一般都達(dá)到最高202M。

IO初始化
將IO口配置為對(duì)應(yīng)的功能選項(xiàng),同時(shí)一般會(huì)點(diǎn)亮相應(yīng)的LED燈。

中斷初始化
2410的內(nèi)存空間沒(méi)有remap的機(jī)制,應(yīng)該中斷入口時(shí)鐘位于零地址。因此中斷服務(wù)機(jī)制可以描述如下:
首先,不管使用那種啟動(dòng)方式,必須確保一下代碼段位于內(nèi)存的0x0地址:
b&nbspResetHandler
b&nbspHandlerUndef handler&nbspfor&nbspUndefined&nbspmode
b&nbspHandlerSWI handler&nbspfor&nbspSWI&nbspinterrupt
b&nbspHandlerPabort handler&nbspfor&nbspPAbort
b&nbspHandlerDabort handler&nbspfor&nbspDAbort
b&nbsp. reserved
b&nbspHandlerIRQ handler&nbspfor&nbspIRQ&nbspinterrupt
b&nbspHandlerFIQ handler&nbspfor&nbspFIQ&nbspinterrupt
除ResetHandler外,其余各項(xiàng)都是由如下的宏定義的一段代碼:
HandlerFIQ&nbspHANDLER&nbspHandleFIQ
MACRO
$HandlerLabel&nbspHANDLER $HandleLabel
$HandlerLabel
sub&nbspsp,sp,#4 decrement&nbspsp(to&nbspstore&nbspjump&nbspaddress)
stmfd&nbspsp!,{r0} PUSH&nbspthe&nbspwork&nbspregister&nbspto&nbspstack
ldr&nbspr0,=$HandleLabel load&nbspthe&nbspaddress&nbspof&nbspHandleXXX&nbspto&nbspr0
ldr&nbspr0,[r0] load&nbspthe&nbspcontents
str&nbspr0,[sp,#4] store&nbspthe&nbspcontents(ISR)&nbspof&nbspHandleXXX&nbspto&nbspstack
ldmfd&nbspsp!,{r0,pc} POP&nbspthe&nbspwork&nbspregister&nbspand&nbsppc(jump&nbspto&nbspISR)
MEND
這段代碼的含義是通過(guò)堆棧將中斷向量表中的內(nèi)容賦給PC指針(如HandleFIQ是存放著FIQ服務(wù)程序入口地址的地址),自然程序就跳到相應(yīng)的入口地址。
可見,中斷向量表存放的是各個(gè)中斷服務(wù)程序的入口地址,它是用來(lái)被加載的,而并不是可執(zhí)行代碼。為了統(tǒng)一,所有示例程序都將中斷向量表放在0x33ffff00開始的地址,并根據(jù)入口地址依次排列。
需要注意的是如果各種模式的服務(wù)程序用C語(yǔ)言定義,那么類型必須用__irq定義,以保證能夠正確返回。

初始化串口
串口統(tǒng)一選用UART0,模式采用115200、1bit&nbspSTOP、No&nbspParity。

最后跳轉(zhuǎn)到我們自己的應(yīng)用程序!

附:我得程序所使用的地址空間結(jié)構(gòu)以及MMU中C、B的設(shè)置:

Blank&nbspArea:&nbspRW_FAULT&nbsp0x5b000000 ~&nbsp0xffffffff

Sram &&nbspSFR:&nbspNCNB&nbsp0x40000000 ~&nbsp0x4affffff

Blank&nbspArea:&nbspRW_FAULT&nbsp0x34000000 ~&nbsp0x3fffffff

Int_Vec,&nbspStack,&nbspMTT:&nbspCNB&nbsp0x33f00000 ~&nbsp0x33ffffff

SDRAM&nbspDownload:&nbspNCNB&nbsp0x31000000 ~&nbsp0x33efffff

SDRAM&nbspExec&nbspRW:&nbspCB&nbsp0x30800000 ~&nbsp0x30ffffff

SDRAM&nbspExec&nbspR&nbspCNB&nbsp0x30000000 ~&nbsp0x307fffff

Bank5,&nbspFPGA:&nbspNCNB&nbsp0x28000000 ~&nbsp0x2fffffff

Bank4,&nbspFPGA:&nbspNCNB&nbsp0x20000000 ~&nbsp0x27ffffff

Bank3,&nbspBottom&nbspNIC:&nbspNCNB&nbsp0x18000000 ~&nbsp0x1fffffff

Bank2,&nbspBottom&nbspFlash:&nbspCNB&nbsp0x10000000 ~&nbsp0x17ffffff

Bank1,&nbspBottom&nbspSram:&nbspCNB&nbsp0x08000000 ~&nbsp0x0fffffff

Bank0,&nbspFlash&nbspor&nbspSram:&nbspCNB&nbsp0x00000000 ~&nbsp0x07ffffff


Nor&nbspFlash&nbspBootloader
這是我著手寫的第一個(gè)程序,我的想法是讓這個(gè)程序同時(shí)支持通過(guò)串口對(duì)Nand 和&nbspNor&nbspFLASH的燒寫,如果不進(jìn)行任何燒

寫,那么就跳到Nor&nbspFlash的第二個(gè)section啟動(dòng)應(yīng)用程序,這樣一來(lái),即使脫離JTGA,我也可以使用串口進(jìn)行盲調(diào)。

由于有現(xiàn)成的初始化文件和flash燒寫的示例程序,開發(fā)起來(lái)還比較快。當(dāng)然也遇到了一些問(wèn)題,一開始連flash的device&nbspID都讀

不出來(lái),后來(lái)發(fā)現(xiàn)我指針沒(méi)有定義成volatile類型,flash的操作時(shí)序被編譯器優(yōu)化了;再者,在對(duì)Nor&nbspFlash進(jìn)行操作時(shí),bank0

在MMU中的類型一定要設(shè)為NCNB,這樣比較保險(xiǎn)。

遇到最大的問(wèn)題就是下面的了,一開始我用jtag把程序下載到 0x30000000的地方運(yùn)行,對(duì)Nor&nbspFlash的燒寫完全正常,但是當(dāng)

把程序下載到Nor&nbspFlash中啟動(dòng)運(yùn)行后,再對(duì)Nor&nbspFlash的section&nbsp2進(jìn)行燒寫時(shí),就出現(xiàn)了問(wèn)題。所幸沒(méi)多久我就意

識(shí)到了問(wèn)題,將程序放在 Nor&nbspFlash中運(yùn)行,同時(shí)有對(duì)同一片flash進(jìn)行操作,那么操作時(shí)序勢(shì)必會(huì)被CPU的指令讀取時(shí)序所破

壞,因此程序必須搬運(yùn)到 SDRAM中運(yùn)行。

但是啟動(dòng)地址有必須是零地址,所以我采用了前文提到的scatter文件的方法,將非必要的代碼全部搬到sdram中運(yùn)行,scf文件格式

就是前文中的那個(gè)。當(dāng)然采用了__main的入口,調(diào)用了ADS的鏈接庫(kù),讓它幫忙建立程序的運(yùn)行環(huán)境。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多