1.w25q64概述
1. 空间
- 首先w25q64有8mb的空间,属于nor flash 然后分128个块,每块64kb, 每一个块分为16个扇区,每个扇区4kb,每个扇区分128页,每页的空间为256b,如下图

2. 指令集
busy ,每次对w25q64操作都必须当它busy为0才行

- 每次对w25q64进行写操作时,都要进行写使能,即发送0x06

- 这是下面常用的指令 0x03 ,0x02 ,0xD8

2. SPI通信协议
这里不再多说了,需要注意的是
SPI只有主模式和从模式之分,没有读和写的说法,外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。
spi通信的模式,一般选择模式0,即空闲态时,SCLK处于低电平,数据采样是在第1个边沿
3.代码
1. spi.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
| #include "gd32f10x.h" #include "spi.h"
void SPI0_Init(void) { rcu_periph_clock_enable(RCU_SPI0); rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_5|GPIO_PIN_7); gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_6); spi_parameter_struct spi_config_t; spi_i2s_deinit(SPI0); spi_config_t.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; spi_config_t.device_mode = SPI_MASTER ; spi_config_t.endian = SPI_ENDIAN_MSB ; spi_config_t.frame_size = SPI_FRAMESIZE_8BIT; spi_config_t.nss = SPI_NSS_SOFT; spi_config_t.prescale =SPI_PSC_2 ; spi_config_t.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init(SPI0,&spi_config_t); spi_enable(SPI0); }
uint8_t SPI0_ReadWriteByte(uint8_t txd) { while(spi_i2s_flag_get(SPI0,SPI_FLAG_TBE) != 1); spi_i2s_data_transmit(SPI0,txd); while(spi_i2s_flag_get(SPI0,I2S_FLAG_RBNE) != 1); return spi_i2s_data_receive(SPI0); }
void SPI0_SendData(uint8_t *txd,uint16_t len) { uint16_t i; for( i = 0; i < len; i++) { SPI0_ReadWriteByte(txd[i]); } }
void SPI0_ReceData(uint8_t *rxd,uint16_t len) { uint16_t i; for( i = 0; i < len; i++) { rxd[i] = SPI0_ReadWriteByte(0xff); } }
|
2. w25q64
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
| #include "gd32f10x.h" #include "spi.h" #include "w25q64.h"
void W25Q64_Init(void) { rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4); W25Q64_CS_DISENABLE; SPI0_Init(); }
void W25Q64_WaitBusy(void) { uint8_t res; do{ W25Q64_CS_ENABLE; SPI0_ReadWriteByte(0x05); res = SPI0_ReadWriteByte(0xff); W25Q64_CS_DISENABLE; }while((res & 0x01) == 0x01); }
void W25Q64_Enable(void) { W25Q64_WaitBusy(); W25Q64_CS_ENABLE; SPI0_ReadWriteByte(0x06); W25Q64_CS_DISENABLE; }
void W25Q64_Erase64K(uint8_t blockNB) { uint8_t wdata[4]; wdata[0] = 0xD8; wdata[1] = (blockNB*64*1024) >> 16; wdata[2] = (blockNB*64*1024) >> 8; wdata[3] = (blockNB*64*1024) >> 0; W25Q64_WaitBusy(); W25Q64_Enable(); W25Q64_CS_ENABLE; SPI0_SendData(wdata,4); W25Q64_CS_DISENABLE; W25Q64_WaitBusy(); }
void W25Q64_Write_Page(uint8_t *wbuff, uint16_t pageNB) { uint8_t wdata[4]; wdata[0] = 0x02; wdata[1] = (pageNB*256) >> 16; wdata[2] = (pageNB*256) >> 8; wdata[3] = (pageNB*256) >> 0; W25Q64_WaitBusy(); W25Q64_Enable(); W25Q64_CS_ENABLE; SPI0_SendData(wdata,4); SPI0_SendData(wbuff,256); W25Q64_CS_DISENABLE; }
void W25Q64_Read(uint32_t addr,uint8_t *rbuff, uint32_t len) { uint8_t wdata[4]; wdata[0] = 0x03; wdata[1] = (addr) >> 16; wdata[2] = (addr) >> 8; wdata[3] = (addr) >> 0; W25Q64_WaitBusy(); W25Q64_CS_ENABLE; SPI0_SendData(wdata,4); SPI0_ReceData(rbuff,len); W25Q64_CS_DISENABLE; }
|
- 主程序验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| int main(void){
uint16_t i,j; Delay_Init(); Usart0_Init(921600); W25Q64_Init(); W25Q64_Erase64K(0); for(i=0;i<256;i++){ for(j=0;j<256;j++) wdata[j] = i; W25Q64_Write_Page(wdata,i); } Delay_ms(50);
for(i=0;i<256;i++){ W25Q64_Read(i*256,rdata,256); for(j=0;j<256;j++) u0_printf("%d=%x\r\n",i*256+j,rdata[j]); } while(1){ } }
|