bsp.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/*
 * bsp.h
 *
 *  Created on: Apr 22, 2021
 *      Author: Administrator
 */

#ifndef BSP_H_
#define BSP_H_

#include "main.h"
#include "stdio.h"
#include "string.h"

void user_Assert(char *file,uint32_t line);


#endif /* BSP_H_ */

bsp.c

 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
/*
 * bsp.c
 *
 *  Created on: Apr 22, 2021
 *      Author: Administrator
 */
#include "bsp.h"


/**
  * 函数功能: 检查代码异常,打印出异常的位置(文件名与行号)
  * 输入参数: file: 源代码文件名称。关键字__FILE__表示源代码文件名。
  *        line: 代码行号,关键字__LINE__表示源代码行号
   * 返回值:  void

  * 说明:
  *    1、在需要断言的地方直接调用user_Assert(__FILE__,__LINE__);
  */
void user_Assert(char *file,uint32_t line)
{
	printf("Wrong parameters value: file %s on line %d\r\n",file, (unsigned int)line);

    /* 这是一个死循环,断言失败时程序会卡此处死机,以便于用户差错 */
	if(line == 0)
	{
		return;
	}
	while(1)
	{

	}
}

bsp_qspi_w25q128.h

  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
/*
 * bsp_quadspi_W25Q128.h
 *
 *  Created on: Apr 21, 2021
 *      Author: Administrator
 *
  *  该bsp用于华邦的w25q128JV,跟华邦的w25q128JV不一样
  *  坑爹的
 */

#ifndef BSP_QSPI_W25Q128_H_
#define BSP_QSPI_W25Q128_H_

#include "bsp.h"
#include "quadspi.h"
#include "stdio.h"

/* 宏定义 --------------------------------------------------------------------*/
#define FLASH_BEGIN_ADDRESS 0x00000

#define W25Q128FV_FLASH_SIZE                  0x1000000 /* 128 MBits => 16MBytes */
#define W25Q128FV_BLOCK_SIZE                  0x10000   /* 256 Blocks of 64KBytes */
#define W25Q128FV_HALF_BLOCK_SIZE             0x8000    /* 128 Blocks  of 32KBytes */
#define W25Q128FV_SECTOR_SIZE                 0x1000    /* 4096 sectors of 4kBytes */
#define W25Q128FV_PAGE_SIZE                   0x100     /* 65536 pages of 256 bytes */

#define W25Q128FV_DUMMY_CYCLES_READ           4
#define W25Q128FV_DUMMY_CYCLES_READ_QUAD      10

#define W25Q128FV_BULK_ERASE_MAX_TIME         250000//ms
#define W25Q128FV_SECTOR_ERASE_MAX_TIME       3000
#define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME    800

#define W25Q128FV_FLASH_ID                    0XEF4018
/*  W25Q128FV 指令  */
/* 复位操作 */
#define RESET_ENABLE_CMD                      0x66
#define RESET_MEMORY_CMD                      0x99

#define ENTER_QPI_MODE_CMD                    0x38
#define EXIT_QPI_MODE_CMD                     0xFF

/* 读取ID指令 */
#define READ_ID_CMD                           0x90
#define DUAL_READ_ID_CMD                      0x92
#define QUAD_READ_ID_CMD                      0x94
#define READ_JEDEC_ID_CMD                     0x9F

/* 读操作指令 */
#define READ_CMD                              0x03
#define FAST_READ_CMD                         0x0B
#define DUAL_OUT_FAST_READ_CMD                0x3B
#define DUAL_INOUT_FAST_READ_CMD              0xBB
#define QUAD_OUT_FAST_READ_CMD                0x6B
#define QUAD_INOUT_FAST_READ_CMD              0xEB

/* 写使能操作指令 */
#define WRITE_ENABLE_CMD                      0x06
#define WRITE_DISABLE_CMD                     0x04

/* 读写状态寄存器操作指令 */
#define READ_STATUS_REG1_CMD                  0x05
#define READ_STATUS_REG2_CMD                  0x35
#define READ_STATUS_REG3_CMD                  0x15

#define WRITE_STATUS_REG1_CMD                 0x01
#define WRITE_STATUS_REG2_CMD                 0x31
#define WRITE_STATUS_REG3_CMD                 0x11

/* 编程指令 */
#define PAGE_PROG_CMD                         0x02
#define QUAD_INPUT_PAGE_PROG_CMD              0x32

/* 擦除Flash指令 */
#define SECTOR_ERASE_CMD                      0x20
#define BLOCK_32KB_ERASE_CMD                  0x52
#define BLOCK_64KB_ERASE_CMD                  0xD8
#define CHIP_ERASE_CMD                        0xC7

