一、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
}