教程:AT32F435 QSPI 读写W25Q256

这篇具有很好参考价值的文章主要介绍了教程:AT32F435 QSPI 读写W25Q256。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文使用的是雅特力 AT32F435VGT7作为测试QSPI接口的单片机主要参数如下:

博客原文链接

封装:LQFP100
Flash:1024KB
RAM:384KB
最大主频:288MHz
QSPI接口Flash:W25Q256FVEG
QSPI接口为2个 这里使用的是QSPI1

使用的接口为QSPI1,引脚对应如下:

单片机引脚 引脚定义 W25Q256引脚
35 QSPI_IO0 5脚DI
32 QSPI_IO1 2脚DO
33 QSPI_IO2 3脚WP
34 QSPI_IO3 7脚HOLD
36 QSPI_SCK 6脚CLK
47 QSPI_CS 1脚CS#

如下图所示:
w25q256中文数据手册,AT32F4系列,单片机,stm32,嵌入式硬件w25q256中文数据手册,AT32F4系列,单片机,stm32,嵌入式硬件
AT32F435的QSPI简介:
官方文档参考:
链接: AN0088_AT32_MCU_QSPI_Application_Note_ZH_V2.0.3w25q256中文数据手册,AT32F4系列,单片机,stm32,嵌入式硬件

W25Q256需要几个重要的命令如下表:

命令类型 命令 说明
W25X_WriteEnable 0x06 写使能
W25X_ReadStatusReg1 0x05 读状态寄存器1
W25X_ReadStatusReg2 0x35 读状态寄存器2
W25X_ReadStatusReg3 0x15 读状态寄存器3
W25X_WriteStatusReg2 0x31 写状态寄存器2
W25X_ManufactDeviceID 0x90 读手册ID
W25X_Enable4ByteAddr 0xB7 使能4字节地址模式
W25X_ChipErase 0xC7 全片擦除
W25X_SectorErase 0x20 扇区擦除
W25X_EnterQPIMode 0x38 使能QSPI模式
W25X_SetReadParam 0xC0 设置读速度
W25X_FastReadData 0x0B 快速读取数据
W25X_PageProgram 0x02 页编程

这里参考正点原子STM32F767开发文档说明:

状态寄存器3 S23 S22 S21 S20 S19 S18 S17 S16
位说明 HODL/RST DRV1 DRV0 WPS ADP ADS
状态寄存器2 S15 S14 S13 S12 S11 S10 S9 S8
位说明 SUS CMP LB3 LB2 LB1 QE SRP1
状态寄存器1 S7 S6 S5 S4 S3 S2 S1 S0
位说明 SRP0 TB BP3 BP2 BP1 BP0 BUSY

上面三个状态寄存器,我们只关心我们需要用到的一些位:ADSQEBUSY 位。其他位
的说明,请看 W25Q256 的数据手册。

ADS 位,表示 W25Q256 当前的地址模式,是一个只读位,当 ADS=0 的时候,表示当前是
3 字节地址模式,当 ADS=1 的时候,表示当前是 4 字节地址模式,我们需要使用 4 字节地址模
式,所以在读取到该位为 0 的时候,必须通过 W25X_Enable4ByteAddr 指令,设置为 4 字节地
址模式。

QE 位,用于使能 4 线模式(Quad),此位可读可写,并且是可以保存的(掉电后可以继续
保持上一次的值)。在本章,我们需要用到 4 线模式,所以在读到该位为 0 的时候,必须通过
W25X_WriteStatusReg2 指令设置此位为 1,表示使能 4 线模式。

BUSY 位,用于表示擦除/编程操作是否正在进行,当擦除/编程操作正在进行时,此位为 1,
此时 W25Q256 不接受任何指令,当擦除/编程操作完成时,此位为 0。此位为只读位,我们在执
行某些操作的时候,必须等待此位为 0。

W25X_ManufactDeviceID 指令,用于读取 W25Q256 的 ID,可以用于判断 W25Q256 是否正常。对于 W25Q256 来说:MF[7:0]=0XEF,ID[7:0]=0X18。

W25X_EnterQPIMode 指令,用于设置 W25Q256 进入 QPI 模式。上电时,W25Q256 默认是 SPI
模式,我们需要通过该指令设置其进入 QPI 模式。注意:在发送该指令之前,必须先设置状态
寄存器 2 的 QE 位为 1!!

