一、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控制器
}
/*******************************************************************************
* 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
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
}