求助:Mega128 外部扩展SRAM,Nand Flash 问题
现在一个项目,需要使用外部SRAM,外部Flash,外部SRAM挂总线上,使用没有问题,请问,怎样同时把 Flash 也挂在总线上?1. SRAM 使用 32KB
2. Flash使用 K9F1208。大家帮我想想办法,明天再自已看看总线的读写时序,我也继续实验。 flash好像不能挂到总线上吧?如果是nor flash好像才行。 nor flash可以的吧, 没办法了,从Flash读数据到外部SRAM时,从时序上看有问题,如果不使用外部SRAM,Flash是可以挂总线上的。 将SRAM和K9F1208统一编址,k9f1208占用3个地址口,不要去模拟它的时序...
可以任意使用....... 是么?
有没有实际使用过? 1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_225398.JPG #ifndef __K9F1208U0M_H
#define __K9F1208U0M_H
#define FLASH_ADDR_DATA (*(volatile unsigned char *)0x8000)
#define FLASH_ADDR_COMMAND (*(volatile unsigned char *)0x8001)
#define FLASH_ADDR_ADDRESS (*(volatile unsigned char *)0x8002)
unsigned long NF_ReadID(void);
unsigned char NF_EraseBlock(unsigned long Block);
void NF_ReadPage(unsigned longBlock, unsigned charPage, unsigned char *Buff);
unsigned char NF_WritePage(unsigned longBlock, unsigned charPage, unsigned char *Buff);
#endif //*
//*********************************************************************************************************
//* Function : static void NF_Reset(void)
//* Describe : NF Reset
//*--------------------------------------------------------------------------------------------------------
//* Author :
//* Date :
//*--------------------------------------------------------------------------------------------------------
//* Mender :
//* Date :
//* Describe :
//*********************************************************************************************************
//*
void NF_Reset(void)
{
unsigned charStatus;
FLASH_ADDR_COMMAND = 0xFF;//Reset Command
//Read Staus Register
while(1)
{//Device Operation --- BIT6
FLASH_ADDR_COMMAND = 0x70;
Status = FLASH_ADDR_DATA;
if(Status & (1<<6))
{//Busy : "0" Ready : "1"
break;
}
}
}
//*
//*********************************************************************************************************
//* Function : void NF_ReadID(void)
//* Describe : 读取NAND Flash ID
//*--------------------------------------------------------------------------------------------------------
//* Author :
//* Date :
//*--------------------------------------------------------------------------------------------------------
//* Mender :
//* Date :
//* Describe :
//*********************************************************************************************************
//*
unsigned long NF_ReadID(void)
{
unsigned char Buff;
FLASH_ADDR_COMMAND = 0x90;
FLASH_ADDR_ADDRESS = 0x00;
__no_operation();
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
return(*((unsigned long *)Buff));
}
//*
//*********************************************************************************************************
//* Function : unsigned char NF_EraseBlock(unsigned long Block)
//* Describe : 擦除指定块
//*--------------------------------------------------------------------------------------------------------
//* Author :
//* Date :
//*--------------------------------------------------------------------------------------------------------
//* Mender :
//* Date :
//* Describe :
//*********************************************************************************************************
//*
unsigned char NF_EraseBlock(unsigned long Block)
{
unsigned char cpu_sr;
unsigned charStatus;
unsigned longBlockPage;
BlockPage = Block<<5;
//读写NAND的时候,总线不可以变化,中断读写特殊寄存器可能引起总线跳变
cpu_sr = OS_CPU_SR_Save();//关中断
FLASH_ADDR_COMMAND = 0x60;
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>8 & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>16 & 0xFF);
FLASH_ADDR_COMMAND = 0xD0;
//Read Staus Register
while(1)
{//Device Operation --- BIT6
FLASH_ADDR_COMMAND = 0x70;
Status = FLASH_ADDR_DATA;
if(Status & (1<<6))
{//Busy : "0" Ready : "1"
break;
}
}
//Read Staus Register
//Total Pass/Fail -- BIT0
FLASH_ADDR_COMMAND = 0x70;
Status = FLASH_ADDR_DATA;
if(Status & (1<<0))
{//Fail : "1"
OS_CPU_SR_Restore(cpu_sr);//开中断
return 0;
}
else
{//Pass : "0"
OS_CPU_SR_Restore(cpu_sr);//开中断
return 1;
}
}
//*
//*********************************************************************************************************
//* Function : void NF_ReadPage()
//* Describe : 读取NAND Flash 指定块指定页
//*--------------------------------------------------------------------------------------------------------
//* Author :
//* Date :
//*--------------------------------------------------------------------------------------------------------
//* Mender :
//* Date :
//* Describe :
//*********************************************************************************************************
//*
void NF_ReadPage(unsigned longBlock,
unsigned charPage,
unsigned char *Buff)
{
unsigned char cpu_sr;
unsigned short j;
unsigned longBlockPage;
//每块32页,每页512字节
Page &= 0x1F; //
//计算实际地址
BlockPage = (Block<<5) + Page; //
//读写NAND的时候,总线不可以变化,中断读写特殊寄存器可能引起总线跳变
cpu_sr = OS_CPU_SR_Save();//关中断
FLASH_ADDR_COMMAND = 0x00;
FLASH_ADDR_ADDRESS = 0x00;
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>8 & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>16 & 0xFF);
//The 528 bytes of data within the selected page are
//transferred to the data registers in less than 12us(tR).
for(j=0; j<25; j++);
for(j=0; j<(32 + 1); j++)
{//提高数据吞吐速度
*Buff++ = FLASH_ADDR_DATA;//1
*Buff++ = FLASH_ADDR_DATA;//2
*Buff++ = FLASH_ADDR_DATA;//3
*Buff++ = FLASH_ADDR_DATA;//4
*Buff++ = FLASH_ADDR_DATA;//5
*Buff++ = FLASH_ADDR_DATA;//6
*Buff++ = FLASH_ADDR_DATA;//7
*Buff++ = FLASH_ADDR_DATA;//8
*Buff++ = FLASH_ADDR_DATA;//9
*Buff++ = FLASH_ADDR_DATA;//10
*Buff++ = FLASH_ADDR_DATA;//11
*Buff++ = FLASH_ADDR_DATA;//12
*Buff++ = FLASH_ADDR_DATA;//13
*Buff++ = FLASH_ADDR_DATA;//14
*Buff++ = FLASH_ADDR_DATA;//15
*Buff++ = FLASH_ADDR_DATA;//16
}
OS_CPU_SR_Restore(cpu_sr);//开中断
}
//*
//*********************************************************************************************************
//* Function : void NF_WritePage()
//* Describe : 写NAND Flash 指定块指定页
//*--------------------------------------------------------------------------------------------------------
//* Author :
//* Date :
//*--------------------------------------------------------------------------------------------------------
//* Mender :
//* Date :
//* Describe :
//*********************************************************************************************************
//*
unsigned char NF_WritePage(unsigned longBlock,
unsigned charPage,
unsigned char *Buff
)
{
unsigned char cpu_sr;
unsigned charStatus;
unsigned short j;
unsigned longBlockPage;
//每块32页,每页512字节
Page &= 0x1F; //
//计算实际地址
BlockPage = (Block<<5) + Page; //
//读写NAND的时候,总线不可以变化,中断读写特殊寄存器可能引起总线跳变
cpu_sr = OS_CPU_SR_Save();//关中断
FLASH_ADDR_COMMAND = 0x80;
FLASH_ADDR_ADDRESS = 0x00;
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>8 & 0xFF);
FLASH_ADDR_ADDRESS = (unsigned char)(BlockPage>>16 & 0xFF);
for(j=0; j<(32 + 1); j++)
{//数据块区域
FLASH_ADDR_DATA = *Buff++;//1
FLASH_ADDR_DATA = *Buff++;//2
FLASH_ADDR_DATA = *Buff++;//3
FLASH_ADDR_DATA = *Buff++;//4
FLASH_ADDR_DATA = *Buff++;//5
FLASH_ADDR_DATA = *Buff++;//6
FLASH_ADDR_DATA = *Buff++;//7
FLASH_ADDR_DATA = *Buff++;//8
FLASH_ADDR_DATA = *Buff++;//9
FLASH_ADDR_DATA = *Buff++;//10
FLASH_ADDR_DATA = *Buff++;//11
FLASH_ADDR_DATA = *Buff++;//12
FLASH_ADDR_DATA = *Buff++;//13
FLASH_ADDR_DATA = *Buff++;//14
FLASH_ADDR_DATA = *Buff++;//15
FLASH_ADDR_DATA = *Buff++;//16
}
FLASH_ADDR_COMMAND = 0x10;
//Read Staus Register
while(1)
{//Device Operation --- BIT6
FLASH_ADDR_COMMAND = 0x70;
Status = FLASH_ADDR_DATA;
if(Status & (1<<6))
{//Busy : "0" Ready : "1"
break;
}
}
//Read Staus Register
//Total Pass/Fail -- BIT0
FLASH_ADDR_COMMAND = 0x70;
Status = FLASH_ADDR_DATA;
if(Status & (1<<0))
{//Fail : "1"
OS_CPU_SR_Restore(cpu_sr);//开中断
return 0;
}
else
{//Pass : "0"
OS_CPU_SR_Restore(cpu_sr);//开中断
return 1;
}
} 非常感谢,我在研究一下先。 很小很强大,非常感谢ATMEGA_007。
是我对Flash读写时序理解有误。
另外请教一个问题:Flash 坏块怎么处理?
上面的程序读取Flash时,没有判断读取是否成功,没有判断块是否无效。 1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_225595.JPG
我的疑惑在这里,在数据读取期间,CE需要一直为0吗?
如果每读一个字节,而该字节写入外部SRAM,那么在写外部
SRAM时,Flash 的 CE 应该是1。 这个函数让我一夜没睡好。
unsigned long NF_ReadID(void)
{
unsigned char Buff;
FLASH_ADDR_COMMAND = 0x90;
FLASH_ADDR_ADDRESS = 0x00;
__no_operation();
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
Buff = FLASH_ADDR_DATA;
return(*((unsigned long *)Buff));
}
现在仔细看了才放心。
Buff在栈上分配,模模糊糊记得是 return 指针了,
所以一早起来看看,还好,返回的是unsigned long型数据。 ATMEGA_007,再次非常感谢你的解答,
但是处于小心敬慎,麻烦您给我一个明确的答复:
你这样的使用方式,是否成功的引用于实际项目?
我今天就要确定方案,昨天画的原理图没有挂总线上,都准备画PCB了,
看了您的解答,很受启发,
如果挂总线上可行,我还是希望把Flash挂总线上。
另外,这种挂接,外部SRAM将浪费掉 4K的低地址空间,可以另外搭地址译码电路解决这个问题。
非常感谢,期待您的答复。
我的QQ:19950770 这是我做的产品,已经成型了
这样连接的确浪费的4KB RAM,系统优先使用内部4KB RAM,所以低4KBRAM的速度最高,超出4KB时候系统自动切换外部
如果吝啬这4K RAM,可以用GAL(比较便宜PLD,)编址,解决这个问题。
写程序要注意的是:
1.读写NAND的时候,总线不可被中断干其他事情,中断其他程序读写特殊寄存器可能引起总线跳变 ,读写的时候要关闭总中断
2. //The 528 bytes of data within the selected page are
//transferred to the data registers in less than 12us(tR).
for(j=0; j<25; j++);
这段小延时也很关键,一定要用避免影响外部总线延时
这些问题都是AVR的弊端决定的,因为他的寄存器和RAM统一编址的,读写一个特殊寄存器都会导致外部地址线跟着乱跳......... 还有就是NAND Flash 大容量的特点决定,
NAND Flash 出厂的时候,允许有坏的数据块,一个块有32页,只要有一个页是坏的,就认为这个块坏了,因为擦出的时候,NAND Flash 提示这个Block已经无法擦除了,所以使用的时候,要标记这个坏的块
但是 NAND Flash 厂家给出,可以保证第0个BLOCK肯定是好的,这就是让你标注坏块和分区使用用的,以K9F1208为例,在不使用FAT的时候,自己分配使用方法,NAND Flash 使用率比FAT高很多,但是向那1G,2G的SD卡最好使用FAT ATMEGA_007 ,再请教一点细节问题:
在你给出的电路图中,
SRAM的读信号为(/RD),而Flash的读信号为(RD),那么电路中是否还加了一个反向器?
还是 SRAM与 FLADH 使用相同的读取信号? SRAM和Flash的读信号都是(/RD)直接连接M128的PIN34
SRAM和Flash的写信号都是(/WR)直接连接M128的PIN33 哦,好的,非常感谢。
我看你原理图两个的网络标签不一样,所以问问。 1http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_226135.JPG
我画的原理图,希望没有问题。 哈哈,错了。。
A15和A13颠倒了,这样的话,编址就有问题了 嗯,检查出来了
还有电源也错了。 顶一下
在GCC里面怎么样才能把占用的4K RAM也利用起来呢?有没有朋友知道? 没办法吧,硬件地址编码决定了。
如果总线上不挂其他东东,A15不接,SRAM片选接地,那么低4K是可以用的,直接用高地址访问,例如:
unsigned char * p ;
p = (unsigned char * ) (0x8000);
这时候,p指向外部SRAM的0x0000了。 macao老师那本书上有一小节提到如何可以不浪费内部的4k RAM,用到一个138和一个与门 本来准备用与非门做地址译码的,我查了一些资料,但发现HC系列的与非门速度跟不上。找了很久也没找到合适的。速度快,工作电压3.3V,温度-40 到 +70 度,我是没找到。 程序出来了吗?等你使用经验呢
我发现在AVR下,用程序读取 R/B 引脚测试芯片BUSY, 芯片无法干活,主要是读取这个脚状态,A0,A1地址线有变化,这2个线是NAND的控制线,后来我图纸没改,用软件读取就可以了,反而省了条线,所以以后的实验一直没做
如果你读取线状态,建议CLE和ALE接到地址线A9 A8上,因为AVR内部寄存器在低地址范围,这样读取端口不会影响CLE和ALE 今天板子回来了,其他事情还比较多,估计还要等几天才能调这部分。 哦,是可能有这个问题,我实验过后再看看。 ATMEGA_007
有新问题请教: 用上面的原理图, 读ID正确,但是读写数据不正确,写保护开了, RB脚也断开拉,我仔细读了一下PDF文档,越读越觉得程序没问题,搞得很郁闷.
请问一下, 你程序用的是什么编译器编译的? 我用GCC加-O2级优化时, buff++ 会被优化掉, 也就是说,指针不加1. 为何一定选74HC138的Y0当Nand Flash 片选?
不选Y0就可以使用那4K SRAM了 Nand_Flash 读写调试成功啦, MEGA_007的程序就一个问题: 读取数据时的延迟问题,在延迟期间,必须保证 Flash 的CE脚为低, 否则读取会被打断,导致读取数据无效。
所以,在读取Flash的15us的延迟期间,不能对 SRAM 进行操作,否者CE会跳变,我延迟通过插入汇编指令实现。
MEGA_007的读取函数,使用下面的程序延时,这是不正确的,如果可用,那只是以外,这可能与编译器有关。
unsigned short j;
for(j=0; j<25; j++);
另外,这个延时程序,一开优化,肯定会被优化掉。
好啦,最后再次感谢MEGA_007 。 再提醒兄弟几点:
1.NANDFlash 坏块是非常常见的(我是经常遇到),也是允许的,所以一定要做好坏块的标注和处理
我的处理方式:
经坏块标注的数组,然后通过映射函数,将逻辑地址映射到物理地址
如:物理块1坏了,逻辑地址块1就对应物理地址2了
如:物理块1,2坏了,逻辑地址块1就对应物理地址3了
.....
2. NAND的位翻转也很常见的(不过我没遇到过)...
我的处理方式:
采用YAFFS的ECC校验:
点击此处下载 ourdev_261622.rar(文件大小:3K) (原文件名:ECC.rar)
3.NANDFlash 价格才考:
我常用的芯片:
K9F1208 :64M 17/片
K9F5608 : 32M 11/片
这都是三星电子大规模生产的芯片,可以放心使用 两位有总线相关的原理图和程序能公布一部分就好了,我对总线方式也很感兴趣。 LS的看清楚没有?
上面的贴难道没有图纸和程序? 这两天搞坏块标注的问题,真的还挺麻烦的。
1. 坏块检测方法:
按照数据手册,我的理解是,块擦除的时候,读取每块的0或1页,然后判断地址 517 byte 是不是 0xFF, 如果不是,表示坏块。这好像不稳妥吧。如果意外擦除了坏块,就可能会有漏网之鱼;
我想这样做:第一次使用,先擦除,然后再全部写0,然后再读出,看是否全部为0x00;如果是,那么表示所以bit都可以编程,这样就没漏网之鱼了。在以后的使用中,如果出现读写异常的,再添加坏块标记;
2. 坏块标识表保存问题:
一般来说,坏块标识,都保存在0块中的,有个问题是,如果有新的坏块添加,这时需要擦除块0,然后写入新的数据,在写数据的时候掉电了怎么办呢?数据全错啦,问题很严重啊。我想,在其他有效块,多做两个备份。
3. 逻辑地址到物理地址映射:
MEGA_007的这个方法很好,我开始想了很多方法,感觉用起来都不方便,使用这个方法可以把函数库的封装性做得很好,不错。
4. 掉电问题,如果写数据的时候,掉电啦,这个问题怎么解决呢?
5. ECC问题:
看了点资料,ECC好像是用来数据纠错的,一般的算法能纠错1bit(如:汉明码),这里有个疑问:这个很有必要吗?对ECC的理解还不够多,我目前的应用都不想加这个功能,我想简单做个CRC,对每页的数据校验一下就OK啦,不想搞纠错。 还有一个坏块数目的问题, 文档上说, 保证 4026块有效, 一共4096块, 也就是说,最大坏块数目为70,是么? 现在我设计的结构,允许最大坏块为255. 不知道够不够? 学习学习... 好样的,学习先, 请教lz和ls的高手:
我现在做考勤机,
里面数据存储器用什么方案好:
1. nor flash(sst39sf040) 太小了,一片存字库,一片存数据
2. nand flash 容量大
3. sd卡 坏了容易换.会不会出现坏块?
4. 其他? mark mark 好文章,,mark avr 也扩展 mark 学习了 mark 记号~! 记下 学习学习。。 mark mark 学习一下 学习一下! 正在学习当中 学习 好文章,留个记号. mark MARK 支持 mark ATMEGA_007 发表于 2008-3-6 16:38 static/image/common/back.gif
//*
//********************************************************************************************** ...
标记mark
MARK{:lol:}{:lol:}
页:
[1]