W25X_Enable4ByteAddr 指令,用于设置 W25Q256 进入 4 字节地址模式。当读取到 ADS 位为
0 的时候,我们必须通过此指令将 W25Q256 设置为 4 字节地址模式,否则将只能访问 16MB 的地
址空间。

W25X_SetReadParam 指令,可以用于设置读参数控制位 P[5:4],具体参考数据手册
我们这里设置 P[5:4]=11,即可工作在 104Mhz的时钟频率下。此时,读取数据时的 dummy 时钟个数为 8 个(参见 W25X_FastReadData 指令)

W25X_WriteEnable 指令,用于设置 W25Q256 写使能。在执行擦除、编程、写状态寄存器等
操作之前,都必须通过该指令,设置 W25Q256 写使能,否则无法写入。

W25X_FastReadData 指令,用于读取 FLASH 数据,在发送完该指令以后,就可以读取 W25Q256
的数据了。该指令发送完成后,我们可以持续读取 FLASH 里面的数据,只要不停的给时钟,就
可以不停的读取数据。

W25X_PageProgram 指令,用于编程 FLASH(写入数据到 FLASH),该指令发送完成后,最
多可以一次写入 256 字节到 W25Q256,超过 256 字节则需要多次发送该指令。

W25X_SectorErase 指令,用于擦除一个扇区(4KB)的数据。因为 FLASH 具有只可以写 0,
不可以写 1 的特性,所以在写入数据的时候,一般需要先擦除(归 1),再写。W25Q256 的最小
擦除单位为一个扇区(4KB)。该指令在写入数据的时候,经常要有用。

W25X_ChipErase 指令,用于全片擦除 W25Q256。

接下来设置W25Q256的初始化步骤:
一 初始化AT32 QSPI接口IO引脚并设置为复用

	gpio_init_type gpio_init_struct;
	
  crm_periph_clock_enable(CRM_QSPI1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);


  gpio_default_para_init(&gpio_init_struct);

  //io0
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_0;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE0, GPIO_MUX_10);

  //io1
  gpio_init_struct.gpio_pins = GPIO_PINS_7;
  gpio_init(GPIOA, &gpio_init_struct);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_10);

  //io2
  gpio_init_struct.gpio_pins = GPIO_PINS_4;
  gpio_init(GPIOC, &gpio_init_struct);
  gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE4, GPIO_MUX_10);

	//io3
  gpio_init_struct.gpio_pins = GPIO_PINS_5;
  gpio_init(GPIOC, &gpio_init_struct);
  gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE5, GPIO_MUX_10);

  //sck
  gpio_init_struct.gpio_pins = GPIO_PINS_1;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE1, GPIO_MUX_9);

  //cs
  gpio_init_struct.gpio_pins = GPIO_PINS_10;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE10, GPIO_MUX_9);

二 切换 QSPI 控制器到 XIP 模式或命令从模式

qspi_xip_enable(QSPI1, FALSE);

三 设置 HCLK 到 SCLK 的分频
这里时钟288Mhz 设置为4分频就是72MHz

qspi_clk_division_set(QSPI1, QSPI_CLK_DIV_4);

四 设置 SCLK 在 idle 时的电位

qspi_sck_mode_set(QSPI1, QSPI_SCK_MODE_0);

五 设置 FLASH 规格中 Status 的 WIP 位置

qspi_busy_config(QSPI1, QSPI_BUSY_OFFSET_0);

六 使能QSPI模式

W25Qxx_QSPI_Enable();

七 设置为4字节地址模式,否则只能读到16MB

W25Qxx_QSPI_4ByteAdd();

八 设置QSPI模式为最大时钟104MHz

W25Qxx_QSPI_MaxSCK();

杰西莱展示QSPI具体的QSPI.c和QSPI.h和main.c文件
一 QSPI.h文件

#ifndef __QSPIFLASH_H
#define __QSPIFLASH_H




#include "system.h"



//指令表
#define W25X_WriteEnable        0x06 
#define W25X_WriteDisable       0x04 
#define W25X_ReadStatusReg1     0x05 
#define W25X_ReadStatusReg2     0x35 
#define W25X_ReadStatusReg3     0x15 

