STM32F405驱动华邦W25N01G简介与demo

关于STM32F405驱动华邦W25N01GVZE1G的简介与驱动代码

W25N01G简介

常用flash可分为NOR flash和NAND flash等。比如华邦(winbond)的W25Qxx系列的flash就是NOR系列的,本篇所讲述的W25N01G就是NAND flash系列的。
规格
通过上图可以看到该flash的驱动方式和最高clk频率。这篇文章主要是基于标准SPI的驱动方式,下面就是此次教程的芯片封装和引脚分配。
封装及引脚
引脚分配的说明:
1、/CS(Clip Select) :片选线
2、DO(Serial Data Output(Data Input Output 1)) :串行数据输出线
3、/WP(Write Protect Input (Data Input Output 2)) :写数据保护线
4、GND :地线
5、DI(Serial Data Input(Data Input Output 0)) :串行数据输入线
6、CLK(Serial Clock) :时钟线
7、/Hold(Hold Input (Data Input Output 3)) :数据输入保持线
8、VCC :电源输入

~~下面介绍W25N01G的架构和寻址~~
存储构架
寻址方式
这部分是重点也是难点!!!
从上面两图可以看出,W25N01G的寻址方式是页地址+列地址(Page Add + Column Add),即下图红框中的部分:
寻址
它的列地址大小为2112Byte,由2048Byte的数据缓冲区和64Byte的备用区域(Spare Area)组成。
它的页地址大小1024 x 64 x 2KB,即该flash共有1024个块(Block),每个块包含64页(Page),每页大小为2KB。(对应flash的大小,1024x64x2/1024=128M)
由于NAND Flash在设定上存在坏块,所以就有Spare Area,它被用于标记坏块(bad block)和保存对MainArray中main区的ECC码(Error Checking and Correcting,纠错码)。

W25N01G读写前的必要配置

设备操作流程
上图是设备操作流程,其中BUF、ECC-E的状态会影响选择哪种读取数据的方式Continuous Read或是Buffer Read,这在后面的指令码选择会有用。注意上图紫色方框,读写缓冲区是需要一定的时间的!!
W25N01GV为读取操作提供了两种不同的模式,缓冲读取模式(BUF=1)和连续读取模式(BUF=0)。在进行任何读操作之前,需要一个页数据读命令来启动从内存数组中的指定页到数据缓冲区的数据传输。默认情况下,在电源启动后,第0页中的数据将自动加载到数据缓冲区中,设备已准备好接受任何读命令。
缓冲区读模式(BUF=1)需要一个列地址来开始输出数据缓冲区内的现有数据,并且一旦到达数据缓冲区的末端(字节2,111),DO (IO1) pin将变为high-Z状态。
连续读取模式(BUF=0)不需要起始列地址。设备总是从数据缓冲区的第一列(字节0)开始输出数据,一旦到达数据缓冲区的末尾(字节2,048),数据将进入下一个内存页继续输出。在连续读取模式下,可以使用单个读命令读取整个内存阵列。
接下来就是重头戏了,配置SPI和读写flash:
标准SPI
如上图,标准的SPI指令使用DI输入引脚将指令、地址或数据串行地写入CLK上升沿上的设备。DO输出引脚用于从CLK下降沿上的设备读取数据或状态。支持SPI总线操作模式0(0,0)和3(1,1)。模式0和模式3的主要区别在于CLK的电平,当SPI总线主设备处于待机且数据没有被传输时,对于模式0,CLK信号通常在/CS的下降和上升边缘处是低电平状态的;对于模式3,CLK信号通常在/CS的下降和上升边缘处是高电平状态的。
接下来配置一些必须的寄存器,解除flash的保护状态,看芯片手册可知,W25N01GV提供三个状态寄存器:保护寄存器(SR-1)、配置寄存器(SR-2)和状态寄存器(SR-3)。每个寄存器分别由读状态寄存器和写状态寄存器命令以及1字节寄存器地址访问。读写状态寄存器的命令为 05h 或 0Fh。下面开始介绍这三个寄存器:
1、保护寄存器(SR-1)
SR1
如上图,S7-S2为块保护位,主要提供写保护控制和状态。块保护位上电后的默认值是1,以保护整个flash。如果配置寄存器(SR-2)中的SR1-L位被设置为1,那么其默认值将是OTP锁定的值。WP-E(S1)是写保护启用位,它与SRP1和SRP0(S0)配合使用,用来控制写保护的方式:软件保护或者硬件保护,当WP-E = 0(默认值)时,设备处于软件保护模式,当WP-E = 1时,设备处于硬件保护模式。具体请看手册。
2、配置寄存器(SR-2)
SR2
在SR2中,OTP-L(S7)位主要是锁定OTP区域,设置为1,整个OTP区域将被锁定,以防止数据被更改。如果要使用OPT区域,OPT-E(S6)位必须设置为1,以便使用标准的程序/读取命令来访问OTP区域以及读取唯一的ID或参数页信息,该位开机或复位命令后的默认值为0。SR1-L(S5)位用于OTP锁定保护寄存器(SR-1)中的值。ECC-E(S4)位作用是选择是否启用ECC算法,上电和复位后默认为1,启用算法。BUF(S3)位为读取操作选择位,对应上面说的设备操作流程,及缓冲读取模式(BUF=1)和连续读取模式(BUF=0)。其模式选择对照表如下:
模式选择
3、状态寄存器(SR-3)
SR3
SR3都是一些只读位,表示了当前flash的一些状态。LUT-F(S6)位表示20个内存块链接是否被充分利用。LUT-F的默认值是0,一旦使用了所有20个链接,LUT-F将变成1,并且不能建立更多的内存块链接。在NAND闪存中使用ECC函数来纠正读取操作期间有限的内存错误,ECC状态位(ECC-1、ECC-0)应该在读取操作完成后进行检查,以验证数据的完整性。ECC状态位的值不关心ECC- e是否等于0,因为一个电源周期或复位命令后,这些位将被置0。P-FAIL(S3)和E-FAIL(S2)位主要用于指示内部控制的编程或擦除操作是否成功执行,这两个位将在程序执行或块擦除指令以及设备复位指令开始时被清除。WEL(S1)位为写使能指示位,它在执行写使能指令后被设置为1。当设备写被禁用时,WEL状态位被清除为0。写禁用状态发生在电源启动时或以下任何指令之后:写禁用,程序执行,块擦除,页数据读取,程序执行和OTP页的坏块管理。BUSY(S0)位为忙检测位,当设备正在通电或执行数据读写时,该位被置1,空闲时被清0。
设置好这些寄存器,就可以开干了。

