历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2018年10月12日 | 自己写bootloader倒计时启动内核

2018-10-12 来源:eefocus

start.S源码:

.global _start

_start:

    ldr sp, =0xD0030000  // 初始化栈,因为后面要调用C函数 

    bl clock_init                // 初始化时钟 

    bl ddr_init                   // 初始化内存 

    bl nand_init                // 初始化NAND 

    ldr r0, =0x36000000   // 要拷贝到DDR中的位置 

    ldr r1, =0x0                 // 从NAND的0地址开始拷贝 

    ldr r2, =bss_start         // BSS段的开始地址 

    sub r2,r2,r0                  // 要拷贝的大小 

    bl nand_read              // 拷贝数据 

clean_bss:

    ldr r0, =bss_start

    ldr r1, =bss_end

    mov r3, #0

    cmp r0, r1

    ldreq pc, =on_ddr

clean_loop:

    str r3, [r0], #4

    cmp r0, r1    

    bne clean_loop        

    ldr pc, =on_ddr

on_ddr:

    ldr sp, =0x33000000    // 重新初始化栈,指向内存 

    ldr pc, =main

===================================================================

clock.c源码:

#define APLL_CON      (*(volatile unsigned int *)0xe0100100) 

#define CLK_SRC0      (*(volatile unsigned int *)0xe0100200) 

#define CLK_DIV0      (*(volatile unsigned int *)0xe0100300) 

#define MPLL_CON      (*(volatile unsigned int *)0xe0100108)  

void clock_init(void)

{

    // 设置时钟为:

    // ARMCLK=1000MHz, HCLKM=200MHz, HCLKD=166.75MHz

    // HCLKP =133.44MHz, PCLKM=100MHz, PCLKD=83.375MHz, 

    // PCLKP =66.7MHz

    // SDIV[2:0]  : S = 1

    // PDIV[13:8] : P = 0x3

    // MDIV[25:16]: M = 0x7d

    // LOCKED [29]: 1 = 使能锁

    // ENABLE [31]: 1 = 使能APLL控制器

    // 得出FoutAPLL = 500MHz

    APLL_CON = (1<<31)|(1<<29)|(0x7d<<16)|(0x3<<8)|(1<<0);

    

    // 时钟源的设置

    // APLL_SEL[0] :1 = FOUTAPLL

    // MPLL_SEL[4] :1 = FOUTMPLL

    // EPLL_SEL[8] :1 = FOUTEPLL

    // VPLL_SEL[12]:1 = FOUTVPLL

    // MUX_MSYS_SEL[16]:0 = SCLKAPLL

    // MUX_DSYS_SEL[20]:0 = SCLKMPLL

    // MUX_PSYS_SEL[24]:0 = SCLKMPLL

    // ONENAND_SEL [28]:1 = HCLK_DSYS

    CLK_SRC0 = (1<<28)|(1<<12)|(1<<8)|(1<<4)|(1<<0);

    

    // 设置分频系数

    // APLL_RATIO[2:0]: APLL_RATIO = 0x0

    // A2M_RATIO [6:4]: A2M_RATIO  = 0x4

    // HCLK_MSYS_RATIO[10:8]: HCLK_MSYS_RATIO = 0x4

    // PCLK_MSYS_RATIO[14:12]:PCLK_MSYS_RATIO = 0x1

    // HCLK_DSYS_RATIO[19:16]:HCLK_DSYS_RATIO = 0x3

    // PCLK_DSYS_RATIO[22:20]:PCLK_DSYS_RATIO = 0x1

    // HCLK_PSYS_RATIO[27:24]:HCLK_PSYS_RATIO = 0x4

    // PCLK_PSYS_RATIO[30:28]:PCLK_PSYS_RATIO = 0x1

     CLK_DIV0 = (0x1<<28)|(0x4<<24)|(0x1<<20)|(0x3<<16)|(0x1<<12)|(0x4<<8)|(0x4<<4);

     

    // SDIV[2:0]  : S = 1

    // PDIV[13:8] : P = 0xc

    // MDIV[25:16]: M = 0x29b

    // VSEL   [27]: 0

    // LOCKED [29]: 1 = 使能锁

    // ENABLE [31]: 1 = 使能MPLL控制器

    // 得出FoutAPLL = 667MHz

    APLL_CON = (1<<31)|(1<<29)|(0x29d<<16)|(0xc<<8)|(1<<0);

}

=====================================================================

mem_setup.S源码:

// SDRAM Controller

 

#define APB_DMC_0_BASE            0xF0000000

#define APB_DMC_1_BASE            0xF1400000

#define ASYNC_MSYS_DMC0_BASE        0xF1E00000

#define ELFIN_GPIO_BASE            0xE0200000

// MemControl    BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off

#define DMC0_MEMCONTROL        0x00202400    

// MemConfig0    256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed

#define DMC0_MEMCONFIG_0    0x20E00323    

#define DMC0_MEMCONFIG_1    0x00E00323    // MemConfig1

// TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)

#define DMC0_TIMINGA_REF        0x00000618      

#define DMC0_TIMING_ROW         0x2B34438A      // TimingRow    for @200MHz

#define DMC0_TIMING_DATA        0x24240000      // TimingData   CL=3

#define DMC0_TIMING_PWR         0x0BDC0343      // TimingPower

// MemControl    BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

#define    DMC1_MEMCONTROL        0x00202400    

// MemConfig0    512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed

#define DMC1_MEMCONFIG_0    0x40F00313    

#define DMC1_MEMCONFIG_1    0x00F00313    // MemConfig1

// TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)

#define DMC1_TIMINGA_REF        0x00000618      

#define DMC1_TIMING_ROW         0x2B34438A      // TimingRow    for @200MHz

#define DMC1_TIMING_DATA        0x24240000      // TimingData   CL=3

#define DMC1_TIMING_PWR         0x0BDC0343      // TimingPower

#define MP1_0DRV_SR_OFFSET         0x3CC

#define MP1_1DRV_SR_OFFSET         0x3EC

#define MP1_2DRV_SR_OFFSET         0x40C

#define MP1_3DRV_SR_OFFSET         0x42C

#define MP1_4DRV_SR_OFFSET         0x44C

#define MP1_5DRV_SR_OFFSET         0x46C

#define MP1_6DRV_SR_OFFSET         0x48C

#define MP1_7DRV_SR_OFFSET         0x4AC

#define MP1_8DRV_SR_OFFSET         0x4CC

#define MP2_0DRV_SR_OFFSET         0x4EC

#define MP2_1DRV_SR_OFFSET         0x50C

#define MP2_2DRV_SR_OFFSET         0x52C

