天天看點

spi flash驅動代碼分析(二)

一、spi flash裸機驅動代碼

/*
*W25Q64一共8M容量?
*分為128個快,每塊大小為64K位元組?
*每塊又可以分為16個扇區,每個扇區4K位元組?//每次擦除最少一個扇區,也就是4K位元組?//25Q64?一共有2048個扇區
*一頁256位元組
*/
#define W25Q64_PAGE_SIZE    256                          //一頁的大小,256位元組
#define W25Q64_SECTOR_SIZE (4*1024)                      //扇區大小,位元組
#define W25Q64_BLOCK_SIZE  (16*W25Q64_SECTOR_SIZE)
#define W25Q64_SIZE        (128*W25Q64_BLOCK_SIZE)

void W25q64_Init(void)
{
    1.可以用GPIO模拟SPI
    2.也可以用spi控制器<span style="white-space:pre">	</span>
}

/*******************************************************************************
* Function Name  : W25q_ReadWriteByte 
* Description    : W25q晶片SPI讀寫接口函數
* Input          : None
* Output         : None
* Return         : None
* Date           : 2014-05-14
* Author         : ADT LL
*******************************************************************************/
static uint8_t W25q_ReadWriteByte(uint8_t data)
{
  return SSP_SendData(data);  
}


/*******************************************************************************
* Function Name  : W25q64_WaitForIdle
* Description    : 讀狀态寄存器
* Input          : None
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void W25q64_WaitForIdle(void)
{
  uint8_t status=0;
  CS1_RESET;

  W25q_ReadWriteByte(0x05);

  do
  {
    status = W25q_ReadWriteByte(0xA5);
  }while (status&0x01 == 0x01);

  CS1_SET;
  
}

/*******************************************************************************
* Function Name  : W25q64_WriteEnable
* Description    : 寫使能
* Input          : None
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void W25q64_WriteEnable(void)
{
  CS1_RESET;

  W25q_ReadWriteByte(0x06);

  CS1_SET; 
}

/*******************************************************************************
* Function Name  : W25q64_4KErase
* Description    : 4K片擦除
* Input          : addr:起始位址
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void  W25q64_4KErase(uint32_t addr)
{
  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0x20);
  W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  W25q_ReadWriteByte(addr & 0xFF);

  CS1_SET; 
  
  W25q64_WaitForIdle(); 
}

/*******************************************************************************
* Function Name  : W25q64_32KErase
* Description    : 32K片擦除
* Input          : addr:起始位址
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void  W25q64_32KErase(uint32_t addr)
{
  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0x52);
  W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  W25q_ReadWriteByte(addr & 0xFF);

  CS1_SET;
  
  W25q64_WaitForIdle();  
}

/*******************************************************************************
* Function Name  : W25q64_64KErase
* Description    : 64K片擦除
* Input          : addr:起始位址
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void  W25q64_64KErase(uint32_t addr)
{
  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0xD8);
  W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  W25q_ReadWriteByte(addr & 0xFF);

  CS1_SET;
  
  W25q64_WaitForIdle();  
}

/*******************************************************************************
* Function Name  : W25q64_ChipErase
* Description    : Chip片擦除
* Input          : addr:起始位址
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void  W25q64_ChipErase(uint32_t addr)
{
  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0xC7);
  W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  W25q_ReadWriteByte(addr & 0xFF);

  CS1_SET;
  
  W25q64_WaitForIdle();  
}

/*******************************************************************************
* Function Name  : W25q64_Erase
* Description    : 擦除操作,最小以4K為機關進行,從擦除。
* Input          : sectornum:塊數,擦除的空間大小為sectornum*4K
                    --例如:如果sectornum=1,則擦除4K位元組,
                      sectornum=3,則擦除12K=4K*3個位元組
                   addr:起始位址
* Output         : None
* Return         : 狀态碼
* Date           : 2014-10-25
* Author         : ADT LL
*******************************************************************************/
int W25q64_Erase(uint32_t base_addr,int sector_count)
{

  if (base_addr % W25Q64_SECTOR_SIZE ) {
  	return -1;
  }
  if (base_addr>=W25Q64_SIZE) return -1;
  
  while(sector_count = sector_count / 16) {
  	 W25q64_64KErase(base_addr);
	 base_addr += 16*W25Q64_SECTOR_SIZE;
  }
  while(sector_count = sector_count / 8) {
  	 W25q64_32KErase(base_addr);
	 base_addr += 8*W25Q64_SECTOR_SIZE;
  }
  while(sector_count--) {
  	 W25q64_4KErase(base_addr);
	 base_addr += W25Q64_SECTOR_SIZE;
  }
	
  return 0; 
}



