• 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);
    }
    
  • 相关阅读:
    codeblocks 更换颜色主题
    python3 回顾笔记1
    linux查找目录下的所有文件中是否含有某个字符串
    jupyter notebook 远程访问
    ubuntu ufw防火墙
    加载大量的xml数据 使用压缩方法解决(当然较小时也可以压缩)
    lua string介绍
    Lua和C++交互详细总结
    编写高性能的 Lua 代码
    lua中遍历table的几种方式比较
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709548.html
Copyright © 2020-2023  润新知