前面已经移植好了uboot可以从sd卡启动了,也可以通过tftp下载代码到机器内存上了。有人会说这不是很简单吗,通过tftp下载uboot到内存的某一个位置,然后用nand write命令写入到nand flash中,这样拨码开关拨到nand flash启动的时候uboot就能跑起来了。一开始我也是这么想的,后来发现并没有想的这么简单。
1、尝试验证
因为之前编译出来的uboot是从sd卡启动的,所以我们还需要编译一个从nand flash启动的uboot。
进入到uboot目录,执行
#make tiny6410_config
#make ARCH=arm CROSS_COMPILE=arm-linux-
编译好后将uboot.bin放到tftp下载目录,然后开发板拨码开关拨到sd卡启动,这是会出现之前移植好的uboot菜单,选择q退回原始shell命令行,然后输入tftp c000000 u-boot.bin,将编译好的从nand flash启动的uboot下载到内存c0008000的位置。
#tftp c000000 u-boot.bin
然后执行下面命令,表示把内存地址为0xc000000位置处开始,大小为0x4000大小的数据,写入到nand flash的0地址处,uboot默认放在uboot的0地址开始的位置。
nand write c0000000 0 40000
烧写完后,将开关拨到nand flash启动,重新上电,发现串口没有输出。奇怪,不是已经把uboot下载到内存,然后写入到nand flash里面去了吗?怎么起不来了。
2、猜测分析
第一种猜测是编译生成的从nand flash启动的uboot.bin代码有问题,然后尝试使用dnw通过usb下载uboot到nand flash,烧写完后重新上电发现串口有打印,uboot也能正常跑起来,说明编译生成的uboot是没问题的。
第二种猜测就是tftp下载方式有问题,因为使用dnw下载的代码可以跑起来,使用tftp下载的代码却跑步起来。然后开始分析dnw下载uboot的代码。首先找到uboot源码里面的下载菜单的位置,在/uboot/common/main.c中有一个FriendlyARMMenu函数,这个就是uboot起来后打印出来的菜单。
void FriendlyARMMenu(void)
{
while(1) {
int c;
printf("##### FriendlyARM U-Boot(" RELEASE_MARK ", " BOOT_MEDIA ") for 6410 #####\n");
printf("[f] Format the nand flash\n");
printf("[v] Download u-boot.bin\n");
printf("[k] Download Linux/Android kernel\n");
printf("[y] Download root yaffs2 image\n");
printf("[u] Download root ubifs image\n");
printf("[a] Download Absolute User Application\n");
printf("[n] Download Nboot.nb0 for WinCE\n");
printf("[w] Download WinCE NK.nb0\n");
printf("[s] Set the boot parameter of Linux\n");
printf("[b] Boot Linux\n");
printf("[q] Quit to shell\n");
printf("NAND(%s): %u MiB, RAM: %u MiB\n", NandIsMlc2() ? "MLC2" : (NandIsMlc1()? "MLC1" : "SLC"), FriendlyARMGetNandSizeInMB(), PHYS_SDRAM_1_SIZE >> 20);
if (Lcd != 0) {
printf("LCD type, firmware version: %u %u\n", Lcd, FirmwareVer);
}
printf("Enter your Selection:");
c = getc();
printf("%c\n", c >= ' ' && c <= 127 ? c : ' ');
switch(c) {
unsigned max_size, pos, len;
case 'F': case 'f':
FriendlyARMFormatFrom(0, 1);
break;
case 'V': case 'v':
pos = 0;
max_size = 256 K;
len = 256 K;
FriendlyARMGetDataFromUsbAndWriteNand(max_size, pos, len, "U-Boot.bin");
SetLinuxCommandLine(NULL);
break;
case 'K': case 'k':
if (NandIsMlc()) {
pos = 4 M;
max_size = 5 M - 128 K;
len = 8 M;
NAND_EraseBlock(1 M / NandBlockSizeInByte);
} else {
pos = 4 * 128 K;
max_size = 5 M - 128 K;
len = 5 M;
}
FriendlyARMGetDataFromUsbAndWriteNand(max_size, pos, len, "Linux/Android Kernel");
break;
case 'Y': case 'y':
if (NandIsMlc()) {
printf("Yaffs is not support yet for MLC2 NAND\n");
} else {
FriendlyARMGetDataFromUsbAndWriteNand(126 M, 5 M +