介绍自己前几年的一个产品开发过程(二)

           这一节,我主要要讲解一下我们的bootload 是怎样做的。我们的产品启动代码放置在nor Flash 中,产品上电后,首先执行nor Flash 中的代码. 另外我们的启动代码

是在ADS 环境下开发的,不是运用了类似如uboot和Vivi这类bootload. 我个人认为这类启动代码用在实际产品中还需要做很多的改动,用在开发板上还不错,但做产品就还远

不够。比如产品在使用过程中,需要更新固件,如果要用UART把代码下载到sdram,然后又执行烧写命令等,我想普通用户是做不好的。

          我们是自己写了一个bootload,我在网上看到一个文档 read.pudn.com/downloads68/ebook/245410/ARM嵌入式软件开发.ppt    。 发现和我们的bootload 的流程很相似.

先看一下我们的 scatter 文件吧.

 ROM_LOAD 0xA0000000
{
    ROM +0
    {
        init.o (Init, +First)
        anon$$obj.o
        __main.o(!!!)
        ;* (+RO)
        
    }
    RAM 0x0
    {
        vectors.o(Vect, +First)   
    }
   
    RAM2 0x1000000
    {
        * (+RW, +ZI)  ; put them about 16M, in case crashed with Linux kernel
    
    }    
    
    HEAP 0x1800000 UNINIT
    {
        heap.o (+ZI)
    }

    STACK 0x1900000 UNINIT
    {
        stack.o (+ZI)
    }    
}


解释一下, 0xA0000000 是 nor Flash 启动之后,经过地址重新映射之后的起始地址. SDRAM 经过地址重新映射之后,地址为 0. 

程序启动后,首先执行Nor Flash 中的程序,这是因为IC 有 pin 脚设置的,这是Nor Flash 的开始地址被映射在0地址,在程序的开始

一段时间内,禁止中断,然后计算好程序跳到映射后的地址,再设置好映射,使SDRAM 映射到 0x00, Nor Flash 映射为0xa0000000.

程序如下:

ENTRY
    EXPORT    Reset_Go
Reset_Go
    ; Disable Interrupt, This is for safe ...
    LDR    r0, =AICMDCR
    LDR    r1, =0xFFFFFFFF
    STR    r1, [r0]
    MRS    r0, CPSR
    ORR    r0, r0, #0xC0
    MSR    CPSR_c, r0

;上面是禁止中断,因为程序刚启动,在0x0000000 地址处,是没有中断向量表的,在没有进入main 函数之前,bootload 是一直禁止中断的.

    MRS   r0, cpsr
    BIC   r0, r0, #0x1F
    ORR   r0, r0, #0xD3
    MSR   cpsr_fc, r0

;设置为SVC模式,禁止中断,这里其实是安全起见而已

    LDR    r2, =remap_temp    
    MOV    r1, pc
    LDR r3, =remap_EndSysMapJump    
remap_temp
    MOV lr, #0
    CMP    r2, r1
    LDRGT    lr, =ROM_Start           ;ROM_Start       EQU     0xA0000000   

    SUB    r3, r3, r2
    ADD    r1, r1, r3
    ADD    lr, lr, r1
;上面做的这些加减运算,其实是在做一件事情,就是计算地址重新映射后,PC应该设置为多少. 
    
; Load in the target values into the control registers
     ADRL    r0, remap_SystemInitData    ;
     LDMIA   r0, {r1-r8}
     LDR    r0, =EBICON
    
; Now run critical jump code
     STMIA   r0, {r1-r8}                        ;这里是在设置映射地址
     MOV    pc, lr                                  ;lr 在前面已经计算好了,这里只不过是跳转到映射后的地址
remap_EndSysMapJump

;下面程序执行的地址是在0xa0000000 之后. 也就是映射之后的地址

   B Reset_Handler

remap_SystemInitData
     ; Default sdram configuration
    DCD    0x001529E1                    ; EBICON
    DCD    0x40015550                    ; ROMCON - mapping to 0xA0000000
    DCD    0xFFC00000                    ; ROMCON1
    DCD    0xFFE00000                    ; ROMCON2
    DCD    0x000088CD                    ; SDCONF0 - 32MB SDRAM
    DCD    0x00000800                    ; SDCONF1
    DCD    0x0000015B                    ; SDTIME0
    DCD    0x0000015B                    ; SDTIME1
 
    ALIGN 0

Reset_Handler

; --- Initialise stack pointer registers
        MSR     CPSR_c, #Mode_UNDEF:OR:I_Bit:OR:F_Bit
        LDR     SP, =UND_Stack

        MSR     CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
        LDR     SP, =Abort_Stack

        MSR     CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
        LDR     SP, =IRQ_Stack

        MSR     CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
        LDR     SP, =FIQ_Stack

        MSR     CPSR_c, #Mode_SYS:OR:I_Bit:OR:F_Bit
        LDR     SP, =USR_Stack

        MSR     CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
        LDR     SP, =SVC_Stack

        IMPORT  __main, weak

; --- Now enter the C code
        LDR        r0, =__main
        CMP        r0, #0
        BNE        __main  

99        B        %B99   

上面的代码中,我们看到没有拷贝RW 区域,把ZI区域清0 等设置。我们经常在uboot,vivi 等bootload 中看到,当时我也不是很理解.

其实这是在ADS 中的C library 帮我们做了,在真正进入我们的C语言main函数前,ADS library做了这些事情,我上面推荐的那份资料

里面,讲的很清楚.

     经过上面的一番折腾,程序就进入了 main函数. 进入main 函数后,程序的功能主要分为三个部分:

1) 进入测试模式。 我认为这是做产品和做开发板的一个区别,其实测试模式是很重要的一个功能,在产品的生产过程中,在流水线作业过程中,最后一个

   环节就是检测产品的好与坏,工人很简单,只要他们按一个组合键,就会进入测试模式,可以检测按键的好坏,LCD的好坏, NAND flash 的好坏等.  虽然

   这个很简单,但我认为这是做产品与做开发板的一个很大的区别. 另外一个功能是在在产品有问题时,可以进入测试模式,查看固件版本.

2) 如果连接上了USB,那么进入下载模式,下载不是简单的只是下载固件,还会下载应用数据,PC上我们开发了一个下载工具。

3)如果上面都没有进入,那么就进入启动linux 的模式. 程序会把nand flash 中的启动代码拷贝到IC的内部RAM区,这个IC的内部RAM有16k, 然后程序再跳转到

      内部RAM区执行,内部启动代码把linux内核copy到 SDRAM 区域中,然后启动linux内核

最后,我用一张图片来结束这次说明,这张图片是memory 的分配,是在进入main函数之后,memory 的地址分配情况:

下一次我再讲一讲main函数里面是如何进入 linux内核的.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值