w25q64的使用

来先看个基本款图

 w25q64是一款flash(nor flash)芯片,最大存储8Mbytes的数据,其中8Mbits的存储单元划分为128块(block 64kb),每个块划分为16块(sector 4kb),每个扇区分为了16页(page 256byte),可对照上图

由于flash的特性(读取速度较慢),在和芯片外部数据交互时,通常需要注意

写入操作时:

(后面会详细介绍操作)

1.写入前,必须先使能

2.数据只能由1改写到0,不能由0改写到1(所以写入数据时需要先擦除

3.擦除必须以最小单元进行(w25q64擦出的最小单元时一个扇区 4096 个字节

4.连续写入多个字节时,一次最多写一个页,若超出会从此页的开头覆盖

5. 写入,擦除操作时,芯片会进行忙等待,不响应新的操作

读出操作时:

直接调用读取指令,无需使能,没有额外操作,没有页的限制,读取操作不会进去忙状态,但不能在忙状态读取

看到这儿,你是否对此芯片的操作有大致的步骤了~~~zhi

重点来了,接下来我们看看

w25q64的状态寄存器

BUSY:在写扇区,擦除,写状态寄存器时置1,表示忙,在这时芯片会忽视指令(除了读状态寄存器和暂停擦除指令),所以我们在连续写扇区等指令时要等待 BUSY 位为0

WEL:进行写使能指令后 WEL 置1,当设备写失能时,WEL 置0,或者当执行写扇区,擦除,写状态寄存器指令后自行清零

这里我们不详细介绍BP0,BP1,BP2,TB,SEC位,他们的作用大概为了保护flash的数据,处于保护下不能写和擦除,详细规则可以看上图。注意这几位都为非易失位(掉电不丢失),我们想写和擦除时,就要先解除这种保护,然后根据自己的需求设置保护。

其他的不做介绍,感兴趣的可以去看看手册

w25q64_data_sheet

指令集:

注意:表中带括号的为芯片输出的数据,dummy为无用的数据。

Write Enable:写使能,在写扇区,擦除,写状态寄存器前必须先写使能

Read Status Segiser:读状态寄存器

Sage Program:页编程,(写入数据),首先发送指令码 02h, 接下来我们依次发送地址A23~A0(24位),在发送数据,这里最小1个字节,最大256个,超过会覆盖,需要注意一下

Quar Program:四倍页编程,其速率更大(需要用到额外数据输入线),我们目前不用

Erase:擦除,这里有扇区除,块擦除......,注意的时擦除前需要先写使能,注意每种大小下的地址对齐

比较重要就这么多,感兴趣的可以在去仔细看看数据手册

测试代码:

w25q64.h

#ifndef __W25Q64_H
#define __W25Q64_H

#define W25Q_STATUS_BUSY                 0X01

#define W25Q_WRITE_ENABLE                0X06
#define W25Q_WRITE_DISABLE               0X04
#define W25Q_READ_STATUS_REGISTER_1      0X05
#define W25Q_READ_STATUS_REGISTER_2      0X35
#define W25Q_READ_STATUS_REGISTER        0X01
#define W25Q_PAGE_PROGRAM                0X02
#define W25Q_READ_DATA                   0X03
#define W25Q_QUAR_PAGE_PROGRAM           0X32
#define W25Q_BLOCK_ERASE_64KB            0XD8
#define W25Q_BLOCK_ERASE_32KB            0X52
#define W25Q_SECTOR_ERASE                0X20
#define W25Q_CHIP_ERASE                  0X60
#define W25Q_ERASE_SUSPEND               0X75
#define W25Q_ERASE_RESUME                0X7A
#define W25Q_POWER_DOWN                  0XB9
#define W25Q_HIGH_PERFROMANCE_MODE       0XA3
#define W25Q_CONTIOUS_READ_MODE          0XFF
#define W25Q_RELSE_POWER_DOWN            0XAB
#define W25Q_DEVICE_ID                   0X90
#define W25Q_READ_UNIQUE_ID              0X4B
#define W25Q_JEDEC_ID                    0X9F

#define W25Q_DUMMY_BYTE                  0XFF

void W25Q64_Init(void);
void W25Q64_ReadID(uint8_t* MID,uint16_t* DID);
void W25Q64_PageProgram(uint32_t Address,uint8_t* DataArrany,uint16_t Count);
void W25Q64_SectorEarse(uint32_t Address);
void W25Q64_ReadData(uint32_t Address,uint8_t* DataArrany,uint32_t Count);
void W25Q64_ReadStatusRegister(uint8_t* reg1,uint8_t* reg2);
void W25Q64_WriteStatusRegister(uint8_t reg1,uint8_t reg2);
#endif

main

#include "myspi.h"
#include "w25q64.h"

void W25Q64_Init(void){
	MySPI_Init();
	
}

void W25Q64_ReadID(uint8_t* MID,uint16_t* DID){
	
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_JEDEC_ID);
	*MID = MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	*DID = MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	*DID <<= 8;
	*DID |= MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	MySPI_Stop();
}


void W25Q64_WriteEnable(void){
	MySPI_Start();
	MySPI_SwapByte_Soft(0x06);
	MySPI_Stop();
}

void W25Q64_WAIT_BUSY(void){
	uint32_t TimeOut;
	TimeOut = 100000;
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_READ_STATUS_REGISTER_1);
	while(MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE) & W25Q_STATUS_BUSY){
		TimeOut --;
		if(!TimeOut){
			break;
		}
	}
	MySPI_Stop();
}