#define PROG_ERASE_RESUME_CMD                 0x7A
#define PROG_ERASE_SUSPEND_CMD                0x75

/* 状态寄存器标志位 */
#define W25Q128FV_FSR_BUSY                    ((uint8_t)0x01) /* busy */
#define W25Q128FV_FSR_WREN                    ((uint8_t)0x02) /* write enable */
#define W25Q128FV_FSR_QE                      ((uint8_t)0x02) /* quad enable */

/* Flash 状态码*/
#define FLASH_OK                          ((uint8_t)0x00)
#define FLASH_ERROR                       ((uint8_t)0x01)
#define FLASH_BUSY                        ((uint8_t)0x02)
#define FLASH_NOT_SUPPORTED               ((uint8_t)0x04)
#define FLASH_SUSPENDED                   ((uint8_t)0x08)



uint32_t QSPI_W25Qx_ReadID(void);
void QSPI_W25Qx_Reset_Memory();
void QSPI_W25Qx_EraseSector(uint32_t _SectorAddr);
uint8_t QSPI_W25Qx_Write_Buffer(uint8_t *_pBuf,uint32_t _write_Addr,uint16_t _write_Size);
void QSPI_W25Qx_Read_Buffer(uint8_t *_pBuf,uint32_t _read_Addr,uint32_t _read_Size);


#endif /* BSP_QSPI_W25Q128_H_ */

bsp_qspi_w25q128.c

  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
/*
 * bsp_quadspi_W25Q128.c
 *
 *  Created on: Apr 25, 2021
 *      Author: Administrator
 *
 *
 *
 *
 *
 */
#include <bsp_qspi_w25q128.h>


