39_SPI通讯W25Q128实验

目录

上篇写了具体的SPI通信原理

SPI工作原理

SPI引脚配置

​编辑

SPI相关库函数

程序配置过程

W25Q128硬件连接图

实验源码

上篇写了具体的SPI通信原理

SPI工作原理

1.硬件上为4根线。

2.主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。

3.串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。

4.外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的个字节,就必须发送一个空字节来引发从机的传输。

SPI引脚配置

 

 

SPI相关库函数

void SPI_I2S_Delnit(SPI_TypeDef* SPIx); //复位函数
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); //SPI初始化函数
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); //SPI使能函数
woid SPI_I2S_ITConfig(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT, FunctionalState NewState);//中断配置函数
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);//DMA配置

void SPI_I2S SendData(SPI_TypeDef* SPlx, uint16_t Data); //发送数据
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPlx);//接受数据
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);//SPI数据配置

FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPlx, uint16_t SPI_I2S_FLAG);//获取标志位
void SPI_I2S_ClearFlag(SPI_TypeDef* SPlx, uint16_t SPI_I2S_FLAG);//清除标志
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT);//获取中断状态
void SPI_I2S_ClearlTPendingBit(SPI_TypeDef* SPlx, uint8_t SPI_I2S_IT);//清除中断状态标志

程序配置过程

1.配置相关引脚的复用功能,使能SPlx时钟

void GPIO Init(GPIO_TypeDef* GPIOx, GPIO InitTypeDef* GPIO_InitStruct);

2.初始化SPIx,设置SPIx工作模式

void SPI_Init(SPL TypeDef* SPIx, SPI Init TypeDef* SPL InitStruct);

3.使能SPIx

void SPI Cmd(SPI TypeDef* SPIx, FunctionalState NewState);

4.SPI传输数据

void SPI_I2S_SendData(SPITypeDef* SPIx, uint16 Data);

uint16 SPI_I2S_ReceiveData(SPI TypeDef* SPlx);

5.查看SPI传输状态

SPI_I2S_GetFlagStatus(SPI2, SPI_2S FLAGRXNE);

W25Q128硬件连接图

 W25Q128(W25Q64)将16M(8M)的容量分为256(128)个块(Block)每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25Qxx的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们需要给W25Qxx开辟一个至少4K的缓存区,这样对SRAM要求比较高,要求芯片必须有4K以上SRAM才能很好的操作。

实验源码

/**
  ******************************************************************************
  * @file           : user_rcc_config.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_rcc_config.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		RCC配置
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Rcc_config(void)
{	
	/*使能GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*使能UART1时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	/*使能GPIOB时钟*/
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );
	/*SPI2时钟使能*/
	RCC_APB1PeriphClockCmd(	RCC_APB1Periph_SPI2,  ENABLE );	

}

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_gpio.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_gpio.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		GPIO初始化函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Gpio_Init(void)
{	
	/*GPIO结构体*/
	GPIO_InitTypeDef GPIO_InitTypeDefstruct;
	
	/*UART1发送引脚配置*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_AF_PP;//推挽复用输出
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*写入结构体到GPIOA*/
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*UART1接收引脚配置*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_10;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*写入结构体到GPIOA*/	
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*配置SPI 13 时钟 14 MISO 15 MOSI*/
	GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_AF_PP;  //PB12/13/14/15复用推挽输出 MISO推挽也正常
	GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_50MHz;
	/*写入结构体到GPIOB*/	
	GPIO_Init(GPIOB,&GPIO_InitTypeDefstruct);
	
	/*配置SPI 12 CS*/
	GPIO_InitTypeDefstruct.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitTypeDefstruct.GPIO_Mode = GPIO_Mode_Out_PP;  //PB12
	GPIO_InitTypeDefstruct.GPIO_Speed = GPIO_Speed_50MHz;
	/*写入结构体到GPIOB*/	
	GPIO_Init(GPIOB,&GPIO_InitTypeDefstruct);
	
	/*高电平*/
	GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
}

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_uart.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/

extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];


/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/
#if 1
#pragma import(__use_no_semihosting)  
/*实现Printf代码*/
struct __FILE 
{ 
	int handle; 

}; 
FILE __stdout;       

void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 




/*!
	\brief		UART1初始化
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void Uart1_Init(u32 bound)
{
	/*UART结构体*/
	USART_InitTypeDef USART_InitTypeDefstruct;
	
	/*UART结构体配置*/
	USART_InitTypeDefstruct.USART_BaudRate = bound; //波特率
	USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //不使用硬件流
	USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送接收使能
	USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //不使用奇偶校验
	USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1个停止位
	USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8个数据位
	/*写入USART1*/
	USART_Init(USART1,&USART_InitTypeDefstruct);
	
	/*使能串口1*/
	USART_Cmd(USART1,ENABLE);

}