#define W25X_WriteStatusReg1    0x01 
#define W25X_WriteStatusReg2    0x31 
#define W25X_WriteStatusReg3    0x11 

#define W25X_ReadData			     0x03 
#define W25X_FastReadData		   0x0B 
#define W25X_FastReadDual		   0x3B 
#define W25X_PageProgram		   0x02
#define W25X_QPIPageProgram    0x32
#define W25X_BlockErase			   0xD8 
#define W25X_SectorErase		   0x20 
#define W25X_ChipErase			   0xC7 
#define W25X_PowerDown			   0xB9 
#define W25X_ReleasePowerDown	 0xAB 
#define W25X_DeviceID			     0xAB 
#define W25X_ManufactDeviceID	 0x90 
#define W25X_JedecDeviceID		 0x9F 
#define W25X_Enable4ByteAddr   0xB7
#define W25X_Exit4ByteAddr     0xE9
#define W25X_SetReadParam		   0xC0 
#define W25X_EnterQPIMode      0x38
#define W25X_ExitQPIMode       0xFF


void W25Qxx_QSPI_Init(void);

void W25Qxx_QSPI_Enable(void);
u16  W25Qxx_QSPI_readID(void);
void W25Qxx_QSPI_4ByteAdd(void);
void W25Qxx_QSPI_MaxSCK(void);
void W25Qxx_QSPI_EraseChip(void);
void W25Qxx_QSPI_EraseSector(u32 Addr);
void W25Qxx_QSPI_Page(u8* pbuff,u32 Addr,u16 wlen);

void W25Qxx_QSPI_Read(u8* pbuff,u32 Addr,u16 rlen);
void W25Qxx_QSPI_Write(u8* pBuffer,u32 WriteAddr,u16 wlen);

#endif

二 QSPI.c文件

#include "QSPIFlash.h"
#include "CH340N.h"

u8 W25Qxx_QSPI_readSR(u8 cmd);
void W25Qxx_QSPI_SendCMD(u8 cmd);
void W25Qxx_QSPI_writeSR(u8 cmd,u8 data);

//初始化
void W25Qxx_QSPI_Init(void)
{
	gpio_init_type gpio_init_struct;
	
  crm_periph_clock_enable(CRM_QSPI1_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);


  gpio_default_para_init(&gpio_init_struct);

  //io0
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_0;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE0, GPIO_MUX_10);

  //io1
  gpio_init_struct.gpio_pins = GPIO_PINS_7;
  gpio_init(GPIOA, &gpio_init_struct);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_10);

  //io2
  gpio_init_struct.gpio_pins = GPIO_PINS_4;
  gpio_init(GPIOC, &gpio_init_struct);
  gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE4, GPIO_MUX_10);

	//io3
  gpio_init_struct.gpio_pins = GPIO_PINS_5;
  gpio_init(GPIOC, &gpio_init_struct);
  gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE5, GPIO_MUX_10);

  //sck
  gpio_init_struct.gpio_pins = GPIO_PINS_1;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE1, GPIO_MUX_9);

  //cs
  gpio_init_struct.gpio_pins = GPIO_PINS_10;
  gpio_init(GPIOB, &gpio_init_struct);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE10, GPIO_MUX_9);
	
	qspi_xip_enable(QSPI1, FALSE);
  qspi_clk_division_set(QSPI1, QSPI_CLK_DIV_4);
  qspi_sck_mode_set(QSPI1, QSPI_SCK_MODE_0);
  qspi_busy_config(QSPI1, QSPI_BUSY_OFFSET_0);
	
	W25Qxx_QSPI_Enable();
	W25Qxx_QSPI_4ByteAdd();
	W25Qxx_QSPI_MaxSCK();
}