#define MP2_3DRV_SR_OFFSET         0x54C

#define MP2_4DRV_SR_OFFSET         0x56C

#define MP2_5DRV_SR_OFFSET         0x58C

#define MP2_6DRV_SR_OFFSET         0x5AC

#define MP2_7DRV_SR_OFFSET         0x5CC

#define MP2_8DRV_SR_OFFSET         0x5EC

#define DMC_CONCONTROL             0x00

#define DMC_MEMCONTROL             0x04

#define DMC_MEMCONFIG0             0x08

#define DMC_MEMCONFIG1             0x0C

#define DMC_DIRECTCMD             0x10

#define DMC_PRECHCONFIG         0x14

#define DMC_PHYCONTROL0         0x18

#define DMC_PHYCONTROL1         0x1C

#define DMC_RESERVED             0x20

#define DMC_PWRDNCONFIG         0x28

#define DMC_TIMINGAREF             0x30

#define DMC_TIMINGROW             0x34

#define DMC_TIMINGDATA             0x38

#define DMC_TIMINGPOWER         0x3C

#define DMC_PHYSTATUS             0x40

#define DMC_CHIP0STATUS         0x48

#define DMC_CHIP1STATUS         0x4C

#define DMC_AREFSTATUS             0x50

#define DMC_MRSTATUS             0x54

#define DMC_PHYTEST0             0x58

#define DMC_PHYTEST1             0x5C

#define DMC_QOSCONTROL0         0x60

#define DMC_QOSCONFIG0             0x64

#define DMC_QOSCONTROL1         0x68

#define DMC_QOSCONFIG1             0x6C

#define DMC_QOSCONTROL2         0x70

#define DMC_QOSCONFIG2             0x74

#define DMC_QOSCONTROL3         0x78

#define DMC_QOSCONFIG3             0x7C

#define DMC_QOSCONTROL4         0x80

#define DMC_QOSCONFIG4             0x84

#define DMC_QOSCONTROL5         0x88

#define DMC_QOSCONFIG5             0x8C

#define DMC_QOSCONTROL6         0x90

#define DMC_QOSCONFIG6             0x94

#define DMC_QOSCONTROL7         0x98

#define DMC_QOSCONFIG7             0x9C

#define DMC_QOSCONTROL8         0xA0

#define DMC_QOSCONFIG8             0xA4

#define DMC_QOSCONTROL9         0xA8

#define DMC_QOSCONFIG9             0xAC

#define DMC_QOSCONTROL10         0xB0

#define DMC_QOSCONFIG10         0xB4

#define DMC_QOSCONTROL11         0xB8

#define DMC_QOSCONFIG11         0xBC

#define DMC_QOSCONTROL12         0xC0

#define DMC_QOSCONFIG12         0xC4

#define DMC_QOSCONTROL13         0xC8

#define DMC_QOSCONFIG13         0xCC

#define DMC_QOSCONTROL14         0xD0

#define DMC_QOSCONFIG14         0xD4

#define DMC_QOSCONTROL15         0xD8

#define DMC_QOSCONFIG15         0xDC

// SDRAM Controller

 

#define APB_DMC_0_BASE            0xF0000000

#define APB_DMC_1_BASE            0xF1400000

#define ASYNC_MSYS_DMC0_BASE        0xF1E00000

#define DMC_CONCONTROL             0x00

#define DMC_MEMCONTROL             0x04

#define DMC_MEMCONFIG0             0x08

#define DMC_MEMCONFIG1             0x0C

#define DMC_DIRECTCMD             0x10

#define DMC_PRECHCONFIG         0x14

#define DMC_PHYCONTROL0         0x18

#define DMC_PHYCONTROL1         0x1C

#define DMC_RESERVED             0x20

#define DMC_PWRDNCONFIG         0x28

#define DMC_TIMINGAREF             0x30

#define DMC_TIMINGROW             0x34

#define DMC_TIMINGDATA             0x38

#define DMC_TIMINGPOWER         0x3C

#define DMC_PHYSTATUS             0x40

#define DMC_CHIP0STATUS         0x48

#define DMC_CHIP1STATUS         0x4C

#define DMC_AREFSTATUS             0x50

#define DMC_MRSTATUS             0x54

#define DMC_PHYTEST0             0x58

#define DMC_PHYTEST1             0x5C

#define DMC_QOSCONTROL0         0x60

#define DMC_QOSCONFIG0             0x64

#define DMC_QOSCONTROL1         0x68

#define DMC_QOSCONFIG1             0x6C

#define DMC_QOSCONTROL2         0x70

#define DMC_QOSCONFIG2             0x74

#define DMC_QOSCONTROL3         0x78

#define DMC_QOSCONFIG3             0x7C

#define DMC_QOSCONTROL4         0x80

#define DMC_QOSCONFIG4             0x84

#define DMC_QOSCONTROL5         0x88

#define DMC_QOSCONFIG5             0x8C

#define DMC_QOSCONTROL6         0x90

#define DMC_QOSCONFIG6             0x94

#define DMC_QOSCONTROL7         0x98

#define DMC_QOSCONFIG7             0x9C

#define DMC_QOSCONTROL8         0xA0

#define DMC_QOSCONFIG8             0xA4

#define DMC_QOSCONTROL9         0xA8

#define DMC_QOSCONFIG9             0xAC

#define DMC_QOSCONTROL10         0xB0

#define DMC_QOSCONFIG10         0xB4

#define DMC_QOSCONTROL11         0xB8

#define DMC_QOSCONFIG11         0xBC

#define DMC_QOSCONTROL12         0xC0

#define DMC_QOSCONFIG12         0xC4

#define DMC_QOSCONTROL13         0xC8

#define DMC_QOSCONFIG13         0xCC

#define DMC_QOSCONTROL14         0xD0

#define DMC_QOSCONFIG14         0xD4

#define DMC_QOSCONTROL15         0xD8

#define DMC_QOSCONFIG15         0xDC

    .globl ddr_init