/*!
	\brief		UART1中断服务函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void USART1_IRQHandler(void)
{

}
	

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_spi.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_spi.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/


/*!
	\brief		设置SPI通信速度
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void SPI2_SetSpeed(uint8_t SPI_BaudRatePrescaler)
{
	/*断言库函数里的*/
	assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
	/*清除第bit3、4、5位可以进库函数去看分频具体数值,分频就是操作 3 4 5bit位*/
	SPI2->CR1&=0XFFC7;
	/*设置SPI2速度*/
	SPI2->CR1|=SPI_BaudRatePrescaler;
	/*重新使能SPI*/
	SPI_Cmd(SPI2,ENABLE); 

} 

/*!
\brief		    读写函数,SPI因为2个位移寄存器相连写一个字节的时候会返回上一次接受到的字节
	\param[in]	发送数据
	\param[in]	none
	\retval 	读取的字节
*/
uint8_t SPI2_ReadWriteByte(uint8_t TxData)
{		
	/*等待超时时间*/
	uint8_t retry=0;
	/*检查指定的SPI标志位设置与否:发送缓存空标志位*/
	while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) 
		{
			retry++;
			if(retry>200)
			{
				return 0;
			}
		}	
	/*通过外设SPI2发送一个数据*/
	SPI_I2S_SendData(SPI2, TxData); 
	/*等待超时时间*/
	retry=0;
	/*检查指定的SPI标志位设置与否:接受缓存非空标志位*/
	while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) 
		{
			retry++;
			if(retry>200)
			{
				return 0;			
			}

		}
    /*返回通过SPIx最近接收的数据*/
	return SPI_I2S_ReceiveData(SPI2); 				    
}


/*!
	\brief		SPI初始化
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Spi_Init(void)
{	
    /*SPI结构体*/
    SPI_InitTypeDef  SPI_InitStructure;
	/*SPI配置*/
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;	 //设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿(下降)数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//片选又软件控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//APB1(36M)/256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//数据传输从MSB(高)位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI2, &SPI_InitStructure);         //写入SPI2里面
	/*使能SPI外设*/
	SPI_Cmd(SPI2, ENABLE); 
	
	/*主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输*/
	SPI2_ReadWriteByte(0xFF);
}

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_w25q128.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Define to prevent recursive incluson---------------------------------------*/
#ifndef _USER_W25Q128_H__
#define _USER_W25Q128_H__

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include "user_spi.h"
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
//指令表数据手册上的
#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg		0x05 
#define W25X_WriteStatusReg		0x01 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
//片选引脚
#define	W25Q128_CS  BIT_ADDR(GPIOB_ODR_Addr,12)  //W25QXX的片选信号 1取消片选 0 选中
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/
uint16_t  W25Q128_ReadID(void);  	    		//读取FLASH ID
void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   //读取flash
void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
void W25Q128_Init(void); //初始化

#endif

/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_w25q128.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_w25q128.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/*中转变量发现有其他值的全部取出来,然后擦除一个扇区在写回去*/
uint8_t W25Q128_BUFFER[4096];
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		W25Q128初始化
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Init(void)
{	
	/*W25Q128不片选*/
	W25Q128_CS=1;
	/*初始化SPI*/
	Spi_Init();
	/*//设置为36/2=18M时钟,高速模式*/
	SPI2_SetSpeed(SPI_BaudRatePrescaler_2);
}

/*!
	BIT7  6   5   4   3   2   1   0
	SPR   RV  TB BP2 BP1 BP0 WEL BUSY
 	SPR:默认0,状态寄存器保护位,配合WP使用
 	TB,BP2,BP1,BP0:FLASH区域写保护设置
 	WEL:写使能锁定
 	BUSY:忙标记位(1,忙;0,空闲)
 	默认:0x00
	\brief		读取W25Q128状态寄存器
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
uint8_t W25Q128_ReadSR(void)   
{  
	/*接收数据变量*/
	uint8_t byte=0;   
	/*选中片选*/
	W25Q128_CS=0;
	/*发送读取状态命令,同时会返回一个无用字节*/
	SPI2_ReadWriteByte(W25X_ReadStatusReg); 
	/*写一个无用字节,返回状态寄存器值*/
	byte=SPI2_ReadWriteByte(0XFF);
	/*取消片选*/
	W25Q128_CS=1;  
	/*返回状态*/
	return byte;   
}

/*!  SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写
	\brief		写W25Q128状态寄存器
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Write_SR(uint8_t sr)   
{  
	/*选中片选*/
	W25Q128_CS=0;     
	/*发送写取状态寄存器命令*/	
	SPI2_ReadWriteByte(W25X_WriteStatusReg); 
	/*写入一个字节*/
	SPI2_ReadWriteByte(sr);
	/*取消片选*/
	W25Q128_CS=1;                                	      
} 

