STM32-SPI读写falsh-W25Q64

发布于:2023-01-22 ⋅ 阅读:(198) ⋅ 点赞:(0)

目录

1. SPI简介

1.1. SPI功能框图

1.2. 时钟时序图

 1.3. 全双工模式下寄存器变化示意图

 2. W25Q64简介

3. 编写驱动实现Flash读写

3.1. Cubemx配置SPI1通信

3.2. 编写程序


1. SPI简介

1.1. SPI功能框图

通常SPI通过4个引脚与外部器件相连:
● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
● SCK:串口时钟,作为主设备的输出,从设备的输入
● NSS:从设备选择。这是一个可选的引脚

1.2. 时钟时序图

SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态保持低电平;如果CPOL被置’1’,SCK引脚在空闲状态保持高电平。
如果CPHA(时钟相位)位被置’1’,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0’,SCK时钟的第一边沿(CPOL位为’0’时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位采样,数据在第一个时钟边沿被锁存。

 1.3. 全双工模式下寄存器变化示意图

主模式、全双工模式下(BIDIMODE=0并且RXONLY=0)连续传输时,TXE/RXNE/BSY的变化示意图

 2. W25Q64简介

W25Q64BV是64Mbit(即8MByte)的flash,通过SPI接口与STM32进行通信。

具体支持的特性如下:

• Family of SpiFlash Memories
– W25Q64BV: 64M-bit / 8M-byte (8,388,608)
– 256-bytes per programmable page
• Standard, Dual or Quad SPI
– Standard SPI: CLK, /CS, DI, DO, /WP, /Hold
– Dual SPI: CLK, /CS, IO0, IO1, /WP, /Hold
– Quad SPI: CLK, /CS, IO0, IO1, IO2, IO3
• Highest Performance Serial Flash
– Up to 6X that of ordinary Serial Flash
– 80MHz clock operation
– 160MHz equivalent Dual SPI
– 320MHz equivalent Quad SPI
– 40MB/S continuous data transfer rate
• Efficient “Continuous Read Mode”
– Low Instruction overhead
– As few as 8 clocks to address memory
– Allows true XIP (execute in place) operation
– Outperforms X16 Parallel Flash

• Low Power, Wide Temperature Range
– Single 2.7 to 3.6V supply
– 4mA active current, <1μA Power-down (typ.)
– -40°C to +85°C operating range
• Flexible Architecture with 4KB sectors
– Uniform Sector Erase (4K-bytes)
– Block Erase (32K and 64K-bytes)
– Program one to 256 bytes
– More than 100,000 erase/write cycles
– More than 20-year data retention
• Advanced Security Features
– Software and Hardware Write-Protect
– Top or Bottom, Sector or Block selection
– Lock-Down and OTP protection(1)
– 64-Bit Unique ID for each device(1)
• Space Efficient Packaging
– 8-pin SOIC 208-mil
– 8-pin PDIP 300-mil
– 8-pad WSON 8x6-mm
– 16-pin SOIC 300-mil
– Contact Winbond for KGD and other options

 扇区、块划分图:

 供应商和设备标识:

指令配置表:

3. 编写驱动实现Flash读写

3.1. Cubemx配置SPI1通信

模式:全双工主机模式

不开启硬件NSS

数据长度:8bit

MSB先行、时钟配置模式0(CPOL=0、CPHA=0)、分频因子配置为4:

 配置软件NSS为推挽输出: 

3.2. 编写程序

打开spi.h,输入如下代码:

#define WRITE_ENABLE     0x06
#define WRITE_DISABLE    0x04
#define DUMMY            0x00
#define WRITE_DATA       0x02
#define SECTOR_ERASE     0x20
#define JEDEC_ID         0x9F
#define READ_DATA        0x03
#define READ_STATUS1     0x05
#define FLASH_INFO(fmt,arg...)           printf("<<-FLASH-INFO->> "fmt"\n",##arg)

void writeW25Q64(uint8_t *address,uint8_t *writeData, uint16_t Size);
void readW25Q64(uint8_t *address,uint8_t *readData, uint16_t Size);
void jedecIDW25Q64(uint8_t *readData);
void sectorErase25Q64(uint8_t *address);
void waitForWriteEndW25Q64(void);

打开gpio.h:

#define W25Q_CS_L     HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET)
#define W25Q_CS_H     HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET)

 打开spi.c:

#include "gpio.h"
#include <stdio.h>

void writeEnableW25Q64(void)
{
	W25Q_CS_L;
	uint8_t instruction=WRITE_ENABLE;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	W25Q_CS_H;
}

void sectorErase25Q64(uint8_t *address)
{
	writeEnableW25Q64();
	W25Q_CS_L;
	uint8_t instruction=SECTOR_ERASE;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	HAL_SPI_Transmit(&hspi1, address, 3, 100);
	W25Q_CS_H;
	waitForWriteEndW25Q64();
}

void writeW25Q64(uint8_t *address,uint8_t *writeData, uint16_t Size)
{
	writeEnableW25Q64();
	W25Q_CS_L;
	uint8_t instruction=WRITE_DATA;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	HAL_StatusTypeDef tran=HAL_SPI_Transmit(&hspi1, address, 3, 100);
	HAL_SPI_Transmit(&hspi1, writeData, Size, 100);
	W25Q_CS_H;
	waitForWriteEndW25Q64();
}

void readW25Q64(uint8_t *address,uint8_t *readData, uint16_t Size)
{
	W25Q_CS_L;
	uint8_t instruction=READ_DATA;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	HAL_SPI_Transmit(&hspi1, address, 3, 100);
	HAL_SPI_Receive(&hspi1, readData, Size, 100);
	W25Q_CS_H;
}

void jedecIDW25Q64(uint8_t *readData)
{
	W25Q_CS_L;
	uint8_t instruction=JEDEC_ID;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	HAL_SPI_Receive(&hspi1, readData, 3, 100);
	W25Q_CS_H;
}

void waitForWriteEndW25Q64(void)
{
	W25Q_CS_L;
	uint8_t instruction=READ_STATUS1;
	HAL_SPI_Transmit(&hspi1, &instruction, 1, 100);
	uint8_t readData;
	HAL_SPI_Receive(&hspi1, &readData, 1, 100);
	while((readData&0x01)==1)
	{
		HAL_SPI_Receive(&hspi1, &readData, 1, 100);
	}
	W25Q_CS_H;
}

 打开main.c,测试是否成功发送和接收Flash数据:

	//读取JedecID
	uint8_t readJedecID[3];
	jedecIDW25Q64(readJedecID);
	printf("\nreadData:");
	for(int i=0;i<3;i++)
	{
		printf("%02X ",readJedecID[i]);
	}

	//擦除一个sector(4KB)
	uint8_t address[3]={0,0,0};
	sectorErase25Q64(address);
	
	//写入数据
	uint8_t writeData[30];
	for(int i=0;i<30;i++)
	{
		writeData[i]=i+9;
	}
	printf("\nwirteData:");
	for(int i=0;i<30;i++)
	{
		printf("%02X ",writeData[i]);
	}
	
	writeW25Q64(address,writeData, 30);
	
	//读取数据
	uint8_t readData[30];
	readW25Q64(address,readData, sizeof(readData)/sizeof(uint8_t));
	printf("\nreadData:");
	for(int i=0;i<30;i++)
	{
		printf("%02X ",readData[i]);
	}

 

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到