一、GD25Qxx芯片简单介绍
- W25Q64存储容量共 :64M-bit/ 8M-byte
- W25Q128存储容量共 :128M-bit / 16M-Byte
- 页:256 Bytes
- 扇区:16 Pages(4KB)
- 块:16 Sector(64KB)
- High Speed Clock Frequency (SPI最大时钟频率)
-
- 133MHz for fast read with 30PF load
-
- Dual I/O Data transfer up to 266Mbits/s
-
- Quad I/O Data transfer up to 532Mbits/s
- **双倍SPI指令:**使用"Fast Read Dual Output and Dual I/O(3B和BBhex)"指令支持双倍速SPI操作。这些指令允许数据以正常速度的两到三倍的在设备间传输。双倍读指令适用于 上电时快速加载代码到RAM 或者 直接从SPI总线上执行代码(XIP) 的情形。当使用双倍速SPI指令时,DI和DO引脚将充当 IO 0和IO 1.
- 四倍速SPI指令:使用"Fast Read Quad Output"、" Fast Read Quad I/O" 、"Word Read Quad I/O" 和 "Octal Word Quad I/O"指令(6B、EB、E7、E3)支持四倍速SPI操作。这些指令允许数据以正常速度的四到六倍的在设备间传输。四倍读指令显著提升连续和随机访问传输速度,这速度满足将代码快速加载到RAM或者直接在SPI总线上执行(XIP)。使用四倍速SPI指令时,DI和DO引脚将充当 IO 0和IO 1 ,WP和HOLD充当IO2 和IO 3。四倍速SPI指令要求状态寄存器2中的QE功能位打开
- 数据写入的时候只能按照Page来写入 ,最多一次只能写256个字节,也就是一个页的空间。每次写入都要先擦除。
- 数据擦除只能按扇区擦除或按块擦除。可以按 16 页一组(4KB 扇区擦除)、128 页一组(32KB 块擦除)、256 页一组(64KB 块擦除)或者整片擦除(chip erase)。
二、如何读取FLASH_ID