/*!
	\brief		写W25Q128使能
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Write_Enable(void)   
{
	/*选中片选*/
	W25Q128_CS=0; 
	/*发送写使能命令*/
    SPI2_ReadWriteByte(W25X_WriteEnable);
 	/*取消片选*/
	W25Q128_CS=1;                           	     	      
} 

/*!
	\brief		写W25Q128禁止
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Write_Disable(void)   
{  
	/*选中片选*/
	W25Q128_CS=0;    
	/*发送写禁止指令*/
    SPI2_ReadWriteByte(W25X_WriteDisable);  
	/*取消片选*/
	W25Q128_CS=1;                              	      
} 
/*!
	\brief		读取ID
	\param[in]	none
	\param[in]	none
	\retval 	0XEF17,表示芯片型号为W25Q128
*/
uint16_t W25Q128_ReadID(void)
{
	/*ID返回变量*/
	uint16_t Temp = 0;
	/*选中片选*/	
	W25Q128_CS=0;	
	/*发送读取ID命令*/
	SPI2_ReadWriteByte(W25X_ManufactDeviceID);
	/*发送24bit位的地址*/
	SPI2_ReadWriteByte(0x00); 	    
	SPI2_ReadWriteByte(0x00); 	    
	SPI2_ReadWriteByte(0x00);
	/*发无用字节,接收ID*/
	Temp|=SPI2_ReadWriteByte(0xFF)<<8;  
	Temp|=SPI2_ReadWriteByte(0xFF);	 
	/*取消片选*/
	W25Q128_CS=1;	
	/*返回ID*/
	return Temp;
} 

/*!
	\brief		擦除一个扇区
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Erase_Sector(u32 Dst_Addr)   
{  
	/*一个扇区是4096个字节*/
 	Dst_Addr*=4096;
	/*写使能*/
    W25Q128_Write_Enable(); 	
	/*等待BUSY位清空*/
    while((W25Q128_ReadSR()&0x01)==0x01); 
	/*选中片选*/		
  	W25Q128_CS=0;
	/*发送扇区擦除指令*/
    SPI2_ReadWriteByte(W25X_SectorErase);
	/*发送24bit地址*/
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));  	   
    SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPI2_ReadWriteByte((u8)Dst_Addr); 
	/*取消片选*/	
	W25Q128_CS=1;                               	      
	/*等待擦除完成*/
    while((W25Q128_ReadSR()&0x01)==0x01);  				   	
}  

/*!
	\brief		擦除整个芯片
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void W25Q128_Erase_Chip(void)   
{                                   
	/*写使能*/
    W25Q128_Write_Enable(); 
	/*等待BUSY位清空*/
    while((W25Q128_ReadSR()&0x01)==0x01); 
	/*选中片选*/		
  	W25Q128_CS=0;
	/*发送片擦除命令*/   
    SPI2_ReadWriteByte(W25X_ChipErase); 
	/*取消片选*/		
	W25Q128_CS=1;                            	     	      
	/*等待擦除完成*/
    while((W25Q128_ReadSR()&0x01)==0x01); 
}

/*!
	\brief		读取函数
	\param[in]	读取BUFF
	\param[in]	要读取的地址(24bit)
	\param[in]	要读取的数量(65535字节最大)
	\retval 	none
*/
void W25Q128_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{ 
 	uint16_t i;
	/*选中片选*/		
	W25Q128_CS=0;                            	
	/*发送读取命令*/	
    SPI2_ReadWriteByte(W25X_ReadData);
	/*发送读取命令*/
    SPI2_ReadWriteByte((u8)((ReadAddr)>>16));    
    SPI2_ReadWriteByte((u8)((ReadAddr)>>8));   
    SPI2_ReadWriteByte((u8)ReadAddr); 
	/*开始发空指令,返回寄存器的值*/
    for(i=0;i<NumByteToRead;i++)
	{    
		/*循环读数*/
        pBuffer[i]=SPI2_ReadWriteByte(0XFF);   	 
    }
	/*取消片选*/	
	W25Q128_CS=1;  				    	      
}  

/*!
	\brief		写一页256个字节
	\param[in]	写BUFF
	\param[in]	要写的地址(24bit)
	\param[in]	要写的数量(256字节最大)
	\retval 	none
*/
void W25Q128_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
	/*写使能*/
    W25Q128_Write_Enable();                  	
	/*选中片选*/		
	W25Q128_CS=0;       
	/*发送写页命令*/
    SPI2_ReadWriteByte(W25X_PageProgram); 
	/*发送24bit地址*/
    SPI2_ReadWriteByte((u8)((WriteAddr)>>16));    
    SPI2_ReadWriteByte((u8)((WriteAddr)>>8));   
    SPI2_ReadWriteByte((u8)WriteAddr);  
	/*开始循环写数*/
    for(i=0;i<NumByteToWrite;i++){
		SPI2_ReadWriteByte(pBuffer[i]);
	}
	/*取消片选*/
	W25Q128_CS=1;                            
	/*等待擦除完成*/
    while((W25Q128_ReadSR()&0x01)==0x01); 
} 

