W25Q128 将 16M 的容量分为 256 个块(Block),每个块大小为 64K 字节,每个块又分为 16个扇区(Sector),每个扇区 4K 个字节。 W25Q128 的最少擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。操作需要给 W25Q128 开辟一个至少 4K 的缓存区,对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。 利用串行FLASH 可以实现代码映射到 RAM,直接通过 SPI 方式来执行代码,存储声音, 文本, 数据。 W25Q128 供电范围为 2.7——3.6V, 在激活状态下电流功耗低到 4MA,睡眠状态下则降低到 1UA。其硬件接口如下:
typedef struct
{
ht_uint32_t SectorSize;
ht_uint32_t SectorCount;
ht_uint32_t PageSize;
ht_uint32_t PageCount;
ht_uint32_t BlockSize;
ht_uint32_t BlockCount;
ht_uint32_t readId;
}spiflashCtr;
void spiflashhardwareInit(ht_int8_t *name,ht_int16_t devno)
{
ht_int8_t str[64];
spiflashCtr *spiflash_td=NULL;
spiflash_dev =(ht_device_t) cmMalloc(sizeof(struct ht_device) );
if(spiflash_dev==NULL)
{
cmFault(SYS_ERROR_MEMMALLOC_ABNORMAL,RECORD_FLAG);
}
cmMemset(spiflash_dev,0,sizeof(struct ht_device));
spiflash_dev -> open = bspspiflashOpen;
spiflash_dev -> close = bspspiflashClose;
spiflash_dev -> read = bspSPIFlashRead;
spiflash_dev->control = bspspiflashDevctl;
spiflash_dev->write = bspSPIFlashWrite;
spiflash_dev->del=bspspiflashdel;
spiflash_dev->help=spiflashhelp;
spiflash_td=(spiflashCtr*) cmMalloc(sizeof(spiflashCtr) );
if(spiflash_td==NULL)
{
cmFault(SYS_ERROR_MEMMALLOC_ABNORMAL,RECORD_FLAG);
}
spiflash_dev->user_privatedata = (void*)spiflash_td;
spiflashdevno=devno;
sprintf(str,"%s-%d",name,devno);
if(SpihardwareInit("spi",devno)>0)
{
htDevFsRegister( spiflash_dev,str);
htDevFsAssociated(spiflash_dev,"spi",devno);
}
else
{
cmFree(spiflash_dev);
}
}
/**********************************************************************************************************
*
* 函数名:bspspiflashOpen
* 功 能:
* 参 数:
* 返回值:
* 版 本:REV1.0.0 2016/04/27 Create
*
**********************************************************************************************************/
ht_inline ht_int32_t bspspiflashOpen (ht_device_t dev, ht_uint32_t oflag)
{
spicfg_t spicfg;
spiflashCtr *spiflash_td;
ht_uint32_t IdFlash;
if(dev->isChildFlag)
{
spifd=htDevFsOpen(dev->childname,0);
if(spifd==NULL)
{
return -1;
}
spicfg.mode=SPI_CPOL_LOW|SPI_CPHA_2|SPI_DB_08B;
spicfg.clock_rate=1000000;
spicfg.csno=0;
htDevFsControl(spifd,CMD_SPI_CFG,(void*)&spicfg);//配置SPI接口
IdFlash=SPI_FLASH_ReadID();
ht_printk("IdFlash=%04x\r\n",IdFlash);
spiflash_td=(spiflashCtr*)dev->user_privatedata;
switch(IdFlash)
{
case W25X128_ID:
spiflash_td->SectorCount=4096;
spiflash_td->SectorSize=SECTORSIZE;
spiflash_td->PageSize=256;
spiflash_td->PageCount=65536;
spiflash_td->readId=IdFlash;
spiflash_td->BlockSize=65536;
spiflash_td->BlockCount=256;
break;
case W25X64_ID:
spiflash_td->SectorCount=2048;
spiflash_td->SectorSize=SECTORSIZE;
spiflash_td->PageSize=256;
spiflash_td->PageCount=32768;
spiflash_td->readId=IdFlash;
spiflash_td->BlockSize=65536;
spiflash_td->BlockCount=128;
break;
case W25X32_ID:
spiflash_td->SectorCount=1024;
spiflash_td->SectorSize=SECTORSIZE;
spiflash_td->PageSize=256;
spiflash_td->PageCount=16384;
spiflash_td->readId=IdFlash;
spiflash_td->BlockSize=65536;
spiflash_td->BlockCount=64;
break;
case W25X16_ID:
spiflash_td->SectorCount=512;
spiflash_td->SectorSize=SECTORSIZE;
spiflash_td->PageSize=256;
spiflash_td->PageCount=8192;
spiflash_td->readId=IdFlash;
spiflash_td->BlockSize=65536;
spiflash_td->BlockCount=32;
break;
default:
return -1;
}
}else
return -1;
}
/**********************************************************************************************************
*
* 函数名:bspspiflashClose
* 功 能:
* 参 数:
* 返回值:
* 版 本:REV1.0.0 2016/04/27 Create
*
**********************************************************************************************************/
ht_inline ht_int32_t bspspiflashClose (ht_device_t dev)
{
htDevFsClose(spifd);
return HT_EOK;
}
/**********************************************************************************************************
*
* 函数名:bspSPIFlashRead
* 功 能:
* 参 数:
* 返回值:
* 版 本:
*
**********************************************************************************************************/
ht_inline ht_int32_t bspSPIFlashRead(ht_device_t dev,ht_uint32_t ReadAddr,void* buffer,ht_int32_t NumByteToRead)
{
return SPI_Flash_Read((ht_uint8_t *)buffer,ReadAddr,NumByteToRead);
}
/**********************************************************************************************************
*
* 函数名:bspSPIFlashWrite
* 功 能:
* 参 数:
* 返回值:
* 版 本:
*
**********************************************************************************************************/
ht_inline ht_int32_t bspSPIFlashWrite (ht_device_t dev, ht_uint32_t WriteAddr, const void *buffer, ht_int32_t NumByteToWrite)
{
ht_uint8_t *pBuffer;
ht_uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp= 0;
/*这里划分好数据需要写多少页,写地址,写大小*/
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
pBuffer=(ht_uint8_t *)buffer;
if (Addr == 0)
{
if(NumOfPage == 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else
{
while(NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
else
{
if(NumOfPage == 0)
{
if(NumOfSingle > count)
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
if(NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
}
return NumByteToWrite;
}
/**********************************************************************************************************
*
* 函数名:bspspiflashdel
* 功 能:
* 参 数:
* 返回值:
* 版 本:REV1.0.0 2016/04/27 Create
*
**********************************************************************************************************/
ht_inline ht_int32_t bspspiflashdel(ht_device_t dev)
{
spiflashCtr *spiflash_td;
htDevFsUnregister(dev);//卸载驱动
cmFree(dev);//释放Device
if(dev->user_privatedata)
{
spiflash_td=(spiflashCtr*)dev->user_privatedata;
cmFree(spiflash_td);
}
return 1;
}
/**********************************************************************************************************
*
* 函数名:bspspiflashDevctl
* 功 能:
* 参 数:
* 返回值:
* 版 本:REV1.0.0 2016/04/27 Create
*
**********************************************************************************************************/
ht_inline ht_int32_t bspspiflashDevctl(ht_device_t handle, ht_uint8_t cmd,void *arg)
{
ht_uint32_t i;
spifashcfg_t *spifashcfg;
switch(cmd)
{
case CMD_SPIFLASH_ERASE:
spifashcfg=(spifashcfg_t *)arg;
if((spifashcfg->eraseStart%SECTORSIZE)==0)
{
for(i=0;ieraseNum;i++)
{
SPI_FLASH_SectorErase(spifashcfg->eraseStart+i*SECTORSIZE);
}
}
break;
case CMD_SPIFLASH_READ:
spifashcfg->readId=SPI_FLASH_ReadID();
break;
}
return 1;
}
/**********************************************************************************************************
*
* 函数名:spiflashhelp
* 功 能:
* 参 数:
* 返回值:
* 版 本:REV1.0.0
*ds18b20test ds18b20
**********************************************************************************************************/
ht_uint8_t rbuffer[128];
ht_int32_t spiflashhelp (ht_device_t dev, ht_int8_t argc, ht_int8_t * argv[])
{
int arg=0,i;
static int cnt=0;
htDevFsHandle fd;
ht_uint8_t buffer[128];
ht_uint16_t temp;
if(arg<=argc)
{
if (strcmp((char const *) argv[2], "test")==0)
{
ht_printk("devname %s\r\n",argv[1]);
fd=htDevFsOpen( argv[1],0);
if(fd!=NULL)
{
SPI_FLASH_SectorErase(0);
cnt++;
for(i=0;i<128;i++)buffer[i]=cnt;
htDevFsWrite(fd,0,buffer,128);
htDevFsRead(fd,0,rbuffer,128);
ht_printk("Dat:");
for(i=0;i<128;i++)
ht_printk("%02x ",rbuffer[i]);
ht_printk("\r\n");
htDevFsClose(fd);
}
else
{
ht_printk("can not find dev\r\n");
}
}
}
}
/**********************************************************************************************************
*
* 函数名:SPI_FLASH_PageWrite
* 功 能:
* 参 数:
* 返回值:
* 版 本:
*
**********************************************************************************************************/
ht_inline void SPI_FLASH_PageWrite(ht_uint8_t* pBuffer, ht_uint32_t WriteAddr, ht_uint16_t NumByteToWrite)
{
/*写使能并且判断FLASH状态*/
spimsg_t spimsg;
ht_uint8_t FLASH_Status = 0;
ht_uint8_t wbuffer[16];
ht_uint8_t rbuffer[16];
if(spifd!=NULL)
{
SPI_FLASH_WriteEnable();
htDevFsControl(spifd,CMD_SPI_CS_OFF,NULL);//使能器件
wbuffer[0]=Page_Program;//发送读取命令
wbuffer[1]=(ht_uint8_t)((WriteAddr & 0xFF0000) >> 16); //发送24bit地址
wbuffer[2]=(ht_uint8_t)((WriteAddr & 0xFF00) >> 8);
wbuffer[3]=(ht_uint8_t)(WriteAddr & 0xFF);
spimsg.wmsg=&wbuffer[0];//发送地址
spimsg.len=4;
htDevFsControl(spifd,CMD_SPI_WRITE,(void*)&spimsg);
spimsg.wmsg=&pBuffer[0];//发送数据
spimsg.len=NumByteToWrite;
htDevFsControl(spifd,CMD_SPI_WRITE,(void*)&spimsg);
htDevFsControl(spifd,CMD_SPI_CS_ON,NULL);
SPI_FLASH_WaitForWriteEnd();
}
}
/**********************************************************************************************************
*
* 函数名:SPI_FLASH_SectorErase
* 功 能:
* 参 数:
* 返回值:
* 版 本:
*
**********************************************************************************************************/
ht_inline void SPI_FLASH_SectorErase(ht_uint32_t SectorAddr)
{
/*写使能并且判断FLASH状态*/
spimsg_t spimsg;
ht_uint8_t FLASH_Status = 0;
ht_uint8_t wbuffer[16];
ht_uint8_t rbuffer[16];
if(spifd!=NULL)
{
/*写使能并且判断FLASH状态*/
SPI_FLASH_WriteEnable();
SPI_FLASH_WaitForWriteEnd();
/*这里开始是FLASH擦除操作*/
htDevFsControl(spifd,CMD_SPI_CS_OFF,NULL);//使能器件
wbuffer[0]=0x20;//发送读取命令
wbuffer[1]=(ht_uint8_t)((SectorAddr & 0xFF0000) >> 16); //发送24bit地址
wbuffer[2]=(ht_uint8_t)((SectorAddr & 0xFF00) >> 8);
wbuffer[3]=(ht_uint8_t)(SectorAddr & 0xFF);
spimsg.wmsg=&wbuffer[0];//发送地址
spimsg.len=4;
htDevFsControl(spifd,CMD_SPI_WRITE,(void*)&spimsg);
htDevFsControl(spifd,CMD_SPI_CS_ON,NULL);
/*再次判断FLASH状态确保可以执行下一次操作*/
SPI_FLASH_WaitForWriteEnd();
}
}
/**********************************************************************************************************
*
* 函数名:SPI_Flash_Read
* 功 能:
* 参 数:
* 返回值:
* 版 本:
*
**********************************************************************************************************/
ht_inline ht_int32_t SPI_Flash_Read(ht_uint8_t* pBuffer,ht_uint32_t ReadAddr,ht_uint32_t NumByteToRead)
{
spimsg_t spimsg;
ht_uint8_t wbuffer[16];
if(spifd!=NULL)
{
htDevFsControl(spifd,CMD_SPI_CS_OFF,NULL);//使能器件
wbuffer[0]=Read_Data;//发送读取命令
wbuffer[1]=(ht_uint8_t)((ReadAddr)>>16); //发送24bit地址
wbuffer[2]=(ht_uint8_t)((ReadAddr)>>8);
wbuffer[3]=(ht_uint8_t)ReadAddr;
spimsg.wmsg=&wbuffer[0];//发送数据
spimsg.len=4;
htDevFsControl(spifd,CMD_SPI_WRITE,(void*)&spimsg);
spimsg.rmsg=&pBuffer[0];//读取数据
spimsg.len=NumByteToRead;
htDevFsControl(spifd,CMD_SPI_READ,(void*)&spimsg);
htDevFsControl(spifd,CMD_SPI_CS_ON,NULL);//取消片选
return NumByteToRead;
}
return 0;
}