构建驱动模块4--STM32 spiflash W25Q128 驱动

构建驱动模块4--STM32 spiflash W25Q128 驱动

一、硬件接口

        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。其硬件接口如下:

二、驱动程序

1、初始化spiflash设备,获取W25Q128型号,根据信号配置参数。

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);
	}
}

2、实现open、close 、write、 read、 control等操作,open设置SPI接口模式和速度,并获取SPIFLASH型号;write实现SPIFLASH写,read实现SPIFLASH读取。


/**********************************************************************************************************
 *
 *  函数名: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;i<spifashcfg->eraseNum;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");
		}
	}
}
 	
}

3、按照spiflash芯片命令操作设备。包括页写、flash读、flash操作


/**********************************************************************************************************
 *
 *  函数名: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;
}

4、测试结果:

猜你喜欢

转载自blog.csdn.net/u011996698/article/details/83546848
今日推荐