/*******************************************************************************
* Function Name  : W25q64_PageProgram
* Description    : 頁寫
* Input          : buf:要寫内的資料
                   len:資料長度
                   add:起始位址
* Output         : None
* Return         : 狀态碼
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
static int  W25q64_PageProgram(uint8_t *buf, uint16_t len, uint32_t addr)
{
  if (addr>=W25Q64_SIZE) return -1;
  if (len<=0 || len>256) return -1;//沒有資料不操作

  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0x02);
  W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  W25q_ReadWriteByte(addr & 0xFF);

  while (len--)
  {
    W25q_ReadWriteByte(*buf);
    buf++;   
  }

  CS1_SET;
  
  W25q64_WaitForIdle();
  
  return 0;   
}

/*******************************************************************************
* Function Name  : W25q64_Write
* Description    : 資料存儲,為防止意外的擦除
* Input          : buf:要寫内的資料
                   len:資料長度
                   add:起始位址
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void W25q64_Write(uint8_t *buf, uint16_t len, uint32_t addr)
{
  uint8_t pagenum;
  uint8_t addrbyte;//最低八位位址
  
  addrbyte = addr%W25Q64_PAGE_SIZE;
  if (len > (W25Q64_PAGE_SIZE - addrbyte))//跨頁了
  {
      W25q64_PageProgram(buf, W25Q64_PAGE_SIZE - addrbyte, addr);//寫滿本頁
      addr += W25Q64_PAGE_SIZE-addrbyte;
      buf += W25Q64_PAGE_SIZE-addrbyte;
      len -= W25Q64_PAGE_SIZE-addrbyte;
      pagenum = len/W25Q64_PAGE_SIZE;
 
      while (pagenum--)
      {
        W25q64_PageProgram(buf, W25Q64_PAGE_SIZE, addr);
        addr += W25Q64_PAGE_SIZE;
        buf += W25Q64_PAGE_SIZE;
        len -= W25Q64_PAGE_SIZE;  
      }
      W25q64_PageProgram(buf, len, addr);
      
  }
  else
  {
    W25q64_PageProgram(buf, len, addr);
   
  } 
}


/*******************************************************************************
* Function Name  : W25q64_WriteStatus
* Description    : 寫狀态寄存器
* Input          : status:狀态值
* Output         : None
* Return         : None
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
void W25q64_WriteStatus(uint16_t status)
{
  W25q64_WriteEnable();

  CS1_RESET;

  W25q_ReadWriteByte(0x01);
  W25q_ReadWriteByte(status & 0xFF);
  W25q_ReadWriteByte((status>>8) & 0xFF);

  CS1_SET;

  W25q64_WaitForIdle();  
  
}

/*******************************************************************************
* Function Name  : W25q64_ReadStatus
* Description    : 讀狀态寄存器
* Input          : None
* Output         : None
* Return         : 狀态寄存器值
* Date           : 2014-10-24
* Author         : ADT LL
*******************************************************************************/
uint16_t W25q64_ReadStatus(void)
{
  uint16_t status=0;
  CS1_RESET;

  W25q_ReadWriteByte(0x05);
  status = W25q_ReadWriteByte(0xFF);

  CS1_SET;

  CS1_RESET;
  W25q_ReadWriteByte(0x35);
  status |= W25q_ReadWriteByte(0xFF)<<8;
  CS1_SET;

  
  return status;  
}

/*******************************************************************************
* Function Name  : W25q64_ReadDeviceID
* Description    : 讀字庫晶片ID
* Input          : None
* Output         : None
* Return         : None
* Date           : 2014-10-20
* Author         : ADT LL
*******************************************************************************/

uint16_t W25q64_ReadDeviceID(void)
{
  uint16_t DeviceID=0;

  CS1_RESET;

  W25q_ReadWriteByte(0x90);
  W25q_ReadWriteByte(0x00);
  W25q_ReadWriteByte(0x00);
  W25q_ReadWriteByte(0x00);

  DeviceID = W25q_ReadWriteByte(0xFF)<<8;
  DeviceID |= W25q_ReadWriteByte(0xFF);

  CS1_SET;

  return DeviceID;
}

/*******************************************************************************
* Function Name  : W25q64_Read
* Description    : 讀資料
* Input          : buf:資料緩沖區
                   len:長度
                   addr:起始位址
* Output         : None
* Return         : 傳回狀态,暫無意義
* Date           : 2014-10-20
* Author         : ADT LL
*******************************************************************************/
uint8_t W25q64_Read(uint8_t *buf, uint32_t len, uint32_t addr)
{
  uint32_t i;
  uint8_t status;

  //if (addr>=W25Q64_TOPADDR) return W25Q64_ADDRERROR;
  CS1_RESET;
    
  status = W25q_ReadWriteByte(CODE_READDATA);
  status = W25q_ReadWriteByte((addr & 0xFF0000)>>16);
  status = W25q_ReadWriteByte((addr & 0x00FF00)>>8);
  status = W25q_ReadWriteByte(addr & 0xFF);
  for (i=0; i<len; i++)
  {
    buf[i] = W25q_ReadWriteByte(0xFF);
  }

  status = 0;

  CS1_SET;

  return status;
}
           

二、SPI 接口驅動代碼

1.如果是GPIO模拟SPI

/*GPIO模拟SPI協定讀寫函數*/
uint8_t SPI_RW(uint8_t data)
{  
	char buf[24];
	uint8_t bit_ctr;
   	for(bit_ctr=0;bit_ctr<8;bit_ctr++)   // output 8-bit
   	{
		if((data & 0x80)) {
			MOSI_H;
		} else {
			MOSI_L;
		}
		data = (data << 1); 

		SCK_H;
		delayUs(1);
		data |= MISO ? 1 : 0;
		SCK_L;
		delayUs(1);
   	}

    return(data);    
}
           

2.如果是spi控制器讀寫spi

spi flash的CS片選如果接spi接口的SSEL要注意,由于 spi控制器的SSEL端不受代碼控制的,這裡我單獨用了一個gpio來做CS片選。

uint8_t  SSP_SendData(uint8_t data)
{  
#ifndef GPIO_SPI
    LPC_SSP1->DR = data;
    while( (LPC_SSP1->SR & 0x01) == 0 );   /* 等待TFE置位,即發送FIFO空    */
    while((LPC_SSP1->SR & 0x04) == 0);    /*等待接收fifo不為空*/
    return (LPC_SSP1->DR);
#else
    return SPI_RW(data);
#endif
}