STM32 串行FLASH W25Q64 移植文件系统FatFs ——(1)

引言

在嵌入式系统中,外部存储器如串行FLASH在数据存储和管理方面起到了至关重要的作用。本文将介绍如何在STM32平台上通过软件模拟SPI(Soft SPI)完成对W25Q64串行FLASH的控制,并编写相应的驱动程序。这个过程是移植文件系统FatFs的第一步。

准备工作

硬件准备

  1. STM32开发板:本文使用野火霸道开发板,芯片是STM32F103ZET6。
  2. W25Q64串行FLASH:一个外部存储芯片。
  3. 连接:开发板上已经将W25Q64的引脚和STM32的GPIO引脚连接好。

软件准备

  1. Keil MDK: 用于编写和调试代码。

引脚连接

下面是对应野火霸道开发板的引脚连接方案,具体连接根据自己使用开发板而定。

W25Q64引脚 STM32引脚
CS         PA4
DO(对应主机MISO) PA6
WP                 3.3V
GND         GND
DI(对应主机MOSI) PA7
CLK PA5
HOLD 3.3V
VCC 3.3V

软件模拟SPI的实现

GPIO初始化

为了更好的移植性,这里将使用到的GPIO引脚通过宏进行了定义,这样在后续有移植需求的情况下,只需要更改宏即可。

//CS(NSS)引脚 片选选普通GPIO即可
#define      FLASH_SPI_CS_APBxClock_FUN        RCC_APB2PeriphClockCmd
#define      FLASH_SPI_CS_CLK                  RCC_APB2Periph_GPIOA    
#define      FLASH_SPI_CS_PORT                 GPIOA
#define      FLASH_SPI_CS_PIN                  GPIO_Pin_4

//SCK引脚
#define      FLASH_SPI_SCK_APBxClock_FUN       RCC_APB2PeriphClockCmd
#define      FLASH_SPI_SCK_CLK                 RCC_APB2Periph_GPIOA   
#define      FLASH_SPI_SCK_PORT                GPIOA   
#define      FLASH_SPI_SCK_PIN                 GPIO_Pin_5
//MISO引脚
#define      FLASH_SPI_MISO_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define      FLASH_SPI_MISO_CLK                RCC_APB2Periph_GPIOA    
#define      FLASH_SPI_MISO_PORT               GPIOA 
#define      FLASH_SPI_MISO_PIN                GPIO_Pin_6
//MOSI引脚
#define      FLASH_SPI_MOSI_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define      FLASH_SPI_MOSI_CLK                RCC_APB2Periph_GPIOA    
#define      FLASH_SPI_MOSI_PORT               GPIOA 
#define      FLASH_SPI_MOSI_PIN                GPIO_Pin_7 


/* 控制W25Q64的相关GPIO初始化函数 */
void W25QXX_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
    FLASH_SPI_CS_APBxClock_FUN(FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|
							FLASH_SPI_MISO_PIN|FLASH_SPI_MOSI_PIN, ENABLE);
	
	
	/* 配置SPI的 CS引脚 */
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);

	/* 配置SPI的 SCK引脚*/
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
	GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
	
	/* 配置SPI的 MOSI引脚*/
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
	GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);


	/* 配置SPI的 MISO引脚*/
	GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);

	
	/* 停止信号 FLASH: CS引脚高电平*/
	SPI_FLASH_CS_HIGH();
}

SPI基本操作

编写通过SPI来进行读写的函数,因为使用的四线SPI是全双工的协议,发送一个字节数据的同时也会接收到一个字节数据,所以这里将读写一个字节的函数写成一个函数。

//通过下面的宏来完成基本的SPI操作
#define  	 SPI_FLASH_CS_LOW()     		   GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
#define  	 SPI_FLASH_CS_HIGH()    		   GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )

#define  	 SPI_FLASH_SCLK_LOW()     		   GPIO_ResetBits( FLASH_SPI_SCK_PORT, FLASH_SPI_SCK_PIN )
#define  	 SPI_FLASH_SCLK_HIGH()    		   GPIO_SetBits( FLASH_SPI_SCK_PORT, FLASH_SPI_SCK_PIN )

#define  	 SPI_FLASH_MOSI_LOW()     		   GPIO_ResetBits( FLASH_SPI_MOSI_PORT, FLASH_SPI_MOSI_PIN )
#define  	 SPI_FLASH_MOSI_HIGH()    		   GPIO_SetBits( FLASH_SPI_MOSI_PORT, FLASH_SPI_MOSI_PIN )    


/* SPI读写一个字节数据的函数 */
uint8_t SPI1_ReadWriteByte(u8 dat)
{
	u8 i, read_data;
	
	SPI_FLASH_SCLK_HIGH();	//时钟线拉高
	
	for (i = 0; i< 8; i++)
	{
		read_data <<= 1;
		
		if (0x80 == ((dat << i)&0x80))
		{
			SPI_FLASH_MOSI_HIGH();
		}	
		else
		{
			 SPI_FLASH_MOSI_LOW();
		}
		SPI_FLASH_SCLK_LOW();	//拉低时钟线,向总线输出数据
		delay_us(1);
		SPI_FLASH_SCLK_HIGH();	//拉高时钟线,准备读取数据
		delay_us(1);
		
		if (GPIO_ReadInputDataBit(FLASH_SPI_MISO_PORT, FLASH_SPI_MISO_PIN))
		{
			read_data |= 0x01;    //读取到数据位为1
		}
	}
	
	SPI_FLASH_SCLK_HIGH();	
	
	return read_data;    
}

W25Q64基础驱动函数

写使能/写禁止函数

查看数据手册,对应指令如下:

#define W25X_WriteEnable		      	0x06 
#define W25X_WriteDisable		      	0x04 


//W25QXX写使能
//将WEL置位
void W25QXX_Write_Enable(void)
{
	SPI_FLASH_CS_LOW();
	SPI1_ReadWriteByte(W25X_WriteEnable);
	SPI_FLASH_CS_HIGH();
}

//W25QXX写禁止
//将WEL清零
void W25QXX_Write_Disable(void)
{
	SPI_FLASH_CS_LOW();
	SPI1_ReadWriteByte(W25X_WriteDisable);
	SPI_FLASH_CS_HIGH();
}

读写状态寄存器

查看数据手册,对应指令如下:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值