1.因为源中没有smdk2440配置,参考smdk2410,添加smdk2440
a.cp /board/smdk2410 /board/smdk2440 -rf
b.cp include/configs/ smdk2410.h include/configs/ smdk2440.h
c观察2410的编译。
makesmdk2410_config // 配置2410开发板信息
那思考,smdk2410_config设置在哪里?
(1)使用命令:grep “smdk2410_config” * -nR
(2)搜索结果:Makefile:1922:smdk2410_config :unconfig
(3)vim Makefile
在1924行看到以下信息:
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920tsmdk2410 NULL s3c24x0
(4)模仿(注意它们之间的空白行TAB或空格,否则编译报错)
smdk2440_config: unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t smdk2440 NULL s3c24x0
现在,命令可以用来编译
makesmdk2440_config
make
下载使用命令:
进入前烧写u-boot中,按“q进入命令行,
1.usb 130000000
2.使用DNW下载
3.nand erase 0 20000
4.nand write 30000000 0 20000
5.拨开关到NAND启动
没有打印信息。编译不成功。开始修改代码
2.因为串口没有打印任何信息,读取代码,发现问题
(1)、阅读start.S添加其中的代码CONFIG_S3C2410替换成CONFIG_S3C2440,还得同时smdk2440.h中添加#defined(CONFIG_S3C2440) 1
如果你想更好地支持程序,你可以这样做:
#if defined(CONFIG_S3C2440) || defined(CONFIG_S3C2410)
(2)对于这些初始作基本没有问题。
(3)、在lowlevel_init.S的SDRAM需要修改的设置
编译程序,烧写到开发板,串口工具上看不到任何信息。
现在只有重新检查程序。
推荐检查方法:
使用arm-linux-objdump -D u-boot> u-boot.dis
查看u-boot.dis文件,
可知_start = _armboot_start = TEXT_BASE = 0x33f80000
start_armboot= 0x33f80b4c
_bss_start= 0x33f961f8
_bss_end = 0x33f9a91c
可以根据这些信息了解程序的内存分布
由于目前程序连串信息无法输出,请找到相应的函数并查看。
start_armboot
init_sequence
board_init
可以看看到程序在这里设置时钟,用于串口。但在此之前,需要使用时钟。因此,将时钟设置放在这里start.S中,代替start.S分频系数 设置处board_init()中:
clk_power->LOCKTIME= 0xFFFFFF;
clk_power->MPLLCON = ((M_MDIV<< 12) (M_PDIV << 4) M_SDIV);
注释,现在重新编译烧写,在开发板下打印乱码。
虽然是乱码,但终于打印出来了,下面应该修改串口的设置。
3.修改串口信息的设置,使正常输出
一次检查init_sequence中的函数。serial_init与串口有关。
serial_init (cpu/arm920t/s3c24x/serial.c)
serial_setbrg
reg= get_PCLK() / (16 * gd->baudrate) - 1;// 设置波特率
get_PCLK
get_HCLK
&nbp; get_FCLK
get_PLLCLK
检查其中的代码,发现不管是MPLL还是UPLL,最后的返回值都是:
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
这个设置对于JZ_2440来说肯定是不对的。
修改:
if (pllreg == MPLL)
{
r = clk_power->MPLLCON;
m = ((r & 0xFF000) >> 12) +8; // MPLLCON[19:12]
p =((r & 0x003F0) >> 4) + 2; //MPLLCON[9:4]
s = r& 0x3; //MPLLCON[1:0]
return ((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
}
else if (pllreg == UPLL)
{
r = clk_power->UPLLCON;
m = ((r & 0xFF000) >> 12) +8; // MPLLCON[19:12]
p =((r & 0x003F0) >> 4) + 2; //MPLLCON[9:4]
s = r& 0x3; //MPLLCON[1:0]
return ((CONFIG_SYS_CLK_FREQ * m) / (p << s));
}
这个代码一点也不简洁,但是现在先实现功能,到最后再来修改。
现在重新编译,打印如下结果:
U-Boot 1.2.0 (Aug 5 2013 - 15:13:39)
DRAM: 64 MB
Flash:512 kB
***Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
SMDK2410 #
可见修改成功。但是查看上面的打印信息,很明显“Flash:512kb”的信息不符合实际,因为我们的NOR Flash是有2MB的。于是下面就要来更改NOR。
4. 支持NOR Flash
根据上面的错误信息,使用命令“grep "Flash:" * -nR”,其中一条如下:
lib_arm/board.c:183: puts ("Flash: ");
找到函数display_flash_config(),查看它在哪儿被调用。
根据打印信息可以看到应该是在start_armboot中被调用的,因为它紧接在“DRAM” 的打印信息之后,而“DRAM: 64MB”在display_dram_config()函数中被打印。一定要看源代码,不然就云里雾里了。
在函数display_flash_config(size);其中的size是flash_init ()的返回值,所以追本溯源,到flash_init ()函数里查看。
drivers /cfi_flash.c
flash_init
size += flash_info[i].size =flash_get_size (bank_base[i], i);
flash_get_size()
flash_detect_cfi()
在这些函数中,可以看到有很多的打印信息,但是为什么没有被打印出来呢?是不是有某些变量开关呢?仔细预读源代码。找出原因。一路追究下去原来是要定义DEBUG变量
#define DEBUG // 就添加在cfi_flash.c中吧
编译运行,还是打印。重新检查代码,发现在cfi_flash.c的开头还定义了一个变量总开关CFG_FLASH_CFI_DRIVER,所以将这个变量在smdk2440.h中声明: #defineCFG_FLASH_CFI_DRIVER
现在就能打印信息了。(注意,DEBUG应该声明在“#include<common.h>”语句之前,也就是cfi_flash.c文件最开头)
分析打印的结果:
……
Flash: 0 kB
……
修改smdk2440,去掉CONFIG_AMD_LV400
#defineCONFIG_AMD_LV800 1
重新编译:
Flash: 2 MB
如果先打印信息太多,可以将刚才定义的DEBUG变量删去。
NOR Flash
A0-A19:地址输入
Q0-Q14:数据的输入/输出
Q15/A-1:Q15(Word mode)/LSB addr(Byte mode)
CE#:片选信号
WE#:写信号
BYTE#:Word/Byte选择
Reset#:硬件复位引脚/段保护解锁
OE#:输出信号
RY/BY#:准备好/忙
WP/ACC#:写保护/加速引脚
注意:如果没有使用WP/ACC#引脚,那就将这个引脚连接到VCC或是悬空,WP/ACC#内部有个上拉电阻,当没有链接引脚WP/ACC#的时候处于Vih。
5. 添加对NAND Flash的支持
在lib_arm/board.c中找到puts ("NAND: ");
可见要想支持NAND的先定义变量CFG_CMD_NAND,所以在smdk2440.h中将CFG_CMD_NAND的注释去掉。
编译不通过,因为NAND根本就没有被初始化。
在board.c中和nand相关的函数就是nand_init()。
nand_init()
nand_chip_init()
board_nand_init(); // 这是nand初始化的函数,但是在u-boot-1.2.0中没
// 有实现,所以编译会在这儿出错
nand_scan() // 这个函数就是识别出我们开发板里的nand的。
要想NAND能用起来,就先得把初始化的工作完成。
// 这个函数在源中是没有的,自己实现,参照u-boot-2012-04-01
int board_nand_init(struct nand_chip *nand)
{
u_int8_ttacls, twrph0, twrph1;
S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();
puts("board_nand_init()\n");
/*initialize hardware */
tacls= 0;
twrph0= 1;
twrph1= 0;
//+1 my901001106@163.com 2013-8-414:07:48 初始化
s3c_nand->NFCONF=(tacls<<12) | (twrph0<<8) | (twrph1<<4);
/*使能NAND Flash控制器, 初始化ECC, 片选 */
s3c_nand->NFCONT= (1<<4)|(0<<1)|(1<<0); // 这儿的片选一定选中,不然死得很惨
/*initialize nand_chip data structure */
nand->IO_ADDR_R= (void *)&s3c_nand->NFDATA;
nand->IO_ADDR_W= (void *)&s3c_nand->NFDATA;
nand->select_chip= NULL;
/*read_buf and write_buf are default */
/*read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
nand->read_buf= nand_read_buf;
#endif
nand->eccmode = NAND_ECC_SOFT;
/*hwcontrol always must be implemented */
nand->hwcontrol= s3c2440_hwcontrol; // 自定义,用于片选,ALE、CLE的
nand->dev_ready= s3c2440_dev_ready; // 自定义,
#ifdef CONFIG_S3C2440_NAND_BBT
nand->options= NAND_USE_FLASH_BBT;
#else
nand->options= 0;
#endif
return0;
}
// 这个函数写得有点臭了,可以阅读代码再重新修改
static void s3c2440_hwcontrol(structmtd_info *mtd, unsigned int dat)
{
S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();
structnand_chip *this = mtd->priv;
switch(dat) {
caseNAND_CTL_SETCLE:
this->IO_ADDR_W= (void *)&s3c_nand->NFCMD;
break;
caseNAND_CTL_CLRCLE:
this->IO_ADDR_W= (void *)&s3c_nand->NFDATA;
break;
caseNAND_CTL_SETALE:
this->IO_ADDR_W= (void *)&s3c_nand->NFADDR;
break;
caseNAND_CTL_CLRALE:
this->IO_ADDR_W= (void *)&s3c_nand->NFDATA;
break;
caseNAND_CTL_SETNCE:
s3c_nand->NFCONF&= ~(1<<1);
break;
caseNAND_CTL_CLRNCE:
s3c_nand->NFCONF|= (1<<1);
break;
default:
puts("error!\n");
break;
}
}
static int s3c2440_dev_ready(structmtd_info *mtd)
{
S3C2440_NAND* const s3c_nand = S3C2440_GetBase_NAND();
//puts("dev_ready\n");
return(s3c_nand->NFSTAT & 0x01);
}
韦东山的JZ_2440:
nand_flash_ids[37]= {"NAND 256MiB 3,3V8-bit", 0xDA, 0, 256, 0,NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}
6. 让u-boot在NAND Flash中也能启动
在start.S中有这样一段代码:
relocate: /*relocate U-Boot to RAM */
adr r0,_start /* r0 <- currentposition of code */
ldr r1,_TEXT_BASE /* test if werun from flash or RAM */
cmp r0, r1 // 比较链接地址和代码的起始位置是否相等
beq stack_setup
ldr r2,_armboot_start // 0x33f80000
ldr r3,_bss_start // 0x33f961f8
sub r2,r3, r2 /* r2 <- size ofarmboot */
add r2,r0, r2 /* r2 <- source endaddress */
copy_loop:
ldmia r0!,{r3-r10} /* copy from sourceaddress [r0] */
stmia r1!,{r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source endaddreee [r2] */
ble copy_loop
很明显,这段代码只能支持在NOR Flash的启动。现在,我们就得注释掉这段代码,重新写这段重定位的代码。用下面这段代码代替
// 重定位
adr r0, _start //_start的实际运行地址
ldr r1, _TEXT_BASE // 0x33f80000
cmp r0, r1
beq clear_bss
ldr r2, _armboot_start
ldr r3,_bss_start // 0x33fa11fc
sub r2,r3, r2 /* r2 <- size ofarmboot */
bl copyCodeToSDRAM
在这儿我们调用了C函数copyCodeToSDRAM,所以,在这段代码之前还得重新设置栈。即把上面这段代码紧跟在stack_setup之后即可。
下面就是跳转到copyCodeToSDRAM函数的实现。
因为我们的开发板有两个启动模式,一种是NOR,另一种是NAND,那怎么区分?
记住NOR Flash有一个重要的特性,它能像内存一样的执行,但是不能像内存一样的读写。所以我们可以尝试在0地址写入一个数,然后再读出来,如果值没有发生改变,那就是NOR启动方式,若发生改变就是NAND启动方式。注意:先要保存这个0地址的值然后再写入,假如是NAND方式的话,我们还要用这个保存的值恢复0地址。不然程序就会跑飞了。
ntisBootFromNOR(void)
{
volatile unsigned int *p = (volatile unsignedint *)0x0;
unsigned int tmp;
tmp = *p;
*p = 0x12345678;
if(*p == 0x12345678)
{
*p = tmp;
return 0;
}
return 1;
另外还要实现NAND的读函数。看过东山哥视频的都知道怎么写。
就是有点要注意。其中的NFDATA、NFCMD等是8位的。定义的时候不要写顺手了写成:
#define NFCMD (*(volatile unsigned long*)0x4E000008)
#define NFADDR (*(volatile unsigned long*)0x4E00000C)
这样你会死得很惨,怎么调试都觉得程序没有错误,可是就是读不出来数据。所以还是把那个long改成char吧!
编译中遇到的错误:
1. error: unterminated #if
缺少一个#endif结尾,它们成对出现
2. arm-linux-ld: failed to merge target specific data of file/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/libgcc.a(_clz.o)
/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/libgcc.a(_dvmd_lnx.o):In function `__aeabi_ldiv0':
(.text+0x8):undefined reference to `raise'
这个问题由于我是用的是gcc 4.3.x,版本太高了。换成gcc3.4.5编译OK