二、修改相关源文件
主要有三个方面的文件要修改:
1. 我们用的flash是两片在一起,组成了32位寻址。而原来的代码是按16位寻址写的。所以关于flash一系列操作的代码要修改。这部分修改要保证能正确操作flash
2. 关于i2c设备eeprom的相关配置,主是要是设备地址以及设备内存地址的宽度等。同样,这里修改后要保证能正确读写eeprom
3. 关于网卡的设置,网络用了以后我们就可以用过网络从主机上下载相关代码。修改完后要能使用tftp工具进行下载。
1) 、flash
由于我的开发板是两块e28F128J3A flash组成32位寻址,所以与地址操作相关的数据都由原来的16位改为32位。
首先修改flash 相关的命令,在flash_e28_cmi.c 中
#define FLASH_ID_MASK 0xFFFF
#define FLASH_BLOCK_SIZE 0x00010000
#define FLASH_CMD_READ_ID 0x0090
#define FLASH_CMD_RESET 0x00ff
#define FLASH_CMD_BLOCK_ERASE 0x0020
#define FLASH_CMD_ERASE_CONFIRM 0x00D0
#define FLASH_CMD_CLEAR_STATUS 0x0050
#define FLASH_CMD_SUSPEND_ERASE 0x00B0
#define FLASH_CMD_WRITE 0x0040
#define FLASH_CMD_PROTECT 0x0060
#define FLASH_CMD_PROTECT_SET 0x0001
#define FLASH_CMD_PROTECT_CLEAR 0x00D0
#define FLASH_STATUS_DONE 0x0080
这些相关的命令状态值等都是16位的,只能操作一片flash。所以要将其全部改为32位
#define FLASH_ID_MASK 0xFFFFFFFF
#define FLASH_BLOCK_SIZE 0x00040000
#define FLASH_CMD_READ_ID 0x00900090
#define FLASH_CMD_RESET 0x00ff00ff
#define FLASH_CMD_BLOCK_ERASE 0x00200020
#define FLASH_CMD_ERASE_CONFIRM 0x00D000D0
#define FLASH_CMD_CLEAR_STATUS 0x00500050
#define FLASH_CMD_SUSPEND_ERASE 0x00B000B0
#define FLASH_CMD_WRITE 0x00400040
#define FLASH_CMD_PROTECT 0x00600060
#define FLASH_CMD_PROTECT_SET 0x00010001
#define FLASH_CMD_PROTECT_CLEAR 0x00D000D0
#define FLASH_STATUS_DONE 0x00800080
在flash_init() 函数中
size_b0 = flash_get_size((vu_short *)FLASH_BASE0_PRELIM, &flash_info[0]);
这里是读取flash的大小,其传递的地址是vu_short型,只能读取一片flash的信息。所以做如下修改
size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);
CFG_FLASH_BASE在s3c2410.h中定义。是flash的基地址
还有
flash_get_offsets (FLASH_BASE0_PRELIM, &flash_info[0]);
改为
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
下面还要到flash_get_size()函数中进行修改
static ulong flash_get_size (vu_short *addr, flash_info_t *info)
改为
static ulong flash_get_size (vu_long *addr, flash_info_t *info)
vu_short value;
改为
vu_long value;
flash_get_size函数修改结束。
擦除flash 函数 flash_erase()
擦除比较简单,直接往每个sector的起始地址写擦除命令即可
vu_short *addr = (vu_short *)(info->start[sect]);
改为
vu_long *addr = (vu_long *)(info->start[sect]);
这里还要注意一个问题,下面被注释掉的两行是用来判断擦除单个sector是否超时的,它提供了一个擦除起始时间。但它确在下面的擦除循环之前,这样就是擦除所有sector的起始时间,而不是擦除单个sector的起始时间
/*the next two lines will lead to timeing out in this location.
modified by BoySKung 08/11/14 */
//start = get_timer (0);
//last = start;
/* Start erase on unprotected sectors */
for (sect = s_first; sect<=s_last; sect++) { //这里是擦除循环
if (info->protect[sect] == 0) { /* not protected */
//vu_short *addr = (vu_short *)(info->start[sect]);
vu_long *addr = (vu_long *)(info->start[sect]);/*modified by BoySKung 08/11/05 */
unsigned long status;
应该把这个起始时间放到循环里面
start = get_timer (0);/*modified by BoySKung 08/11/14*/
last = start;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
#ifdef DEBUG
printf("Erase sector %d at start addr 0x%08X", sect, (unsigned int)info->start[sect]);
#endif
*addr = FLASH_CMD_CLEAR_STATUS;
*addr = FLASH_CMD_BLOCK_ERASE;
*addr = FLASH_CMD_ERASE_CONFIRM;
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* wait at least 80us - let's wait 1 ms */
udelay (1000);
while (((status = *addr) & FLASH_STATUS_DONE) != FLASH_STATUS_DONE) {
在这里通过上面的起始时间获得当前时间,判断是否超时
if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
printf("Flash erase timeout at address %lx/n", info->start[sect]);
*addr = FLASH_CMD_SUSPEND_ERASE;
*addr = FLASH_CMD_RESET;
return 1;
}
/* show that we're waiting */
if ((now - last) > 1000) { /* every second */
putc ('.');
last = now;
}
}
*addr = FLASH_CMD_RESET;
}
写数据到flash 中
这里涉及到两个函数:
write_buff(); //写数据前进行一些调整
write_word(); //真正的往flash中写数据
这里要修改的地方比较多,主要是数据长度和地址长度方面的凡是我修改的地方都有/*modified by BoySKung 08/11/05*/ 或 /*added by BoySKung 08/11/05*/这样的注释
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
{
ulong cp, wp;
//ushort data;
ulong data;/*modified by BoySKung 08/11/05*/
int i, rc;
int l; /*added by BoySKung 08/11/05*/
if (info->flash_id == FLASH_UNKNOWN) {
return 4;
}
//wp = (addr & ~1); /* get lower word aligned address */
wp = (addr & ~3); /*modified by BoySKung 08/11/05*/
//现我们是32位操作,所以地址应4字节对齐
/*
* handle unaligned start byte
*/
/*
if (addr - wp) {
data = 0;
data = (data << 8) | *src++;
--cnt;
if ((rc = write_short(info, wp, data)) != 0) {
return (rc);
}
wp += 2;
}
*/ /*modified by BoySKung 08/11/05*/
//我把上面那段对未对齐头部处理的代码注释掉,重新写了一段处理代码
//这里要注意,我的cpu初始化后是小端模式
/*
* handle unaligned start byte, our cpu is little-endian
*/
if (l = (addr - wp) > 0)
{
data = 0;
//把从对齐地址wp到目的地址addr的内容保存到data的低字节中,
//这样可避免改变从wp到addr的内容,
//因为往flash中写时,是从对齐地址wp一次写四个字节,
for (i=0, cp=wp; i<l; i++, cp++)
{
data |= (*(uchar *)cp << 8*i);
}
//将内存中开始的数据按字节保存到data中,
for (; i<4 && cnt>0; i++)
{
data |= (*src++ << 8*i);
--cnt;
++cp;
}
//如果要写的总字节数cnt 小于从地址addr到第二个对齐地址wp+4的字节数,
//那么从addr+cnt到wp+4的内容也要保存到data中
for (; cnt=0 && i<4; i++, cp++)
{
data |= (*(uchar *)cp << 8*i);
}
//处理完后开始往flash写,一次写四个字节
if ((rc = write_word(info, wp, data)) != 0)
{
return (rc);
}
wp += 4; //处理完后地址增加四个字节
}
/*
* handle word aligned part
*/
//这里是处理四字节对齐的部分。比较简单
while (cnt >= 4) {
data = 0;
/*
for (i=0; i<2; ++i) {
data = (data << 8) | *src++;
}
*/
data = *(vu_long*)src; /*modified by BoySKung 08/11/05*/
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
//wp += 2;
//cnt -= 2;
src += 4;
wp += 4; /*modified by BoySKung 08/11/05*/
cnt -= 4;
}
if (cnt == 0) {
return (0);
}
/*
* handle unaligned tail bytes
*/
data = 0;
/*
for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
data = (data << 8) | *src++;
--cnt;
}
for (; i<2; ++i, ++cp) {
data = (data << 8) | (*(uchar *)cp);
}*/
//尾部不够四字节的处理,当最后一次写时,剩的字节数n<4, 要将flash中addr+cnt
//后4-n个字节的数据保存到和那剩下的n个字节内容保存到data中,够四字节一次
//写入
for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { /*modified by BoySKung 08/11/05*/
data |= (*src++ << 8*i);
--cnt;
}
for (; i<4; ++i, ++cp) {
data |= (*(uchar *)cp);
}
return (write_word(info, wp, data));
}
对write_word里的修改也主要是对数据或地址长度的修改
/*
* Write 16 bit (short) to flash
*/
/*
* Write 32 bit (short) to flash
*/
//static int write_short (flash_info_t *info, ulong dest, ushort data)
static int write_word (flash_info_t *info, ulong dest, ulong data)/*modified by BoySKung 08/11/05*/
{
//vu_short *addr = (vu_short*)(info->start[0]);
vu_long *addr = (vu_long*)(info->start[0]); /*modified by BoySKung 08/11/05*/
ulong start;
int flag;
/* Check if Flash is (sufficiently) erased */
//if ((*((vu_short *)dest) & data) != data) {
if ((*((vu_long *)dest) & data) != data) { /*modified by BoySKung 08/11/05*/
return (2);
}
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
if (!(info->flash_id & FLASH_VENDMASK)) {
return 4;
}
*addr = FLASH_CMD_ERASE_CONFIRM;
*addr = FLASH_CMD_WRITE;
//*((vu_short *)dest) = data;
*((vu_long *)dest) = data; /*modified by BoySKung 08/11/05*/
/* re-enable interrupts if necessary */
if (flag) {
enable_interrupts();
}
/* data polling for D7 */
start = get_timer (0);
这里要做下说明 ,不能用addr[0] & FLASH_STATUS_DONE的值是否为0来判断其状态是否是完成。因为我们用的是两片flash, FLASH_STATUS_DONE 的值是00800080。这样要是有一片的状态是完成而另一片的状态是没有完成,那么上面表达式结果仍然不为0,也即其状态是完成。这样就会出判断错误
/* wait for error or finish */
//while(!(addr[0] & FLASH_STATUS_DONE)){ /*modified by BoySKung*/
while( (addr[0] & FLASH_STATUS_DONE) != FLASH_STATUS_DONE){
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
addr[0] = FLASH_CMD_RESET;
return (1);
}
}
*addr = FLASH_CMD_RESET;
return (0);
}
对sector 的保护 flash_real_protect()
将
vu_short *addr = (vu_short*)(info->start[sector]);
改为
vu_long *addr = (vu_long*)(info->start[sector]); /*modified by BoySKung 08/11/05*/
到这里整个关于flash操作的代码就移植完毕,可以等下载下目标板后进行验证
在文件的开头有对函数的声明,也要把它们改过来
2 ) 网卡
我们板子上用的是dm9000网卡,找到dirver/dm9000x.c 其初始化程序是eth_init();rcn lib_arm/board.c中的
/*dm9000*/ //added by BoySKung 08/11/06
#ifdef CONFIG_DRIVER_DM9000
eth_init(gd->bd)
#endif
3 )串口
因为我们现在用的是UART2作为打印输出口,所以对初始化序列中的函数board_init()中的代码作如下修改:
gpio->GPHCON = 0x002AFAAA;
改为
gpio->GPHCON = 0x002AAAAA; /*modified by BoySKung 08/11/11*/
这是因为其管脚复用,原来的并未把GPHCON[15-12]设置为1010(RXD2、TXD2).