void W25Q64_PageProgram(uint32_t Address,uint8_t* DataArrany,uint16_t Count){
	uint16_t i;
	uint8_t a;
	W25Q64_WriteEnable();
	MySPI_Start();
	a = MySPI_SwapByte_Soft(W25Q_PAGE_PROGRAM);
	a = MySPI_SwapByte_Soft(Address >> 16);	
	a = MySPI_SwapByte_Soft(Address >> 8);
	a = MySPI_SwapByte_Soft(Address);
	for(i = 0;i<Count;++i){
		MySPI_SwapByte_Soft(DataArrany[i]);
	}
	MySPI_Stop();
	W25Q64_WAIT_BUSY();
}

void W25Q64_SectorEarse(uint32_t Address){
	W25Q64_WriteEnable();
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_SECTOR_ERASE);
	MySPI_SwapByte_Soft(Address >> 16);	
	MySPI_SwapByte_Soft(Address >> 8);
	MySPI_SwapByte_Soft(Address);
	MySPI_Stop();
	W25Q64_WAIT_BUSY();
}

void W25Q64_ReadData(uint32_t Address,uint8_t* DataArrany,uint32_t Count){
	uint16_t i;
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_READ_DATA);
	MySPI_SwapByte_Soft(Address >> 16);	
	MySPI_SwapByte_Soft(Address >> 8);
	MySPI_SwapByte_Soft(Address);
	for(i = 0;i<Count;++i){
		DataArrany[i] = MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	}
	MySPI_Stop();

}

void W25Q64_ReadStatusRegister(uint8_t* reg1,uint8_t* reg2){
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_READ_STATUS_REGISTER_1);
	*reg1 = MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	MySPI_SwapByte_Soft(W25Q_READ_STATUS_REGISTER_2);
	*reg1 = MySPI_SwapByte_Soft(W25Q_DUMMY_BYTE);
	MySPI_Stop();
	
}

void W25Q64_WriteStatusRegister(uint8_t reg1,uint8_t reg2){
	W25Q64_WriteEnable();
	MySPI_Start();
	MySPI_SwapByte_Soft(W25Q_READ_STATUS_REGISTER);
	MySPI_SwapByte_Soft(reg1);
	MySPI_SwapByte_Soft(reg2);
	MySPI_Stop();
	W25Q64_WAIT_BUSY();
	
}

main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "24l01.h"
#include "w25q64.h"


//ecodeing = "ANSI"

	uint16_t DID;
	uint8_t MID;

	uint8_t ArranyWrite[] = "W25Q64 TEST!!!\0";
	uint8_t ArranyRead[50] ;
	uint32_t Adderss = 0x000001;
	uint8_t reg1,reg2;

int main(void)
{	

	OLED_Init();
	W25Q64_Init();
	W25Q64_ReadID(&MID,&DID);
	OLED_ShowHexNum(1,1,MID,4);
	OLED_ShowHexNum(1,8,DID,4);
	W25Q64_ReadStatusRegister(&reg1,&reg2);
	OLED_ShowHexNum(2,1,reg1,2);
	OLED_ShowHexNum(2,4,reg2,2);
	
	reg1 &= 0x9B;
	W25Q64_WriteStatusRegister(reg1,reg2);
	W25Q64_ReadStatusRegister(&reg1,&reg2);
	OLED_ShowHexNum(2,7,reg1,2);
	OLED_ShowHexNum(2,10,reg2,2);
	W25Q64_SectorEarse(Adderss);
	W25Q64_PageProgram(Adderss,ArranyWrite,20);
	W25Q64_ReadData(Adderss,ArranyRead,20);
	
	OLED_ShowString(3,1,ArranyRead);
	while(1);
}

几点补充......

1. <w25q64.c> W24Q64_WAIT_BUSY  函数判断 status register 1 的 BUSY 位,我们程序采用事后等待,写,擦除后等待非忙后退出

2.<main.c> 写操作前注意看看写入的扇区是否允许写入(有的芯片买回来默认全部扇区处于保护模式)

最后看看代码效果~~~~

(OLED 刷新率有点低,,,)

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值