<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x

    基于uboot的2410調試平臺的實現

    發布時間:2010-4-1 17:31    發布者:lelee007
    關鍵詞: uboot , 2410
    --免燒寫nand flash & 不用仿真

    哈哈,平臺!

    名字起的有點大,列位看官莫笑。這年頭,就那么回事。

    如果內容對您有什么用或者幫助,鄙人甚感欣慰;如果沒什么大用,首先,您水平肯定在鄙人之上,其次,就當是看閑書了,雖然筆者筆風不是那么詼諧。

    其實這個東西對于熟悉ARM的人來說,真不是什么難事,太小case了。確實,筆者自己也感覺不過是雕蟲小技而已。但是為什么要寫出來了?!因為筆者也是從51轉到ARM上來的,開始的時候對這個問題困惑了很久,而且就是找不到答案。同時總結出一個問題,不要迷信網絡!網上并非要什么有什么。!RMB,很明顯無法從網上找到。如果從網上實在找不到答案,那么潛心研究研究,可能比網上“盲目”亂找收獲更大。這里之所以給“盲目”二字打上個小引號是因為,這里的盲目并非指您不知道要找什么而去找,而是指您不知道網上到底存不存在您要找的東東,就比如筆者最近總是時不時在網上找關于X11R7.5下ATI顯卡驅動的解決方案,其實AMD官方都沒給出答案,民間又怎么折騰了?如果沒有,您還要浪費時間跟那死找,..........不過經過筆者本次撰述,您就可以在網上找到答案了,KAKA~~~~~~~

    其實要筆者寫點東西也確實難,筆者自己也知道廢話多,但是木有辦法,真正內容就那么點,不扯點廢話,湊不齊篇章。

    廢話到此為止,下面言歸正傳。

    關于這個東東,開始的時候,筆者是因為木有錢買仿真機,而且被一遍一遍的燒寫nand flash折騰的很煩躁,因為nand flash的燒寫速度并不像下載到SRAM或者SDRAM里邊那么快。而且相當nand的壽命有限,燒寫有風險,每次都是heart hard-beating下完成的,生怕nand掛了或者CPU掛了,sigh......生亦何哀,死亦何苦。有痛如斯,夫復何求?!無奈當時對于ARM的MMU還不是很熟悉,而且當時是一邊上班一邊業余折騰,遇到問題了就有點躁。痛定思痛,長痛不如短痛!咬著牙花了一晚上把MMU看了兩遍,結果發現有好幾種配置方式,讓人抓狂哇!哈哈,想想當時真的很傻很天真,就因為有多種配置方式,段式,頁式,頁式還分個粗細,就不知道到底該用哪個更合適,后來想到linux下用哪個方式咱就用哪個方式,然后抱著這個想法去看linux內核代碼,結果不了了之--沒看明白,HOHO~~~~~~~~不過后來是在一個關于ARM MMU的例程中找到了定心丸,就用段式映射,這個最簡單!當時還不知道看SAMSUNG的代碼,很多代碼都是網上雜七雜八搜羅過來的。原理弄明白,方案定下來之后,事情就好辦多了,一步一步實施就是了,無非是代碼出問題了再調試。

    廢話是不是有點多?不過筆者應該是把事情的背景都交代的一清二楚了。接下來就是具體的方案了,請各位看官務必擦亮眼睛,精彩不容錯過!

    原理其實是這樣的,首先移植一個可以用的uboot,至少要包含tftp和go命令,然后將其燒到nand flash里邊,每次系統上電的時候能順利運行uboot;然后我們將編譯鏈接好的目標代碼通過uboot下載到SDRAM里邊,再從uboot里邊go到我們自己的程序去運行。
    實施過程中遇到的幾個問題如下:

    1、代碼的存儲位置和運行位置的問題
    2、中斷向量表的位置問題
    3、中斷入口配置

    第一個問題中關于兩個位置的問題,這應該是連接器要處理的,這個問題不是這里的闡述重點,有興趣的可以參考《arm學習報告》系列文檔,里邊基本講的非常詳細,而且不像GNU Ld那么長篇大論。雖然這個問題不是咱的重點,但是多少對咱是有影響的,不然.............講講到底怎么影響咱的是正事,廢話就不扯了,嘿嘿,因為,廢話已經扯了很多了,GAGA~~~~~~~~~。因為從原理上來看,我們自己編寫的程序用這種方式來調試的話,就不可能再放到0地址開始,讓系統自動加載了,因此存儲地址和運行地址都不能直接用默認的0了,這個地址需要我們在鏈接腳本里邊親自指定一下。為了節省大家時間,筆者在尼度給倆例子吧,一個是源代碼里邊的鏈接腳本文件,一個是鏈接腳本的書寫規則。

    SECTIONS {
    .text
    0x30004000
    :
    {
    head.o
    clock.o
    init.o
    led.o
    serial.o
    timer0.o
    mmu.o
    interrupt.o
    main.o
    }
    }

    這個是鏈接腳本,其中的 0x30004000地址前面的text是指如下內容全是文本段。關于文本段如果您不想看別的資料,就簡單的理解成是代碼段吧。實際也是代碼的運行地址,更確切的說是運行地址的開始,就是我們目標代碼的入口地址。鏈接以后,程序在執行時的一些相對跳轉中,這個地址就是個基地址了。如果在把程序從別的介質加載到運行內存(SDRAM)時,地址發生了錯誤,有些程序就無法正常執行,這就是位置相關和位置無關代碼的區別。

    下面是我注釋的一個lds文件的書寫規則,估計大多數看官都能很快看明白,當然,能把lds的書寫規則系統的研究研究,絕對是大有裨益。



    可能以上內容講的不夠詳細,但是木有辦法,如果這些東西對于您理解這些東西來說還不夠的話,那么強烈建議您認真閱讀下《arm學習報告》系列文檔,共有3篇,《arm學習報告001》、《arm學習報告002》、《arm學習報告003》,因為那個里邊對這個分析的是比較到位的,而且篇幅并不大,絕對值得品味的,筆者也就不再好意思再擱這廢話了。

    之所以講以上關于鏈接的問題,就是因為我們的程序最后不可能放到0地址,然系統一上電就自動去運行,而是要放到SDRAM里邊去,然后從uboot里邊go過去。

    如果是一個非常簡單的程序,不涉及中斷的,那么只講講上面的內容,加上筆者推薦的幾篇文檔,差不多足夠了。但是這樣玩起來就太沒意思了,只夠點個流水燈而已!如果加上中斷,那差不多就把ARM的體系全弄明白了吧。接下來就切入ARM的中斷。
    ARM的中斷體系實際上也不復雜,向量中斷一共就那么8個,reset一個,幾乎是個CPU都會有這玩意,就像男人的撒尿工具。然后就是什么未定義的一個,軟中斷,預取終止,數據終止,中間還有個未使用的,后面就生外部中斷和快中斷了。這8個里邊我們用到最多的也就是reset、外部中斷這兩個,連快中斷都比較少用。

    reset就是一個入口,CPU在上電的時候先找她!如果您有什么工作希望CPU在上電之后就做的話,您也找她!

    外部中斷的入口用處是非常強大的,因為一切外部中斷源都要經過他。2410上的外部中斷實際上是這樣安排的,首先在系統的向量中斷中安排了外部中斷這一級,然后在外部中斷中又安排了下一級的中斷表,這一級就不再是向量式的了,但是這一級的中斷入口都是隔4個字節放置一個,即每個入口的地址用4個字節來描述。這就是2410的二級中斷表。第二級的中斷表其實每個地址也是固定對應一個中斷源的。算了,還是廢話少說,上代碼。

    _start:
    @ 0x00: 中斷向量表并非從0地址開始放置,因為我們使用的直接SDRAM調試時,中斷入口是需要通過MMU來映射的
    @Reset:
    b
    Reset
    @直接在SDRAM中調試的話,實際是不使用Reset的,因此一Reset,硬件系統將從nand flash中讀取uboot來執行,所以此處實際是個空語句處理
    @ 0x04: Undefined instruction exception
    HandleUndef:
    b
    HandleUndef
    @ 0x08: Software interrupt exception
    HandleSWI:
    b
    HandleSWI
    @ 0x0c: Prefetch Abort (Instruction Fetch Memory Abort)
    HandlePrefetchAbort:
    b
    HandlePrefetchAbort
    @ 0x10: Data Access Memory Abort
    HandleDataAbort:
    b
    HandleDataAbort
    @ 0x14: Not used
    HandleNotUsed:
    b
    HandleNotUsed
    @ 0x18: IRQ(Interrupt Request) exception
    ldr
    pc,HandleIRQAddr
    @
    ldr
    pc,=HandleIRQ
    @ 0x1c: FIQ(Fast Interrupt Request) exception
    HandleFIQ:
    b
    HandleFIQ

    這幾行是最基本的,不用講也該明白。

    lelee-debug.tar

    29.51 KB, 下載積分: 積分 -1

    本文地址:http://www.portaltwn.com/thread-10096-1-1.html     【打印本頁】

    本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
    lelee007 發表于 2010-4-1 17:31:32
    接下來就是咱們的二級中斷表了。

            HandleEINT0:
           .long      0
           HandleEINT1:
           .long      0
           HandleEINT2:
           .long      0
           HandleEINT3:
           .long      0
           HandleEINT4_7:
           .long      0
           HandleEINT8_23:
           .long      0
           HandleRSV6:
           .long      0
           HandleBATFLT:
           .long      0
           HandleTICK:
           .long      0
           HandleWDT:
           .long      0
           HandleTIMER0:
    @   .long      Timer0_Handle
           .long      0
           HandleTIMER1:
           .long      0
           HandleTIMER2:
           .long      0
           HandleTIMER3:
           .long      0
           HandleTIMER4:
           .long      0
           HandleUART2:
           .long      0
           HandleLCD:
           .long      0
           HandleDMA0:
           .long      0
           HandleDMA1:
           .long      0
           HandleDMA2:
           .long      0
           HandleDMA3:
           .long      0
           HandleMMC:
           .long      0
           HandleSPI0:
           .long      0
           HandleUART1:
           .long      0
           HandleRSV24:
           .long      0
           HandleUSBD:
           .long      0
           HandleUSBH:
           .long      0
           HandleIIC:
           .long      0
           HandleUART0:
           .long      0
           HandleSPI1:
           .long      0
           HandleRTC:
           .long      0
           HandleADC:
           .long      0

    這個表實際上僅僅是聲明了一個long型的量,先占上4個字節,具體的內容將由我們自己來填寫。填寫什么內容好了?!當然是對應的中斷的處理函數了。從標號可以看出來,這些是用來處理中斷的,你說不填寫中斷處理函數,填什么了?!至于中斷函數怎么填,這個是C語言的問題了。

    光有這倆表是遠遠不夠的。因為還有很多問題沒解決。首先,表放到那兒?其次,中斷來了怎么找這個表?其實這倆問題合起來也算是一個問題,系統如果知道表在哪兒了,那肯定能找到;但是也不一定就真的只是一個問題,如果你放的位置不正確,那么就算系統知道在哪兒,他如果跑不過去,那也不算找到了!

    表放哪兒的問題很好解決,2410手冊里有講,向量中斷表只有兩種放法,低地址和高地址!低地址就是從0開始存放,高地址就是從0XFFFF0000開始存放。這個是通過配置協處理器寄存器實現的。有兩種放法,有兩種放法?有兩種放法?!倒塌。!哪種放法好?哪種更合適?到底怎么放好啊~~~~~~~~~~~~~別急,看需求,看習慣。如果你不啟用MMU,高端是沒法用的,因為你的系統肯定不會在高端地址處配置一個ROM。那就只能用低端了唄。如此以來,可以把表放到2410的小石頭里邊去了?磥聿婚_啟MMU也挺好,就那么一種選擇,省去不少事。不過筆者這里要介紹的是開啟MMU之后的用法。當然開啟MMU之后就比這個靈活多了,您想用高端用高端,想用低端用低端。只需要將您選定的地址映射到物理內存中就O了,比如咱想放低端,就是0開始的地址,那咱用MMU把邏輯0地址給映射到SDRAM的0X30F00000,那么在程序啟動之后就把中斷表copy到0X30F00000處,然后配置MMU映射表,最后開啟MMU,O了!放高端的話,以此類推。當然具體地址咱可以隨便定,但是也不能太隨便了,免得自己給自己找麻煩。MMU映射表的代碼可以在附件中找到,就是MMU.c中。Copy中斷表的代碼這里可以列出來

    void       copy_vectors_to_high()//by lelee,用于SDRAM調試的時候,copy中斷向量表,實際是從SDRAM里copy,而不再是從nand copy 了

    {
           unsigned int i = 0;      
           for(i = 0;i < 128;i++){
                  (*(unsigned int *)(0x33ff0000 + (i << 2)))=(*(unsigned int *)(0x30004000 + (i << 2)));
           }
    }

    就這么簡單,中斷表搞定了。

    最后一個問題就是中斷入口的配置問題了。這里是外部中斷擴展出來的真正的外部中斷源的入口配置問題,這個很關鍵。中斷處理流程請查找2410手冊,不過這里可以簡略介紹,省去您找手冊的麻煩。

    HandleIRQ:
           sub  lr, lr, #4         @計算返回地址
           stmdb    sp!,        { r0-r12,lr }  @保存使用到的寄存器
    @added from a-nan
           sub  sp,sp,#4        @堆棧指針減4,空出一個單元,以便后面放入PC需要的字 reserved for PC
           stmfd     sp!,{r8-r9}           @r8,r9入棧,此時存儲r8,r9的兩個堆棧單元下面的一個單元是空的
    @   ldr   r9,=INTOFFSET       @INTOFFSET寄存器中存放中斷源號,標明是哪個中斷,CHIP規定死的,相當于查表。
           ldr   r9,=0x4A000014
           ldr   r9,[r9]           @
    @   ldr   r8,=HandleEINT0      @入口可以隨便放,與中斷向量表沒有關系
           ldr   r8,=0xffff0024
           add r8,r8,r9,lsl #2       @中斷號乘以4,然后加上HandleEINT0,得到的將是該中斷的入口
           ldr   r8,[r8]
           str   r8,[sp,#8]             @把得到的中斷向量的內容(timer0Handler的地址)放入最開始空出的堆棧單元,由于這個單元在r8,r9下面,所以位置是sp+8
           ldr   lr,    =int_return   @設置返回地址      
          ldmfd    sp!,{r8-r9,pc}      @把堆棧頂部的三個單元分別出棧到r8,r9,和pc,此時pc會跳轉到中斷向量里存儲的地址,也就是timer0Handler
    @added from a-nan
    @   ldr   lr,    =int_return   @設置返回地址      
    @   ldr   pc, =Timer0_Handle @調用中斷處理函數,在interrupt.c中
    int_return:
           ldmia     sp!,        { r0-r12,pc }^      @中斷返回, ^表示將spsr的值復制到cpsr

    我的解釋看明白了沒有?嘿嘿

    實際上外部中斷是用向量中斷里的一個中斷來擴展的,然后有用于擴展的寄存器,比如 INTOFFSET,里邊的10進制數表明了是順序為多少的中斷發生了,外部中斷來了之后,先讀該寄存器,然后判斷往哪兒跳。跳的過程就是先把 INTOFFSET讀到r9里邊去,然后把二級表的開始地址讀到r8里邊去,接著將r9里邊的值乘以4再加上r8里邊的值,結果還是放到r8中,r8中的值就是我們最后要跳轉的目的地址,然后壓棧,跳轉就是靠彈棧實現的,將r8的值彈到pc里邊去,下一條指令的時候,就跳到r8的值指定的地址進行取指譯碼之類的操作了。后面的幾條指令就是設置中斷返回地址了。

    最后再廢話一點點,關于二級表的位置。void     copy_vectors_to_high()這個函數里邊實現了將向量中斷表和二級中斷表一起copy到高端地址。在copy的時候,MMU木有開啟,中斷也給屏蔽了,所以看代碼可以看出,copy過程中使用的地址都是物理地址。二級表的填充就很easy了,對應的各個表項地址都聲明了對應的名字,由預定義完成的,如何填寫,這也是C語言的問題。不贅述。由于二級表可以在程序中隨意配置,所以也可以叫動態配置的二級中斷表。比如拿代碼中的timer0來作例子說事,我們可以在初始化函數中這個樣子:

    void Timer0_init()
    {
           TCFG0 = 119;     //Prescaler0 = 119              
           TCFG1 = 0x03;   //Select MUX input for PWM Timer0:divider=16
    //     TCNTB0 = 3125;       //0.5秒鐘觸發一次中斷
    //     TCNTB0 = 13020;     //0.5秒鐘觸發一次中斷
           TCNTB0 = 26040;     //0.5秒鐘觸發一次中斷
    //     TCNTB0 = 3255;
    //     TCON |=  (1<<1);     //Timer 0 manual update
           TCON = 0x02;
           TCON = 0x09;    /*Timer 0 auto reload on
                           Timer 0 output inverter off
                           清"Timer 0 manual update"
                           Timer 0 start */
    //     ISR_TIMER0 + 4 = (unsigned int)Timer0_Handle;
           ISR_TIMER0 = (unsigned int)Timer0_Handle;
    }

    然后在 Timer0_Handle()函數中再將 ISR_TIMER0的內容給換了,比如:

    void Timer0_Handle()
    {
           /*   
           if(INTOFFSET == 10){
                  GPBDAT = ~(GPBDAT & (0xf << 7));
           //     timer0_flag = !timer0_flag;
           }
           */
           if (timer0_flag == 1)
                  {
                         timer0_flag = 0;
                  }
           else
                  {
                         timer0_flag = 1;
                         ISR_TIMER0 = (unsigned int)Timer0_Handle001;//動態配置中斷服務程序入口
                  }

           if(timer0_flag){
                  //wait(100000);
                  //led_red_on();
                  led_grn_on();
                  //wait(100000);
                  led_red_off();
                  //led_grn_on();
                  printk("This is Timer0_Handle!!!\n\r");
           }
           else{
                  led_red_on();
                  led_grn_off();
           }
           //清中斷
           SRCPND = 1 << INTOFFSET;
           INTPND = INTPND;      
    }

    差不多,就這么著,可勁的折騰吧。

    最后總結一下,其實很簡單,如果對編譯鏈接理解透了,同時對MMU和2410的中斷表的放置熟悉了,就足夠折騰出這玩意了。有了這個,咱調試起來就方便了,新增加的程序,或者其他要使用的中斷,加進來就是了。程序編譯完了,通過uboot DOWN到SDRAM的0x30004000地址處,這個是鏈接地址,程序的入口在這里,入了口之后,此地址之前的16K空間是預備后來初始化MMU時存放映射表的。因為要16K的空間存放映射表,所以程序入口選擇放在SDRAM的16K地址之后開始存放。SDRAM的開始地址是0X30000000。DOWN完之后再從uboot里邊go 0x30004000,好了,接下來就不再是運行uboot了,運行的就是咱自己的程序了,跟uboot半點關系都木有了。這么下來,是不是發現很簡單?!確實是雕蟲小技。

    附件中是相關代碼,其中有readme.txt,里邊有告訴怎么操作。如果感興趣又沒全看明白的,給俺發郵件,最好是擱公社里邊白話。
    lelee007 發表于 2010-4-1 17:31:58
    暈翻,插入的圖片位置不對頭
    huizijingxin 發表于 2010-4-1 17:33:05
    麗麗gg牛
    忘情天書 發表于 2010-4-1 17:58:49
    贊一個!
    f.luo 發表于 2010-4-1 18:04:00
    丫丫的,原本以為3月都在幾大牛人都現身了,我四月再冒泡泡,現在看來虧了!再等等!
    lelee007 發表于 2010-4-1 19:19:13
    有一點東西大意了,代碼里邊關于LED控制的GPIO

    哈哈,如果板子上的配置跟俺不一樣的,可得把代碼仔細改改了
    dddg 發表于 2010-4-1 19:27:25
       這個語文水平,有待提高...  還是肉皮語文好一些.
    lelee007 發表于 2010-4-1 20:10:55
    咱是拋磚引玉
    linux_Ultra 發表于 2010-4-1 20:28:03
    對于三星24xx這個分支uboot 一直都不用mmu和caches吧?
    龍龍 發表于 2010-4-1 20:29:30
    這么有技術含量的東西也放灌水菜園里~~拆遷辦的呢。!趕緊的!{:4_83:}
    f.luo 發表于 2010-4-1 20:40:35
    嗯,等待拆遷辦的出現。
    lelee007 發表于 2010-4-1 20:42:44
    uboot中,MMU是沒開啟,cache那部分的代碼沒研究過
    admin 發表于 2010-4-2 10:07:28
    這是lele的參賽文章?
    lelee007 發表于 2010-4-2 10:51:34
    恩啦,哈哈,寫的比較糙,見笑了
    老郭 發表于 2010-4-2 14:56:35
    昨天沒看到。
    俺把你那些沒有的空行刪掉了,這樣更緊湊些。圖片也插到地方了。
    很不錯,和阿南、RP的風格不一樣
    lelee007 發表于 2010-4-2 15:33:21
    娃哈哈,還是老郭識貨哇,嘿嘿

    每段的縮進沒了
    lelee007 發表于 2010-4-3 16:23:50
    跟rp說的過了潑水節似的
    f.luo 發表于 2010-4-3 16:54:35
    放假嘛,大多去玩了。
    lelee007 發表于 2010-4-3 16:59:28
    哈哈哈哈

    看看放假之后還有木有人過來翻
    12下一頁
    您需要登錄后才可以發表評論 登錄 | 立即注冊

    廠商推薦

    • Microchip視頻專區
    • EtherCAT®和Microchip LAN925x從站控制器介紹培訓教程
    • MPLAB®模擬設計器——在線電源解決方案,加速設計
    • 讓您的模擬設計靈感,化為觸手可及的現實
    • 深度體驗Microchip自動輔助駕駛應用方案——2025巡展開啟報名!
    • 貿澤電子(Mouser)專區

    相關視頻

    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