**

W25N01GV常用命令表

**
命令表
W25N01GV常用命令如上图所示。

**

W25N01GV读写示例

**
我们以读取设备ID为例,先看时序图:
读ID
具体操作步骤如下:
1、/CS拉低,选中IC
2、发送指令0x9F
3、发送无用指令(0x00)占用8个虚拟时钟(dummy clock)
4、然后接收ID的高8位(temp|=data<<16、EFh为Winbond的ID)
5、再接收ID的中8位(temp|=data<<8)
6、最后接收ID的低8位(temp|=data,AA21h为设备的ID)
7、/CS拉高,退出
上代码

/***********************************************************************************************
**     name: W25_ReadID
** function: 读取芯片ID 
**parameter: void
**   return: 返回值如下:
						 0XAA21,表示芯片型号为W25N01GV 
**     date: 2019/8/27
**   create: @曼珠沙华
************************************************************************************************/
u16 W25_ReadID(void){
	
	u32 Temp = 0;	  
	
	FLASH_CS = 0;				
	
	SPI1_ReadWriteByte(W25X_JedecDeviceID);               //发送读取ID命令	    
	SPI1_ReadWriteByte(0x00); 	     	 			   
	Temp |= SPI1_ReadWriteByte(0xFF) << 16;  
	Temp |= SPI1_ReadWriteByte(0xFF) << 8;	 
	Temp |= SPI1_ReadWriteByte(0xFF);
	
	FLASH_CS = 1;			
	
	return Temp;
} 

就是这么简单的哟。

**

使用过程中遇到的问题总结

**
1、在编写程序时要注意列地址(Column Address)和页地址(Page Address)的组合及搭配,我在程序中将它们分离开了。
2、在读写的时候要注意,因为写入数据需要两步,先写缓冲,再写flash。有缓冲区的存在,要先写入缓冲区,再执行写入flash指令,要有一定的延时时间,不然会写不进去或者读不出来数据。
3、使用NAND FLASH最好是使用BBM(Bad Block Management)坏块管理,因为它本来生产就不可避免地出现坏块,这样做避免数据错误和系统崩溃。另外可以采取一些策略来提高它的寿命和效率,例如是磨损均衡管理等。
比如写数据代码:

