Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1321964
  • 博文数量: 482
  • 博客积分: 13297
  • 博客等级: 上将
  • 技术积分: 2890
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-12 16:25
文章分类

全部博文(482)

文章存档

2012年(9)

2011年(407)

2010年(66)

分类: 嵌入式

2011-02-08 17:21:11

s3c2440对NOR Flash的支持

本节主要讲述支持NOR Flash,本人的开发板上的NOR Flash芯片型号是:SST39VF1601

上面所编译出来的U-BOOB.bin文件还无法通过U-BOOT的命令来烧写NOR FLASH,在配置文件include/configs/fs2410.h里默认的信号是AM29LV400,而我的是SST39VF1601。所以要对其进行修改,修改如下(include/configs/smdk2440.h):
添加:
#define CONFIG_SST_39VF1601   1
#define CFG_MAX_FLASH_BANKS 1
#define PHYS_FLASH_SIZE       0x200000  
#define CFG_MAX_FLASH_SECT    (512)      
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x40000)  
并将关于AM29LV400和AM29LV800的信息全部注释掉,当然也可不必注释掉,只要保证选择的是SST就可以。


另外,NOR FLASH的操作函数在board/smdk2440/flash.c中实现。它支持AM29LV400和AM29LV800.为了快速了解 NORFLASH的操作并达到目的,本人直接修改这个文件。修改以上步骤以后,接下来我们修改board/smdk2440/flash.c:
将:
#define MAIN_SECT_SIZE 0x10000
修改为:
#define MAIN_SECT_SIZE 0x1000 (按sector操作)

将:
#define MEM_FLASH_ADDR1     (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555 << 1)))
#define MEM_FLASH_ADDR2     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AA << 1)))
修改为:
#define MEM_FLASH_ADDR1     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000005555 << 1)))
#define MEM_FLASH_ADDR2     (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AAA << 1)))
这个参数参看SST39VF1601的手册可以得到。

在flash_init函数里仿照:
if defined(CONFIG_AMD_LV400)
            (AMD_MANUFACT & FLASH_VENDMASK) |
            (AMD_ID_LV400B & FLASH_TYPEMASK);
添加对SST39VF1601厂商ID和DEVICE ID的设置:
添加:
#if defined (CONFIG_SST_39VF1601)  
            (SST_MANUFACT & FLASH_VENDMASK)
            (SST_ID_xF1601 & FLASH_TYPEMASK);

由于SST39VF1601每个SECTOR的大小都是一样的。所以修改:
将:
for (j = 0; j < flash_info[i].sector_count; j++) {
            if (j <= 3) {
               
                if (j == 0) {
                    flash_info[i].start[j] =
                        flashbase + 0;
                }
........
........
修改为:
for (j = 0; j < flash_info[i].sector_count; j++) {
     flash_info[i].start[j] =flashbase + j*MAIN_SECT_SIZE;
                }

当我们键入flinfo命令的时候,将我们的nor flash的信息答应,这里我们在flash_print_info添加相应的支持:
在:
case (AMD_MANUFACT & FLASH_VENDMASK):
        printf ("AMD: ");
        break;
后添加:
case (SST_MANUFACT & FLASH_VENDMASK):
        printf ("SST: ");
        break;

在:
case (AMD_ID_LV800B & FLASH_TYPEMASK):
        printf ("1x Amd29LV800BB (8Mbit)\n");
        break;
之后添加:
case (SST_ID_xF1601& FLASH_TYPEMASK):
        printf ("1x SST39VF1610 (16Mbit)\n");
        break;
接下来修改flash_erase函数,这里我们用SECTOR进行擦出操作。具体修改如下:
将:
if ((info->flash_id & FLASH_VENDMASK) !=
        (AMD_MANUFACT & FLASH_VENDMASK)) {
        return ERR_UNKNOWN_FLASH_VENDOR;
修改为:if ((info->flash_id & FLASH_VENDMASK) !=
        (SST_MANUFACT & FLASH_VENDMASK)) {
        return ERR_UNKNOWN_FLASH_VENDOR;
将以前的块的擦出操作的内容修改为:
首先看一下SST39VF1601的datasheet,看第3页可以知道:
U-BOOT移植(五)Data# Polling (DQ7)                                           
When the SST39LF/VF160 are in the internal Program
operation, any attempt to read DQ7 will produce the com-
plement of the true data. Once the Program operation is
completed, DQ7 will produce true data. Note that even
though DQ7 may have valid data immediately following the
completion of an internal Write operation, the remaining
data outputs may still be invalid: valid data on the entire
data bus will appear in subsequent successive Read
cycles after an interval of 1 μs. During internal Erase opera-
tion, any attempt to read DQ7 will produce a ‘0’. Once the
internal Erase operation is completed, DQ7 will produce a
‘1’. The Data# Polling is valid after the rising edge of fourth
WE# (or CE#) pulse for Program operation. For Sector-,
Block- or Chip-Erase, the Data# Polling is valid after the ris-
ing edge of sixth WE# (or CE#) pulse. See Figure 5 for
Data# Polling timing diagram and Figure 16 for a flowchart.

TOggle bit (DQ6)
During the internal Program or Erase operation, any con-
secutive attempts to read DQ6 will produce alternating 1s
and 0s, i.e., toggling between 1 and 0. When the internal
Program or Erase operation is completed, the DQ6 bit will
stop toggling. The Toggle Bit is valid after the rising edge of
fourth WE# (or CE#) pulse for Program operation. For Sec-
tor-, Block- or Chip-Erase, the Toggle Bit is valid after the
rising edge of sixth WE# (or CE#) pulse. See Figure 6 for
Toggle Bit timing diagram and Figure 16 for a flowchart.
和一个时序操作图参看第6页可以得到。
通过这些信息,在我们的驱动里进行相应的修改,具体如下:                                                             

for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
        printf ("Erasing sector %2d ... ", sect);

       
        reset_timer_masked ();

        if (info->protect[sect] == 0) {   
            vu_short *addr = (vu_short *) (info->start[sect]);

            MEM_FLASH_ADDR1 = CMD_UNLOCK1;
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;
            MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;

            MEM_FLASH_ADDR1 = CMD_UNLOCK1;
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;
            *addr = CMD_ERASE_CONFIRM;
           
            while (1)
            {

                if ((*addr & 0x40) != (*addr & 0x40))
                    continue;
                if (*addr & 0x80)
                {
                    rc = ERR_OK;

                    break;
                }
            }
            printf ("ok.\n");

然后修改对FLASH的写函数,参考手册在上面以阐述:
    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
    MEM_FLASH_ADDR1 = CMD_PROGRAM;
    *addr = data;

   
    reset_timer_masked ();
   
    while (1)
    {
        //unsigned short i = *(volatile unsigned short *) addr & 0x40;
        if ((*addr & 0x40) != (*addr & 0x40))  
            continue;
        if ((*addr & 0x80) == (data & 0x80))
        {
            rc = ERR_OK;
            break;      
        }
    }
保存所作的修改,重新进行编译,

阅读(862) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~