1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/dma-w25n01gv

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
w25n01gv.c 8.3 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
bxgj Отправлено 19.11.2017 09:41 519f00a
#include "w25n01gv.h"
/*---------------------------------以下为接口----------------------------------*/
/*--------------------------请根据自己的实际情况修改---------------------------*/
/*
函数原型:void FlashDelay(u16 n);
函数功能:延时
参数:n 延时的毫秒数
返回值:无
*/
void (*FlashDelay)(unsigned short n) = (void (*)(unsigned short))&delay;
/*
函数原型:u8 FlashRW(u8 dat);
函数功能:SPI读写一字节
参数:dat 要写入的数据
返回值:读出的数据
*/
unsigned char (*FlashRW)(unsigned char dat) = &SPI_ReadWriteByte;
/*
函数原型:void FlashEnable(u8 s);
函数功能:SPI片选
参数:s 片选状态,0未选中,非0选中
返回值:无
*/
void FlashEnable(unsigned char s)
{
if (s)
{
SPI_CS = 0;
}
else
{
SPI_CS = 1;
}
}
/*--------------------------------以下为驱动程序-------------------------------*/
unsigned char FlashReset(void)
{
FlashEnable(1);
FlashRW(FLASH_DEVICE_RESET);
FlashEnable(0);
FlashDelay(1);//手册上说复位时间约为5-500us,这里延时1ms
if(FlashWaitBusy(100))
{
return 1;//等待复位超时
}
return 0;
}
unsigned char FlashInit(void)
{
unsigned int id = 0;
FlashEnable(1);
FlashRW(FLASH_JEDEC_ID);
id |= FlashRW(0x00) << 24;//第一字节忽略
id |= FlashRW(0x00) << 16;//第二字为0xEF
id |= FlashRW(0x00) << 8;//第三字为0xAA
id |= FlashRW(0x00);//第四字为0x21
FlashEnable(0);
if((id & FLASH_ID_W25N01GV) != FLASH_ID_W25N01GV)
{
//芯片型号不对,或芯片已损坏?
return 1;
}
if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
{
//坏块映射表已满,继续使用不能保证数据的正确性
return 2;
}
//芯片设置
id = FlashReadStatusRegister(FLASH_STATUS_REG1_ADDR);
id = 0;//禁用所有写保护
FlashWriteStatusRegister(FLASH_STATUS_REG1_ADDR, id & 0x000000FF);
id = FlashReadStatusRegister(FLASH_STATUS_REG2_ADDR);
id |= (0x10 | 0x80);//开启ECC,禁用读取缓冲区
FlashWriteStatusRegister(FLASH_STATUS_REG2_ADDR, id & 0x000000FF);
return 0;
}
//等待芯片操作完成,时间单位ms
unsigned char FlashWaitBusy(unsigned short int timeout)
{
while(timeout--)
{
if((FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BUSY) != FLASH_SR_BUSY)
{
return 0;//等待结束
}
FlashDelay(1);
}
return 1;//等待超时
}
void FlashWriteEnable(void)
{
FlashEnable(1);
FlashRW(FLASH_WRITE_ENABLE);
FlashEnable(0);
}
void FlashWriteDisable(void)
{
FlashEnable(1);
FlashRW(FLASH_WRITE_DISABLE);
FlashEnable(0);
}
unsigned char FlashReadStatusRegister(unsigned char RegAddr)
{
unsigned char tmp;
FlashEnable(1);
FlashRW(FLASH_READ_STATUS_REGISTER);
FlashRW(RegAddr);
tmp = FlashRW(0x00);
FlashEnable(0);
return tmp;
}
void FlashWriteStatusRegister(unsigned char RegAddr, unsigned char Value)
{
FlashEnable(1);
FlashRW(FLASH_WRITE_STATUS_REGISTER);
FlashRW(RegAddr);
FlashRW(Value);
FlashEnable(0);
}
//读取一页,返回值为ECC校验结果
unsigned char FlashReadPage(unsigned short int page, unsigned char *buf)
{
unsigned short int i = 0;
//输入要读取的页地址
FlashEnable(1);
FlashRW(FLASH_PAGE_DATA_READ);
FlashRW(0x00);
FlashRW((unsigned char)(page >> 8));
FlashRW((unsigned char)(page & 0x00FF));
FlashEnable(0);
FlashDelay(1);
//开始读取
FlashEnable(1);
FlashRW(FLASH_READ);
FlashRW(0x00);
FlashRW(0x00);
FlashRW(0x00);
//三个空字节后开始接收数据
for(i = 0; i < 2048; i++)
{
*buf = FlashRW(0x00);
buf++;
}
FlashEnable(0);
return FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & 0x30;
}
//写入一页,0成功,1失败
unsigned char FlashWritePage(unsigned short int page, unsigned char *buf)
{
unsigned short int i = 0;
FlashWriteEnable();
FlashDelay(1);
//将数据送到Flash
FlashEnable(1);
FlashRW(FLASH_PROGRAM_DATA_LOAD);
FlashRW(0x00);//填充字节
FlashRW(0x00);//填充字节
for(i = 0; i < 2048; i++)
{
FlashRW(*buf);
buf++;
}
FlashEnable(0);
FlashDelay(1);
//执行写入操作
FlashEnable(1);
FlashRW(FLASH_PROGRAM_ECECUTE);
FlashRW(0x00);
FlashRW((unsigned char)(page >> 8));
FlashRW((unsigned char)(page & 0x00FF));
FlashEnable(0);
FlashWaitBusy(100);//等待写入完成
//检查是否写入成功
if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_WRITE_FAIL)
{
return 1;
}
return 0;
}
//擦除区块,0成功,1失败
unsigned char FlashBlockErase(unsigned short int BlockNum)
{
FlashWriteEnable();
FlashEnable(1);
FlashRW(FLASH_BLOCK_ERASE);
FlashRW((unsigned char)(0x00));
FlashRW((unsigned char)(BlockNum >> 8));
FlashRW((unsigned char)(BlockNum & 0x00FF));
FlashEnable(0);
if(FlashWaitBusy(100))
{
//等待擦除完成,手册上说最大不超过10ms
return 1;
}
//检查是否擦除成功
if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_ERASE_FAIL)
{
return 1;
}
return 0;
}
//区块扫描,可以用来检查擦除是否成功或扫描出厂时的坏块标记
unsigned char BlockScan(unsigned short int BlockNum)
{
int i = 0;
//把块地址换算成页地址
BlockNum <<= 6;
FlashEnable(1);
FlashRW(FLASH_PAGE_DATA_READ);
FlashRW(0x00);
FlashRW((unsigned char)(BlockNum >> 8));
FlashRW((unsigned char)(BlockNum & 0x00FF));
FlashEnable(0);
FlashDelay(1);
//开始读取
FlashEnable(1);
FlashRW(FLASH_READ);
FlashRW(0x00);
FlashRW(0x00);
FlashRW(0x00);
//三个空字节后开始接收数据
for(i = 0; i < 128 * 1024; i++)
{
if(FlashRW(0x00) != 0xFF)
{
FlashEnable(0);
return 1;
}
}
FlashEnable(0);
return 0;
}
//专门用于找出出厂时的坏块标记,手册上说出厂时坏块的第一页的第一个字节会被标记为非0xFF,
unsigned char BadBlockScan(unsigned short int BlockNum)
{
//把块地址换算成页地址
BlockNum <<= 6;
FlashEnable(1);
FlashRW(FLASH_PAGE_DATA_READ);
FlashRW(0x00);
FlashRW((unsigned char)(BlockNum >> 8));
FlashRW((unsigned char)(BlockNum & 0x00FF));
FlashEnable(0);
FlashDelay(1);
//开始读取
FlashEnable(1);
FlashRW(FLASH_READ);
FlashRW(0x00);
FlashRW(0x00);
FlashRW(0x00);
//三个空字节后开始接收数据
//出厂时,坏块的第一页的第一个字节会被标记为非0xFF,后面的就不用继续扫描了
if(FlashRW(0x00) != 0xFF)
{
FlashEnable(0);
return 1;
}
FlashEnable(0);
return 0;
}
//LBA(Logical Block Address)是坏块地址,PBA(Physical Block Address)是要替换的区块地址
//返回0正常,1坏块表已满
unsigned char BadBlockMapping(unsigned short int LBA, unsigned short int PBA)
{
if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
{
return 1;
}
FlashEnable(1);
FlashRW(FLASH_BAD_BLOCK_MANAGEMENT);
FlashRW((unsigned char)(LBA >> 8));
FlashRW((unsigned char)(LBA & 0x00FF));
FlashRW((unsigned char)(PBA >> 8));
FlashRW((unsigned char)(PBA & 0x00FF));
FlashEnable(0);
return 0;
}
//Bad Block Management Look Up Table
//BBMLUT需要80字节存储(实际上应当是40个unsigned short数据)
//格式是LBA0,PBA0,LBA1,PBA1......LBA19,PBA19
void ReadBBMLUT(unsigned short int *BBMLUT)
{
int i = 0;
FlashEnable(1);
FlashRW(FLASH_READ_BBM_LUT);
FlashRW(0x00);
for(i = 0; i < 80; i++)
{
*BBMLUT = FlashRW(0x00) << 8;
BBMLUT++;
*BBMLUT |= FlashRW(0x00);
}
FlashEnable(0);
}
//读出最后一个ECC错误的页地址
unsigned short int LastECCFailPageAddr(void)
{
unsigned short int PageAddr = 0;
FlashEnable(1);
FlashRW(FLASH_LAST_ECC_FAILURE_PAGE_ADDR);
FlashRW(0x00);
PageAddr |= FlashRW(0x00) << 8;
PageAddr |= FlashRW(0x00);
FlashEnable(0);
return PageAddr;
}
//在正式使用前建议执行一次坏块扫描
//使用前不要向Flash写入任何数据,否则可能覆盖出厂时的坏块信息
void BadBlockManage(void)
{
unsigned short int i = 0, n = 0;
unsigned short int BBT[40] = {0};//Bad Block Table
printf("开始坏块扫描 \r\n");
for(i = 0; i < 1024; i++)
{
printf("正在扫描第 %d 块 \r\n", i);
if(BadBlockScan(i))//快速扫描,只扫描每页的第一字节
{
printf("第 %d 块为坏块 \r\n", i);
//自动填入映射表还是手动填?
if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
{
printf("坏块映射表已满,无法映射 \r\n");
}
else
{
ReadBBMLUT(BBT);
//1000到1023一共24个Block用于替换,BBMLUT一共能保存20个映射关系
//多出来的4块是考虑到这20个块中还有坏块的情况
for(n = 0; n < 20; n++)
{
if(BBT[n * 2] == 0x0000 && BBT[n * 2 + 1] == 0x0000)
{
n += 1000;
BadBlockMapping(i, n);
printf("第 %d 块被映射为第 %d 块 \r\n", i, n);
break;
}
}
}
}
}
printf("坏块扫描结束 \r\n");
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/dma-w25n01gv.git
git@api.gitlife.ru:oschina-mirror/dma-w25n01gv.git
oschina-mirror
dma-w25n01gv
dma-w25n01gv
master