cpp
#define SFLASH_ID 0xC83015 //W25X16
#define SFLASH_ID 0xC84015 //W25Q16
#define SFLASH_ID 0xC84018 //W25Q128
三、标准SPI读写代码
offChipFlash.h
cpp
#ifndef __OFFCHIPFLASH_H
#define __OFFCHIPFLASH_H
#include "head.h"
#define SPI_FLASH_PAGE_SIZE 0x100
#define SPI_FLASH_CS_LOW() gpio_bit_reset(GPIOA,GPIO_PIN_15)
#define SPI_FLASH_CS_HIGH() gpio_bit_set(GPIOA,GPIO_PIN_15)
void spi_flash_init(void);
uint32_t spi_flash_read_id(void);
void spi_flash_sector_erase(uint32_t sector_addr);
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write);
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read);
#endif
offChipFlash.c
cpp
#include "offChipFlash.h"
#define WRITE 0x02 /* write to memory instruction */
#define QUADWRITE 0x32 /* quad write to memory instruction */
#define WRSR 0x01 /* write status register instruction */
#define WREN 0x06 /* write enable instruction */
#define READ 0x03 /* read from memory instruction */
#define QUADREAD 0x6B /* read from memory instruction */
#define RDSR 0x05 /* read status register instruction */
#define RDID 0x9F /* read identification */
#define SE 0x20 /* sector erase instruction */
#define BE 0xC7 /* bulk erase instruction */
#define WIP_FLAG 0x01 /* write in progress(wip) flag */
#define DUMMY_BYTE 0xA5
void spi_flash_init(void)
{
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_SPI2);
gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_3|GPIO_PIN_4| GPIO_PIN_5);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3|GPIO_PIN_4| GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_3|GPIO_PIN_4| GPIO_PIN_5);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
/* chip select invalid */
SPI_FLASH_CS_HIGH();
/* SPI2 parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_32;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI2, &spi_init_struct);
spi_enable(SPI2);
}
uint32_t spi_flash_read_id(void)
{
uint32_t temp = 0, temp0 = 0, temp1 = 0, temp2 = 0;
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send "RDID " instruction */
spi_flash_send_byte(RDID);
/* read a byte from the flash */
temp0 = spi_flash_send_byte(DUMMY_BYTE);
/* read a byte from the flash */
temp1 = spi_flash_send_byte(DUMMY_BYTE);
/* read a byte from the flash */
temp2 = spi_flash_send_byte(DUMMY_BYTE);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
temp = (temp0 << 16) | (temp1 << 8) | temp2;
return temp;
}
void spi_flash_sector_erase(uint32_t sector_addr)
{
/* send write enable instruction */
spi_flash_write_enable();
/* sector erase */
/* select the flash: chip select low */
SPI_FLASH_CS_LOW();
/* send sector erase instruction */
spi_flash_send_byte(SE);
/* send sector_addr high nibble address byte */
spi_flash_send_byte((sector_addr & 0xFF0000) >> 16);
/* send sector_addr medium nibble address byte */
spi_flash_send_byte((sector_addr & 0xFF00) >> 8);
/* send sector_addr low nibble address byte */
spi_flash_send_byte(sector_addr & 0xFF);
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
/* wait the end of flash writing */
spi_flash_wait_for_write_end();
}
void spi_flash_buffer_write(uint8_t* pbuffer, uint32_t write_addr, uint16_t num_byte_to_write)
{
uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;
addr = write_addr % SPI_FLASH_PAGE_SIZE;
count = SPI_FLASH_PAGE_SIZE - addr;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
/* write_addr is SPI_FLASH_PAGE_SIZE aligned */
if(0 == addr){
/* num_byte_to_write < SPI_FLASH_PAGE_SIZE */
if(0 == num_of_page){
spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
}else{
/* num_byte_to_write >= SPI_FLASH_PAGE_SIZE */
while(num_of_page--){
spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
spi_flash_page_write(pbuffer,write_addr,num_of_single);
}
}else{
/* write_addr is not SPI_FLASH_PAGE_SIZE aligned */
if(0 == num_of_page){
/* (num_byte_to_write + write_addr) > SPI_FLASH_PAGE_SIZE */
if(num_of_single > count){
temp = num_of_single - count;
spi_flash_page_write(pbuffer,write_addr,count);
write_addr += count;
pbuffer += count;
spi_flash_page_write(pbuffer,write_addr,temp);
}else{
spi_flash_page_write(pbuffer,write_addr,num_byte_to_write);
}
}else{
/* num_byte_to_write >= SPI_FLASH_PAGE_SIZE */
num_byte_to_write -= count;
num_of_page = num_byte_to_write / SPI_FLASH_PAGE_SIZE;
num_of_single = num_byte_to_write % SPI_FLASH_PAGE_SIZE;
spi_flash_page_write(pbuffer,write_addr, count);
write_addr += count;
pbuffer += count;
while(num_of_page--){
spi_flash_page_write(pbuffer,write_addr,SPI_FLASH_PAGE_SIZE);
write_addr += SPI_FLASH_PAGE_SIZE;
pbuffer += SPI_FLASH_PAGE_SIZE;
}
if(0 != num_of_single){
spi_flash_page_write(pbuffer,write_addr,num_of_single);
}
}
}
}
void spi_flash_buffer_read(uint8_t* pbuffer, uint32_t read_addr, uint16_t num_byte_to_read)
{
/* select the flash: chip slect low */
SPI_FLASH_CS_LOW();
/* send "read from memory " instruction */
spi_flash_send_byte(READ);
/* send read_addr high nibble address byte to read from */
spi_flash_send_byte((read_addr & 0xFF0000) >> 16);
/* send read_addr medium nibble address byte to read from */
spi_flash_send_byte((read_addr& 0xFF00) >> 8);
/* send read_addr low nibble address byte to read from */
spi_flash_send_byte(read_addr & 0xFF);
/* while there is data to be read */
while(num_byte_to_read--){
/* read a byte from the flash */
*pbuffer = spi_flash_send_byte(DUMMY_BYTE);
/* point to the next location where the byte read will be saved */
pbuffer++;
}
/* deselect the flash: chip select high */
SPI_FLASH_CS_HIGH();
}
main.c
cpp
#include "head.h"
#define BUFFER_SIZE 256
#define FLASH_WRITE_ADDRESS 0x000000
uint8_t tx_buffer[256];
uint8_t rx_buffer[256];
int main(void)
{
systick_config();//时钟配置
gd_485_com_init(PCS_COM,9600);
gd_485_com_en(1);//发送使能
spi_flash_init();
while(1)
{
for(int i = 0; i < BUFFER_SIZE; i++) {tx_buffer[i] = i;}
spi_flash_sector_erase(FLASH_WRITE_ADDRESS);
spi_flash_buffer_write(tx_buffer, FLASH_WRITE_ADDRESS, BUFFER_SIZE);
delay_1ms(10);
spi_flash_buffer_read(rx_buffer, FLASH_WRITE_ADDRESS, BUFFER_SIZE);
for(int i = 0; i < BUFFER_SIZE; i++) {printf("0x%x",rx_buffer[i]);}
printf("\r\n");
}
}