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

1

2

3

SPI配置步骤

1.使能SPI时钟
2.使能GPIO端口时钟
3.初始化GPIO,配置引脚模式
4.初始化SPI
5.使能SPI
6.SPI读写数据
7.查看SPI传输状态

1

举例
1
2
3

1
2

3

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);
}
posted @ 2017-08-22 15:33  thomas_blog  阅读(625)  评论(0编辑  收藏  举报