/***********************************************************************************************
**     name: W25_WriteData
** function: SPI在一页(0~65535)内写入少于256个字节的数据
						 在指定地址开始写入最大256字节的数据
**parameter: pBuffer 数据存储区
             BytesAddr 写入的具体字节地址(0-1023)
						 BlockAddr 写入的块地址(0-1023)
             PageAddr  写入的页地址(0-63)
             NumByteToWrite 要写入的数据个数(0-65535),该数不应该超过该页的剩余字节数!!!
**   return: void
**     date: 2019/8/27
**   create: @曼珠沙华
************************************************************************************************/
void W25_WriteData(u8* pBuffer,u16 BytesAddr, u16 BlockAddr, u8 PageAddr,u16 NumByteToWrite){
  
	W25_Write_Enable();                                             //SET WEL 
	delay_xms(20);
	W25_WriteBuff(BytesAddr,pBuffer,NumByteToWrite);                //先写到buff
	delay_xms(20);
	
	FLASH_CS = 0;                                                   //使能器件
	
	SPI1_ReadWriteByte(W25X_ProgramExecute);                        //发送写命令 
  SPI1_ReadWriteByte(0);                                          //8-bit dummy clocks  
	SPI1_ReadWriteByte((u8)((BlockAddr >> 2)  & 0xFF));              //发送16bit地址     
	SPI1_ReadWriteByte((u8)((BlockAddr << 6) | PageAddr) & 0xFF);  
	
	FLASH_CS = 1;                                                   //取消片选 
	W25_Wait_Busy();					                                      //等待写入结束
	W25_Write_Disable();
	delay_xms(20);
} 
/***********************************************************************************************
**     name: W25_WriteBuff
** function: 将数据写入W25的数据缓冲区,数据不超过2048byte
**parameter: CA_add         写入的具体字节地址(0-2047)
						 pBuffer        欲写入的数据地址
						 NumByteToWrite 要写入的数据个数(0-65535),该数不应该超过该页的剩余字节数!!!
**   return: void
**     date: 2019/8/29
**   create: @曼珠沙华
************************************************************************************************/
void W25_WriteBuff(u16 CA_add,u8 *pBuffer,u16 NumByteToWrite){
	
	u16 i;
                             
	FLASH_CS = 0;                                       //使能器件
	
	SPI1_ReadWriteByte(W25X_PageProgram);               //发送写缓冲区命令        
	SPI1_ReadWriteByte((u8)((CA_add >> 8) & 0x07));     //发送16bit地址    
	SPI1_ReadWriteByte((u8)CA_add & 0xFF);  
		
	for(i = 0; i < NumByteToWrite; i++){
		SPI1_ReadWriteByte(pBuffer[i]);                   //循环写数  
	}
	FLASH_CS = 1;                                       //取消片选 
} 

写入是要两步的,一定要有延时。
以上都是我个人的一些总结,如有错误,还请各位大佬多多指正,感谢。
最后,附上驱动代码,没有带坏块管理的,就是普通驱动代码、SPI的配置代码和芯片手册:
https://download.csdn.net/download/cxieyunsky/12258945
----------------------------------------------------------------------------------------------------------2020/3/20
----------------------------------------------------------------------------------------------------------@曼珠沙华

  • 13
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要使用STM32F405驱动TCS3200识别颜色,需要进行以下步骤: 1. 连接硬件:将TCS3200模块的VCC连接到STM32F405的3.3V电源,GND连接到STM32F405的GND,S0、S1、S2、S3连接到STM32F405的GPIO引脚。 2. 配置GPIO引脚:使用STM32F405的GPIO库函数将S0、S1、S2、S3引脚配置为输出模式。 3. 配置定时器:使用STM32F405的定时器库函数,配置一个定时器用于测量TCS3200输出的频率。可以选择使用TIM2或TIM5定时器。定时器的时钟源可以选择内部时钟或外部时钟。如果选择外部时钟,需要将TCS3200的OUT引脚连接到定时器的输入捕获通道。 4. 配置中断:使用STM32F405的中断库函数,配置一个中断用于定时器的溢出或输入捕获事件。 5. 读取颜色数据:在中断处理函数中,读取TCS3200输出的频率,并根据预先定义的颜色频率范围来判断颜色。 6. 输出结果:将识别到的颜色结果输出到显示器或者其他设备上。 注意事项: 1. 需要根据TCS3200的规格书来确定S0、S1、S2、S3引脚的工作频率选择。 2. 需要根据TCS3200的规格书来确定颜色频率范围。 3. 如果使用外部时钟,需要通过TCS3200的OUT引脚来提供时钟信号。 4. 在读取颜色数据时,需要注意定时器计数器的溢出问题,以及在输入捕获事件中读取捕获值的方式。 以上是大致的流程,具体实现还需要根据具体的需求和硬件情况进行调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值