ddr_init:

    // DMC0 Drive Strength (Setting 2X) 

    ldr    r0, =ELFIN_GPIO_BASE

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #0x3cc]

    str    r1, [r0, #MP1_0DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_1DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_2DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_3DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_4DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_5DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_6DRV_SR_OFFSET]

    ldr    r1, =0x0000AAAA

    str    r1, [r0, #MP1_7DRV_SR_OFFSET]

    ldr    r1, =0x00002AAA

    str    r1, [r0, #MP1_8DRV_SR_OFFSET]

    // DMC0 initialization at single Type

    ldr    r0, =APB_DMC_0_BASE

    ldr    r1, =0x00101000                @PhyControl0 DLL parameter setting, manual 0x00101000

    str    r1, [r0, #DMC_PHYCONTROL0]

    ldr    r1, =0x00000086                @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case

    str    r1, [r0, #DMC_PHYCONTROL1]

    ldr    r1, =0x00101002                @PhyControl0 DLL on

    str    r1, [r0, #DMC_PHYCONTROL0]

    ldr    r1, =0x00101003                @PhyControl0 DLL start

    str    r1, [r0, #DMC_PHYCONTROL0]

find_lock_val:

    ldr    r1, [r0, #DMC_PHYSTATUS]        @Load Phystatus register value

    and    r2, r1, #0x7

    cmp    r2, #0x7                @Loop until DLL is locked

    bne    find_lock_val

    and    r1, #0x3fc0

    mov    r2, r1, LSL #18

    orr    r2, r2, #0x100000

    orr    r2 ,r2, #0x1000

    orr    r1, r2, #0x3                @Force Value locking

    str    r1, [r0, #DMC_PHYCONTROL0]

    // setting DDR2 

    ldr    r1, =0x0FFF2010                @ConControl auto refresh off

    str    r1, [r0, #DMC_CONCONTROL]

@MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

    ldr    r1, =DMC0_MEMCONTROL            

    str    r1, [r0, #DMC_MEMCONTROL]

@MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed

    ldr    r1, =DMC0_MEMCONFIG_0            

    str    r1, [r0, #DMC_MEMCONFIG0]

    ldr    r1, =DMC0_MEMCONFIG_1            @MemConfig1

    str    r1, [r0, #DMC_MEMCONFIG1]

    ldr    r1, =0xFF000000                @PrechConfig

    str    r1, [r0, #DMC_PRECHCONFIG]

@TimingAref    7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)

    ldr    r1, =DMC0_TIMINGA_REF            

    str    r1, [r0, #DMC_TIMINGAREF]

    ldr    r1, =DMC0_TIMING_ROW            @TimingRow    for @200MHz

    str    r1, [r0, #DMC_TIMINGROW]

    ldr    r1, =DMC0_TIMING_DATA            @TimingData    CL=4

    str    r1, [r0, #DMC_TIMINGDATA]

    ldr    r1, =DMC0_TIMING_PWR            @TimingPower

    str    r1, [r0, #DMC_TIMINGPOWER]

    ldr    r1, =0x07000000                @DirectCmd    chip0 Deselect

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x01000000                @DirectCmd    chip0 PALL

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00020000                @DirectCmd    chip0 EMRS2

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00030000                @DirectCmd    chip0 EMRS3

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00010400                @DirectCmd    chip0 EMRS1 (MEM DLL on, DQS# disable)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00000542                @DirectCmd    chip0 MRS (MEM DLL reset) CL=4, BL=4

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x01000000                @DirectCmd    chip0 PALL

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x05000000                @DirectCmd    chip0 REFA

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x05000000                @DirectCmd    chip0 REFA

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00000442                @DirectCmd    chip0 MRS (MEM DLL unreset)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00010780                @DirectCmd    chip0 EMRS1 (OCD default)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00010400                @DirectCmd    chip0 EMRS1 (OCD exit)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x07100000                @DirectCmd    chip1 Deselect

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x01100000                @DirectCmd    chip1 PALL

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00120000                @DirectCmd    chip1 EMRS2

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00130000                @DirectCmd    chip1 EMRS3

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00110400                @DirectCmd    chip1 EMRS1 (MEM DLL on, DQS# disable)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00100542                @DirectCmd    chip1 MRS (MEM DLL reset) CL=4, BL=4

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x01100000                @DirectCmd    chip1 PALL

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x05100000                @DirectCmd    chip1 REFA

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x05100000                @DirectCmd    chip1 REFA

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00100442                @DirectCmd    chip1 MRS (MEM DLL unreset)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00110780                @DirectCmd    chip1 EMRS1 (OCD default)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x00110400                @DirectCmd    chip1 EMRS1 (OCD exit)

    str    r1, [r0, #DMC_DIRECTCMD]

    ldr    r1, =0x0FF02030                @ConControl    auto refresh on

    str    r1, [r0, #DMC_CONCONTROL]

    ldr    r1, =0xFFFF00FF                @PwrdnConfig

    str    r1, [r0, #DMC_PWRDNCONFIG]

@MemControl    BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

    ldr    r1, =0x00202400                

    str    r1, [r0, #DMC_MEMCONTROL]

    mov    pc, lr

=====================================================================

nand.c源码:

#define    NFCONF  (*(volatile unsigned int *)0xB0E00000) 

#define    NFCONT  (*(volatile unsigned int *)0xB0E00004)     

#define    NFCMMD  (*(volatile unsigned char *)0xB0E00008) 

#define    NFADDR  (*(volatile unsigned char *)0xB0E0000C)

#define    NFDATA  (*(volatile unsigned char *)0xB0E00010)

#define    NFSTAT  (*(volatile unsigned int *)0xB0E00028)

#define    MP0_3CON  (*(volatile unsigned int *)0xE0200320)

#define   MP0_1CON  (*(volatile unsigned int *)0xE02002E0)

        

#define PAGE_SIZE    2048

#define NAND_SECTOR_SIZE_LP    2048

void wait_idle(void)

{

    int i;

    while(!(NFSTAT&(1<<0)));

    for(i=0; i<10; i++);

}

void nand_select_chip(void)

{

    int i;

    NFCONT &= ~(1<<1);

    for(i=0; i<10; i++);

}

void nand_deselect_chip(void)

{

    NFCONT |= (1<<1);

}

void write_cmd(int cmd)

{

    NFCMMD = cmd;

}

void write_addr(unsigned int addr)

{

    int i;

    NFADDR = (addr>>0) & 0xFF;

    wait_idle();

    NFADDR = (addr>>8) & 0x7;

    wait_idle();

    NFADDR = (addr>>11) & 0xFF;

    wait_idle();

    NFADDR = (addr>>19) & 0xFF;

    wait_idle();

    NFADDR = (addr>>27) & 0x1;

    wait_idle();

}

unsigned char read_data(void)

{

    return NFDATA;

}

static void nand_reset(void)

{

    nand_select_chip();

    write_cmd(0xff);  // 复位命令

    wait_idle();

    nand_deselect_chip();

}

void nand_init(void)

{

    // 设置时间参数(HCLK_PSYS = 667MHz/5 = 133MHz)

    // TACLS[15:12]: TACLS  = 1     1/133Mhz  = 7.5ns

    // TWRPH0[11:8]: TWRPH0 = 1     7.5ns * 2 = 15ns

    // TWRPH1 [7:4]: TWRPH1 = 1    7.5ns * 2 = 15ns

    // AddrCycle[1]: 1 = 指明地址周期为5次,这个是和2440的区别

    NFCONF |= 1<<12 | 1<<8 | 1<<4;

    NFCONF |= 1<<1;

    // 使能NAND控制器

    // 关闭片选信号

    NFCONT |= (1<<0)|(1<<1); 

    // 设置相应管脚用于Nand Flash控制器 

    MP0_3CON = 0x22222222;

    // 复位NAND Flash 

    nand_reset();

    return;

}

// 读ID 

void nand_read_id(char id[])

{

    int i;

    

    nand_select_chip();

    write_cmd(0x90);

    write_addr(0x00);

    for (i = 0; i < 5; i++)

        id[i] = read_data();

    nand_deselect_chip();

}

// 读一页的函数 

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

{

    int i, j;

    // 选中芯片 

    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);) 

    {

        // 发出READ0命令 

        write_cmd(0);

        // Write Address 

        write_addr(i);

        write_cmd(0x30);        

        wait_idle();

        for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) 

        {

            *buf = read_data();

            buf++;

        }

    }

    // 取消片选信号 

    nand_deselect_chip();

}

void nand_write(int sdram_addr, int nand_addr, int size)

{

}

====================================================================

uart.c源码:

#define GPA0CON      (*(volatile unsigned int *)0xE0200000) 

#define ULCON0      (*(volatile unsigned int *)0xE2900000) 

#define UCON0          (*(volatile unsigned int *)0xE2900004) 

#define UTRSTAT0      (*(volatile unsigned int *)0xE2900010)

#define UTXH0          (*(volatile unsigned char *)0xE2900020) 

#define URXH0          (*(volatile unsigned char *)0xE2900024) 

#define UBRDIV0     (*(volatile unsigned int *)0xE2900028) 

#define UDIVSLOT0      (*(volatile unsigned int *)0xE290002C)

void uart_init(void)

{

    // 设置对应GPIO用于UART0 

    GPA0CON |= 0x22;

            

    // 设置UART0寄存器 

    // bit[1:0]:0x3 = 8位数据位

    // 其他位默认,即1位停止位,无校验,正常模式

    ULCON0 |= (0x3<<0);

    // Receive Mode [1:0]:1 = 接收采用查询或者中断模式

    // Transmit Mode[3:2]:1 = 发送采用查询或者中断模式

    // bit[6]:1 = 产生错误中断

    // bit[10]:0 = 时钟源为PCLK

    UCON0 = (1<<6)|(1<<2)|(1<<0);

    

    // 设置波特率(详细信息请参考手册或者学习日记)

    // DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16

    // DIV_VAL = (PCLK / (bps x 16)) - 1

    UBRDIV0 = 0x23;

    UDIVSLOT0 = 0x808;

    return;

}

char uart_getchar(void)

{

    char c;

    // 查询状态寄存器,直到有有效数据 

    while (!(UTRSTAT0 & (1<<0)));

    

    c = URXH0; // 读取接收寄存器的值 

        

    return c;

}

void uart_putchar(char c)

{

    // 查询状态寄存器,直到发送缓存为空 

    while (!(UTRSTAT0 & (1<<2)));

    

    UTXH0 = c; // 写入发送寄存器 

    

    return;

}

=====================================================================

lcd.c源码:

#define GPF0CON        (*(volatile unsigned int *)0xE0200120)

#define GPF1CON        (*(volatile unsigned int *)0xE0200140)

#define GPF2CON        (*(volatile unsigned int *)0xE0200160)

#define GPF3CON        (*(volatile unsigned int *)0xE0200180)

#define GPD0CON        (*(volatile unsigned int *)0xE02000A0)

#define GPD0DAT        (*(volatile unsigned int *)0xE02000A4)

#define CLK_SRC1    (*(volatile unsigned int *)0xe0100204)

#define CLK_DIV1    (*(volatile unsigned int *)0xe0100304)

#define DISPLAY_CONTROL    (*(volatile unsigned int *)0xe0107008)

#define VIDCON0        (*(volatile unsigned int *)0xF8000000)

#define VIDCON1        (*(volatile unsigned int *)0xF8000004)

#define VIDTCON2     (*(volatile unsigned int *)0xF8000018)

#define VIDTCON3     (*(volatile unsigned int *)0xF800001c)

#define WINCON0     (*(volatile unsigned int *)0xF8000020)

#define WINCON2     (*(volatile unsigned int *)0xF8000028)

#define SHADOWCON     (*(volatile unsigned int *)0xF8000034)

#define VIDOSD0A     (*(volatile unsigned int *)0xF8000040)

#define VIDOSD0B     (*(volatile unsigned int *)0xF8000044)

#define VIDOSD0C     (*(volatile unsigned int *)0xF8000048)

#define VIDW00ADD0B0     (*(volatile unsigned int *)0xF80000A0)

#define VIDW00ADD1B0     (*(volatile unsigned int *)0xF80000D0)

#define VIDW00ADD2       (*(volatile unsigned int *)0xF8000100)

#define VIDTCON0     (*(volatile unsigned int *)0xF8000010)

#define VIDTCON1     (*(volatile unsigned int *)0xF8000014)

#define VSPW       9  

#define VBPD       13 

#define LINEVAL    479

#define VFPD       21 

#define HSPW       19 

#define HBPD       25 

#define HOZVAL     799

#define HFPD       209

#define LeftTopX     0

#define LeftTopY     0

#define RightBotX   799

#define RightBotY   479

#define FRAME_BUFFER   (0x3f000000)

void lcd_init(void)

{

    // 1. 设置相关GPIO引脚用于LCD 

    GPF0CON = 0x22222222;        // GPF0[7:0]

    GPF1CON = 0x22222222;        // GPF1[7:0]

    GPF2CON = 0x22222222;        // GPF2[7:0]

    GPF3CON = 0x22222222;        // GPF3[7:0]

    // 使能LCD本身 

    GPD0CON |= 1<<4;

    GPD0DAT |= 1<<1;

    // 该寄存器是时钟相关

    // Display path selection 

    // 10: RGB=FIMD I80=FIMD ITU=FIMD

     

    DISPLAY_CONTROL = 2<<0;

    // 2. 初始化210的display controller 

    // 2.1 hsync,vsync,vclk,vden的极性和时间参数

    // 2.2 行数、列数(分辨率),象素颜色的格式

    // 2.3 分配显存(frame buffer),写入display controller

     

    // CLKVAL_F[13:6]:该值需要根据LCD手册做相应的修改

    //                  HCLKD=166.75MHz,DCLK(min) = 20ns(50MHz)

    //                VCLK = 166.75 / (5+1) = 28MHz

    // CLKDIR  [4]:1 = Divided by CLKVAL_F

    // ENVID   [1]:1 = Enable the video output and the Display control signal. 

    // ENVID_F [0]:1 = Enable the video output and the Display control signal.  

    VIDCON0 &= ~((3<<26) | (1<<18) | (0xff<<6)  | (1<<2));     // RGB I/F, RGB Parallel format,  

    VIDCON0 |= ((5<<6) | (1<<4) );

    // 设置极性(该值需要根据LCD手册做相应的修改)

    // IVDEN [4]:0 = Normal

    // IVSYNC[5]:1 = Inverted

    // IHSYNC[6]:1 = Inverted

    // IVCLK [7]:0 = Video data is fetched at VCLK falling edge

    VIDCON1 &= ~(1<<7);   // 在vclk的下降沿获取数据 

    VIDCON1 |= ((1<<6) | (1<<5));  // HSYNC极性反转, VSYNC极性反转 

    // 设置时序(需要修改) 

    VIDTCON0 = (VBPD << 16) | (VFPD << 8) | (VSPW << 0);

    VIDTCON1 = (HBPD << 16) | (HFPD << 8) | (HSPW << 0);

    // 设置屏幕的大小

    // LINEVAL[21:11]:多少行   = 480

    // HOZVAL [10:0] :水平大小 = 800

    VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);

    // WSWP_F   [15] :1    = Swap Enable(为什么要使能),很关键的一位,能够解决掉重影问题

    // BPPMODE_F[5:2]:1011 = unpacked 24 BPP (non-palletized R:8-G:8-B:8 )

    // ENWIN_F  [0]:  1    = Enable the video output and the VIDEO control signal.

    WINCON0 &= ~(0xf << 2);

    WINCON0 |= (0xB<<2)|(1<<15);

    // 窗口0,左上角的位置(0,0) 

    // 窗口0,右下角的位置(800,480) 

    VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);

    VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);

    

    // 大小 

    VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);

    VIDW00ADD0B0 = FRAME_BUFFER;

    

    // VBASEL = VBASEU + (LINEWIDTH+OFFSIZE) x (LINEVAL+1) 

    //        = 0 + (800*4 + 0) * 479

    //        = 

    VIDW00ADD1B0 =  (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);

    //VIDW00ADD1B0 = FRAME_BUFFER + HOZVAL * LINEVAL * 4; // 新加的,是该这个吗? 

    SHADOWCON = 0x1; // 使能通道0 

    // LCD控制器开启 

    VIDCON0  |= 0x3; // 开启总控制器 

    WINCON0 |= 1;     // 开启窗口0 

}

void lcd_draw_pixel(int row, int col, int color)

{

    int * pixel = (int *)FRAME_BUFFER;

    *(pixel + row * (HOZVAL+1) + col) = color;    

    return;

void lcd_clear_screen(int color)

{

    int i, j;

        

    for (i = 0; i < (LINEVAL+1); i++)

        for (j = 0; j < (HOZVAL+1); j++)

        {

            lcd_draw_pixel(i, j, color);

        }

    return;

}

void lcd_draw_bmp(int bmp_file_addr)

{

    int i, j;

    char * p = (char *)bmp_file_addr;

    int blue, green, red;

    int color;

    // read bmp file

    // bmp file header is 54 bytes

    p += 54;

    

    for (i = 0; i < 480; i++)

        for (j = 0; j < 800; j++)

        {

            blue = *p++;

            green = *p++;

            red = *p++;

        

            color = red << 16 | green << 8 | blue << 0;

            

            lcd_draw_pixel(480-i, j, color);

        }

    return;

}

====================================================================

lib.c源码:

#include "uart.h"

#define UTRSTAT0      (*(volatile unsigned int *)0xE2900010)

#define UTXH0          (*(volatile unsigned char *)0xE2900020) 

#define URXH0          (*(volatile unsigned char *)0xE2900024) 

void delay(void)

{

    volatile int i = 0x100000;

    while (i--);

}

void putchar_hex(char c)

{

    char * hex = "0123456789ABCDEF";

    

    uart_putchar(hex[(c>>4) & 0x0F]);

    uart_putchar(hex[(c>>0) & 0x0F]);

    return;

}

int putchar(int c)

{

    if(c == '\r')

    {

        while(!(UTRSTAT0&(1<<1)));

        UTXH0 = '\n';

    }

    

    if(c == '\n')

    {

        while(!(UTRSTAT0&(1<<1)));

        UTXH0 = '\r';

    }

    while(!(UTRSTAT0&(1<<1)));

    UTXH0 = c;

}

int getchar(void)

{

    int c;

    

    c = (int)uart_getchar();

    

    if (c == '\r')

        return '\n';

    

    return c;

}

int puts(const char * s)

{

    while (*s)

        putchar(*s++);

        

    return 0;

}

char * gets(char * s)

{

    char * p = s;

    while ((*p = getchar()) != '\n')

    {

        if (*p != '\b')

            putchar(*p++);

        else  

        {  

            if (p > s)

            {

                puts ("\b \b");

                p--;

            } 

        }                  

    }

    

    *p = '\0';

    putchar('\n');

        

    return s;

}

void putint_hex(int a)

{

    putchar_hex( (a>>24) & 0xFF );

    putchar_hex( (a>>16) & 0xFF );

    putchar_hex( (a>>8) & 0xFF );

    putchar_hex( (a>>0) & 0xFF );

}

char * itoa(int a, char * buf)

{

    int num = a;

    int i = 0;

    int len = 0;

    

    do 

    {

        buf[i++] = num % 10 + '0';

        num /= 10;        

    } while (num);

    buf[i] = '\0';

    

    len = i;

    for (i = 0; i < len/2; i++)

    {

        char tmp;

        tmp = buf[i];

        buf[i] = buf[len-i-1];

        buf[len-i-1] = tmp;

    }

    

    return buf;    

}

int strcmp(const char * s1, const char * s2)

{

    while (*s1 == *s2)

    {

        if (*s1 == '\0')

            return 0;    

        s1++;

        s2++;                

    }

    

    return *s1 - *s2;

}

int atoi(char * buf)

{

    int value = 0;    

    int base = 10;

    int i = 0;

    

    if (buf[0] == '0' && buf[1] == 'x')

    {

        base = 16;

        i = 2;

    }

    

    // 123 = (1 * 10 + 2) * 10 + 3

    // 0x1F = 1 * 16 + F(15)    

    while (buf[i])

    {

        int tmp;

        

        if (buf[i] <= '9' && buf[i] >= '0') 

            tmp = buf[i] - '0';

        else

            tmp = buf[i] - 'a' + 10;

                    

        value = value * base + tmp;

        

        i++;

    }

    

    return value;

}

typedef int * va_list;

#define va_start(ap, A)        (ap = (int *)&(A) + 1)

#define va_arg(ap, T)        (*(T *)ap++)

#define va_end(ap)        ((void)0)

int wy_printf(const char * format, ...)

{

    char c;    

    va_list ap;

        

    va_start(ap, format);

    

    while ((c = *format++) != '\0')

    {

        switch (c)

        {

            case '%':

                c = *format++;

                

                switch (c)

                {

                    char ch;

                    char * p;

                    int a;

                    char buf[100];

                                    

                    case 'c':

                        ch = va_arg(ap, int);

                        putchar(ch);

                        break;

                    case 's':

                        p = va_arg(ap, char *);

                        puts(p);

                        break;                    

                    case 'x':

                        a = va_arg(ap, int);

                        putint_hex(a);

                        break;        

                    case 'd':

                        a = va_arg(ap, int);

                        itoa(a, buf);

                        puts(buf);

                        break;    

                    

                    default:

                        break;

                }                

                break;        

        

            default:

                putchar(c);

                break;

        }

    }

    

    return 0;    

}

====================================================================

timer.c源码:

#include "lib.h"

#define    GPD0CON     (*(volatile unsigned int *)0xE02000A0) 

#define    TCFG0           (*(volatile unsigned int *)0xE2500000) 

#define    TCFG1           (*(volatile unsigned int *)0xE2500004) 

#define    TCON            (*(volatile unsigned int *)0xE2500008) 

#define    TCNTB0         (*(volatile unsigned int *)0xE250000C) 

#define    TCMPB0        (*(volatile unsigned int *)0xE2500010) 

#define    TCNTO0        (*(volatile unsigned int *)0xE2500014) 

void pwm_init(void)

{

    // 配置为GPD0_0用于PWM输出 

    GPD0CON |= (0x2 << 0);     // TOUT_0 

}

void timer0_init(void)

{

    // 设置时钟源

    // Timer0 input clock Frequency = 66700000 / ( {prescaler + 1} ) / {divider value} 

    //      = 66700000 / (1+1) / 1

    //      = 33350000( 即1s计数33350000次 )

    TCFG0 &= ~(0xff);

    TCFG0  |= 1;           // Prescaler = 1 

    TCFG1  &= ~0xf;     // 0000 = 1/1 

    // 设置TCNTB0(即PWM的频率) 

    TCNTB0 = 33350;   // PWM的频率为1KHz       

                          

    // 设置TCMPB0(即PWM的占空比) 

    TCMPB0 = 16675;  // 占空比为50% 

    TCON &= ~(1<<2); // 不进行电平反转(即引脚初始值为0) 

    TCON |= (1<<3);  // auto-reload 

}

void pwm_start(void)

{

    TCON |= (1<<1);  // set manual update 

    TCON |= (1<<0);  // start timer 0 

    TCON &= ~(1<<1); // clean manual update 

}

void pwm_stop(void)

{

    TCON &= ~(1<<0);   // stop timer 0 

}

===================================================================

command.c源码:

#include "lib.h"

#include "nand.h"

#include "setup.h"

extern void (*fp)(int, int, int);

int help(int argc, char * argv[])

{

    wy_printf("do_command 《%s》 \n", argv[0]);//实际为“<”

    wy_printf("help message: \n");

    wy_printf("md - memory dispaly\n");

    wy_printf("mw - memory write\n");

    wy_printf("nand read - nand read sdram_addr nand_addr size\n");

    wy_printf("nand write - nand write sdram_addr nand_addr size\n");

    wy_printf("bootm - boot zImage\n");

    return 0;

}

int md(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int i, j;

    wy_printf("do_command 《%s》 \n", argv[0]);

    if (argc <= 1) {

        wy_printf ("Usage:\n%s\n", "md address");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    for (j = 0; j < 16; j++)

    {    

        wy_printf("%x: ", p);

        for (i = 0; i < 4; i++)

            wy_printf("%x ", *p++);    

        wy_printf("\n");

    }

        

    return 0;

}

int mw(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int v = 0;

    wy_printf("do_command 《%s》 \n", argv[0]);//实际为“<”

    if (argc <= 2) {

        wy_printf ("Usage:\n%s\n", "md address data");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    if (argc >= 3)

        v = atoi(argv[2]);

        

    *p = v;

    

    return 0;

}

int nand(int argc, char *argv[])

{

    int nand_addr, sdram_addr;

    unsigned int size;

    

    if (argc < 5)

    {

        wy_printf("nand read sdram_addr nand_addr size\n");

        wy_printf("nand write sdram_addr nand_addr size\n");

        return 0;

    }

    sdram_addr = atoi(argv[2]);

    nand_addr = atoi(argv[3]);

    size = atoi(argv[4]);

    wy_printf("do_command 《%s》 \n", argv[0]); //实际为“<”

    wy_printf("sdram 0x%x, nand 0x%x, size 0x%x\n", sdram_addr, nand_addr, size);

    if (strcmp(argv[1], "read") == 0)

        nand_read((unsigned char *)sdram_addr, nand_addr, size);

    if (strcmp(argv[1], "write") == 0)

        nand_write(sdram_addr, nand_addr, size);    

    wy_printf("nand %s finished!\n", argv[1]);

    return 0;

}

int bootm(int argc, char * argv[])

{

    wy_printf("loading linux from 0x400000 to 0x20008000...\n");

    nand_read(0x20008000, 0x400000, 0x800000);

    wy_printf("boot linux ...\n");

    fp(0, 2456, 0x20000100);

    

    return 0;

}

void run_command(int argc, char * argv[])

{

    if (strcmp(argv[0], "help") == 0)

    {

        help(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "md") == 0)

    {

        md(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "mw") == 0)

    {

        mw(argc, argv);

        return;

    }

    if (strcmp(argv[0], "bootm") == 0)

    {

        bootm(argc, argv);

        return;

    }

    if (strcmp(argv[0], "nand") == 0)

        nand(argc, argv);

    if(argc >= 1)

        wy_printf("Unknown command '%s' - try 'help' \n",argv[0]);

    return;

}

===================================================================

main.c源码:

#include "command.h"

#include "clock.h"

#include "led.h"

#include "uart.h"

#include "lib.h"

#include "nand.h"

#include "lcd.h"

#include "timer.h"

#include "setup.h"

#define UTRSTAT0      (*(volatile unsigned int *)0xE2900010)

#define  CFG_PROMPT   "WY_BOOT # " // Monitor Command Prompt    

#define  CFG_CBSIZE   256          // Console I/O Buffer Size    

#define  BOOTDELAY   5             // 倒计时 

void (*fp)(int, int, int);

char *argv[10];

int readline (const char *const prompt)

{

    char console_buffer[CFG_CBSIZE];        // console I/O buffer    

    char *buf = console_buffer;

    int argc = 0;

    int state = 0;

    //puts(prompt);

    wy_printf("%s",prompt);

    gets(console_buffer);

    

    while (*buf)

    {

        if (*buf != ' ' && state == 0)

        {

            argv[argc++] = buf;

            state = 1;

        }

        

        if (*buf == ' ' && state == 1)

        {

            *buf = '\0';

            state = 0;

        }

        

        buf++;    

    }

    

    return argc;

}

void message(void)

{

    wy_printf("\nThis bootloader support some command to test peripheral:\n");

    wy_printf("Such as: LCD, IIS, BUZZER \n");

    wy_printf("Try 'help' to learn them \n\n");    

}

const char cmd[] = "root=/dev/nfs nfsroot=192.168.1.104:/work/nfs_root/wy_fs ip=192.168.1.17 console=ttySAC0";

void init_tag(int addr)

{

    struct tag * p;

    int i;

    

    p = (struct tag*) addr;

    p->hdr.tag  =  ATAG_CORE;

    p->hdr.size = tag_size(tag_core);

    p->u.core.flags = 0;

    p->u.core.pagesize = 0;

    p->u.core.rootdev = 0;

    p = tag_next(p);

    p->hdr.tag = ATAG_CMDLINE;

    p->hdr.size =  (sizeof (cmd) + sizeof(struct tag_header) + 3) >>2;    

    for(i=0; i< sizeof (cmd); i++)    

        p->u.cmdline.cmdline[i] = cmd[i];

    p = tag_next(p);

    p->hdr.tag = ATAG_MEM;

    p->hdr.size = tag_size(tag_mem32);

    p->u.mem.size = 512*1024*1024;

    p->u.mem.start = 0x20000000;

    p = tag_next(p);

    p->hdr.tag = ATAG_NONE;

    p->hdr.size = 0;

}

void init_boot_parameter(void)

{

    int addr = 0x20008000;

    int taglist_mem_address = 0x20000100;

    

    fp = (void (*)(int, int, int))addr;

    

    init_tag(taglist_mem_address);    

}

int tstc (void)

{

    return UTRSTAT0 & 0x1;

}

void autoboot(void)

{

    int i;

    char bootdelay = BOOTDELAY;

    while(1)

    {

        wy_printf("Hit any key to stop autoboot: %d \n", bootdelay);    

        

        if(bootdelay == 0)

        {

            wy_printf("loading linux from 0x400000 to 0x20008000...\n");

            nand_read(0x20008000, 0x400000, 0x800000);

            wy_printf("boot linux ...\n");

            fp(0, 2456, 0x20000100);

            

            return;

        }

        for(i=0;i<=8;i++)

        {

            delay();

            if( tstc() )

                return;

        }

        bootdelay--;

    }

    return;

}

int main(void)

{

    char buf[6];

    int argc = 0;

    int i = 0;

    led_init(); // 设置对应管脚为输出 

    uart_init(); // 初始化UART0 

    lcd_init(); // 初始化LCD 

    nand_read_id(buf);

    timer0_init(); // 初始化定时器0,用于PWM输出 

    init_boot_parameter(); // 初始化启动内核需要的相关类容 

        

    wy_printf("\nloading logo from NAND 0xc00000 to DDR 0x3fc00000...");

    nand_read((unsigned char *)0x3fc00000, 0xC00000, 0x300000);

    

    wy_printf("\n**********************************************************\n");

    wy_printf("                     wy_bootloader\n");

    wy_printf("                     vars: %d \n",2012);

    wy_printf("                     nand id:");

    putchar_hex(buf[0]);

    putchar_hex(buf[1]);

    putchar_hex(buf[2]);

    putchar_hex(buf[3]);

    putchar_hex(buf[4]);

    wy_printf("\n**********************************************************\n");

    lcd_draw_bmp(0x3fc00000); //  显示LOGO 

    autoboot();  // 延时自启动 

    while (1)

    {

        argc = readline (CFG_PROMPT);

        if(argc == 0 && i ==0)

        {

            message();

            i=1;

        }

        run_command(argc, argv);

    }

    return 0;

}

=====================================================================

Makefile文件:

uart.bin:start.s main.c uart.c clock.c led.c lib.c command.c nand.c mem_setup.S lcd.c timer.c

    arm-linux-gcc -nostdlib -c start.s -o start.o

    arm-linux-gcc -nostdlib -c main.c -o main.o

    arm-linux-gcc -nostdlib -c uart.c -o uart.o

    arm-linux-gcc -nostdlib -c lib.c -o lib.o

    arm-linux-gcc -nostdlib -c clock.c -o clock.o    

    arm-linux-gcc -nostdlib -c led.c -o led.o    

    arm-linux-gcc -nostdlib -c command.c -o command.o    

    arm-linux-gcc -nostdlib -c nand.c -o nand.o    

    arm-linux-gcc -nostdlib -c lcd.c -o lcd.o    

    arm-linux-gcc -nostdlib -c mem_setup.S -o mem_setup.o    

    arm-linux-gcc -nostdlib -c timer.c -o timer.o    

    arm-linux-ld -T bootloader.lds start.o main.o uart.o lib.o clock.o led.o command.o nand.o mem_setup.o lcd.o timer.o -o uart_elf

    arm-linux-objcopy -O binary -S uart_elf uart.bin

clean:

    rm -rf *.o *.bin uart_elf *.dis

    

=====================================================================

bootloader.lds链接文件:

SECTIONS {

    . = 0x36000010;

    .text : {

        * (.text)

    }

    . = ALIGN(4);

    .rodata : {

        * (.rodata)

    }

    

    . = ALIGN(4);

    .data : {

        * (.data)

    }

    . = ALIGN(4);

    bss_start = .;

    .bss  : { *(.bss)  *(COMMON) }

    bss_end = .;

}

==================================================================

倒计时自启动内核:

用官方的u-boot的时候,总是有倒计时启动内核,感觉特别的爽,因此,我得给自己写的bootloader加上该功能(方法比较粗糙)。

这部分代码没有任何难道,大家一看代码就能够明白,添加类容如下:

void autoboot(void)

{

    int i;

    char bootdelay = BOOTDELAY;

    while(1)

    {

        wy_printf("Hit any key to stop autoboot: %d \n", bootdelay);    

        

        if(bootdelay == 0)

        {

            wy_printf("loading linux from 0x400000 to 0x20008000...\n");

            nand_read(0x20008000, 0x400000, 0x800000);

            wy_printf("boot linux ...\n");

            fp(0, 2456, 0x20000100);

            

            return;

        }

        for(i=0;i<=8;i++)

        {

            delay();

            if( tstc() )     // 这个函数只是去读UART的状态而已 

                return;

        }

        bootdelay--;

    }

    return;

}

该部分代码放在了"Tiny210学习日记_代码"目录下了,名为"bootloader_bootdelay"。


推荐阅读

史海拾趣

C-TON Industries公司的发展小趣事

在电子行业中,产品质量的稳定性是企业生存的关键。C-TON深知这一点,因此从公司成立之初就高度重视品质管理。公司建立了一套严格的质量检测体系,确保每一件产品都符合高标准的质量要求。此外,C-TON还不断引进先进的生产设备和技术,提升生产效率和产品质量。这些努力使得C-TON的产品在市场上获得了良好的口碑,也为其赢得了众多忠实客户。

High Voltage Power Solutions Inc公司的发展小趣事

在电子行业中,产品质量的稳定性是企业生存的关键。C-TON深知这一点,因此从公司成立之初就高度重视品质管理。公司建立了一套严格的质量检测体系,确保每一件产品都符合高标准的质量要求。此外,C-TON还不断引进先进的生产设备和技术,提升生产效率和产品质量。这些努力使得C-TON的产品在市场上获得了良好的口碑,也为其赢得了众多忠实客户。

帝特(DTECH)公司的发展小趣事

广州帝特电子科技有限公司成立于2000年4月,公司创始团队凭借对市场趋势的敏锐洞察和坚定信心,决定将主营业务定位于电脑外设产品的研发和生产。在创立初期,帝特就注重产品质量和技术创新,通过不断的技术研发和产品优化,逐渐在电脑外设领域崭露头角。

辰颐电子公司的发展小趣事

辰颐电子公司成立于XXXX年,由一群热衷于电子技术的年轻人共同创立。他们看到了电子行业巨大的市场潜力和技术革新的重要性,决定投身于这一领域。初创时期,公司面临着资金短缺、技术瓶颈和市场竞争等多重挑战。然而,他们凭借对技术的执着追求和对市场的敏锐洞察,成功研发出了一款具有创新性的电子产品,并迅速在市场上打开了局面。

Honeywell公司的发展小趣事

背景:随着科技的进步,霍尼韦尔开始将目光投向更广阔的领域,其中航空航天成为重要的发展方向。

发展:霍尼韦尔在航空航天领域取得了多项技术突破,其仪器仪表和控制系统在多个重要项目中发挥了关键作用。其中,最著名的莫过于1969年阿波罗11号登月任务中,霍尼韦尔的仪器仪表为宇航员提供了稳定的控制和导航支持。

关键事件:阿波罗11号任务的成功不仅展示了霍尼韦尔在航空航天领域的实力,也进一步提升了公司的国际声誉和市场地位。

EUCHNER公司的发展小趣事

EUCHNER公司的历史可追溯到1940年,由艾米·安士能先生创立的工程事务所。艾米·安士能先生是一位热衷于机械运动和系统工程领域的创新者。在1952年,他成功发明了世界上第一个组合行程开关,这一创新技术为公司的未来发展奠定了坚实的基础。1953年,EUCHNER公司正式成立,开始专注于机电控制产品的研究与开发。

问答坊 | AI 解惑

单片机学习的误区

 单片机因其优异的性能得到了越来越广泛的应用,现在几乎所有的电子产品都用到了它,因此学习单片机的人也越来越多。随着技术的进步,单片机的种类也层出不穷,不断有新型高性能的单片机出现,令学习者看得眼花缭乱,忙不暇接,经常有人问学那一种 ...…

查看全部问答>

这里有个小程序PIC12C508的,可能看有什么问题?

#include __CONFIG (INTRC & PROTECT & MCLREN & WDTEN); const unsigned char cs @ 0x1FF; void DelayUs( int  x)    // 32US {while(--x!=0)   { CLRWDT();     NOP();     unsigned ...…

查看全部问答>

瞬时无功理论谐波检测方法

瞬时无功理论谐波检测方法的资料下载,免费贡献给大家…

查看全部问答>

基于FPGA的B超成像系统图像采集的原理和实现

1、引言 医学超声诊断成像技术大多数采用超声脉冲回波法,即利用探头产生超声波进入人体,由人体组织反射产生的回波经换能器接收后转换为电信号,经过提取、放大、处理,再由数字扫描变换器转换为标准视频信号,最后由显示器进行显示。在基于FPGA+ ...…

查看全部问答>

UART接收程序丢失数据的问题

各位大侠,我用AVR ATMEGA16的UART来接收上位机串口调试助手发来的数据,假设为0x53,0x26,0x53,0x89,0x47,前面两个数据总是对的,然后第三位就接到了最后一个数据,中间的数据就丢失了。 接收中断程序如下: #pragma interrupt_handler uart_rx_ ...…

查看全部问答>

请教9261的串口收发问题

请教9261的串口收发问题 我在核中添加了下面的代码: at91_register_uart(AT91SAM9261_ID_US1, 1, ATMEL_UART_RTS); at91_register_uart(AT91SAM9261_ID_US2, 2, ATMEL_UART_RTS); at91_register_uart(AT91SAM9261_ID_US3, 3, ATMEL_UART_RTS ...…

查看全部问答>

EVC下EDIT控件为何无法进行输入法的输入

编辑完对话框类后无法在EDIT里输入汉字; 还有请帮忙看看一下代码怎么修改 LOGFONT m_lf;                 //字体结构 strcpy(m_lf.lfFaceName,ipadress ); 报错:error C2664: \ ...…

查看全部问答>

为什么直接耦合共射放大电路的直流负载线和交流负载线重合?

图为直接耦合共射放大电路~ 直流通路里有直流电源Vcc,可是交流通路里没有Vcc啊,负载线方程怎么会相同呢? 请最好把Uce和Ic的函数关系式即负载线方程写出来~…

查看全部问答>

大家有没有学MSP5438A系列的,交流交流啊

5438A刚买了板子,还没入门,想求一些易入门的资料…

查看全部问答>

【美资“上海”和“成都”两地急招】DSP 工程师 (audio芯片)

请将中英文简历各一份发到邮箱:Recruiting.Chengdu@conexant.com 公司介绍:美国科胜讯国际有限公司是全球著名无工厂IC设计公司之一,在宽带通讯、企业网和数字家庭领域的芯片技术处于世界领导地位。科胜讯数字电视(成都)有限公司是美国科胜 ...…

查看全部问答>