×
单片机 > 单片机程序设计 > 详情

Tiny210裸机之DDR_SDRAM重定位

发布时间:2020-06-06 发布时间:
|

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, =0x3f000000    // 重新初始化栈,指向内存 

    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);

}

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

memset.S中DDR初始化汇编源码:

// 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

#define DMC0_MEMCONTROL        0x00202400    // MemControl    BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off

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

#define DMC0_MEMCONFIG_1    0x00E00323    // MemConfig1

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

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

#define DMC0_TIMING_DATA        0x24240000      // TimingData   CL=3

#define DMC0_TIMING_PWR         0x0BDC0343      // TimingPower

#define    DMC1_MEMCONTROL        0x00202400    // MemControl    BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

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

#define DMC1_MEMCONFIG_1    0x00F00313    // MemConfig1

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

#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]

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

    str    r1, [r0, #DMC_MEMCONTROL]

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

    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]

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

    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]

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

    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)

{

}

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

main.c源码:

#include "command.h"

#include "clock.h"

#include "led.h"

#include "uart.h"

#include "lib.h"

#include "nand.h"

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

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

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");    

}

int main(void)

{

    char buf[6];

    int argc = 0;

    int i = 0;

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

    uart_init(); // 初始化UART0 

    nand_read_id(buf);

    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");

    while (1)

    {

        argc = readline (CFG_PROMPT);

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

        {

            message();

            i=1;

        }

        run_command(argc, argv);

    }

    return 0;

}

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

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;

}

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

Makefile文件:

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

    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 mem_setup.S -o mem_setup.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 -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 = .;

}

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

要支持DDR,仅仅只需要做一些初始化工作就行,而在S5PV210芯片手册中的598页已经给出了相信的初始化话步骤,我就不再多说什么了。

另外大家可以听一下韦东三的6410的一期视频里面关于DDR的视频,会对大家对DDR的了解有所帮助。

另外推荐大家看两篇文章:

1).DDR2_SDRAM操作时序.pdf

2).内存的原理和时序(SDRAM、DDR、DDR-Ⅱ、Rambus_DRAM).pdf

参考代码我已经给出(其实我也是参考u-boot里面的,只是自己从头对照寄存器去理解了一下,完全符合598页的初始化步骤),放在了"Tiny210学习日记_代码"目录下了,名为"7_ddr"

注意:之前的代码,包括该部分代码,都没有重定位的操作,IROM最多可以拷贝16K的代码到IRAM中,够用了!

但是,由于后面我会讲到LCD显示图片,声卡播放WAV文件,bootloader也随之慢慢变大,16K的大小可能不够,再加上现在已经把重定位的条件都准备好了,所以接下来将是重定位。(相关知识,大家可以学习韦东三一期视频的重定位部分),这里,我就不在细说,直接给出代码,和讲几个关键地方。

以下为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               // 拷贝数据 

// 以下将BSS段清0 

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, =0x3f000000    // 重新初始化栈,指向内存 

    ldr pc, =main

注意:

1).ldr r1, =0x0不能写成adr r1, =_start,因为拷贝数据是从Nand Flash的0地址开始拷贝,而adr r1, =_start表示当前程序执行的地址,该地址是0xD0020000而不是0(我在"Tiny210学习日记(2)"中已讲过)。

2).大家注意位置无关码,以及r0对应C函数的参数1,r1对应C函数的参数2,r2对应C函数的参数3的问题!!

以下为连接脚本:

SECTIONS {

    . = 0x36000010;    // 注意这个值 

    .text : {

        * (.text)

    }

    . = ALIGN(4);

    .rodata : {

        * (.rodata)

    }

    . = ALIGN(4);

    .data : {

        * (.data)

    }

    . = ALIGN(4);

    bss_start = .;

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

    bss_end = .;

}

注意:

连接地址一定要是0x36000010,而不是0x36000000,虽然我们是将Nand Flash的数据拷贝到0x36000000地址处,但是我在"Tiny210学习日记(2)"中已讲过,前16字节的数据是头部信息,而不是真正的可执行代码!!

重定位的相应代码放在了"Tiny210学习日记_代码"目录下了,名为"8_reload"。





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址