//使能QSPI 4线模式
void W25Qxx_QSPI_Enable(void)
{
	u8 state=0;
	qspi_cmd_type qspi_cmd_struct;
	
	//读状态寄存器2
	qspi_cmd_struct.pe_mode_enable = FALSE;
  qspi_cmd_struct.pe_mode_operate_code = 0;
  qspi_cmd_struct.instruction_code = W25X_ReadStatusReg2;
  qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
  qspi_cmd_struct.address_code = 0;
  qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
  qspi_cmd_struct.data_counter = 1;
  qspi_cmd_struct.second_dummy_cycle_num = 0;
  qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_111;
  qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
  qspi_cmd_struct.read_status_enable = FALSE;
  qspi_cmd_struct.write_data_enable = FALSE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_RXFIFORDY_FLAG) == RESET);
	state=qspi_byte_read(QSPI1);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	
	if((state&0x02)==0)
	{
		//发送写使能
		qspi_cmd_struct.pe_mode_enable = FALSE;
		qspi_cmd_struct.pe_mode_operate_code = 0;
		qspi_cmd_struct.instruction_code = W25X_WriteEnable;
		qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
		qspi_cmd_struct.address_code = 0;
		qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
		qspi_cmd_struct.data_counter = 0;
		qspi_cmd_struct.second_dummy_cycle_num = 0;
		qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_111;
		qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
		qspi_cmd_struct.read_status_enable = FALSE;
		qspi_cmd_struct.write_data_enable = TRUE;
		qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
		while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
		qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
		
		//写状态寄存器
		state|=1<<1;
		qspi_cmd_struct.pe_mode_enable = FALSE;
		qspi_cmd_struct.pe_mode_operate_code = 0;
		qspi_cmd_struct.instruction_code = W25X_WriteStatusReg2;
		qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
		qspi_cmd_struct.address_code = 0;
		qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
		qspi_cmd_struct.data_counter = 1;
		qspi_cmd_struct.second_dummy_cycle_num = 0;
		qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_111;
		qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
		qspi_cmd_struct.read_status_enable = FALSE;
		qspi_cmd_struct.write_data_enable = TRUE;
		qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	
		while(qspi_flag_get(QSPI1, QSPI_TXFIFORDY_FLAG) == RESET);
		qspi_byte_write(QSPI1, state);
	
		while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
		qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	}
	
	//发送4线命令
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_EnterQPIMode;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = 0;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	qspi_cmd_struct.data_counter = 0;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_111;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
}

//读W25Q256FVEG ID
u16 W25Qxx_QSPI_readID(void)
{
	u16 temp=0,ID=0;
	
	qspi_cmd_type qspi_cmd_struct;
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
  qspi_cmd_struct.pe_mode_operate_code = 0;
  qspi_cmd_struct.instruction_code = W25X_ManufactDeviceID;
  qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
  qspi_cmd_struct.address_code = 0;
  qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_3_BYTE;
  qspi_cmd_struct.data_counter = 2;
  qspi_cmd_struct.second_dummy_cycle_num = 0;
  qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
  qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
  qspi_cmd_struct.read_status_enable = FALSE;
  qspi_cmd_struct.write_data_enable = FALSE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_RXFIFORDY_FLAG) == RESET);
	
	temp=qspi_half_word_read(QSPI1);
	
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	
	ID=(temp<<8)|(temp>>8);
	
	return ID;
}

//写使能
void W25Qxx_QSPI_writeEN(void)
{
	qspi_cmd_type qspi_cmd_struct;
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_WriteEnable;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = 0;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	qspi_cmd_struct.data_counter = 0;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
}

//设置4字节地址模式
void W25Qxx_QSPI_4ByteAdd(void)
{
	qspi_cmd_type qspi_cmd_struct;
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_Enable4ByteAddr;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = 0;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	qspi_cmd_struct.data_counter = 0;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
}


//忙检查
void W25Qxx_QSPI_Busy(void)
{
	u8 state=0;
	qspi_cmd_type qspi_cmd_struct;
	do
	{
		qspi_cmd_struct.pe_mode_enable = FALSE;
		qspi_cmd_struct.pe_mode_operate_code = 0;
		qspi_cmd_struct.instruction_code = W25X_ReadStatusReg1;
		qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
		qspi_cmd_struct.address_code = 0;
		qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
		qspi_cmd_struct.data_counter = 1;
		qspi_cmd_struct.second_dummy_cycle_num = 0;
		qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
		qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
		qspi_cmd_struct.read_status_enable = FALSE;
		qspi_cmd_struct.write_data_enable = FALSE;
		qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
		while(qspi_flag_get(QSPI1, QSPI_RXFIFORDY_FLAG) == RESET);
		state=qspi_byte_read(QSPI1);
		while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
		qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	}while(state&0x01);
}


