本次记录的移植是使该u-boot支持eMMC,开发板为real210最新版的开发板,标配eMMC 8GB flash,之前的移植都是在之前的210硬件上进行的核心板版本为v2,flash为nand 512MB。本次修改让其支持eMMC,并且添加菜单操作。
首先考虑到emmc和SD卡操作协议兼容,那么之前做的u-boot是不是可以启动呢,说做就做,使用配带的u-boot把我自己的u-boot烧写进开发板,嘿嘿,可以跑起来,我下载的u-boot已经把环境变量的保存修改为了SD卡。结果环境变量也可以正常保存。开发板emmc接的是SD0通道。
说的是支持,其实基本什么也没做,呵呵。
既然可以用,那么就相对容易多了。下面就是怎么使用自己制作的u-boot下载自己的u-boot,而且可以正常跑起来。想法是正确的,现实是残酷的,~~~~(>_<)~~~~ 。
好不容易成功的把u-boot能够烧写进emmc了,可是无法启动,并且提示check num error。虽然没有启动,但是提示的错误就很明显了,校验和校验失败。那么怎么会校验失败呢,原因就是在写入的时候没有进行校验和计算。
所以就改进加入了校验和的计算代码,再次写入,嘿嘿,OK了,可以正常跑起来了。
下面说说修改方法:
使用命令tftp 3ff00000 /u-boot/u-boot.bin把u-boot加载进内存(这里建立在有u-boot能够启动的情况下,这里的u-boot是使用板子配带的u-boot烧写的)
烧写BL1,命令是mmc write 3ff00000 1 10,注意这里的数字是16进制,那么这条命令的含义是什么呢,烧写u-boot的前16个blocks的数据,一个block大小为2k,实际上BL1只使用了8K,所以只要不少于8K的代码,都是可以的,当然了不能大于48了,因为第49 block开始存放的是BL2,也即完整的u-boot。
烧写BL2,命令是mmc write 3ff00000 31 400,起始为第49 block(16进制为31),大小为1024 blocks(16进制为400)。
完成后重启,悲剧了,error。原因是校验和校验失败,因此需要在烧写时对前8K进行校验和计算再写入才行。
那么问题就来了,命令行无法进行校验和计算啊,所以需要用代码实现了。
那好,就编写代码吧,另外我为了调试方便,顺便增加了调试用的菜单选项。
主要函数如下
void tftp_burn(char *cmd) { if (!strcmp(cmd, "u-boot")) { char *buf; ulong checksum = 0; int i = 0; ExecuteCmd("tftp 3ff00000 /u-boot/u-boot.bin");/*先拷贝u-boot.bin到内存3ff00000处*/ buf = 0x3ff00000 + 16;/*把u-boot首地址偏移16字节的内存地址赋值给buf,此时u-boot的首地址是3ff00000*/ for(i = 16;i < 8192;i++)/*循环进行u-boot的前8K代码校验和校验,i赋值为16是因为u-boot的前16字节可不必要校验和校验*/ { checksum += *buf; buf++; } *((volatile u32 *)(0x3ff00000 + 0x8)) = checksum;/*把计算出的校验和写入3ff00008地址处等待写入EMMC*/ printf("\nBL1 checksum is:%08x\n\n", checksum); /*printf("erase start block 1 (count 1073 blocks)..."); ExecuteCmd("mmc erase 1 431");*/ printf("writing BL1 start block 1 (count 16 blocks)..."); ExecuteCmd("mmc write 3ff00000 1 10");/*烧写BL1到eMMC的第一个block,长度为16 block(注意此时是10,但是为16进制)*/ printf("\n"); printf("writing u-boot.bin start block 49 (count 1024 blocks)..."); ExecuteCmd("mmc write 3ff00000 31 400");/*烧写u-boot到eMMC的第49个block,长度为1024 block(注意此时是400,但是为16进制)*/ } else if(!strcmp(cmd, "debug")) { ExecuteCmd("tftp 3ff00000 /u-boot/u-boot.bin"); printf("Run u-boot in 3ff00000\n"); ExecuteCmd("go 3ff00000"); } } void realarm_tftp() { unsigned char select; while(1) { printf("\n#**** Select the fuction ****#\n"); /*由于system过大,所以tftp下不能下载文件系统*/ printf("[1] Tftp burn u-boot\n"); printf("[2] Tftp burn kernel\n"); printf("[3] Tftp debug u-boot\n"); printf("[4] Exit\n"); printf("Enter your Selection:"); select = getc(); printf("%c\n", select >= ' ' && select <= 127 ? select : ' '); switch(select) { case '1': tftp_burn("u-boot"); break; case '2': tftp_burn("kernel"); break; case '3':/*此选项功能需要屏蔽u-boot配置头文件中的#define CONFIG_SKIP_LOWLEVEL_INIT,且CONFIG_SYS_TEXT_BASE需要修 改为3ff00000*/ tftp_burn("debug");/*u-boot 调试命令,tftp下载u-boot然后使用go命令运行之*/ break; default: break; } } }
static void ExecuteCmd(char *cmd) { parse_string_outer(cmd, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); }
ulong checksum = 0; int i = 0; ExecuteCmd("tftp 3ff00000 /u-boot/u-boot.bin");/*先拷贝u-boot.bin到内存3ff00000处*/ buf = 0x3ff00000 + 16;/*把u-boot首地址偏移16字节的内存地址赋值给buf,此时u-boot的首地址是3ff00000*/ for(i = 16;i < 8192;i++)/*循环进行u-boot的前8K代码校验和校验,i赋值为16是因为u-boot的前16字节可不必要校验和校验*/ { checksum += *buf; buf++; } *((volatile u32 *)(0x3ff00000 + 0x8)) = checksum;/*把计算出的校验和写入3ff00008地址处等待写入EMMC*/ printf("\nBL1 checksum is:%08x\n\n", checksum);
完成后会有如下的界面
选项3的功能是tftp下载了u-boot之后直接跳转到指定内存地址运行,不烧写到emmc中,这个是为了防止由于修改错误导致emmc启动失败而带来的麻烦,是调试更加的有效率,O(∩_∩)O~!
本次记录到此。