ADI的BF561双核DSP怎么做开发,我来说一说(十一)NANDFLASH的读写
作者的话
ADI的双核DSP,最早的一颗是Blackfin系列的BF561,这颗DSP我用了很久,比较熟悉,且写过一些给新手的教程。
硬件准备
ADZS-BF561-EZKIT开发板:ADI原厂评估板
AD-ICE20000仿真器:ADI现阶段性能最好的DSP仿真器
产品链接:https://item.taobao.com/item.htm?id=753233120844
软件准备
Visual DSP++5.1.2
CCES2.11.1
硬件环境的搭建
程序实现的功能
通过 ADSP-BF561 处理器 EBIU(外部总线接口单元)实现对 NAND FLASH 的读写 。
硬件的实现:
如图所示,在硬件设计中,利用 EBIU 接口与 K9F2G08 进行连接,用地址线接口控制NANDFLASH 的 ALE、CLE。CPLD 通过地址译码为 NANDFLASH 提供片选地址,PF11 连接FLASH 的 RDY,用于判断 FLASH 的状态。 K9F2G08 为 8 位总线接口方式,在硬件设计中,利用 0 欧姆跳线电阻保留了与总线的连接,以适应与 BF561 时序匹配的 flash 的应用。
FLASH 寄存器:
FLASH 寄存器的访问,是通过/ALE 和/CLE 的配置,配合读写信号线完成的。在访问寄存器时,先将地址线置高,
NAND FLASH 的结构:
NANDFLASH 存储结构是按块,页,字节分的。每块 64 页,每页 2K+64 字节。
NAND FLASH 的寻址:
NANDFLASH 的地址线 A0-A11 为 2K+64Byte 的页内寻址地址线,A12-A28 为块地址寻址地址线。
NAND FLASH 的存储与其他存储设备不同,它在写操作前必须要对块进行擦除。这是因为NAND FLASH 的存储结构只能将 1 写成 0,如果不对该块擦除就进行写操作,保存的数据会是写入的数据加上原有的数据,造成数据错误。所以在对每个块操作前,必须将该块所有的存储单元置 1,擦除命令就是以块为单位,将所指定的块单元数据置 1。
块地址与页地址的转换:
每一个块包含 64 个页,即 2 的 6 次方。在页地址和块地址相互转换时,只需将块地址左移6 位即可。例如我们现在对页地址 Page_Address 所在的块区域 Block_Address 进行擦除操作,页地址 Page_Address 的地址为:
第一次送入地址 0x00; //非字节操作
第二次送入地址 0x00;
第三次送入地址 Page_Address&0xff;
第四次送入地址(Page_Address>>8)&0xff;
第五送入地址(Page_Address>>16)&0xff;
块擦除地址是 A12-A28,所以三个周期就能送完。
因为 Block_Address=Page_Address/64;即 Block_Address=Page_Address << 6;替换页地址寻址后为
第一次送入地址(Block_Address<<6)&0xff;
第二次送入地址(Block_Address>>2)&0xff;
第三次送入地址(Block_Address>>10)&0xff;
CPLD 配置:
NAND FLASH 模块映射在异步 BANK3 中,其地址为:
核心代码分析
void Read_Chip_ID(void) //读取器件 ID 函数
{
unsigned char Chip_ID0 ;
unsigned char Chip_ID1 ;
Write_Command(0x90);
Write_Addr(0x00);
Chip_ID0 = *pFlash_Data;
Chip_ID1 = *pFlash_Data; //读取器件 ID
printf(“The Nandflash ID is %X%X\n\r”,Chip_ID0,Chip_ID1); //打印 ID
if(Chip_ID0 == 0xec)
{
switch(Chip_ID1) //根据读取的 ID 判断芯片容量
{
case 0xd3 : printf(“The Nandflash is 1024M\n\r”);
bytecount = 4096;
break;
case 0xda : printf(“The Nandflash is 256M\n\r”);
bytecount = 2048;
break;
default: printf(“Read ID is ERROR!!!\n\r”);
bytecount = 2048;
break;
}
}
Else //如果读取 ID 错误
{
printf(“Read ID is ERROR!!!\n\r”); //打印出错
bytecount = 2048;
return false;
}
}
bool write_page(unsigned int Page_Address,unsigned char *Buffer) //页写入函数
{
int i;
Write_Command(0x80); //写命令 0x80
Write_Addr(0x00); //写页内字节地址
Write_Addr(0x00); //写页内字节地址
Write_Addr(Page_Address&0xff); //写页地址
Write_Addr((Page_Address>>8)&0xff); //写页地址
Write_Addr((Page_Address>>16)&0x07); //写页地址
for(i = 0;i<bytecount;i++)
{
*pFlash_Data = *((unsigned char *)Buffer+i); //写入数据
udelay(1);
}
Write_Command(0x10);
Wait_NAND_RADY();
return true;
}
bool read_page(unsigned int Page_Address,unsigned char *Buffer1) //读页内数据函数
{
int i;
Write_Command(0x00); //写命令 0
Write_Addr(0x00); //写页内字节地址
Write_Addr(0x00); //写页内字节地址
Write_Addr(Page_Address&0xff); //写页地址
Write_Addr((Page_Address>>8)&0xff); //写页地址
Write_Addr((Page_Address>>16)&0x07); //写页地址
Write_Command(0x30);
udelay(200);
for(i = 0;i<bytecount;i++)
{
*((unsigned char *)Buffer1+i) = *pFlash_Data; //读出页内数据
}
}
运行程序后,得到下面的结果:
对比数据如图
如果数据对比出现错误,如图
数据发生变化,则得到的打印结果图