//设置读最大时钟104MHz
void W25Qxx_QSPI_MaxSCK(void)
{
	u8 data=0;
	qspi_cmd_type qspi_cmd_struct;
	
	W25Qxx_QSPI_writeEN();
	W25Qxx_QSPI_Busy();
	
	data=3<<4;
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_SetReadParam;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = 0;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	qspi_cmd_struct.data_counter = 1;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);

	while(qspi_flag_get(QSPI1, QSPI_TXFIFORDY_FLAG) == RESET);
	qspi_byte_write(QSPI1, data);

	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
}

//整片擦除
void W25Qxx_QSPI_EraseChip(void)
{
	qspi_cmd_type qspi_cmd_struct;
	
	W25Qxx_QSPI_writeEN();
	W25Qxx_QSPI_Busy();
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_ChipErase;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = 0;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_0_BYTE;
	qspi_cmd_struct.data_counter = 0;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	
	W25Qxx_QSPI_Busy();
}


//扇区擦除
void W25Qxx_QSPI_EraseSector(u32 Addr)
{
	qspi_cmd_type qspi_cmd_struct;
	
	W25Qxx_QSPI_writeEN();
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
	qspi_cmd_struct.pe_mode_operate_code = 0;
	qspi_cmd_struct.instruction_code = W25X_SectorErase;
	qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
	qspi_cmd_struct.address_code = Addr;
	qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_4_BYTE;
	qspi_cmd_struct.data_counter = 0;
	qspi_cmd_struct.second_dummy_cycle_num = 0;
	qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
	qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
	qspi_cmd_struct.read_status_enable = FALSE;
	qspi_cmd_struct.write_data_enable = TRUE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
	qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
	
	W25Qxx_QSPI_Busy();
}

//读取数据
void W25Qxx_QSPI_Read(u8* pbuff,u32 Addr,u16 rlen)
{
	u16 len=0,i=0;
	qspi_cmd_type qspi_cmd_struct;
	
	qspi_cmd_struct.pe_mode_enable = FALSE;
  qspi_cmd_struct.pe_mode_operate_code = 0;
  qspi_cmd_struct.instruction_code = W25X_FastReadData;
  qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
  qspi_cmd_struct.address_code = Addr;
  qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_4_BYTE;
  qspi_cmd_struct.data_counter = rlen;
  qspi_cmd_struct.second_dummy_cycle_num = 8;
  qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
  qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
  qspi_cmd_struct.read_status_enable = FALSE;
  qspi_cmd_struct.write_data_enable = FALSE;
	qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
	
	do
	{
		if(rlen>=128) //FIFO最大128字节
			len=128;
		else
			len=rlen;
		
		while(qspi_flag_get(QSPI1, QSPI_RXFIFORDY_FLAG) == RESET);
		for(i = 0; i < len; i++)
    {
      *pbuff++ = qspi_byte_read(QSPI1);
    }
		rlen-=len;
	}while(rlen);
	
	while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET){}
  qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
}


// 页写入 最大256字节
void W25Qxx_QSPI_Page(u8* pbuff,u32 Addr,u16 wlen)
{
	u16 len=0,i=0;
	qspi_cmd_type qspi_cmd_struct;
	
	do
  {
		W25Qxx_QSPI_writeEN();
		W25Qxx_QSPI_Busy();
		
		qspi_cmd_struct.pe_mode_enable = FALSE;
		qspi_cmd_struct.pe_mode_operate_code = 0;
		qspi_cmd_struct.instruction_code = W25X_PageProgram;
		qspi_cmd_struct.instruction_length = QSPI_CMD_INSLEN_1_BYTE;
		qspi_cmd_struct.address_code = Addr;
		qspi_cmd_struct.address_length = QSPI_CMD_ADRLEN_4_BYTE;
		qspi_cmd_struct.data_counter = wlen;
		qspi_cmd_struct.second_dummy_cycle_num = 0;
		qspi_cmd_struct.operation_mode = QSPI_OPERATE_MODE_444;
		qspi_cmd_struct.read_status_config = QSPI_RSTSC_HW_AUTO;
		qspi_cmd_struct.read_status_enable = FALSE;
		qspi_cmd_struct.write_data_enable = TRUE;
		qspi_cmd_operation_kick(QSPI1,&qspi_cmd_struct);
		
		if(wlen>=128)
			len=128;
		else
			len=wlen;
		
    for(i = 0; i < len; i++)
    {
      while(qspi_flag_get(QSPI1, QSPI_TXFIFORDY_FLAG) == RESET);
      qspi_byte_write(QSPI1, *pbuff++);
    }
    wlen -= len;
    Addr += len;
		
    while(qspi_flag_get(QSPI1, QSPI_CMDSTS_FLAG) == RESET);
    qspi_flag_clear(QSPI1, QSPI_CMDSTS_FLAG);
		
    W25Qxx_QSPI_Busy();
  }while(wlen);
}

