#include <STC12C5A60S2.H>
#include "W25Q80.H"
//4Kbytes为一个Sector
//16个扇区为1个Block
//W25X40
//容量为512K字节,共,128个Sector
//读取SPI_FLASH的状态寄存器
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR:默认0,状态寄存器保护位,配合WP使用
//TB,BP2,BP1,BP0:FLASH区域写保护设置
//WEL:写使能锁定
//BUSY:忙标记位(1,忙;0,空闲)
//默认:0x00
/*
1 /CS I 片选端输入
2 DO(IO1) I/O 数据输出(数据输入输出1)*1
3 /WP(IO2) I/O 写保护输入(数据输入输出2)*2
5 DI(IO0) I/O 数据输入(数据输入输出0)*1
6 CLK I 串行时钟输入
7 /HOLD(IO3) I/O 保持端输入(数据输入输出3)*2
*/
sbit CS = P1^7;
sbit DO = P0^6;
sbit WP = P1^5;
sbit HOLD = P1^4;
sbit CLK = P1^3;
sbit DI0 = P1^2;
sbit DI1 = P1^6;
sbit DI2 = P1^5;
sbit DI3 = P1^4;
/* 模拟SPI时序 */
UINT8 spi(UINT8 Spi_Byte)
{
UINT8 i;
for(i=0;i<8;i++)
{
if(Spi_Byte & 0x80) SI = 1;
else SI = 0;
Spi_Byte <<= 1;
CLK = 1;
if(SO) Spi_Byte |= 0X1;
CLK = 0;
}
return Spi_Byte;
}
/* 写使能 */
UINT8 Write_Enable(void)
{
char Spi_Byte;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X06); //发送指令
CS = 1;
return Spi_Byte;
}
/* 写禁止 */
void Write_Disable(void)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X04); //发送指令
CS = 1;
}
/* 读状态寄存器
输入: 状态寄存器1 / 状态寄存器2
输出:u8
u8 状态寄存器值1
或者
u8 状态寄存器值2
*/
UINT8 Read_Status_Register(UINT8 Status_Reg)
{
UINT8 temp=0;
CS = 0; //片选
if(Status_Reg == 1)
spi(0X05); //发送指令
if(Status_Reg == 2)
spi(0x35); //发送指令
temp |= spi(0Xff); //读寄存器
CS = 1;
return temp;
}
/* 写状态寄存器
输入: u16 状态寄存器值
*/
void Wriet_Status_Register(UINT16 Status_Reg)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X01); //发送指令
spi(Status_Reg>>8); //发送寄存器值
spi(Status_Reg); //发送寄存器值
CS = 1;
}
/* 掉电模式 */
void Power_down(void)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0XAB); //发送指令
CS = 1;
}
/* 读取制造商/设备 ID
输入: 无
输出:u16
b24-b16 数据0x00
b15-b8 Manufacturer ID
b7-b0 Manufacturer ID
*/
UINT32 Read_ManufacturerID(void)
{
UINT32 temp=0;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X90); //发送指令
spi(0X00);
spi(0X00);
temp |= (temp|=spi(0Xff))<<16;
temp |= (temp|=spi(0Xff))<<8;
temp |= spi(0Xff);
CS = 1;
return temp;
}
/* 读取JEDEC ID
输入: 无
输出:u32
b24-b16 制造商 ID=0xEF
b15-b8 JEDEC ID
b7-b0 JEDEC ID
*/
UINT32 Read_JEDECID(void)
{
UINT32 temp=0;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X9f); //发送指令
temp |= (temp|=spi(0Xff))<<16;
temp |= (temp|=spi(0Xff))<<8;
temp |= spi(0Xff);
CS = 1;
return temp;
}
/* 读取Unique ID
输入: 8byt指针
输出:8byt Unique ID
*/
void Read_UniqueID(UINT8 *UniqueID)
{
UINT8 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X4b); //发送指令
spi(0Xff);
spi(0Xff);
spi(0Xff);
spi(0Xff);
for(i=0;i<8;i++)
{
*UniqueID++ = spi(0Xff);
}
CS = 1;
}
/* 读取Read SFDP Register
输入: 地址,指针,长度
输出:SFDP Register
*/
void Read_SFDP_Register(UINT8 SFDP_Addr, UINT8 *SFDP_Data, UINT16 SFDP_Length)
{
UINT16 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X5A); //发送指令
spi(0X00);
spi(0X00);
spi(SFDP_Addr); //发送地址
spi(0X00);
for(i=0;i<SFDP_Length;i++)
{
*SFDP_Data++ = spi(0Xff);
}
CS = 1;
}
/* Erase Security Registers(擦除安全寄存器)
输入: 选择安全寄存器1,2,3
输出:NUM
*/
void Erase_Security_Registers(UINT8 Security_Registers)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X44); //发送指令
spi(0x00);
spi(Security_Registers<<4);
spi(0x00); //发送地址
CS = 1;
}
/* Program Security Registers(编程安全寄存器)
输入: 选择安全寄存器1,2,3
寄存器开始地址
寄存器值指针
长度
输出:NUM
*/
void Program_Security_Registers(UINT8 Security_Registers, UINT8 Security_Add, UINT8 *Regedit_Data, UINT16 Length)
{
UINT16 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X42); //发送指令
spi(0x00);
spi(Security_Registers<<4);
spi(Security_Add); //发送地址
for(i=0;i<Length;i++)
{
spi(*Regedit_Data++);
}
CS = 1;
}
/* Read Security Registers(读取安全寄存器)
输入: 选择安全寄存器1,2,3
寄存器开始地址
寄存器值指针
长度
输出:读取指针
*/
void Read_Security_Registers(UINT8 Security_Registers, UINT8 Security_Add, UINT8 *Regedit_Data, UINT16 Length)
{
UINT16 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X48); //发送指令
spi(0x00);
spi(Security_Registers<<4);
spi(Security_Add); //发送地址
spi(0x00); //伪数据
for(i=0;i<Length;i++)
{
*Regedit_Data++ = spi(0xff);//读取数据
}
CS = 1;
}
/* 读取数据
输入: 24b地址
输出:地址上的数据
*/
UINT8 Read_Data(UINT32 address)
{
UINT8 temp;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0x03); //发送读指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
temp = spi(0xff);
CS = 1;
return temp;
}
/* 快速读取单线数据
输入: 24b地址
缓存指针
长度
输出:地址上的数据
*/
void Fast_Read(UINT32 address, UINT8* pBuffer, UINT16 Length)
{
UINT16 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0x0b); //发送读指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
spi(0x00);
for(i=0;i<Length;i++)
{
*pBuffer++ = spi(0xff);
}
CS = 1;
}
/* 写入数据 (一次写入256字节,地址不为页开始地址会循环覆盖前面字节)
输入: 24b地址
缓存指针
长度
输出:无
*/
void Page_Program(UINT32 address, UINT8* pBuffer, UINT16 Length)
{
UINT16 i;
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0x02); //发送读指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
for(i=0;i<Length;i++)
{
spi(*pBuffer++);
}
CS = 1;
}
/* 擦除扇区(4kbye)
输入: 24b地址
输出:无
*/
void Sector_Erase(UINT32 address)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X20); //发送指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
CS = 1;
}
/* 擦除块(32kbye)
输入: 24b地址
输出:无
*/
void Block_Erase_32KB(UINT32 address)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X52); //发送指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
CS = 1;
}
/* 擦除块(64kbye)
输入: 24b地址
输出:无
*/
void Block_Erase_64KB(UINT32 address)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0Xd8); //发送指令
spi(address>>16); //发送地址
spi(address>>8);
spi(address);
CS = 1;
}
/* 擦除整片
输入: 24b地址
输出:无
*/
void Chip_Erase(void)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0XC7); //发送指令
CS = 1;
}
/* 暂停编程或擦除
输入: 无
输出:无
*/
void Erase_Program_Suspend(void)
{
volatile i;
CS = 0; //片选
spi(0X75); //发送指令
CS = 1;
for(i=0;i<1000;i++); //延时大于20us
}
/* 恢复编程或擦除
输入: 无
输出:无
*/
void Erase_Program_Resume(void)
{
while(BUSY);//等待芯片空闲
CS = 0; //片选
spi(0X7A); //发送指令
CS = 1;
}