/* 仅限本文件使用的函数 */
static void QSPI_W25Qx_Write_Enable(QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_W25Qx_AutoPollingMemRead(uint32_t Timeout);
static void QSPI_W25Qx_Enter(QSPI_HandleTypeDef *hqspi);
static void QSPI_W25Qx_Exit(QSPI_HandleTypeDef *hqspi);

/**
  * 函数功能: 读取Flash状态并等待操作结束
  * 输入参数: Timeout:等待时间
 *
  * 返回值: Flash的状态
  * 说明:
 *
 *
 */
static uint8_t QSPI_W25Qx_AutoPollingMemRead(uint32_t Timeout)
{
	QSPI_CommandTypeDef     s_command={0};
    QSPI_AutoPollingTypeDef s_config={0};

    /* 基本配置 */
    s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
    s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
    s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
    s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
    s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

    /* 配置自动轮询模式 */
    s_command.Instruction       = READ_STATUS_REG1_CMD;  //读取状态寄存器
    s_command.AddressMode       = QSPI_ADDRESS_NONE;     //没有地址
    s_command.DataMode          = QSPI_DATA_1_LINE;      //1线数据
    s_command.DummyCycles       = 0;                     //无空周期

    /* 配置自动轮询寄存器(不断查询状态寄存器bit0,等待其为0) */
    s_config.Match           = 0x00;				   //等待其为0
    s_config.Mask            = W25Q128FV_FSR_BUSY;     //状态寄存器bit0
    s_config.MatchMode       = QSPI_MATCH_MODE_AND;	   //逻辑与
    s_config.StatusBytesSize = 1;
    s_config.Interval        = 0x10;
    s_config.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

    /* 自动轮询模式等待编程结束 */
    if(HAL_QSPI_AutoPolling(&hqspi,&s_command,&s_config,Timeout) != HAL_OK)
    {
	   user_Assert(__FILE__,__LINE__);
    }

    return FLASH_OK;

}

/**
  * 函数功能: 读取外部FLASH的ID
  * 输入参数: 无
 *
  * 返回值: uint32_t
  * 说明:
 *  1、使用SPI模式的指令
 *
 */
uint32_t QSPI_W25Qx_ReadID(void)
{
	uint32_t uiID;

	QSPI_CommandTypeDef s_command = {0};
	uint8_t buf[3];

	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 读取JEDEC ID */
	s_command.Instruction       = READ_JEDEC_ID_CMD;  //读取ID命令: 0x9F
	s_command.AddressMode       = QSPI_ADDRESS_NONE;  //没有地址
	s_command.DataMode          = QSPI_DATA_1_LINE;   //1线数据
	s_command.DummyCycles       = 0;                  //无空周期
	s_command.NbData            = 3;                  //读取三个数据

	/* 发送指令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 启动接收 */
	if(HAL_QSPI_Receive(&hqspi,buf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	uiID = (buf[0] << 16) | (buf[1] << 8) | buf[2];

	return uiID;
}

/**
  * 函数功能:  外部FLASH写使能
  * 输入参数:  hqspi  QSPI_HandleTypeDef句柄
 *
  * 返回值: 无
  * 说明:
 *  1、使用SPI模式的指令
 *
 */
static void QSPI_W25Qx_Write_Enable(QSPI_HandleTypeDef *hqspi)
{
	QSPI_CommandTypeDef s_command = {0};
	QSPI_AutoPollingTypeDef s_config={0};

	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	//s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 写入使能配置 */
	s_command.Instruction       = WRITE_ENABLE_CMD;   //写使能命令
	s_command.AddressMode       = QSPI_ADDRESS_NONE;  //没有地址
	s_command.DataMode          = QSPI_DATA_NONE;     //没有数据
	s_command.DummyCycles       = 0;                  //无空周期
	s_command.NbData            = 0;                  //空数据

	/* 发送指令 */
	if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 配置自动轮询模式等待操作完成 */
	s_config.Match           = W25Q128FV_FSR_WREN;
	s_config.Mask            = W25Q128FV_FSR_WREN;
	s_config.MatchMode       = QSPI_MATCH_MODE_AND;
	s_config.StatusBytesSize = 1;
	s_config.Interval        = 0x10;
	s_config.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

	s_command.Instruction = READ_STATUS_REG1_CMD;
	s_command.DataMode    = QSPI_DATA_1_LINE;
	s_command.NbData      = 1;

	if(HAL_QSPI_AutoPolling(hqspi,&s_command,&s_config,HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

}

/**
  * 函数功能:  擦除外部FLASH的扇区(大小:4KB)
  * 输入参数:  _uiSectorAddr: 扇区地址,以4KB为单位的地址,比如0,4096,8192等
 *
  * 返回值: 无
  * 说明:
 *  1、
 *
 */
void QSPI_W25Qx_EraseSector(uint32_t _SectorAddr)
{
	QSPI_CommandTypeDef	s_command = {0};

	/* 写使能 */
	QSPI_W25Qx_Write_Enable(&hqspi);

	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 擦除扇区配置 */
	s_command.Instruction       = SECTOR_ERASE_CMD;     //扇区擦除指令
	s_command.AddressMode       = QSPI_ADDRESS_1_LINE;  //1线地址方式
	s_command.DataMode          = QSPI_DATA_NONE;       //没有数据
	s_command.Address           = _SectorAddr;          //扇区的首地址,保证是4KB整数倍
	s_command.DummyCycles       = 0;                    //无空周期

	/* 发送指令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 自动轮询模式等待编程结束 */
	if(QSPI_W25Qx_AutoPollingMemRead(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

}

/**
  * 函数功能:  页编程,通过QSPI将数据写入外部FALSH
  * 输入参数:  _pBuf: 需要存入数据的指针
 *          _write_Addr: 目标区域首地址,即页首地址,比如0,256,512等。
 *          _write_Size: 数据个数,不能超过页的大小,可以填入(1 ~ 256)
  * 返回值: 无
  * 说明:
 *    1、华邦的W25Q128FV仅仅支持SPI模式写入
 */
uint8_t QSPI_W25Qx_Write_Buffer(uint8_t *_pBuf,uint32_t _write_Addr,uint16_t _write_Size)
{
	QSPI_CommandTypeDef	s_command = {0};

	/* 防止写入的大小超过256字节 */
	if(_write_Size > W25Q128FV_PAGE_SIZE)
	{
		/* 进入断言,提示错误 */
		user_Assert(__FILE__,__LINE__);
	}

	QSPI_W25Qx_Write_Enable(&hqspi);  //写使能

	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/*写入序列配置 */
	s_command.Instruction       = QUAD_INPUT_PAGE_PROG_CMD;   //24位四线快速写入指令
	s_command.AddressMode       = QSPI_ADDRESS_1_LINE;        //1线地址方式
	s_command.DataMode          = QSPI_DATA_4_LINES;          //4线数据方式
	s_command.Address           = _write_Addr;                //写入数据的地址
	s_command.NbData            = _write_Size;                //写入数据的大小
	s_command.DummyCycles       = 0;                          //无空周期

	/* 发送指令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 启动传输 */
	if(HAL_QSPI_Transmit(&hqspi,_pBuf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 自动轮询模式等待编程结束 */
	if(QSPI_W25Qx_AutoPollingMemRead(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	return 1;
}

/**
  * 函数功能:  外部FLASH芯片进入QSPI模式
  * 输入参数:  *hqspi: qspi句柄
 *
  * 返回值: 无
  * 说明:
 *
 */
static void QSPI_W25Qx_Enter(QSPI_HandleTypeDef *hqspi)
{
	QSPI_CommandTypeDef	s_command = {0};
	/* 配置FLASH进入QPSI模式 */
	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 写入序列配置 */
	s_command.Instruction       = ENTER_QPI_MODE_CMD;         //进入QSPI模式
	s_command.AddressMode       = QSPI_ADDRESS_NONE;          //无地址方式
	s_command.DataMode          = QSPI_DATA_NONE;             //无数据方式
	s_command.DummyCycles       = 0;                          //0空闲状态周期

	/* 发送指令 */
	if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

}

/**
  * 函数功能:  外部FLASH芯片退出QSPI模式
  * 输入参数:  *hqspi: qspi句柄
 *
  * 返回值: 无
  * 说明:
 *
 */
static void QSPI_W25Qx_Exit(QSPI_HandleTypeDef *hqspi)
{
	QSPI_CommandTypeDef	s_command = {0};

    /* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_4_LINES;	  //4线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 写入序列配置 */
	s_command.Instruction       = EXIT_QPI_MODE_CMD;         //进入QSPI模式
	s_command.AddressMode       = QSPI_ADDRESS_NONE;          //无地址方式
	s_command.DataMode          = QSPI_DATA_NONE;             //无数据方式
	s_command.DummyCycles       = 0;                          //0空闲状态周期

	/* 发送指令 */
	if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}
}

/**
  * 函数功能:  连续读取若干字节,字节的个数不能超出芯片容量
  * 输入参数:  _pBuf: 读取数据的存放地址
 *          _read_Addr: 起始的地址
 *          _read_Size: 数据个数,可以大于W25Q128FV_PAGE_SIZE,但不能超出芯片总容量
  * 返回值: 无
  * 说明:
 *    1、从SPI模式切换到QSPI模式,读取完毕后切换回SPI模式(其他函数仅仅支持SPI模式)。
 */
void QSPI_W25Qx_Read_Buffer(uint8_t *_pBuf,uint32_t _read_Addr,uint32_t _read_Size)
{
	QSPI_CommandTypeDef	s_command = {0};

	/* 进入QSPI模式 */
	QSPI_W25Qx_Enter(&hqspi);

	/* 开始从FLASH读取数据 */
	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_4_LINES;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/*读取序列配置 */
	s_command.Instruction       = QUAD_INOUT_FAST_READ_CMD;     //24位四线快速写入指令
	s_command.AddressMode       = QSPI_ADDRESS_4_LINES;       //4线地址方式
	s_command.DataMode          = QSPI_DATA_4_LINES;          //4线数据方式
	s_command.Address           = _read_Addr;                 //写入数据的地址
	s_command.NbData            = _read_Size;                 //写入数据的大小
	s_command.DummyCycles       = 2;                          //两个空闲状态周期(4个时钟周期),结合时序理解

	/* 发送指令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 读取数据 */
	if(HAL_QSPI_Receive(&hqspi,_pBuf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 退出QSPI模式 */
	QSPI_W25Qx_Exit(&hqspi);

}

/**
  * 函数功能: 复位外部Flash
  * 输入参数: 无
 *
  * 返回值: void
  * 说明:
 *
 */
void QSPI_W25Qx_Reset_Memory()
{
	QSPI_CommandTypeDef s_command = {0};

	/* 基本配置 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;	  //1线方式发送指令
	s_command.AddressSize       = QSPI_ADDRESS_24_BITS;       //24位地址
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  //无交替字节
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      //W25Q128FV不支持DDR模式
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  //DDR模式,数据输出延迟
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;   //每次传输都发指令

	/* 复位使能W25x */
	s_command.Instruction       = RESET_ENABLE_CMD;   //复位使能命令
	s_command.AddressMode       = QSPI_ADDRESS_NONE;  //没有地址
	s_command.DataMode          = QSPI_DATA_NONE;     //没有数据
	s_command.DummyCycles       = 0;                  //无空周期

	/* 发送复位使能命令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 发送复位命令 */
	s_command.Instruction       = RESET_MEMORY_CMD;   //复位命令
	/* 发送复位使能命令 */
	if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

	/* 自动轮询模式等待等待完成 */
	if(QSPI_W25Qx_AutoPollingMemRead(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		user_Assert(__FILE__,__LINE__);
	}

}