//不检查擦除写入
void W25Qx_QSPI_wNoCheck(u8* pBuffer,u32 WriteAddr,u16 wlen)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(wlen<=pageremain)pageremain=wlen;//不大于256个字节
	while(1)
	{	   
		W25Qxx_QSPI_Page(pBuffer,WriteAddr,pageremain);
		
		if(wlen==pageremain)
			break;//写入结束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;
			
			wlen-=pageremain;			  //减去已经写入了的字节数
			
			if(wlen>256)
				pageremain=256; 							//一次可以写入256个字节
			else 
				pageremain=wlen; 	  //不够256个字节了
		}
	}   
} 


//数据写入函数
u8 W25QXX_BUFFER[4096];		 
void W25Qxx_QSPI_Write(u8* pBuffer,u32 WriteAddr,u16 wlen)   
{ 
	u32 secpos;
	u16 secoff;
	u16 secremain;	   
 	u16 i;    
	u8 * W25QXX_BUF;	  
   	W25QXX_BUF=W25QXX_BUFFER;	     
 	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小   
 	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
 	if(wlen<=secremain)secremain=wlen;//不大于4096个字节
	while(1) 
	{	
		W25Qxx_QSPI_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			W25Qxx_QSPI_EraseSector(secpos);//擦除这个扇区
			for(i=0;i<secremain;i++)	   //复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			W25Qx_QSPI_wNoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  

		}
		else 
			W25Qx_QSPI_wNoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
		if(wlen==secremain)
			break;//写入结束了
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 

		  pBuffer+=secremain;  		  //指针偏移
			WriteAddr+=secremain;		  //写地址偏移	   
		  wlen-=secremain;//字节数递减
			
			if(wlen>4096)
				secremain=4096;					  //下一个扇区还是写不完
			else 
				secremain=wlen;	//下一个扇区可以写完了
		}	 
	};	 
}

三main.c文件

#include "system.h"
#include "at32f435_437_clock.h"
#include "CH340N.h"
#include "Time_APP.h"
#include "QSPIFlash.h"


u8 buf1[]="10086111";
u8 buf2[20]={0};

int main(void)
{
	u8 state1=0,state2=0,state3=0;
	
	system_clock_config();
	
	SYS_clock_Init();
	
	SYS_nvic_config();
	
	User_Time_Init();
	
	CH340N_Init(115200);
	
	
	W25Qxx_QSPI_Init();
	
	CH340_Printf("AT32 MCU init\r\n");
	CH340_Printf("Flash ID:%04X\r\n",W25Qxx_QSPI_readID());
	
	CH340_Printf("Erase done\r\n");
	
	W25Qxx_QSPI_EraseSector(0);
	W25Qxx_QSPI_Page(buf1,0,strlen((char *)buf1));
	W25Qxx_QSPI_Read(buf2,0,strlen((char *)buf1));
	
	CH340_Printf("read:%s\r\n",buf2);
	

	while(1)
	{
	
	}
}

到这里文章已完结,后续测试一下读写的速度。以上内容如有侵权请联系我删除。
个人微信:LLQuser 注明来意。也可技术交流

转载本文章请注明出处文章来源地址https://www.toymoban.com/news/detail-663198.html

