首页 > 代码库 > 使用JLink间接烧写s3c6410 nand_flash的方法

使用JLink间接烧写s3c6410 nand_flash的方法

原文:使用JLink间接烧写s3c6410 nand_flash的方法

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