stm32 SPI-FLASH W25Q64
The W25Q64BV array is organized into 32,768 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time. Pages can be erased in groups of 16 (sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or the entire chip (chip erase)
BUSY is a read only bit in the status register (S0) that is set to a 1 state when the device is executing a Page Program, Sector Erase, Block Erase, Chip Erase or Write Status Register instruction
W25Q64
SPI配置步骤
1.使能SPI时钟
2.使能GPIO端口时钟
3.初始化GPIO,配置引脚模式
4.初始化SPI
5.使能SPI
6.SPI读写数据
7.查看SPI传输状态
举例
typedef struct
{
uint16_t SPI_Direction;
uint16_t SPI_Mode;
uint16_t SPI_DataSize; //数据帧格式
uint16_t SPI_CPOL; //时钟极性
uint16_t SPI_CPHA; //时钟相位
uint16_t SPI_NSS; //软件从设备管理
uint16_t SPI_BaudRatePrescaler; //波特率控制
uint16_t SPI_FirstBit; //帧格式
uint16_t SPI_CRCPolynomial; //CRC多项式寄存器
}SPI_InitTypeDef;
#define EN25X_WriteEnable 0x06
#define EN25X_WriteDisable 0x04
#define EN25X_ReadStatusReg 0x05
#define EN25X_WriteStatusReg 0x01
#define EN25X_ReadData 0x03
#define EN25X_FastReadData 0x0B
#define EN25X_FastReadDual 0x3B
#define EN25X_PageProgram 0x02
#define EN25X_BlockErase 0xD8
#define EN25X_SectorErase 0x20
#define EN25X_ChipErase 0xC7
#define EN25X_PowerDown 0xB9
#define EN25X_Continue_Read 0xFF
#define EN25X_ReleasePowerDown 0xAB
#define EN25X_DeviceID 0xAB
#define EN25X_ManufactDeviceID 0x90
#define EN25X_JedecDeviceID 0x9F
void SPI_init()
{
GPIO_InitTypeDef gpio =
{
GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15,
GPIO_Speed_50MHz,
GPIO_Mode_AF_PP
};
SPI_InitTypeDef spi =
{
SPI_Direction_2Lines_FullDuplex,
SPI_Mode_Master, //0x0104
SPI_DataSize_8b,
SPI_CPOL_High,
SPI_CPHA_2Edge,
SPI_NSS_Soft,
SPI_BaudRatePrescaler_256,
SPI_FirstBit_MSB,
7
};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //使能SPI时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIO端口时钟
GPIO_Init(GPIOB, &gpio); //初始化GPIO,配置引脚模式
SPI_Init(SPI2, &spi); //初始化SPI
SPI_Cmd(SPI2, ENABLE); //使能SPI
}
void SPI2_SetSpeed(u8 rate)
{
SPI2->CR1 &= 0xFFC7;
SPI2->CR1 |= rate;
SPI_Cmd(SPI2, ENABLE);
}
void EN25Q64_init()
{
GPIO_InitTypeDef gpiob =
{
GPIO_Pin_12,
GPIO_Speed_50MHz,
GPIO_Mode_Out_PP
};
GPIO_InitTypeDef gpiog13 =
{
GPIO_Pin_13,
GPIO_Speed_50MHz,
GPIO_Mode_Out_PP
};
GPIO_InitTypeDef gpiog14 =
{
GPIO_Pin_13,
GPIO_Speed_50MHz,
GPIO_Mode_Out_PP
};
GPIO_InitTypeDef gpiof =
{
GPIO_Pin_9,
GPIO_Speed_50MHz,
GPIO_Mode_Out_PP
};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG | RCC_APB2Periph_GPIOF, ENABLE);
GPIO_Init(GPIOB, &gpiob);
SPI2_NSS = 1; //以太网模块片选(拉高,防止干扰)
GPIO_Init(GPIOG, &gpiog13);
FLASH_CS = 1; //FLASH片选
GPIO_Init(GPIOG, &gpiog14);
SD_CS = 1; //SD卡模块片选
GPIO_Init(GPIOF, &gpiof);
TUB_4 = 1; //NRF24L01模块片选
SPI_init();
}
u8 SPI_read_write(u16 d) //SPI读写数据
{
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) != SET);
SPI_I2S_SendData(SPI2, d);
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != SET);
return SPI_I2S_ReceiveData(SPI2);
}
u16 EN25Q64_read_id()
{
u16 r;
FLASH_CS = 0;
SPI_read_write(EN25X_ManufactDeviceID);
SPI_read_write(0); //dummy
SPI_read_write(0);
SPI_read_write(0);
r = SPI_read_write(EN25X_Continue_Read) << 8;
r = SPI_read_write(EN25X_Continue_Read);
FLASH_CS = 1;
return r;
}
void EN25Q64_read_unique_id(u8 *id)
{
int i = 0;
FLASH_CS = 0;
SPI_read_write(0x4B);
SPI_read_write(0); //dummy
SPI_read_write(0);
SPI_read_write(0);
SPI_read_write(0);
for(i = 0; i < 8; i++)
{
id[i] = SPI_read_write(0xFF);
}
FLASH_CS = 1;
}
u8 EN25Q64_read_status()
{
u8 r;
FLASH_CS = 0;
SPI_read_write(EN25X_ReadStatusReg);
r = SPI_read_write(EN25X_Continue_Read);
FLASH_CS = 1;
return r;
}
void EN25Q64_read(u8 *buf, u32 addr, u16 num)
{
u16 i = 0;
FLASH_CS = 0;
SPI_read_write(EN25X_ReadData);
SPI_read_write((u8)(addr) >> 16); //24bit地址
SPI_read_write((u8)(addr) >> 8);
SPI_read_write((u8)addr);
for(i = 0; i < num; i++)
{
buf[i] = SPI_read_write(EN25X_Continue_Read);
}
FLASH_CS = 1;
}
void EN25Q64_write_enable()
{
FLASH_CS = 0;
SPI_read_write(EN25X_WriteEnable);
FLASH_CS = 1;
}
void EN25Q64_write_disable()
{
FLASH_CS = 0;
SPI_read_write(EN25X_WriteEnable);
FLASH_CS = 1;
}
void EN25Q64_write_status(u8 s)
{
FLASH_CS = 0;
SPI_read_write(EN25X_WriteDisable);
SPI_read_write(s);
FLASH_CS = 1;
}
void EN25Q64_is_busy()
{
while((EN25Q64_read_status() & 0x01) == 0x01); //BUSY
}
void EN25Q64_write_page(u8 *buf, u32 addr, u16 num) //页写
{
u16 i = 0;
EN25Q64_write_enable();
FLASH_CS = 0;
SPI_read_write(EN25X_PageProgram); //Page Program
SPI_read_write(addr >> 16);
SPI_read_write(addr >> 8);
SPI_read_write(addr);
for(i = 0; i < num; i++)
{
SPI_read_write(buf[i]);
}
FLASH_CS = 1;
EN25Q64_is_busy();
}
void EN25Q64_write_nocheck(u8 *buf, u32 addr, u16 num)
{
u8 *b = buf;
u32 a = addr;
u16 n = num;
n = 256 - (num % 256); //写满一页
while(1)
{
EN25Q64_write_page(b, a, n);
if(n == num)
{
break;
}
b += n;
a += n;
num -= n;
if(num > 256)
{
n = 256;
}
else
{
n = num;
}
}
}
void EN25Q64_sector_erase(u32 a)
{
EN25Q64_write_enable();
EN25Q64_is_busy();
FLASH_CS = 0;
SPI_read_write(EN25X_SectorErase);
SPI_read_write((u8)a >> 16);
SPI_read_write((u8)a >> 8);
SPI_read_write(a);
FLASH_CS = 1;
EN25Q64_is_busy();
}
u8 EN25QXX_BUF[4096];
void EN25Q64_write(u8 *buf, u32 addr, u16 num)
{
u16 i;
u32 pos;
u16 offset;
u16 n;
u8 *b = buf;
pos = addr / 4096; //扇区位置
offset = addr % 4096;
n = 4096 - offset ; //写满扇区
if(num <= n)
{
n = num;
}
while(1)
{
EN25Q64_read(EN25QXX_BUF, pos * 4096, 4096); //读出整个扇区
EN25Q64_sector_erase(pos); //擦除整个扇区
for(i = 0; i < n; i++)
{
EN25QXX_BUF[i + offset] = b[i];
}
EN25Q64_write_nocheck(EN25QXX_BUF, pos * 4096, 4096); //写入整个扇区
if(n == num)
{
break;
}
pos++;
num -= n;
offset = 0;
b += n;
if(num > 4096)
{
n = 4096;
}
else
{
n = num;
}
}
}
void EN25Q64_chip_erase()
{
EN25Q64_write_enable();
EN25Q64_is_busy();
FLASH_CS = 0;
SPI_read_write(EN25X_ChipErase);
FLASH_CS = 1;
EN25Q64_is_busy();
}
void EN25Q64_power_down()
{
FLASH_CS = 0;
SPI_read_write(EN25X_PowerDown);
FLASH_CS = 1;
delay_us(3);
}
void EN25Q64_release_power_down()
{
FLASH_CS = 0;
SPI_read_write(EN25X_ReleasePowerDown);
FLASH_CS = 1;
delay_us(3);
}