到了这里,关于教程:AT32F435 QSPI 读写W25Q256的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023版 STM32实战11 SPI总线读写W25Q

    英文全称:Serial peripheral Interface 串行外设接口 -1- 串行(逐bit传输) -2- 同步(共用时钟线) -3- 全双工(收发可同时进行) -4- 通信只能由主机发起(一主,多从机) -1- CS片选一般配置为软件控制 -2- 片选低电平有效,从器件CS引脚可直接连接GND -3- 从机不能主动给主机发数据 -4- 主机想要

    2024年02月08日
    浏览(36)
  • 【STM32】STM32学习笔记-硬件SPI读写W25Q64(40)

    在大容量产品和互联型产品上,SPI接口可以配置为支持SPI协议或者支持I2S音频协议。SPI接口默认工作在SPI方式,可以通过软件把功能从SPI模式切换到I2S模式。 在小容量和中容量产品上,不支持I2S音频协议。 串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方式

    2024年02月19日
    浏览(68)
  • 【STM32】STM32学习笔记-软件SPI读写W25Q64(38)

    在大容量产品和互联型产品上,SPI接口可以配置为支持SPI协议或者支持I 2 S音频协议。SPI接口默认工作在SPI方式,可以通过软件把功能从SPI模式切换到I2S模式。 在小容量和中容量产品上,不支持I 2 S音频协议。 串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方

    2024年01月24日
    浏览(46)
  • 【STM32CubeMX学习】SPI读写W25Q16

            SPI分为主从工作模式,通常有一个主设备和一个或多个从设备,本文中MCU为主机,W25Q16为从机。 SPI通信有以下四根线: MISO:主设备数据输入,从设备数据输出。 MOSI:主设备数据输出,从设备数据输入。 SCLK:时钟信号,由主设备产生。 CS:从设备片选信号,由

    2024年02月03日
    浏览(46)
  • 基于STM32实现W25Q16读写操作(spi)

    在之前我们学习了flash闪存,这个更多的是内部数据存储,容量也是会比较小。这次我们来学习一下更多的存储单元w25q16,顺便了解spi———串行外围设备接口。 在我们的核心板子上基本都会有这么一块芯片,只是有的容量会计较大,大家可以查看板子的原理图,如图所示:

    2024年01月19日
    浏览(36)
  • stm32使用外部flash w25Q128实现读写操作

    数据保存是所有项目的基本功能,但是对于STM32C8T6的原flash进行操作,一方面大小有可能不够,另一方面单片机的运行程序本来就放在这个里面,所以还是外接的好。这里选用w25Q128 FLASH存储器,参考实现简单读写。 作为一个初学者,技能都是东拼西凑的,基础可能不扎实,如

    2023年04月08日
    浏览(50)
  • 【STM32】SPI初步使用 读写FLASH W25Q64

    (1) SS( Slave Select):从设备选择信号线,常称为片选信号线,每个从设备都有独立的这一条 NSS 信号线,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI通讯。所以 SPI通讯以 NSS 线置低电

    2024年02月10日
    浏览(53)
  • STM32—SPI详解入门(使用SPI通讯读写W25Q128模块)

    目录 一、SPI是什么 二、SPI物理架构 三、SPI工作原理 四、SPI工作模式 五、SPI相关寄存器介绍 六、SPI用到的结构体与函数 1.结构体 2.函数 七、W25Q128芯片 1.W25Q128介绍 2.W25Q128存储架构 3.W25Q128常用指令 4.W25Q128状态寄存器 5.W25Q128常见操作流程 八、实验(使用SPI通讯读写W25Q128模块

    2024年02月14日
    浏览(50)
  • STM32-SPI通信(W25Q64芯片简介,使用SPI读写W25Q64存储器芯片)

    ​  SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)。 ​SPI通信具有以下特点: 同步,全双工; 支持总线挂载多设备(SPI仅支持一主多从); 在不

    2024年02月08日
    浏览(46)
  • STM32使用QUADSPI读写外部Nor Flash(以W25Q64为例)

    QUADSPI 是一种专用的通信接口,连接单、双或四(条数据线) SPI Flash 存储介质。该接 口可以在以下三种模式下工作: ①间接模式:使用 QUADSPI 寄存器执行全部操作。 ②状态轮询模式:周期性读取外部 Flash 状态寄存器,而且标志位置 1 时会产生中断(如擦除或烧写完成,会

    2024年02月11日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包