以前的裸板程序都是通过u-boot或自我更新程序update下载到内存运行,今天实现更新程序update,程序运行时会输出一个菜单供选择。
系统:ubuntu 10.04.4
单板:s5pc100
编译器:arm-linux-gcc-4.3.2
搭建开发环境详见ubuntu 10.04.4开发环境配置。
目标:串口输出菜单,有以下·功能供选择
[w] write the nand flash
[r] read the nand flash
[e] erase the nand flash
[g] get file, and write to nand flash 0 block
[x] get file to ddr(0x22000000), run it
[s] reset the programe
即实现读写nand,通过V2.2.exe/gtkterm发送文件到内存,再写到NADN flash 0地址,以及重启update程序。
改程序主要功能是实现更新程序,以及把程序放到内存运行·。
一、编写源代码
根据s5pc100手册编写代码,包括源文件start.S clock.S cpu_init.S nand.c main.c uart.c lib.c lib.h Makefile
文件start.S:
.global
_start:
/*1. Disable Watchdog */
/*1.鍏崇湅闂ㄧ嫍*/
ldr r0, =0xEA200000
mov r1, #0
str r1, [r0]
bl clock_init
//bl test
bl mp1_x_drive_strength_init
bl mem_ctrl_asm_init
ldr sp, =0xD0038000
bl init_uart
bl nand_init
//bl test
ldr r0, =0x0
ldr r1, =0x21000000
ldr r2, =bss_start
sub r2, r2, r1
bl copy_code_to_sdram
//bl test
//b main
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, =0x21800000 /* 设置堆栈*/
//bl test
ldr pc, =main
文件clock.S:
.globl clock_init
clock_init:
/* 1.设置LOCK_TIME */
ldr r0, =0xe0100000 //CLOCK_POWER_BASE
mov r1, #0xe00
orr r1, r1, #0x10
str r1, [r0, #0x0] /* APLL_LOCK */
str r1, [r0, #0x4] /* MPLL_LOCK */
str r1, [r0, #0x8] /* EPLL_LOCK */
str r1, [r0, #0x0c] //HPLL_LOCK
//#define OTHERS 0x7e00f900
// @ set async mode /* 当CPU时钟 != HCLK时,要设为异步模式 */
// ldr r0, =OTHERS
// ldr r1, [r0]
// bic r1, r1, #0xc0 /* 1100,0000 */
// str r1, [r0]
//loop1: /* 等待,直到CPU进入异步模式 */
// ldr r0, =OTHERS
// ldr r1, [r0]
// and r1, r1, #0xf00
// cmp r1, #0
// bne loop1
/* SYNC667 */
/* MISC_CON[19] = 0 */
//#define ARM_RATIO 0 /* ARMCLK = DOUTAPLL / (ARM_RATIO + 1) */
//#define HCLKX2_RATIO 1 /* HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) */
//#define HCLK_RATIO 1 /* HCLK = HCLKX2 / (HCLK_RATIO + 1) */
//#define PCLK_RATIO 3 /* PCLK = HCLKX2 / (PCLK_RATIO + 1) */
//#define MPLL_RATIO 0 /* DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) */
// ldr r0, =0x7E00F020 /* CLK_DIV0 */
// ldr r1, =(ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_//RATIO << 12)
// str r1, [r0]
/* CLK_DIV0 */
#define APLL_RATIO 0
#define ARM_RATIO 4
#define D0_BUS_RATIO 8
#define PCLKD0_RATIO 12
#define SECSS_RATIO 16
ldr r1, [r0, #0x300] //CLK_DIV0 Clock divider
ldr r2, =0x3fff
bic r1, r1, r2
ldr r2, =(1<<APLL_RATIO) | (0<<ARM_RATIO) | (4<<D0_BUS_RATIO) | (1<<PCLKD0_RATIO) | (1<<SECSS_RATIO)
orr r1, r1, r2
str r1, [r0, #0x300] //CLK_DIV0
ldr r2, =((1<<16) | (1<<12) | (1<<8) | (1<<4))
orr r1 ,r1, r2
str r1, [r0, #0x304] //CLD_DIV1
/* 2.配置时钟 */
/* 2.1 配置APLL */
/* 2.1.1 设置APLL
* 2.1.2 MUXAPLL
* 2.1.3 SYNC667
* 2.1.4 DIVAPLL
*/
//#define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
// ldr r0, =0x7E00F00C
// ldr r1, =APLL_CON_VAL
// str r1, [r0] /* APLL_CON, FOUTAPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
#define APLL_VAL ((1<<31) | (417 << 16) | (3 << 8) | (0))
//ldr r0, =0xe0100100 //APLL_CON
ldr r1, =APLL_VAL
str r1, [r0, #0x100] /* MPLL_CON, FOUTMPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
/* 2.2 配置MPLL */
/* 2.2.1 设置MPLL
* 2.2.2 MUXMPLL
* 2.2.3 SYNCMUX
* 2.2.4 SYNC667
* 2.2.5 HCLKX2_RATIO
* 2.2.6 PCLK_RATIO
*/
//#define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
//CONFIG_CLK_833_166_66
#define MPLL_VAL ((1<<31) | (89 << 16) | (2 << 8) | (1))
#define EPLL_VAL ((1<<31) | (135 << 16) | (3 << 8) | (3))
#define HPLL_VAL ((1<<31) | (96 << 16) | (6 << 8) | (3))
ldr r1, =MPLL_VAL
str r1, [r0, #0x104]
ldr r1, =EPLL_VAL
str r1, [r0, #0x108]
ldr r1, =HPLL_VAL
str r1, [r0, #0x10c]
/* 3.选择PLL的输出作为时钟源 */
ldr r1, [r0, #0x200] //CLK_SRC0 0xe0100200
ldr r2, =0x1111
orr r1, r1, r2
str r1, [r0, #0x200] //FOUT: APLL MPLL EPLL HPLL
mov r1, #0x10000
1: subs r1, r1, #1
bne 1b
mov pc, lr
文件cpu_init.S:
//#include "s5pc100.h"
/* Port Group MP1_X Drive Strength Control */
#define MP1_0DRV_OFFSET 0x03CC
#define MP1_1DRV_OFFSET 0x03EC
#define MP1_2DRV_OFFSET 0x040C
#define MP1_3DRV_OFFSET 0x042C
#define MP1_4DRV_OFFSET 0x044C
#define MP1_5DRV_OFFSET 0x046C
#define MP1_6DRV_OFFSET 0x048C
#define MP1_7DRV_OFFSET 0x04AC
#define MP1_8DRV_OFFSET 0x04CC
/*
* Bus Matrix
*/
#define ELFIN_MEM_SYS_CFG 0x7e00f120
/*
* Memory controller
*/
#define ELFIN_SROM_BASE 0xE7000000
#define SROM_BW_REG __REG(ELFIN_SROM_BASE+0x0)
#define SROM_BC0_REG __REG(ELFIN_SROM_BASE+0x4)
#define SROM_BC1_REG __REG(ELFIN_SROM_BASE+0x8)
#define SROM_BC2_REG __REG(ELFIN_SROM_BASE+0xC)
#define SROM_BC3_REG __REG(ELFIN_SROM_BASE+0x10)
#define SROM_BC4_REG __REG(ELFIN_SROM_BASE+0x14)
#define SROM_BC5_REG __REG(ELFIN_SROM_BASE+0x18)
/*
* SDRAM Controller
*/
#define APB_DMC_BASE 0xE6000000
#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_PHYCONTROL2 0x20
#define DMC_PWRDNCONFIG 0x28
#define DMC_TIMINGAREF 0x30
#define DMC_TIMINGROW 0x34
#define DMC_TIMINGDATA 0x38
#define DMC_TIMINGPOWER 0x3C
#define DMC_PHYSTATUS0 0x40
#define DMC_PHYSTATUS1 0x44
#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_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
/*
* Memory Chip direct command
*/
#define PRO_ID_BASE 0xE0000000
#define PRO_ID_OFFSET 0x00
#define OMR_OFFSET 0x04
/*
* GPIO
*/
#define ELFIN_GPIO_BASE 0xE0300000
.globl mp1_x_drive_strength_init
/*
* Init MP1_X Driver Strength for SDRAM
* void mp1_x_drive_strength_init(void)
*/
mp1_x_drive_strength_init:
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0xaaaa
str r1, [r0, #MP1_0DRV_OFFSET]
str r1, [r0, #MP1_1DRV_OFFSET]
str r1, [r0, #MP1_2DRV_OFFSET]
str r1, [r0, #MP1_3DRV_OFFSET]
str r1, [r0, #MP1_4DRV_OFFSET]
str r1, [r0, #MP1_5DRV_OFFSET]
str r1, [r0, #MP1_6DRV_OFFSET]
str r1, [r0, #MP1_7DRV_OFFSET]
str r1, [r0, #MP1_8DRV_OFFSET]
mov pc, lr
.globl mem_ctrl_asm_init
mem_ctrl_asm_init:
ldr r0, =APB_DMC_BASE @APB_DMC_BASE 0xE6000000
ldr r1, =PRO_ID_BASE
ldr r2, [r1, #PRO_ID_OFFSET]
bic r2, #0xfffffdff
mov r2, r2, lsr #9
cmp r2, #0x1
beq onenand_pop
single:
/************ delay loop *************/
#if 0
ldr r1, =0x10000000
mov r2, #0
loop1:
cmp r2, r1
addne r2, r2, #0x1
bne loop1
#endif
/************ DLL initialization *************/
ldr r1, =0x6A101000 @ Phycontrol0 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x000084F4 @Phycontrol1 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL1]
ldr r1, =0x00000000 @Phycontrol2 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL2]
ldr r1, =0x6A101002 @DLL on
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x6A101003 @Dll start
str r1, [r0, #DMC_PHYCONTROL0]
ldr r2, = 0xE6000040 @DMC_PHYSTATUS0
loop1:
ldr r1, [r2] @Check DLL lock
ands r1, r1, #4
beq loop1
ldr r1, [r2]
mov r1, r1, LSR #(0x6)
and r1, r1, #(0xff)
mov r1, r1, LSL #(0x18)
ldr r2, = 0xE6000018 @DMC_PHYCONTROL0
ldr r3, [r2]
bic r3, r3, #(0xff000000)
orr r1, r3, r2
str r1, [r2]
ldr r1, =0x6A101003 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x6A101009 @Dll off
str r1, [r0, #DMC_PHYCONTROL0]
#if 0
ldr r1, =0x6A101000 @ Phycontrol0 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x00008484 @Phycontrol1 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL1]
ldr r1, =0x00000000 @Phycontrol2 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL2]
#endif
/************ DLL initialization - END *************/
ldr r1, =0x0FF01010 @auto refresh off
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =0x00202400 @ BL=4 , 1 chip , DDR2
str r1, [r0, #DMC_MEMCONTROL]
#if 1 // add xxs 256MB enable
ldr r1, =0x20F01323
str r1, [r0, #DMC_MEMCONFIG0]
ldr r1, =0x40F00323
str r1, [r0, #DMC_MEMCONFIG1]
#else // 128MB enable
ldr r1, =0x20F81313
str r1, [r0, #DMC_MEMCONFIG0]
ldr r1, =0x40F80313
str r1, [r0, #DMC_MEMCONFIG1]
#endif
ldr r1, =0x20000000
str r1, [r0, #DMC_PRECHCONFIG]
ldr r1, =0x00100004 @ PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
#ifdef CONFIG_HCLKD0_222
ldr r1, =0x000006c3 @7.8us*222MHz=0x6c3, 7.8us*166MHz=1294(0x50E)
str r1, [r0, #DMC_TIMINGAREF]
/* T-rfc 127.5nS/5ns 64 */
ldr r1, =0x202332C8 @TimingRow @222MHz
str r1, [r0, #DMC_TIMINGROW]
ldr r1, =0x24450304 @CL=5
str r1, [r0, #DMC_TIMINGDATA]
#else
ldr r1, =0x0000050E
str r1, [r0, #DMC_TIMINGAREF]
ldr r1, =0x16233297 @TimingRow @166MHz
str r1, [r0, #DMC_TIMINGROW]
@; ldr r1, =0x24250304 @CL=5
ldr r1, =0x23230000 @CL=3
str r1, [r0, #DMC_TIMINGDATA]
#endif
ldr r1, =0x07c80232 @ Timing Power
str r1, [r0, #DMC_TIMINGPOWER]
/* Direct Command for DDR2 */
ldr r1, =0x07000000 @chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00020000 @chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00030000 @chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010400 @chip0 EMRS1 (MEM DLL on = DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
@; ldr r1, =0x00000552 @chip0 MRS (MEM DLL reset) CL=5, Burst Length=4
ldr r1, =0x00000532 @chip0 MRS (MEM DLL reset) CL=3, Burst Length=4
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
@; ldr r1, =0x00000452 @chip0 MRS (MEM DLL unreset) , BL=4 , CL=5
ldr r1, =0x00000432 @chip0 MRS (MEM DLL unreset) , BL=4 , CL=3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010780 @chip0 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]
// ldr r1, =0x00010400 @chip0 EMRS1 (OCD exit)
ldr r1, =0x00010402 @chip0 EMRS1 (OCD exit) Reduced Strength
// ldr r1, =0x00010000 @chip0 EMRS1 (OCD exit) ODT Disabled
str r1, [r0, #DMC_DIRECTCMD]
/* Direct Command for LPDDR - END */
ldr r1, =0x00FF20B0 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]
#if 0
ldr r1, =0x001000FF @ PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
#endif
ldr r1, =0x00212413 @ MemControl
str r1, [r0, #DMC_MEMCONTROL]
b exit_cpu_init
onenand_pop:
ldr r1, =0x50101000 @Phycontrol0 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x000000F4 @Phycontrol1 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL1]
ldr r1, =0x00000000 @Phycontrol2 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL2]
ldr r1, =0x50101002 @Dll on
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x50101003 @dll start
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x50101003 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x50101001 @Dll off
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0xFF001010 @auto refresh off
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =0x00212100 @Dll off
str r1, [r0, #DMC_MEMCONTROL]
@; ldr r1, =0x28F80222
ldr r1, =0x28F00222
str r1, [r0, #DMC_MEMCONFIG0]
ldr r1, =0x20F80222
str r1, [r0, #DMC_MEMCONFIG1]
ldr r1, =0x20000000
str r1, [r0, #DMC_PRECHCONFIG]
ldr r1, =0x0000050E
str r1, [r0, #DMC_TIMINGAREF]
ldr r1, =0x0C233287 @TimingRow @133MHz
str r1, [r0, #DMC_TIMINGROW]
ldr r1, =0x32330303
str r1, [r0, #DMC_TIMINGDATA]
ldr r1, =0x04141433 @Timing Power
str r1, [r0, #DMC_TIMINGPOWER]
ldr r1, =0x07000000 @chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00000032 @chip0 MRS
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x07100000 @chip1 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01100000 @chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00100032 @chip1 MRS
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0xFF002030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =0x00100002 @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
@; ldr r1, =0xFF212113 @MemControl
ldr r1, =0xFF212100 @MemControl
str r1, [r0, #DMC_MEMCONTROL]
b exit_cpu_init
exit_cpu_init:
mov pc, lr
文件nand.c:
//#define MEM_SYS_CFG (*((volatile unsigned long *)0x7E00F120))
#define NFCONF (*((volatile unsigned long *)0xE7200000))
#define NFCONT (*((volatile unsigned long *)0xE7200004))
#define NFCMMD (*((volatile unsigned long *)0xE7200008))
#define NFADDR (*((volatile unsigned long *)0xE720000C))
#define NFDATA (*((volatile unsigned char *)0xE7200010))
#define NFSTAT (*((volatile unsigned long *)0xE7200028))
void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len);
void copy_code_to_sdram(unsigned int src, unsigned int dest, unsigned int len)
{
nand_read(src, dest, len);
}
void nand_select(void)
{
NFCONT &= ~(1<<1);
}
void nand_deselect(void)
{
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
NFCMMD = cmd;
}
void nand_addr(unsigned char addr)
{
NFADDR = addr;
}
unsigned char nand_get_data(void)
{
return NFDATA;
}
void nand_send_data(unsigned char data)
{
NFDATA = data;
}
void wait_ready(void)
{
while ((NFSTAT & 0x1) == 0);
}
void nand_reset(void)
{
/* 选中 */
nand_select();
/* 发出0xff命令 */
nand_cmd(0xff);
/* 等待就绪 */
wait_ready();
/* 取消选中 */
nand_deselect();
}
/*void clear_bss(void)
{
extern int __bss_start, __bss_end;
int *p = &__bss_start;
for (; p < &__bss_end; p++)
*p = 0;
}
*/
void nand_init(void)
{
/* 让xm0csn2用作nand flash cs0 片选引脚 */
//MEM_SYS_CFG &= ~(1<<1);
/* 设置时间参数 */
#define TACLS 7
#define TWRPH0 7
#define TWRPH1 7
NFCONF &= ~((1<<30) | (7<<12) | (7<<8) | (7<<4));
NFCONF |= ((TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4));
/* 使能nand flash controller */
NFCONT |= 1;
NFCONT &= ~(1<<16); /* 森止soft lock */
nand_reset();
}
void nand_send_addr(unsigned int addr)
{
#if 1
unsigned int page = addr / 2048;
//unsigned int colunm = addr & (2048 - 1);
unsigned int colunm = addr % 2048;
volatile int i;
/* 这两个地址表示从页内哪里开始 */
nand_addr(colunm & 0xff);
for (i = 0; i < 10; i++);
nand_addr((colunm >> 8) & 0xff);
for (i = 0; i < 10; i++);
/* 下面三个地址表示哪一页 */
nand_addr(page & 0xff);
for (i = 0; i < 10; i++);
nand_addr((page >> 8) & 0xff);
for (i = 0; i < 10; i++);
nand_addr((page >> 16) & 0xff);
for (i = 0; i < 10; i++);
#else
nand_addr(addr & 0xff); /* a0~a7 */
nand_addr((addr >> 8) & 0x0f); /* 程序的角度: a8~a11 */
nand_addr((addr >> 12) & 0xff); /* 程序的角度: a12~a19 */
nand_addr((addr >> 20) & 0xff); /* 程序的角度: a20~a27 */
nand_addr((addr >> 28) & 0x7); /* 程序的角度: a28 ~a30 */
#endif
}
void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len)
{
unsigned int addr = nand_start;
int i = nand_start % 2048;
int left = i;
int count = 0;
unsigned char *dest = (unsigned char *)ddr_start;
unsigned char data = 0;
/* 选中芯片 */
nand_select();
while (count < len)
{
/* 发出命令0x00 */
nand_cmd(0x00);
/* 发出地址 */
nand_send_addr(addr);
/* 发出命令0x30 */
nand_cmd(0x30);
/* 等待就绪 */
wait_ready();
/* 读数据 */
//for (; i < (4096-left) && count < len; i++)//从某页的i处开始读
for (; i < (2048-left) && count < len; i++)//从某页的i处开始读
{
data = nand_get_data();
/*(addr<16384)//前4页每次只能写2K
{
if(i<(2048-left))
{
dest[count++] = data;
}
}
else
{
dest[count++] = data;
}*/
dest[count++] = data;
addr++;
}
i = 0;
left = i;
}
/* 取消片选 */
nand_deselect();
// return 0;
}
void nand_erase_block(unsigned long addr)
{
int page = addr / 2048;
nand_select();
nand_cmd(0x60);
nand_addr(page & 0xff);
nand_addr((page >> 8) & 0xff);
nand_addr((page >> 16) & 0xff);
nand_cmd(0xd0);
wait_ready();
nand_deselect();
}
void nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len)
{
unsigned long count = 0;
unsigned long addr = nand_start;
int i = nand_start % 2048;
//int left = i;
nand_select();
while (count < len)
{
nand_cmd(0x80);
nand_send_addr(addr);
//for (; i < (2048-left) && count < len; i++)
for (; i < 2048 && count < len; i++)
{
/*if(addr<16384)//写前2K
{
if(i<(2048-left))//前2页每页只能写2K
{
nand_send_data(buf[count++]);
}
}
else
{
nand_send_data(buf[count++]);
}*/
nand_send_data(buf[count++]);
addr++;
}
nand_cmd(0x10);
wait_ready();
i = 0;
//left = i;
}
nand_deselect();
}
文件main.c:
#include "lib.h"
#define GPH1CON (*(volatile unsigned int *)0xe0300C20)
#define GPH1DAT (*(volatile unsigned int *)0xe0300c24)
extern void nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len);
extern void nand_erase_block(unsigned long addr);
extern void nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len);
int strlen(char *str)
{
int i = 0;
while (str[i])
{
i++;
}
return i;
}
void nand_write_test(void)
{
char buf[20] = {"abcd1234ABCD"};
unsigned long addr;
unsigned long size;
puts("enter the start address:0x80000 ");
//scanf("%s", buf);
//addr = strtoul(buf, NULL, 0);
addr = 0x80000;
puts("enter the string:abcd1234ABCD ");
//scanf("%s", buf);
size = strlen(buf) + 1;
puts(" size= ");
puthex(size);
puts("\n\r");
nand_write(addr, buf, size);
}
void nand_read_test(void)
{
int i;
char buf[100];
unsigned long addr;
unsigned long size;
puts("enter the start address: 0x80000");
//scanf("%s", buf);
//addr = strtoul(buf, NULL, 0);
addr = 0x80000;
//puts("read addr = 0x%x\n\r", addr);
puts("enter the size: 0x60");
//scanf("%s", buf);
//size = strtoul(buf, NULL, 0);
size = 0x60;
if (size > 100)
{
puts("the max size is 100\n\r");
size = 100;
}
nand_read(addr, buf, size);
puts("datas: \n\r");
for (i = 0; i < size; i++)
{
// printf("%02x ", buf[i]);
putbyte(buf[i]);
puts("\t");
if ((i+1) % 8 == 0)
{
puts("\n\r");
}
}
puts("\n\r");
}
void nand_erase_test(void)
{
//char buf[100];
unsigned long addr;
puts("enter the start address: ");
//scanf("%s", buf);
//addr = strtoul(buf, NULL, 0);
addr = 0x80000;
puts("erase addr = ");
puthex(addr);
puts("\n\r");
nand_erase_block(addr);
}
void update_program(void)
{
unsigned char *buf = (unsigned char *)0x22000000;
//unsigned char *buf = (unsigned char *)0xD0036000;
unsigned long len = 0;
int have_begin = 0;
int nodata_time = 0;
unsigned long erase_addr;
char c;
int i;
/* 璇讳覆鍙h幏寰楁暟鎹?*/
puts("\n\ruse V2.2.exe/gtkterm to send file\n\r");
while (1)
{
if (getc_nowait(&buf[len]) == 0)
{
have_begin = 1;
nodata_time = 0;
len++;
}
else
{
if (have_begin)
{
nodata_time++;
}
}
if (nodata_time == 1000)
{
break;
}
}
puts("\n\rhave get data:");
puthex(len);
puts(" bytes\n\r");
puts("the first 16 bytes data: \n\r");
for (i = 0; i < 16; i++)
{
// put("%02x ", buf[i]);
putbyte(buf[i]);
puts("\t");
}
puts("\n\r");
puts("Press Y to program the flash: \n\r");
c = getc();
putc(c);
puts("\n\r");
if (c == 'y' || c == 'Y')
{
/* 鐑у啓鍒皀and flash block 0 */
for (erase_addr = 0; erase_addr < ((len + 0x1FFFF) & ~0x1FFFF); erase_addr += 0x20000)
{
nand_erase_block(erase_addr);
}
nand_write(0, buf, len);
puts("update program successful\n\r");
}
else
{
puts("Cancel program!\n\r");
}
}
void run_program(void)
{
unsigned char *buf = (unsigned char *)0x22000000;
//unsigned char *buf = (unsigned char *)0xD0036000;
unsigned long len = 0;
int have_begin = 0;
int nodata_time = 0;
void (*theProgram)(void);
int i;
/* 璇讳覆鍙h幏寰楁暟鎹?*/
puts("\n\r use gtkterm to send file\n\r");
while (1)
{
if (getc_nowait(&buf[len]) == 0)
{
have_begin = 1;
nodata_time = 0;
len++;
}
else
{
if (have_begin)
{
nodata_time++;
}
}
if (nodata_time == 10000)
{
break;
}
}
//printf("have get %d bytes data\n\r", len);
puts("\n\r have get data:");
puthex(len);
puts(" bytes\n\r");
puts("the first 16 bytes data: \n\r");
for (i = 0; i < 16; i++)
{
// put("%02x ", buf[i]);
putbyte(buf[i]);
puts("\t");
//putc('\0');
}
puts("\n\r");
puts("jump to 0x22000000 to run it\n\r");
theProgram = (void (*)(void))0x22000000;
theProgram();
}
int main()
{
char c;
volatile unsigned long *mem = (volatile unsigned long *)0x22000000;
volatile unsigned long *tmem = (volatile unsigned long *)0x21000010;
volatile unsigned long *tsram = (volatile unsigned long *)0xD0034010;
printf("\n\r[0x22000000] = %x\n\r",*mem);
printf("[0x21000010] = %x\n\r",*tmem);
printf("[0xD0034010] = %x\n\r",*tsram);
printf("\n\r********************************\n\r");
printf(" The board:CES-100(s5pc100)\n\r");
printf(" The NAND:K9K8G08U0B %dMB\n\r",1024);
printf(" The DDR:K4T1G164QQ-HCE6\n\r");
printf(" The NET:DM9000CEP\n\r");
printf(" date: %d,.%d,.%d \n\r",2013,4,25);
printf("***********************************\n\r");
while (1)
{
puts("[w] write the nand flash\n\r");
puts("[r] read the nand flash\n\r");
puts("[e] erase the nand flash\n\r");
puts("[g] get file, and write to nand flash 0 block\n\r");
puts("[x] get file to ddr(0x22000000), run it\n\r");
puts("[s] reset the programe\n\r");
puts("Please enter the chose:\n\r");
do {
c = getc();
if (c == '\n' || c == '\r')
{
puts("\n\r");
}
else
{
putc(c);
}
} while (c == '\n' || c == '\r');
switch (c)
{
case 'w':
case 'W':
{
nand_write_test();
break;
}
case 'r':
case 'R':
{
nand_read_test();
break;
}
case 'e':
case 'E':
{
nand_erase_test();
break;
}
case 'g':
case 'G':
{
update_program();
break;
}
case 'x':
case 'X':
{
run_program();
break;
}
case 's':
case 'S':
{
//volatile unsigned long *mcode = (volatile unsigned long *)0x21000010;
void (*theProgram)(void);
//printf("the 0x21000010 value:%x\n\r",*mcode);
theProgram = (void (*)(void))0xD0034010;
theProgram();
break;
}
}
}
return 0;
}
文件uart.c:
#define ULCON0 (*((volatile unsigned long *)0xEC000000))
#define UCON0 (*((volatile unsigned long *)0xEC000004))
#define UFCON0 (*((volatile unsigned long *)0xEC000008))
#define UMCON0 (*((volatile unsigned long *)0xEC00000C))
#define UTRSTAT0 (*((volatile unsigned long *)0xEC000010))
#define UFSTAT0 (*((volatile unsigned long *)0xEC000018))
#define UTXH0 (*((volatile unsigned char *)0xEC000020))
#define URXH0 (*((volatile unsigned char *)0xEC000024))
#define UBRDIV0 (*((volatile unsigned long *)0xEC000028))
#define UDIVSLOT0 (*((volatile unsigned long *)0xEC00002C))
#define GPACON (*((volatile unsigned long *)0xE0300000))
#define ENABLE_FIFO
void init_uart(void)
{
GPACON &= ~0xffff;
GPACON |= 0x2222;
/* ULCON0 */
ULCON0 = 0x3;
UCON0 = 0x5;
#ifdef ENABLE_FIFO
UFCON0 = 0x07; /* FIFO enable */
#else
UFCON0 = 0x00; /* FIFO disable */
#endif
UMCON0 = 0;
/* DIV_VAL = (PCLK / (bps x 16 ) ) - 1
* bps = 115200
* DIV_VAL = (66500000 / (115200 x 16 ) ) - 1
* = 35.08
*/
UBRDIV0 = 35;
/* x/16 = 0.08
* x = 1
*/
UDIVSLOT0 = 3;
UTXH0 = 0x4f4f4f4f;
}
文件lib.c:
#define UTRSTAT0 (*((volatile unsigned long *)0xEC000010))
#define UFSTAT0 (*((volatile unsigned long *)0xEC000018))
#define UTXH0 (*((volatile unsigned char *)0xEC000020))
#define URXH0 (*((volatile unsigned char *)0xEC000024))
#define ENABLE_FIFO
static void delay1(void)
{
volatile int i = 10;
while (i--);
}
unsigned char getc(void)
{
#ifdef ENABLE_FIFO
while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)delay1();
#else
while ((UTRSTAT0 & (1<<0)) == 0);
#endif
return URXH0;
}
int getc_nowait(unsigned char *pChar)
{
#ifdef ENABLE_FIFO
if ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)
#else
if ((UTRSTAT0 & (1<<0)) == 0)
#endif
{
return -1;
}
else
{
*pChar = URXH0;
return 0;
}
}
void putc(char c)
{
#ifdef ENABLE_FIFO
while (UFSTAT0 & (1<<14))delay1();
#else
while ((UTRSTAT0 & (1<<2)) == 0);
#endif
UTXH0 = c;
}
void puts(char *str)
{
int i = 0;
while (str[i])
{
putc(str[i]);
i++;
}
}
void test()
{
puts("init: OK\n\r");
}
void puthex(unsigned int val)
{
// 0x1234abcd
int i;
int j;
puts("0x");
for (i = 0; i < 8; i++)
{
j = (val >> ((7-i)*4)) & 0xf;
if ((j >= 0) && (j <= 9))
putc('0' + j);
else
putc('A' + j - 0xa);
}
}
void putbyte(unsigned char val)
{
/* 0x1234abcd */
int i;
int j;
puts("0x");
for (i = 0; i < 2; i++)
{
j = (val >> ((1-i)*4)) & 0xf;
if ((j >= 0) && (j <= 9))
putc('0' + j);
else
putc('A' + j - 0xa);
}
}
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;
}
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 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);
putc(ch);
break;
case 's':
p = va_arg(ap, char *);
puts(p);
break;
case 'x':
a = va_arg(ap, int);
puthex(a);
break;
case 'd':
a = va_arg(ap, int);
itoa(a, buf);
puts(buf);
break;
default:
break;
}
break;
default:
putc(c);
break;
}
}
return 0;
}
文件lib.h:
unsigned char getc(void);
int getc_nowait(unsigned char *pChar);
void putc(char c);
void puts(char *str);
//int puts(const char * s);
void test();
void puthex(unsigned int val);
//void puthex(int a);
void putbyte(unsigned char val);
char * itoa(int a, char * buf);
int printf(const char * format, ...);
文件Makefile:
update.bin:start.S clock.S cpu_init.S nand.c main.c uart.c lib.c
arm-linux-gcc -c start.S -o start.o
arm-linux-gcc -c clock.S -o clock.o
arm-linux-gcc -c cpu_init.S -o cpu_init.o
arm-linux-gcc -c main.c -o main.o
arm-linux-gcc -c nand.c -o nand.o
arm-linux-gcc -c uart.c -o uart.o
arm-linux-gcc -c lib.c -o lib.o
arm-linux-ld -T bootloader.lds start.o clock.o cpu_init.o nand.o main.o uart.o lib.o -o update_elf
arm-linux-objcopy -O binary -S update_elf update.bin
clean:
rm -rf *.o *.bin update_elf *.dis
二、编译源代码
change@change:~$ cd Si/s5pc100/update/
change@change:~/Si/s5pc100/update$ make
arm-linux-gcc -c start.S -o start.o
arm-linux-gcc -c clock.S -o clock.o
arm-linux-gcc -c cpu_init.S -o cpu_init.o
arm-linux-gcc -c main.c -o main.o
In file included from main.c:1:
lib.h:4: warning: conflicting types for built-in function 'putc'
lib.h:5: warning: conflicting types for built-in function 'puts'
main.c: In function 'nand_read_test':
main.c:66: warning: passing argument 2 of 'nand_read' makes integer from pointer without a cast
arm-linux-gcc -c nand.c -o nand.o
arm-linux-gcc -c uart.c -o uart.o
uart.c: In function 'init_uart':
uart.c:45: warning: large integer implicitly truncated to unsigned type
arm-linux-gcc -c lib.c -o lib.o
lib.c:40: warning: conflicting types for built-in function 'putc'
lib.c:50: warning: conflicting types for built-in function 'puts'
arm-linux-ld -T bootloader.lds start.o clock.o cpu_init.o nand.o main.o uart.o lib.o -o update_elf
arm-linux-objcopy -O binary -S update_elf update.bin
change@change:~/Si/s5pc100/update$ ./mktiny210spl.exe update.bin updates.bin
change@change:~/Si/s5pc100/update$ cp updates.bin /home/change/work/tftpboot/
三、烧写、测试
通过单板已有u-boot烧写程序,系统从NAND启动上电:
OK
U-Boot 1.3.4-dirty (Nov 19 2012 - 10:50:02) for CES-C100
************************************************************
** CES-C100 Nand boot **
** Shenzhen Haitianxiong Electronic Co.,Ltd.(China) **
** http://www.ces-tech.com **
************************************************************
CPU: S5PC100@834MHz
Fclk = 1668MHz, Hclk = 166MHz, Pclk = 66MHz, Serial = PCLK
Board: CES-C100
I2C: ready
VGA: OK
DRAM: 256 MB
Net: DM9000cep
NAND: s3c_nand_oob_slc_64 is selected1024 MB
*** Warning - using default environment
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
##### s5pc100 Bootloader for OpenJTAG #####
[n] Download u-boot to Nand Flash
[o] Download u-boot to Nor Flash
[k] Download Linux kernel uImage
[j] Download root_jffs2 image
[y] Download root_yaffs image
[d] Download to SDRAM & Run
[z] Download zImage into RAM
[g] get file, and write to nand flash 0 block
[f] Read the Nand Flash
[w] Write the nand flash
[e] Erase one nand block
[s] Set the boot parameters
[b] Boot the system
[r] Reboot u-boot
[q] Quit from menu
Enter your selection: q
CES-C100 # set ipaddr 172.16.1.133
CES-C100 # set gatewayip 172.16.1.1
CES-C100 # set serverip 172.16.1.135
CES-C100 # ping 172.16.1.135
ERROR: resetting DM9000 -> not responding
dm9000 i/o: 0x88000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 00:40:5c:26:0a:5b
operating at 100M full duplex mode
host 172.16.1.135 is alive
CES-C100 # tftp 0x22000000 updates.bin
ERROR: resetting DM9000 -> not responding
dm9000 i/o: 0x88000000, id: 0x90000a46
DM9000: running in 16 bit mode
MAC: 00:40:5c:26:0a:5b
operating at 100M full duplex mode
TFTP from server 172.16.1.135; our IP address is 172.16.1.133
Filename 'updates.bin'.
Load address: 0x22000000
Loading: ##
done
Bytes transferred = 24576 (0x6000)
CES-C100 # nand erase 0 0x40000
NAND erase: device 0 offset 0x0, size 0x40000
Erasing at 0x20000 -- 100% complete.
OK
CES-C100 # nand write 0x22000000 0 0x40000
NAND write: device 0 offset 0x0, size 0x40000
262144 bytes written: OK
CES-C100 #
烧写完毕,单板接着断电重启,设置串口com0 115200 8 n 1,串口输出如下:
O[0x22000000] = 0xFFFFFFFF
[0x21000010] = 0xE59F005C
[0xD0034010] = 0xE59F005C
********************************
The board:CES-100(s5pc100)
The NAND:K9K8G08U0B 1024MB
The DDR:K4T1G164QQ-HCE6
The NET:DM9000CEP
date: 2013,.4,.25
***********************************
[w] write the nand flash
[r] read the nand flash
[e] erase the nand flash
[g] get file, and write to nand flash 0 block
[x] get file to ddr(0x22000000), run it
[s] reset the programe
Please enter the chose:
接着选择相应选型即可,均通过测试OK。eg:
g
use V2.2.exe/gtkterm to send file
注:update更新程序是通过v2.2.exe或者gtkterm传送文件到单板内存,再从单板内存写到NAND Flash。