/*!
	\brief		检查是否一页当中有存其他值,可以换页
	\param[in]	写BUFF
	\param[in]	要写的地址(24bit)
	\param[in]	要写的数量(256字节最大)
	\retval 	none
*/
void W25Q128_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 			 		 
	u16 pageremain;	
	/*单页剩余的字节数*/
	pageremain=256-WriteAddr%256; 
	/*不大于256个字节*/
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
	while(1)
	{	/*写一页256个字节*/  
		W25Q128_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)
		{	/*写入结束*/
			break;	
		}
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	
			/*减去已经写入了的字节数*/
			NumByteToWrite-=pageremain;			  
			/*一次可以写入256个字节*/
			if(NumByteToWrite>256)
			{
				pageremain=256;
			} 
			else
			{	/*不够256个字节了*/
				pageremain=NumByteToWrite;
			}  	  
		}
	}	    
}

/*!
	\brief		写数据
	\param[in]	写BUFF
	\param[in]	要写的地址(24bit)
	\param[in]	要写的数量(65535字节最大)
	\retval 	none
*/
void W25Q128_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
	u32 secpos;
	u16 secoff;
	u16 secremain;	   
 	u16 i;    
	u8 * W25QXX_BUF;	  
   	W25QXX_BUF=W25Q128_BUFFER;	
	/*扇区地址*/	
 	secpos=WriteAddr/4096;
	/*在扇区内的偏移*/	
	secoff=WriteAddr%4096;
	/*扇区剩余空间大小*/		
	secremain=4096-secoff;
	/*不大于4096个字节*/
 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;
	while(1) 
	{	/*读出整个扇区的内容*/
		W25Q128_Read(W25QXX_BUF,secpos*4096,4096);
		/*校验数据*/
		for(i=0;i<secremain;i++)
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)
			{
				/*需要擦除 */
				break;
			}
				 	  
		}
		/*//需要擦除 */
		if(i<secremain)
		{
			/*擦除这个扇区*/
			W25Q128_Erase_Sector(secpos);		
			/*复制*/
			for(i=0;i<secremain;i++)	   		
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			/*写入整个扇区*/
			W25Q128_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//

		}else
		{	/*写已经擦除了的,直接写入扇区剩余区间*/
			W25Q128_Write_NoCheck(pBuffer,WriteAddr,secremain);
		}					   
		if(NumByteToWrite==secremain)
		{	/*写入结束了*/
			break;
		}
		else/*写入未结束*/
		{	/*扇区地址增1*/
			secpos++;
			/*偏移位置为0*/
			secoff=0; 	 
			/*指针偏移*/
		   	pBuffer+=secremain;  				
			/*写地址偏移*/
			WriteAddr+=secremain;				
			/*字节数递减*/
		   	NumByteToWrite-=secremain;
			/*下一个扇区还是写不完*/
			if(NumByteToWrite>4096)
			{
				secremain=4096;
			}
			else 
			{	/*下一个扇区可以写完了*/
				secremain=NumByteToWrite;
			}		
		}	 
	};	 
}
/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_w25q128.h"


/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
#define SIZE sizeof(TEXT_Buffer)
/* Variables 变量--------------------------------------------------------------*/
const uint8_t TEXT_Buffer[]={"SPI TEST AAAAAAAAA"};	 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/


 int main(void)
 {	
	/*ID变量*/
	uint16_t id;
	/*flash大小16M字节*/
	uint32_t FLASH_SIZE = 128*1024*1024;
	/*读出数组*/
	uint8_t datatemp[SIZE];	
	/*打印变量*/
	uint16_t i;	 
	/*配置系统中断分组为2位抢占2位响应*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*W25Q128初始化*/
	 W25Q128_Init();			
	/*死循环*/ 
	 while(1){
		id = W25Q128_ReadID();
		if(id == 0X5217)
		{
			printf("W25Q128\r\n");
		}

		/*从倒数第200个地址处开始,写入SIZE长度的数据*/	 
		W25Q128_Write((uint8_t*)TEXT_Buffer,FLASH_SIZE-200,SIZE);
		/*从倒数第100个地址处开始,读出SIZE个字节*/
		W25Q128_Read(datatemp,FLASH_SIZE-200,SIZE);	
		for(i = 0; i < SIZE; i++)
		{
			printf("%c",datatemp[i]);	
		}
			printf("\r\n");
			delay_ms(1000);
	 }
		

}
 
 /************************************************************** END OF FILE ****/

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值