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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 基于ARM的嵌入式Linux移植真實體驗(2)――BootLoader

          基于ARM的嵌入式Linux移植真實體驗(2)――BootLoader

          作者: 時間:2016-11-09 來源:網(wǎng)絡 收藏
          BootLoader指系統(tǒng)啟動后,在操作系統(tǒng)內核運行之前運行的一段小程序。通過BootLoader,我們可以初始化硬件設備、建立內存空間的映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個合適的狀態(tài),以便為最終調用操作系統(tǒng)內核準備好正確的環(huán)境。通常,BootLoader是嚴重地依賴于硬件而實現(xiàn)的,特別是在嵌入式世界。因此,在嵌入式世界里建立一個通用的 BootLoader 幾乎是不可能的。盡管如此,我們仍然可以對BootLoader歸納出一些通用的概念來,以指導用戶特定的BootLoader設計與實現(xiàn)。
          BootLoader 的實現(xiàn)依賴于CPU的體系結構,因此大多數(shù) BootLoader 都分為stage1 和stage2 兩大部分。依賴于CPU體系結構的代碼,比如設備初始化代碼等,通常都放在 stage1中,而且通常都用匯編語言來實現(xiàn),以達到短小精悍的目的。而stage2 則通常用C 語言來實現(xiàn),這樣可以實現(xiàn)更復雜的功能,而且代碼會具有更好的可讀性和可移植性。
          BootLoader 的 stage1 通常包括以下步驟:
          Ø 硬件設備初始化;
          Ø 為加載Boot Loader的stage2準備 RAM 空間;
          Ø 拷貝Boot Loader的stage2 到RAM空間中;
          Ø 設置好堆棧;
          Ø 跳轉到 stage2 的 C 入口點。
          Boot Loader的stage2通常包括以下步驟:
          Ø 初始化本階段要使用到的硬件設備;
          Ø 檢測系統(tǒng)內存映射(memory map);
          Ø 將kernel 映像和根文件系統(tǒng)映像從flash上讀到 RAM 空間中;
          Ø 為內核設置啟動參數(shù);
          Ø 調用內核。
          本系統(tǒng)中的BootLoader參照韓國mizi公司的vivi進行修改。
          1.開發(fā)環(huán)境
          我們購買了武漢創(chuàng)維特信息技術有限公司開發(fā)的具有自主知識產權的應用于嵌入式軟件開發(fā)的集成軟、硬件開發(fā)平臺ADT(ARM Development Tools)它為基于ARM 核的嵌入式應用提供了一整套完備的開發(fā)方案,包括程序編輯、工程管理和設置、程序編譯、程序調試等。
          ADT嵌入式開發(fā)環(huán)境由ADT Emulator for ARM 和ADT IDE for ARM組成。ADT Emulator for ARM 通過JTAG 實現(xiàn)主機和目標機之間的調試支持功能。它無需目標存儲器,不占用目標系統(tǒng)的任何端口資源。目標程序直接在目標板上運行,通過ARM 芯片的JTAG 邊界掃描口進行調試,屬于完全非插入式調試,其仿真效果接近真實系統(tǒng)。
          ADT IDE for ARM 為用戶提供高效明晰的圖形化嵌入式應用軟件開發(fā)環(huán)境,包括一整套完備的面向嵌入式系統(tǒng)的開發(fā)和調試工具:源碼編輯器、工程管理器、工程編譯器(編譯器、匯編器和連接器)、集成調試環(huán)境、ADT Emulator for ARM 調試接口等。其界面同Microsoft Visual Studio 環(huán)境相似,用戶可以在ADT IDE for ARM 集成開發(fā)環(huán)境中創(chuàng)建工程、打開工程,建立、打開和編輯文件,編譯、連接、設置、運行、調試嵌入式應用程序。
          ADT嵌入式軟件開發(fā)環(huán)境采用主機-目標機交叉開發(fā)模型。ADT IDE for ARM 運行于主機端,而ADT Emulator for ARM 實現(xiàn)ADT IDE for ARM 與目標機之間的連接。開發(fā)時,首先由ADT IDE for ARM 編譯連接生成目標代碼,然后建立與ADT Emulator for ARM 之間的調試通道,調試通道建立成功后,就可以在ADT IDE for ARM 中通過ADT Emulator for ARM 控制目標板實現(xiàn)目標程序的調試,包括將目標代碼下載到目標機中,控制程序運行,調試信息觀察等等。

          2.ARM匯編
          ARM本身屬于RISC指令系統(tǒng),指令條數(shù)就很少,而其編程又以C等高級語言為主,我們僅需要在Bootloader的第一階段用到少量匯編指令
          (1)+-運算
          ADD r0, r1, r2
          ―― r0 := r1 + r2
          SUB r0, r1, r2
          ―― r0 := r1 - r2
          其中的第二個操作數(shù)可以是一個立即數(shù):
          ADD r3, r3, #1
          ―― r3 := r3 + 1
          第二個操作數(shù)還可以是位移操作后的結果:
          ADD r3, r2, r1, LSL #3
          ―― r3 := r2 + 8.r1
          (2)位運算
          AND r0, r1, r2
          ―― r0 := r1 and r2
          ORR r0, r1, r2
          ―― r0 := r1 or r2
          EOR r0, r1, r2
          ―― r0 := r1 xor r2
          BIC r0, r1, r2
          ―― r0 := r1 and not r2
          (3)寄存器搬移
          MOV r0, r2
          ―― r0 := r2
          MVN r0, r2
          ―― r0 := not r2
          (4)比較
          CMP r1, r2
          ―― set cc on r1 - r2
          CMN r1, r2
          ―― set cc on r1 + r2
          TST r1, r2
          ―― set cc on r1 and r2
          TEQ r1, r2
          ―― set cc on r1 or r2
          這些指令影響CPSR寄存器中的 (N, Z, C, V) 位
          (5)內存操作
          LDR r0, [r1]
          ―― r0 := mem [r1]
          STR r0, [r1]
          ―― mem [r1] := r0
          LDR r0, [r1, #4]
          ―― r0 := mem [r1+4]
          LDR r0, [r1, #4] !
          ―― r0 := mem [r1+4] r1 := r1 + 4
          LDR r0, [r1], #4
          ―― r0 := mem [r1] r1 := r1 +4
          LDRB r0 , [r1]
          ―― r0 := mem8 [r1]
          LDMIA r1, {r0, r2, r5}
          ―― r0 := mem [r1] r2 := mem [r1+4] r5 := mem [r1+8]
          {..} 可以包括r0~r15中的所有寄存器,若包括r15 (PC)將導致程序的跳轉。
          (6)控制流
          例1:
          MOV r0, #0 ; initialize counter
          LOOP:
          ADD r0, r0, #1 ; increment counter
          CMP r0, #10 ; compare with limit
          BNE LOOP ; repeat if not equal
          例2:
          CMP r0, #5
          ADDNE r1, r1, r0
          SUBNE r1, r1, r2
          ――
          if (r0 != 5) {
          r1 := r1 + r0 - r2
          }
          3.BootLoader第一階段
          3.1硬件設備初始化
          基本的硬件初始化工作包括:
          Ø 屏蔽所有的中斷;
          Ø 設置CPU的速度和時鐘頻率;
          Ø RAM初始化;
          Ø 初始化LED
          ARM的中斷向量表設置在0地址開始的8個字空間中,如下表:
          每當其中的某個異常發(fā)生后即將PC值置到相應的中斷向量處,每個中斷向量處放置一個跳轉指令到相應的中斷服務程序去進行處理,中斷向量表的程序如下:
          @ 0x00: Reset
          b Reset
          @ 0x04: Undefined instruction exception
          UndefEntryPoint:
          b HandleUndef
          @ 0x08: Software interrupt exception
          SWIEntryPoint:
          b HandleSWI
          @ 0x0c: Prefetch Abort (Instruction Fetch Memory Abort)
          PrefetchAbortEnteryPoint:
          b HandlePrefetchAbort
          @ 0x10: Data Access Memory Abort
          DataAbortEntryPoint:
          b HandleDataAbort
          @ 0x14: Not used
          NotUsedEntryPoint:
          b HandleNotUsed
          @ 0x18: IRQ(Interrupt Request) exception
          IRQEntryPoint:
          b HandleIRQ
          @ 0x1c: FIQ(Fast Interrupt Request) exception
          FIQEntryPoint:
          b HandleFIQ
          復位時關閉看門狗定時器、屏蔽所有中斷:
          Reset:
          @ disable watch dog timer
          mov r1, #0x53000000
          mov r2, #0x0
          str r2, [r1]
          @ disable all interrupts
          mov r1, #INT_CTL_BASE
          mov r2, #0xffffffff
          str r2, [r1, #oINTMSK]
          ldr r2, =0x7ff
          str r2, [r1, #oINTSUBMSK]
          設置系統(tǒng)時鐘:
          @init clk
          @ 1:2:4
          mov r1, #CLK_CTL_BASE
          mov r2, #0x3
          str r2, [r1, #oCLKDIVN]
          mrc p15, 0, r1, c1, c0, 0 @ read ctrl register
          orr r1, r1, #0xc0000000 @ Asynchronous
          mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
          @ now, CPU clock is 200 Mhz
          mov r1, #CLK_CTL_BASE
          ldr r2, mpll_200mhz
          str r2, [r1, #oMPLLCON]
          點亮所有的用戶LED:
          @ All LED on
          mov r1, #GPIO_CTL_BASE
          add r1, r1, #oGPIO_F
          ldr r2,=0x55aa
          str r2, [r1, #oGPIO_CON]
          mov r2, #0xff
          str r2, [r1, #oGPIO_UP]
          mov r2, #0x00
          str r2, [r1, #oGPIO_DAT]
          設置(初始化)內存映射:
          ENTRY(memsetup)
          @ initialise the static memory
          @ set memory control registers
          mov r1, #MEM_CTL_BASE
          adrl r2, mem_cfg_val
          add r3, r1, #52
          1: ldr r4, [r2], #4
          str r4, [r1], #4
          cmp r1, r3
          bne 1b
          mov pc, lr
          設置(初始化)UART:
          @ set GPIO for UART
          mov r1, #GPIO_CTL_BASE
          add r1, r1, #oGPIO_H
          ldr r2, gpio_con_uart
          str r2, [r1, #oGPIO_CON]
          ldr r2, gpio_up_uart
          str r2, [r1, #oGPIO_UP]
          bl InitUART
          @ Initialize UART
          @
          @ r0 = number of UART port
          InitUART:
          ldr r1, SerBase
          mov r2, #0x0
          str r2, [r1, #oUFCON]
          str r2, [r1, #oUMCON]
          mov r2, #0x3
          str r2, [r1, #oULCON]
          ldr r2, =0x245
          str r2, [r1, #oUCON]
          #define UART_BRD ((50000000 / (UART_BAUD_RATE * 16)) - 1)
          mov r2, #UART_BRD
          str r2, [r1, #oUBRDIV]
          mov r3, #100
          mov r2, #0x0
          1: sub r3, r3, #0x1
          tst r2, r3
          bne 1b
          #if 0
          mov r2, #U
          str r2, [r1, #oUTXHL]
          1: ldr r3, [r1, #oUTRSTAT]
          and r3, r3, #UTRSTAT_TX_EMPTY
          tst r3, #UTRSTAT_TX_EMPTY
          bne 1b
          mov r2, #0
          str r2, [r1, #oUTXHL]
          1: ldr r3, [r1, #oUTRSTAT]
          and r3, r3, #UTRSTAT_TX_EMPTY
          tst r3, #UTRSTAT_TX_EMPTY
          bne 1b
          #endif
          mov pc, lr
          此外,vivi還提供了幾個匯編情況下通過串口打印字符的函數(shù)PrintChar、PrintWord和PrintHexWord:
          @ PrintChar : prints the character in R0
          @ r0 contains the character
          @ r1 contains base of serial port
          @ writes ro with XXX, modifies r0,r1,r2
          @ TODO : write ro with XXX reg to error handling
          PrintChar:
          TXBusy:
          ldr r2, [r1, #oUTRSTAT]
          and r2, r2, #UTRSTAT_TX_EMPTY
          tst r2, #UTRSTAT_TX_EMPTY
          beq TXBusy
          str r0, [r1, #oUTXHL]
          mov pc, lr
          @ PrintWord : prints the 4 characters in R0
          @ r0 contains the binary word
          @ r1 contains the base of the serial port
          @ writes ro with XXX, modifies r0,r1,r2
          @ TODO : write ro with XXX reg to error handling
          PrintWord:
          mov r3, r0
          mov r4, lr
          bl PrintChar
          mov r0, r3, LSR #8 /* shift word right 8 bits */
          bl PrintChar
          mov r0, r3, LSR #16 /* shift word right 16 bits */
          bl PrintChar
          mov r0, r3, LSR #24 /* shift word right 24 bits */
          bl PrintChar
          mov r0, #r
          bl PrintChar
          mov r0, #n
          bl PrintChar
          mov pc, r4
          @ PrintHexWord : prints the 4 bytes in R0 as 8 hex ascii characters
          @ followed by a newline
          @ r0 contains the binary word
          @ r1 contains the base of the serial port
          @ writes ro with XXX, modifies r0,r1,r2
          @ TODO : write ro with XXX reg to error handling
          PrintHexWord:
          mov r4, lr
          mov r3, r0
          mov r0, r3, LSR #28
          bl PrintHexNibble
          mov r0, r3, LSR #24
          bl PrintHexNibble
          mov r0, r3, LSR #20
          bl PrintHexNibble
          mov r0, r3, LSR #16
          bl PrintHexNibble
          mov r0, r3, LSR #12
          bl PrintHexNibble
          mov r0, r3, LSR #8
          bl PrintHexNibble
          mov r0, r3, LSR #4
          bl PrintHexNibble
          mov r0, r3
          bl PrintHexNibble
          mov r0, #r
          bl PrintChar
          mov r0, #n
          bl PrintChar
          mov pc, r4
          3.2Bootloader拷貝
          配置為從NAND FLASH啟動,需要將NAND FLASH中的vivi代碼copy到RAM中:
          #ifdef CONFIG_S3C2410_NAND_BOOT
          bl copy_myself
          @ jump to ram
          ldr r1, =on_the_ram
          add pc, r1, #0
          nop
          nop
          1: b 1b @ infinite loop
          #ifdef CONFIG_S3C2410_NAND_BOOT
          @
          @ copy_myself: copy vivi to ram
          @
          copy_myself:
          mov r10, lr
          @ reset NAND
          mov r1, #NAND_CTL_BASE
          ldr r2, =0xf830 @ initial value
          str r2, [r1, #oNFCONF]
          ldr r2, [r1, #oNFCONF]
          bic r2, r2, #0x800 @ enable chip
          str r2, [r1, #oNFCONF]
          mov r2, #0xff @ RESET command
          strb r2, [r1, #oNFCMD]
          mov r3, #0 @ wait
          1: add r3, r3, #0x1
          cmp r3, #0xa
          blt 1b
          2: ldr r2, [r1, #oNFSTAT] @ wait ready
          tst r2, #0x1
          beq 2b
          ldr r2, [r1, #oNFCONF]
          orr r2, r2, #0x800 @ disable chip
          str r2, [r1, #oNFCONF]
          @ get read to call C functions (for nand_read())
          ldr sp, DW_STACK_START @ setup stack pointer
          mov fp, #0 @ no previous frame, so fp=0
          @ copy vivi to RAM
          ldr r0, =VIVI_RAM_BASE
          mov r1, #0x0
          mov r2, #0x20000
          bl nand_read_ll
          tst r0, #0x0
          beq ok_nand_read
          #ifdef CONFIG_DEBUG_LL
          bad_nand_read:
          ldr r0, STR_FAIL
          ldr r1, SerBase
          bl PrintWord
          1: b 1b @ infinite loop
          #endif
          ok_nand_read:
          #ifdef CONFIG_DEBUG_LL
          ldr r0, STR_OK
          ldr r1, SerBase
          bl PrintWord
          #endif
          @ verify
          mov r0, #0
          ldr r1, =0x33f00000
          mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
          go_next:
          ldr r3, [r0], #4
          ldr r4, [r1], #4
          teq r3, r4
          bne notmatch
          subs r2, r2, #4
          beq done_nand_read
          bne go_next
          notmatch:
          #ifdef CONFIG_DEBUG_LL
          sub r0, r0, #4
          ldr r1, SerBase
          bl PrintHexWord
          ldr r0, STR_FAIL
          ldr r1, SerBase
          bl PrintWord
          #endif
          1: b 1b
          done_nand_read:
          #ifdef CONFIG_DEBUG_LL
          ldr r0, STR_OK
          ldr r1, SerBase
          bl PrintWord
          #endif
          mov pc, r10
          @ clear memory
          @ r0: start address
          @ r1: length
          mem_clear:
          mov r2, #0
          mov r3, r2
          mov r4, r2
          mov r5, r2
          mov r6, r2
          mov r7, r2
          mov r8, r2
          mov r9, r2
          clear_loop:
          stmia r0!, {r2-r9}
          subs r1, r1, #(8 * 4)
          bne clear_loop
          mov pc, lr
          #endif @ CONFIG_S3C2410_NAND_BOOT
          3.3進入C代碼
          首先要設置堆棧指針sp,堆棧指針的設置是為了執(zhí)行C語言代碼作好準備。設置好堆棧后,調用C語言的main函數(shù):
          @ get read to call C functions
          ldr sp, DW_STACK_START @ setup stack pointer
          mov fp, #0 @ no previous frame, so fp=0
          mov a2, #0 @ set argv to NULL
          bl main @ call main
          mov pc, #FLASH_BASE @ otherwise, reboot
          4. BootLoader第二階段
          vivi Bootloader的第二階段又分成了八個小階段,在main函數(shù)中分別調用這幾個小階段的相關函數(shù):
          int main(int argc, char *argv[])
          {
          int ret;
          /*
          * Step 1:
          */
          putstr("rn");
          putstr(vivi_banner);
          reset_handler();
          /*
          * Step 2:
          */
          ret = board_init();
          if (ret) {
          putstr("Failed a board_init() procedurern");
          error();
          }
          /*
          * Step 3:
          */
          mem_map_init();
          mmu_init();
          putstr("Succeed memory mapping.rn");
          /*
          * Now, vivi is running on the ram. MMU is enabled.
          */
          /*
          * Step 4:
          */
          /* initialize the heap area*/
          ret = heap_init();
          if (ret) {
          putstr("Failed initailizing heap regionrn");
          error();
          }
          /* Step 5:
          */
          ret = mtd_dev_init();
          /* Step 6:
          */
          init_priv_data();
          /* Step 7:
          */
          misc();
          init_builtin_cmds();
          /* Step 8:
          */
          boot_or_vivi();
          return 0;
          }
          STEP1的putstr(vivi_banner)語句在串口輸出一段字符說明vivi的版本、作者等信息,vivi_banner定義為:
          const char *vivi_banner =
          "VIVI version " VIVI_RELEASE " (" VIVI_COMPILE_BY "@"
          VIVI_COMPILE_HOST ") (" VIVI_COMPILER ") " UTS_VERSION "rn";
          reset_handler進行相應的復位處理:
          void
          reset_handler(void)
          {
          int pressed;
          pressed = is_pressed_pw_btn();
          if (pressed == PWBT_PRESS_LEVEL) {
          DPRINTK("HARD RESETrn");
          hard_reset_handle();
          } else {
          DPRINTK("SOFT RESETrn");
          soft_reset_handle();
          }
          }
          hard_reset_handle會clear內存,而軟件復位處理則什么都不做:
          static void
          hard_reset_handle(void)
          {
          clear_mem((unsigned long)USER_RAM_BASE, (unsigned long)USER_RAM_SIZE);
          }
          STEP2進行板初始化,設置時間和可編程I/O口:
          int board_init(void)
          {
          init_time();
          set_gpios();
          return 0;
          }
          STEP3進行內存映射及MMU初始化:
          void mem_map_init(void)
          {
          #ifdef CONFIG_S3C2410_NAND_BOOT
          mem_map_nand_boot();
          #else
          mem_map_nor();
          #endif
          cache_clean_invalidate();
          tlb_invalidate();
          }
          S3C2410A的MMU初始化只需要調用通用的arm920 MMU初始化函數(shù):
          static inline void arm920_setup(void)
          {
          unsigned long ttb = MMU_TABLE_BASE;
          __asm__(
          /* Invalidate caches */
          "mov r0, #0n"
          "mcr p15, 0, r0, c7, c7, 0n" /* invalidate I,D caches on v4 */
          "mcr p15, 0, r0, c7, c10, 4n" /* drain write buffer on v4 */
          "mcr p15, 0, r0, c8, c7, 0n" /* invalidate I,D TLBs on v4 */
          /* Load page table pointer */
          "mov r4, %0n"
          "mcr p15, 0, r4, c2, c0, 0n" /* load page table pointer */
          /* Write domain id (cp15_r3) */
          "mvn r0, #0n" /* Domains 0, 1 = client */
          "mcr p15, 0, r0, c3, c0, 0n" /* load domain access register */
          /* Set control register v4 */
          "mrc p15, 0, r0, c1, c0, 0n" /* get control register v4 */
          /* Clear out unwanted bits (then put them in if we need them) */
          /* .RVI ..RS B... .CAM */
          "bic r0, r0, #0x3000n" /* ..11 .... .... .... */
          "bic r0, r0, #0x0300n" /* .... ..11 .... .... */
          "bic r0, r0, #0x0087n" /* .... .... 1... .111 */
          /* Turn on what we want */
          /* Fault checking enabled */
          "orr r0, r0, #0x0002n" /* .... .... .... ..1. */
          #ifdef CONFIG_CPU_D_CACHE_ON
          "orr r0, r0, #0x0004n" /* .... .... .... .1.. */
          #endif
          #ifdef CONFIG_CPU_I_CACHE_ON
          "orr r0, r0, #0x1000n" /* ...1 .... .... .... */
          #endif
          /* MMU enabled */
          "orr r0, r0, #0x0001n" /* .... .... .... ...1 */
          "mcr p15, 0, r0, c1, c0, 0n" /* write control register */
          : /* no outputs */
          : "r" (ttb) );
          }
          STEP4設置堆棧;STEP5進行mtd設備的初始化,記錄MTD分區(qū)信息;STEP6設置私有數(shù)據(jù);STEP7初始化內建命令。
          STEP8啟動一個SHELL,等待用戶輸出命令并進行相應處理。在SHELL退出的情況下,啟動操作系統(tǒng):
          #define DEFAULT_BOOT_DELAY 0x30000000
          void boot_or_vivi(void)
          {
          char c;
          int ret;
          ulong boot_delay;
          boot_delay = get_param_value("boot_delay", &ret);
          if (ret) boot_delay = DEFAULT_BOOT_DELAY;
          /* If a value of boot_delay is zero,
          * unconditionally call vivi shell */
          if (boot_delay == 0) vivi_shell();
          /*
          * wait for a keystroke (or a button press if you want.)
          */
          printk("Press Return to start the LINUX now, any other key for vivin");
          c = awaitkey(boot_delay, NULL);
          if (((c != r) && (c != n) && (c != ))) {
          printk("type "help" for help.n");
          vivi_shell();
          }
          run_autoboot();
          return;
          }
          SHELL中讀取用戶從串口輸出的命令字符串,執(zhí)行該命令:
          void
          vivi_shell(void)
          {
          #ifdef CONFIG_SERIAL_TERM
          serial_term();
          #else
          #error there is no terminal.
          #endif
          }
          void serial_term(void)
          {
          char cmd_buf[MAX_CMDBUF_SIZE];
          for (;;) {
          printk("%s> ", prompt);
          getcmd(cmd_buf, MAX_CMDBUF_SIZE);
          /* execute a user command */
          if (cmd_buf[0])
          exec_string(cmd_buf);
          }
          }
          5.電路板調試
          在電路板的調試過程中,我們首先要在ADT新建的工程中添加第一階段的匯編代碼head.S文件,修改Link腳本,將代碼和數(shù)據(jù)映射到S3C2410A自帶的0x40000000開始的4KB內存空間內:
          SECTIONS
          {
          . = 0x40000000;
          .text : { *(.text) }
          Image_RO_Limit = .;
          Image_RW_Base = .;
          .data : { *(.data) }
          .rodata : { *(.rodata) }
          Image_ZI_Base = .;
          .bss : { *(.bss) }
          Image_ZI_Limit = .;
          __bss_start__ = .;
          __bss_end__ = .;
          __EH_FRAME_BEGIN__ = .;
          __EH_FRAME_END__ = .;
          PROVIDE (__stack = .);
          end = .;
          _end = .;
          .debug_info 0 : { *(.debug_info) }
          .debug_line 0 : { *(.debug_line) }
          .debug_abbrev 0 : { *(.debug_abbrev)}
          .debug_frame 0 : { *(.debug_frame) }
          }
          借助萬用表、示波器等儀器儀表,調通SDRAM,并將vivi中自帶的串口、NAND FLASH驅動添加到工程中,調試通過板上的串口和FLASH。如果板電路的原理與三星公司DEMO板有差距,則vivi中硬件的操作要進行相應的修改。全部調試通過后,修改vivi源代碼,重新編譯vivi,將其燒錄入NAND FLASH就可以在復位后啟動這個Bootloader了。
          調試板上的新增硬件時,宜在ADT中添加相應的代碼,在不加載操作系統(tǒng)的情況下,單純地操作這些硬件。如果電路板設計有誤,要進行飛線和割線等處理。
          6.小結
          本章講解了ARM匯編、Bootloader的功能,Bootloader的調試環(huán)境及ARM電路板的調試方法。



          評論


          技術專區(qū)

          關閉