分类: 嵌入式
2009-12-20 11:53:07
环境:
u-boot-1.1.4
FC3
NorFlash SST39VF1601
toolchains Arm-linux-uclibc-
u-boot-1.1.4版本中带有移植好的SMDK2410源代码,使用SMDK2410的配置生成的u-boot.bin烧写到开发板中,已经可以运行和驱动CS8900网卡芯片,但是Flash驱动不同,故环境变量的保存无法实现。本文档主要论述Flash驱动的修改和环境变量保存的实现。
解压u-boot-1.1.4源码包
make smdk2410_config
修改主Makefile
在export CROSS_COMPILE上一行加上CROSS_COMPILE = arm-linux-uclibc-
make
此时会出现一个错误:cc1: error: invalid option `abi=apcs-gnu'
修改/cpu/arm920t/下的config.mk:
将
PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu)
改成:
PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,$(call cc-option,-mabi=apcs-gnu),)
再次make
这次可以完全编译成功,主目录下生成u-boot.bin,使用Flash Programmer主目录下带的BinToS19.exe将u-boot.bin转化为u-boot.s19格式
使用Flash Programmer烧写到FS2410可以看到下列启动画面
从启动画面可以看到,Flash的大小显示的是错误的,并且反复开机都有bad crc出现。测试savenev命令显示可以保存环境变量,但是开机后环境变量还是默认值。
上述问题是由于开发板所使用的Flash与的不同而造成,故下面我们来改写它的flash.c文件。
找一找board中有没有使用SST160 Flash的板子
grep –R ‘SST160A’ ./
看到一大堆的板子,我们选用名字为dave中的flash.c,拷贝这个flash.c到smdk2410目录,
cp board/dave/common/flash.c board/smdk2410/
使用source insight建立一个工程来分析一下这个文件(可以把源码中不相关的内容删掉些)
首先看一下SST39VF1601的datasheet
这个flash是16Mbit的也就是2MB大小
sector 2Kword也就是4Kbyte
block 32Kword也就是64Kbyte
这里要弄清楚这两个参数的目的主要是flash的擦除是要按照sector或block的方式来进行的,每种有不同的指令。
这里我们选用block的方式,故2M的Flash有32个block。这些参数都是要定义到头文件里面的,故我们首先来修改SMDK2410板子的头文件include/configs/smdk2410.h。
在第157行定义的是#define CONFIG_AMD_LV4001
我们把它注掉定义上自己的flash
#define CONFIG_SST_VF160 1
#ifdef CONFIG_SST_VF160
#define PHYS_FLASH_SIZE 0x00200000 /* 2MB */
#define CFG_MAX_FLASH_SECT (32)/* max number of blocks on one chip */
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x030000) /* addr of environment */
#define FLASH_BANK_SIZE 0x01000000
#define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_SIZE 0x10000 /*64K Total Size of Environment Sector */
#define CFG_FLASH_ADDR0 0x5555
#define CFG_FLASH_ADDR1 0x2aaa
#define CFG_FLASH_WORD_SIZE unsigned short /* flash word size */
#define CFG_FLASH_READ0 0x0000 /* A0 = 0 */
#define CFG_FLASH_READ1 0x0001 /* A0 = 1 */
#define CFG_FLASH_READ2 0x0002
#define CFG_MONITOR_LEN (256 * 1024) /* Reserve 256 kB for Monitor */
#define CFG_MONITOR_BASE TEXT_BASE
#endif
这里有几个参数先说明一下,
PHYS_FLASH_SIZE
这个参数定义Flash的容量,因为在flash初始化的时候,程序会去读flash的Manufacturer’s ID和Device ID,然后会根据这个ID来匹配Flash的容量,SST39VF601的参数如下:
Manufacturer’s ID BFH
Device ID 234BH
CFG_MAX_FLASH_SECT
CFG_ENV_ADDR
CFG_ENV_SIZE
第一个参数确定最大的block的数量(我们是按照block来的),值为32(32*64KB = 2M)
第二个参数区定的u-boot环境变量的起始地址,由于Flash的擦除是按块或扇区的,所以需要对其,我们使用64KB块方式,故我们把环境变量的首地址暂时设在0x30000(192KB)处。
第三个参数代表环境变量的大小,我们设置为0x10000,正好是一个block的大小。
CFG_FLASH_ADDR0
CFG_FLASH_ADDR1
CFG_FLASH_WORD_SIZE
前面两个参数是flash软件编程命令字中规定的地址,可以看datasheet。
第三个参数是Flash数据线工作的模式,我们的Flash工作于16bit模式,故这个定义为unsigned char。
CFG_FLASH_READ0
CFG_FLASH_READ1
CFG_FLASH_READ2
这些是用于查询Flash操作状态的,在datasheet中有详细地说明。
CFG_MONITOR_LEN
这个宏和Flash的写保护设置有关。
定义好了这些宏后我们开始来逐个分析flash.c中的函数啦,按照u-boot的启动流程,在board.c中首先要进行flash_init (),但是这个Flash.c中并没有这个函数,我们在dave目录下的b2目录中的flash.c中把这个函数拷贝到我们的flash.c中。为了清除我们去掉它开头和结尾的ifdef和endif
首先我们分析一下里面的flash_get_size函数。根据前述Flash的特点把
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;
改为
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA;
addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x0055;
addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x0090;
这个函数中不识别device ID为234BH的SST39VF1601的片子,故给它添加上如下case代码在include/flash.h中添加宏#define FLASH_SST1601 0x004B
case (CFG_FLASH_WORD_SIZE)SST_ID_xF1601:
info->flash_id += FLASH_SST1601;
info->sector_count = 32;
info->size = 0x00200000;
break; /* => 2 MB */
注释/* set up sector start address table */下面的代码是建立flash的block的分区地址表,我们的block的大小是64KB(0x10000)从下面的代码看出,它的和我们的相符,故不用修改。
info->start[i] = base + (i * 0x00010000);
其次在检查一下flash_get_offsets函数,发现里面的偏移也是64KB,故不用修改。
至此flash_init ()函数修改完毕。
然后我们来检查一下flash的写函数和擦除函数
int flash_erase (flash_info_t *info, int s_first, int s_last)
根据我们Flash的特点,将
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;
addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */
改为:
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA;
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x0055;
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x0080;
addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA;
addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x0055;
addr2[0] = (CFG_FLASH_WORD_SIZE)0x0050; /* block erase */
下面还有扇区擦出的命令字也按这种方式改。
将
while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080)
addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0;/* reset bank */
改为
while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x0080) != (CFG_FLASH_WORD_SIZE)0x0080)
addr[0] = (CFG_FLASH_WORD_SIZE)0x00F0;/* reset bank */
按照上面的方法修改static int write_word (flash_info_t *info, ulong dest, ulong data)种对应的项。
最后修改int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)函数
把里面的#ifdef CONFIG_B2换成CONFIG_SMDK2410
在flash_print_info (flash_info_t *info)
加入:
case FLASH_SST1601: printf ("SST39LF/VF1601 (16 Mbit, uniform. sector size)\n";
break;
至此u-boot-1.1.4 for FS2410的主体移植工作已经完成。
烧入一下,看下我们的成果
发现开机后会显示bad CRC。其实这是正常的,我们可以分析一下u-boot中的源码,首次运行的话u-boot中的环境变量中的crc值时空的,故肯定会显示bad crc,
在env_relocate (void)函数中会检查gd->env_valid的值,而这个值是在env_init中更新的,首次开机检查到的gd->env_valid值为0,故会显示bad crc,随后会执行env_crc_update ()函数将正确的crc记录到环境变量中,此时你要输入一下saveenv命令,把这个crc固化到flash中。故二次开机后就可以了。
如果遇到开机后环境变量没有被跟新的情况,可以按一下方法解决
这是由于ENV_IS_EMBEDDED定义造成的,而此变量定义是在envcrc.c中:
# if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \
((CFG_ENV_ADDR + CFG_ENV_SIZE) <= (CFG_MONITOR_BASE + CFG_MONITOR_LEN))
# define ENV_IS_EMBEDDED 1
# endif
前述定义的#define CFG_MONITOR_BASE TEXT_BASE就是为了解决这个问题的,这样可以使ENV_IS_EMBEDDED 1这个宏不被定义。
使U-boot更加易于使用
u-boot提供了强大的命令行参数,可以发挥出巨大的作用,下面我们举个例子来说明。
在environment.c中定义有
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
可以在smdk2410.h中可以加上下面的宏,定义一些额外命令行参数。