s3c6410对nand_flash的烧写功能,有些公司已经提供了SD卡的方法。但是我们也可以使用JLink把我们的uboot等程序以下面的方式烧写到我们的nand_flash上
硬件环境:JLink V8、三星s3c6410板
软件环境:xp3、JLink4.12驱动、ADS1.2
原理:针对s3c6410,nand flash启动时,系统会把nand flash前4KB的内容自动下载到0xc000000(steppingstone)中运行,我们可以利用
这个特性,来做一些事情,把大的程序烧写到nand flash的0x0地址,这样,在重新启动之后,就会自动运行我们的大程序了。但是这里我们
还忽略了一些细节。细心的读者发现,系统只会把nand flash的地址前4K下载到0xc000000运行,那么大程序如何完全放到内存中运行呢?
如果你玩过uboot的代码搬运的话,那就不是难事了。
s3c6410的0xc000000地址做为steppingstone在nand_flash启动的时候,这段空间是可读可写的。因此我们可以使用JLINK连接板子,并通过JLINK的下载功能,把PC机上的程序写到板子的内存中,通过JLINK的loadbin命令。
1.利用JLINK,烧写能够初始化s3c6410内存的代码到0xc000000,使得内存能够使用
2.利用JLINK,烧写对nand有读写能力并可提供命令处理的程序到内存(没有第一步的初始化内存,我们无法下载程序到内存)
3.烧写我们的第二步的代码到nand flash的0地址,这样在重新启动后,我们的第二步代码就会被下载到0xc000000地址,并运行,
我们可以利用第二步代码所提供的命令来烧写我们其他的程序。第二步的代码往往是引导程序,例如uboot。
学前预备:
1. 对arm体系结构有一定认识,看过s3c6410的datasheet,最起码看过memory map这一章节
2. 会使用ADS1.2 IDE开发工具
3. 会使用JLink工具
步骤:
1.JLink和你的板子连接(别告诉我不会,我截图能力有限)
JLink一端通过JTAG口连接到板子上(具体连接方式还要看硬件连线,不过一般都是这样了,我用的转接板),另一端是USB口连接到你的主机上;
2.运行JLink
如果第一步连接正确,启动后将显示以下界面,如果没有检测到CPU,命令行使用usb命令连接板子,r命令识别CPU,正确识别如下所示:
3.下载程序(nand_flash启动方式)
1)loadbin c:\init.bin 0xc000000
2)setpc 0xc000000
3)g
4)h
5)loadbin c:\boot.bin 0x57e00000
6)setpc 0x57e00000
7)g
解释:loadbin c:\sdram_init.bin 0xc000000,loadbin为JLink内置命令,命令的含义是加载二进制文件到板子的特定地址。c:\sdram_init.bin为二进制文件,0xc000000是地址,如有需要sdram_init程序及源码,请发送邮件。
setpc 0xc000000,setpc是把板子的pc值设置为后面的地址。
g让板子开始执行0xc000000处的代码。
h(halt),停止运行,并显示硬件信息。
loadbin c:\boot.bin 0x57e00000,boot.bin是我的uboot代码,具有nand_flash烧写、网络传输、串口IO等功能,0x57e00000是我的boot.bin代码的运行地址
上面操作的步骤如下图:
setpc 0x57e00000,然后g,打开终端便可以看到你的bootloader已经启动起来了
4.以上的图片是通过串口读出的uboot程序界面,具有nand烧写功能。现在程序被我们放到了0x57e00000,我们把他烧写到nand flash中
使用uboot的命令 nand write.i 0x57e00000 0x0 0x80000。命令的含义为把内存地址0x57e00000地址处0x80000个字节的内容写到
nand flash的0x0地址中。
好了,下次重启时,nand flash前4KB的内容会被放到steppingstone中运行,这前4KB的内容在内存中运行起来之后,把nand flash中
的代码完全拷贝到内存中,便可以使用uboot的全部功能,也可以随便烧写其他程序了,比如说内核、根文件系统,哈哈。
5.上面提到过sdram_init.bin文件,是初始化内存的汇编代码。以下提供s3c6410的内存初始化代码。两个文件:sdram_init.S和sdram_init.inc。sdram_init.S是内存初始化源代码,sdram_init.inc为头文件。代码使用ADS1.2编写:
sdram_init.S内容如下:
GET sdram_init.inc
;====================
;main
;====================
area sdram_init, code, readonly
entry
;====================
;peri port setup
;====================
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4
;====================
;disable watchdog
;====================
ldr r0, =ELFIN_WATCHDOG_BASE
mov r1, #0x0
str r1, [r0]
;====================
;External interrupt pending clear
;====================
ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) ;EINTPEND
ldr r1, [r0]
str r1, [r0]
ldr r0, =ELFIN_VIC0_BASE_ADDR ;0x71200000
ldr r1, =ELFIN_VIC1_BASE_ADDR ;0x71300000
;Disable all interrupts (VIC0 and VIC1)
mvn r3, #0x0
str r3, [r0, #oINTMSK]
str r3, [r1, #oINTMSK]
;Set all interrupts as IRQ
mov r3, #0x0
str r3, [r0, #oINTMOD]
str r3, [r1, #oINTMOD]
;Pending Interrupt Clear
mov r3, #0x0
str r3, [r0, #oVECTADDR]
str r3, [r1, #oVECTADDR]
;====================
;clock init
;====================
ldr r0, =ELFIN_CLOCK_POWER_BASE ;0x7e00f000
ldr r1, [r0, #OTHERS_OFFSET]
mov r2, #0x40
orr r1, r1, r2
str r1, [r0, #OTHERS_OFFSET]
nop
nop
nop
nop
nop
ldr r2, =0x80
orr r1, r1, r2
str r1, [r0, #OTHERS_OFFSET]
check_syncack
ldr r1, [r0, #OTHERS_OFFSET]
ldr r2, =0xf00
and r1, r1, r2
cmp r1, #0xf00
bne check_syncack
mov r1, #0xff00
orr r1, r1, #0xff
str r1, [r0, #APLL_LOCK_OFFSET]
str r1, [r0, #MPLL_LOCK_OFFSET]
str r1, [r0, #EPLL_LOCK_OFFSET]
ldr r1, [r0, #CLK_DIV2_OFFSET]
bic r1, r1, #0x70000
orr r1, r1, #0x30000
str r1, [r0, #CLK_DIV2_OFFSET]
ldr r1, [r0, #CLK_DIV0_OFFSET] ;Set Clock Divider
bic r1, r1, #0x30000
bic r1, r1, #0xff00
bic r1, r1, #0xff
ldr r2, =CLK_DIV_VAL
orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]
ldr r1, =APLL_VAL
str r1, [r0, #APLL_CON_OFFSET]
ldr r1, =MPLL_VAL
str r1, [r0, #MPLL_CON_OFFSET]
ldr r1, =0x80200203 ;FOUT of EPLL is 96MHz
str r1, [r0, #EPLL_CON0_OFFSET]
ldr r1, =0x0
str r1, [r0, #EPLL_CON1_OFFSET]
ldr r1, [r0, #CLK_SRC_OFFSET] ;APLL, MPLL, EPLL select to Fout
ldr r2, =0x2007
orr r1, r1, r2
str r1, [r0, #CLK_SRC_OFFSET]
;wait at least 200us to stablize all clock
mov r1, #0x10000
1 subs r1, r1, #1
bne %B1
;Synchronization for VIC port
ldr r1, [r0, #OTHERS_OFFSET]
orr r1, r1, #0x20
str r1, [r0, #OTHERS_OFFSET]
;====================
;memory init
;====================
ldr r0, =ELFIN_MEM_SYS_CFG ;Memory sussystem address 0x7e00f120
mov r1, #0xd ;Xm0CSn2 = NFCON CS0 设置NAND Flash为存储器
str r1, [r0]
ldr r0, =ELFIN_DMC1_BASE ;DMC1 base address 0x7e001000
; memc_cmd : 010 wake up
ldr r1, =0x04
str r1, [r0, #INDEX_DMC_MEMC_CMD]
; Refresh period = ((Startup_HCLK / 1000 * DDR_tREFRESH) - 1) / 1000000 -> DDR_tREFRESH 7800 ns
ldr r1, = 1308 ; DMC_DDR_REFRESH_PRD
str r1, [r0, #INDEX_DMC_REFRESH_PRD]
; CAS_Latency = DDR_CASL<<1 -> DDR_CASL 3
ldr r1, = 6 ; DMC_DDR_CAS_LATENCY
str r1, [r0, #INDEX_DMC_CAS_LATENCY]
; t_DQSS (clock cycles)
ldr r1, = 1 ; DMC_DDR_t_DQSS
str r1, [r0, #INDEX_DMC_T_DQSS]
; T_MRD (clock cycles)
ldr r1, = 2 ; DMC_DDR_t_MRD
str r1, [r0, #INDEX_DMC_T_MRD]
; T_RAS (clock cycles)
ldr r1, = 7 ; DMC_DDR_t_RAS
str r1, [r0, #INDEX_DMC_T_RAS]
; T_RC Active Bank x to Active Bank x delay(clock cycles)
ldr r1, = 10 ; DMC_DDR_t_RC
str r1, [r0, #INDEX_DMC_T_RC]
; T_RCD RAS to CAD delay(clock cycles)
ldr r1, = 4 ; DMC_DDR_t_RCD
ldr r2, = 8 ; DMC_DDR_schedule_RCD
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RCD]
; T_RFC AutoRefresh(clock cycles)
ldr r1, = 11 ; DMC_DDR_t_RFC
ldr r2, = 256 ; DMC_DDR_schedule_RFC
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RFC]
; T_RP Precharge to RAS delay(clock cycles)
ldr r1, = 4 ; DMC_DDR_t_RP
ldr r2, = 8 ; DMC_DDR_schedule_RP
orr r1, r1, r2
str r1, [r0, #INDEX_DMC_T_RP]
; T_RRD Active Bank x to Active Bank y delay(clock cycles)
ldr r1, = 3 ; DMC_DDR_t_RRD
str r1, [r0, #INDEX_DMC_T_RRD]
; T_WR Write to precharge delay(clock cycles)
ldr r1, =3 ; DMC_DDR_t_WR
str r1, [r0, #INDEX_DMC_T_WR]
; T_WTR Write to Read delay(clock cycles)
ldr r1, = 2 ;DMC_DDR_t_WTR
str r1, [r0, #INDEX_DMC_T_WTR]
; T_XP Exit Power down(clock cycles)
ldr r1, = 2 ; DMC_DDR_t_XP
str r1, [r0, #INDEX_DMC_T_XP]
; T_XSR Exit self refresh(clock cycles)
ldr r1, = 17 ; DMC_DDR_t_XSR
str r1, [r0, #INDEX_DMC_T_XSR]
; T_ESR SelfRefresh(clock cycles)
ldr r1, = 17 ; DMC_DDR_t_ESR
str r1, [r0, #INDEX_DMC_T_ESR]
; Memory Configuration Register
ldr r1, = 0x40010012 ; DMC1_MEM_CFG
str r1, [r0, #INDEX_DMC_MEMORY_CFG]
ldr r1, = 0xb41 ; DMC1_MEM_CFG2
str r1, [r0, #INDEX_DMC_MEMORY_CFG2]
ldr r1, = 0x150f8 ; DMC1_CHIP0_CFG
str r1, [r0, #INDEX_DMC_CHIP_0_CFG]
ldr r1, = 0 ; DMC_DDR_32_CFG
str r1, [r0, #INDEX_DMC_USER_CONFIG]
; The follows is according to the Datasheet initialization sequence
;DMC0 DDR Chip 0 configuration direct command reg
ldr r1, = 0x0c0000 ; DMC_NOP0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
;Precharge All
ldr r1, = 0 ; DMC_PA0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
;Auto Refresh 2 time
ldr r1, = 0x40000 ; DMC_AR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
;MRS
ldr r1, = 0xa0000 ; DMC_mDDR_EMR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
;Mode Reg
ldr r1, = 0x80032 ; DMC_mDDR_MR0
str r1, [r0, #INDEX_DMC_DIRECT_CMD]
;Enable DMC1
mov r1, #0x0
str r1, [r0, #INDEX_DMC_MEMC_CMD]
check_dmc1_ready
ldr r1, [r0, #INDEX_DMC_MEMC_STATUS]
mov r2, #0x3
and r1, r1, r2
cmp r1, #0x1
bne check_dmc1_ready
nop
loop
b loop
end
sdram_init.inc内容如下:
;====================
;interrupt defined
;====================
ELFIN_GPIO_BASE EQU 0x7f008000
EINTPEND_OFFSET EQU 0x924
ELFIN_VIC0_BASE_ADDR EQU 0x71200000
ELFIN_VIC1_BASE_ADDR EQU 0x71300000
oINTMSK EQU 0x14
oINTMOD EQU 0x0c
oVECTADDR EQU 0xf00
;====================
;clock init defined
;====================
ELFIN_WATCHDOG_BASE EQU 0x7e004000
ELFIN_CLOCK_POWER_BASE EQU 0x7e00f000
OTHERS_OFFSET EQU 0x900
APLL_LOCK_OFFSET EQU 0x00
MPLL_LOCK_OFFSET EQU 0x04
EPLL_LOCK_OFFSET EQU 0x08
CLK_DIV2_OFFSET EQU 0x28
CLK_DIV0_OFFSET EQU 0x20
Startup_PCLKdiv EQU 3
Startup_HCLKx2div EQU 1
Startup_HCLKdiv EQU 1
Startup_MPLLdiv EQU 1
Startup_APLLdiv EQU 1
CLK_DIV_VAL EQU ((Startup_PCLKdiv<<12)|(Startup_HCLKx2div<<9)|(Startup_HCLKdiv<<8)|(Startup_MPLLdiv<<4)|Startup_APLLdiv)
APLL_MDIV EQU 266
APLL_PDIV EQU 3
APLL_SDIV EQU 1
APLL_VAL EQU ((1<<31 | APLL_MDIV<<16 | APLL_PDIV<<8 | APLL_SDIV))
APLL_CON_OFFSET EQU 0x0c
MPLL_CON_OFFSET EQU 0x10
EPLL_CON0_OFFSET EQU 0x14
EPLL_CON1_OFFSET EQU 0x18
CLK_SRC_OFFSET EQU 0x1c
MPLL_MDIV EQU 266
MPLL_PDIV EQU 3
MPLL_SDIV EQU 1
MPLL_VAL EQU ((1<<31 | MPLL_MDIV<<16 | MPLL_PDIV<<8 | MPLL_SDIV))
;====================
;mem init defined
;====================
CONFIG_SYS_CLK_FREQ EQU 12000000
Startup_APLL EQU (CONFIG_SYS_CLK_FREQ/(APLL_PDIV<<APLL_SDIV)*APLL_MDIV)
Startup_HCLK EQU (Startup_APLL/(Startup_HCLKx2div+1)/(Startup_HCLKdiv+1))
ELFIN_MEM_SYS_CFG EQU 0x7e00f120
ELFIN_DMC1_BASE EQU 0x7e001000
INDEX_DMC_MEMC_CMD EQU 0x04
DDR_tREFRESH EQU 7800
DMC_DDR_REFRESH_PRD EQU (((Startup_HCLK / 1000 * DDR_tREFRESH) - 1) / 1000000)
INDEX_DMC_REFRESH_PRD EQU 0x10
DDR_CASL EQU 3
DMC_DDR_CAS_LATENCY EQU (DDR_CASL<<1)
INDEX_DMC_CAS_LATENCY EQU 0x14
DMC_DDR_t_DQSS EQU 1
INDEX_DMC_T_DQSS EQU 0x18
DMC_DDR_t_MRD EQU 2
INDEX_DMC_T_MRD EQU 0x1c
DDR_tRAS EQU 45
DMC_DDR_t_RAS EQU (((Startup_HCLK / 1000 * DDR_tRAS) - 1) / 1000000 + 1)
INDEX_DMC_T_RAS EQU 0x20
DDR_tRC EQU 68
DMC_DDR_t_RC EQU (((Startup_HCLK / 1000 * DDR_tRC) - 1) / 1000000 + 1)
INDEX_DMC_T_RC EQU 0x24
DDR_tRCD EQU 23
DMC_DDR_t_RCD EQU (((Startup_HCLK / 1000 * DDR_tRCD) - 1) / 1000000 + 1)
DMC_DDR_schedule_RCD EQU ((DMC_DDR_t_RCD - 3) << 3)
INDEX_DMC_T_RCD EQU 0x28
DDR_tRFC EQU 80
DMC_DDR_t_RFC EQU (((Startup_HCLK / 1000 * DDR_tRFC) - 1) / 1000000 + 1)
DMC_DDR_schedule_RFC EQU ((DMC_DDR_t_RFC - 3) << 5)
INDEX_DMC_T_RFC EQU 0x2c
DDR_tRP EQU 23
DMC_DDR_t_RP EQU (((Startup_HCLK / 1000 * DDR_tRP) - 1) / 1000000 + 1)
DMC_DDR_schedule_RP EQU ((DMC_DDR_t_RP - 3) << 3)
INDEX_DMC_T_RP EQU 0x30
DDR_tRRD EQU 15
DMC_DDR_t_RRD EQU (((Startup_HCLK / 1000 * DDR_tRRD) - 1) / 1000000 + 1)
INDEX_DMC_T_RRD EQU 0x34
DDR_tWR EQU 15
DMC_DDR_t_WR EQU (((Startup_HCLK / 1000 * DDR_tWR) - 1) / 1000000 + 1)
INDEX_DMC_T_WR EQU 0x38
DMC_DDR_t_WTR EQU 2
INDEX_DMC_T_WTR EQU 0x3c
DMC_DDR_t_XP EQU 2
INDEX_DMC_T_XP EQU 0x40
DDR_tXSR EQU 120
DMC_DDR_t_XSR EQU (((Startup_HCLK / 1000 * DDR_tXSR) - 1) / 1000000 + 1)
INDEX_DMC_T_XSR EQU 0x44
DMC_DDR_t_ESR EQU DMC_DDR_t_XSR
INDEX_DMC_T_ESR EQU 0x48
DMC1_MEM_CFG EQU ((1<<30) | (2<<15) | (3<<3) | (2<<0)) ;((1<<30) | (2<<15) | (2<<3) | (2<<0))
INDEX_DMC_MEMORY_CFG EQU 0x0c
DMC1_MEM_CFG2 EQU 0xB41
INDEX_DMC_MEMORY_CFG2 EQU 0x4c
DMC1_CHIP0_CFG EQU 0x150f8 ;128M=0x150f0
INDEX_DMC_CHIP_0_CFG EQU 0x200
DMC_DDR_32_CFG EQU 0x0
INDEX_DMC_USER_CONFIG EQU 0x304
DMC_NOP0 EQU 0x0c0000
DMC_PA0 EQU 0x000000
INDEX_DMC_DIRECT_CMD EQU 0x08
DMC_mDDR_EMR0 EQU 0x0a0000
INDEX_DMC_MEMC_STATUS EQU 0x00
DMC_AR0 EQU 0x040000
DMC_mDDR_MR0 EQU 0x080032
END