当前位置:   article > 正文

教程:AT32F435 QSPI 读写W25Q256

w25q256

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

博客原文链接

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

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

单片机引脚引脚定义W25Q256引脚
35QSPI_IO05脚DI
32QSPI_IO12脚DO
33QSPI_IO23脚WP
34QSPI_IO37脚HOLD
36QSPI_SCK6脚CLK
47QSPI_CS1脚CS#

如下图所示:
W25Q256引脚图MCU引脚图
AT32F435的QSPI简介:
官方文档参考:
链接: AN0088_AT32_MCU_QSPI_Application_Note_ZH_V2.0.3在这里插入图片描述

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

命令类型命令说明
W25X_WriteEnable0x06写使能
W25X_ReadStatusReg10x05读状态寄存器1
W25X_ReadStatusReg20x35读状态寄存器2
W25X_ReadStatusReg30x15读状态寄存器3
W25X_WriteStatusReg20x31写状态寄存器2
W25X_ManufactDeviceID0x90读手册ID
W25X_Enable4ByteAddr0xB7使能4字节地址模式
W25X_ChipErase0xC7全片擦除
W25X_SectorErase0x20扇区擦除
W25X_EnterQPIMode0x38使能QSPI模式
W25X_SetReadParam0xC0设置读速度
W25X_FastReadData0x0B快速读取数据
W25X_PageProgram0x02页编程

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

状态寄存器3S23S22S21S20S19S18S17S16
位说明HODL/RSTDRV1DRV0WPSADPADS
状态寄存器2S15S14S13S12S11S10S9S8
位说明SUSCMPLB3LB2LB1QESRP1
状态寄存器1S7S6S5S4S3S2S1S0
位说明SRP0TBBP3BP2BP1BP0BUSY

上面三个状态寄存器,我们只关心我们需要用到的一些位: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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

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

qspi_xip_enable(QSPI1, FALSE);
  • 1

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

qspi_clk_division_set(QSPI1, QSPI_CLK_DIV_4);
  • 1

四 设置 SCLK 在 idle 时的电位

qspi_sck_mode_set(QSPI1, QSPI_SCK_MODE_0);
  • 1

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

qspi_busy_config(QSPI1, QSPI_BUSY_OFFSET_0);
  • 1

六 使能QSPI模式

W25Qxx_QSPI_Enable();
  • 1

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

W25Qxx_QSPI_4ByteAdd();
  • 1

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

W25Qxx_QSPI_MaxSCK();
  • 1

杰西莱展示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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

二 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;	//下一个扇区可以写完了
		}	 
	};	 
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507

三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)
	{
	
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

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

转载本文章请注明出处

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/124856
推荐阅读
相关标签
  

闽ICP备14008679号