SPI_FLASH

一、编程要点

1、初始化SPI相关外设以及GPIO

2、初始化SPI结构体

3、编写函数

4、进行读写测试

二、结构体&库函数

1、SPI初始化结构体

{
  uint16_t SPI_Direction;           /*!< 传输方向 全双工 */

  uint16_t SPI_Mode;                /*!< 模式设置 主机/从机 模式 */

  uint16_t SPI_DataSize;            /*!< 数据帧长度 16/8 */

  uint16_t SPI_CPOL;                /*!< 时钟极性*/

  uint16_t SPI_CPHA;                /*!< 时钟相位 */

  uint16_t SPI_NSS;                 /*!< 片选信号 软件/硬件控制*/
 
  uint16_t SPI_BaudRatePrescaler;   /*!< 时钟分频因子  */

  uint16_t SPI_FirstBit;            /*!< 设置传输数据 高/低位先行  */

  uint16_t SPI_CRCPolynomial;       /*!< 检验表达式 */
}SPI_InitTypeDef;

2、标志位检测函数

SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG)

while(SPI_I2S_GetFlagStatus(FLASH_SPIX,SPI_I2S_FLAG_TXE)==RESET);//检测TXE标置位
@brief 检测相应标志位
@param1:SPI号
@param2:要检测的标志位

三、SPI读写时序


扫描二维码关注公众号,回复: 1838193 查看本文章

1、SPI读时序

CS(L) -> 8位指令 -> 24位地址 -> 循环读取字节数据 -> CS(H) 

2、SPI写时序

写使能 -> CS(L) -> 8位指令 -> 24位地址 -> 循环读取字节数据 -> CS(H) 

3、SPI擦除扇区时序

等待时序完成 -> 写使能 -> CS(L) -> 8位指令 -> 24位地址 -> 循环读取字节数据 -> CS(H) -> 等待时序完成 

4、24 位地址发送方

SendByte((ReadAddr&0xff0000)>>16);		//高8位地址
SendByte((ReadAddr&0xff00)>>8);			//中
SendByte(ReadAddr&0xff);			//低

四、等待FLASH 内部时序完成

void FLASH_AwaitEnd(void)     //等待flash内部时序完成  擦除等
{
	u8 Stuartflag=0;			//
	
	FLASH_SPI_CS_LOW;
	SendByte(READ_STATUS);			//发送读标志
	do
	{
		Stuartflag=SendByte(0x00);     //获取标志
	}
	while((Stuartflag&0X01)==1);             //最低位置 0 则内部时序完成 
	FLASH_SPI_CS_HIGH;
}

五、程序源码

1、bsp_flash.h文件

#ifndef __EEPROM_H
#define __EEPROM_H

#include "stm32f10x.h"

#define SPI_GPIO_APBX_CLOCK   			RCC_APB2PeriphClockCmd
#define SPI_APBX_CLOCK   			RCC_APB2PeriphClockCmd

#define SPIX_GPIO_CLK 				(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA)
#define FLASH_SPI_CLK 				RCC_APB2Periph_SPI1


#define SPIX_SCK_PORT        		GPIOA
#define SPIX_SCK_PIN        		GPIO_Pin_5

#define SPIX_MOSI_PORT        		GPIOA
#define SPIX_MOSI_PIN        		GPIO_Pin_7

#define SPIX_MISO_PORT        		GPIOA
#define SPIX_MISO_PIN        		GPIO_Pin_6

#define SPIX_CS_PORT        		GPIOC
#define SPIX_CS_PIN        		GPIO_Pin_0


#define FLASH_SPIX    SPI1

#define SPIT_LONG_TIMEOUT		0x1000

//CS引脚配置
#define FLASH_SPI_CS_HIGH  		  GPIO_SetBits(SPIX_CS_PORT,SPIX_CS_PIN);
#define FLASH_SPI_CS_LOW 		  GPIO_ResetBits(SPIX_CS_PORT,SPIX_CS_PIN);

#define DUMMY 						0x00	
#define READ_JEDEC_ID    0x9f		//读设备ID
#define ERASE_SECTOR	0x20		//擦除扇区												
#define READ_STATUS	0x05		//读标志
#define READ_DATA	0x03		//读数据
#define WRITE_ENABLE    0x06		//写使能
#define WRITE_DATA      0x02		//写数据														
																

void SPI_FLASH_config(void);			                //SPI初始化
uint8_t SendByte(uint8_t data);		                        //发送一个字节数据
uint8_t ReadByte(void);						//读取一个字节数据
uint32_t Read_FlashID(void);			                   //读flash设备  ID
void FLASH_Read(uint32_t ReadAddr,uint8_t *data, uint32_t num);  //读flash数据
void FLASH_WriteEn(void); 	                        	//写入使能
void FLASH_AwaitEnd(void);                                     //等待flash内部时序完成  擦除等
void FLASH_SectorErase(uint32_t SectorAddr);			//擦除指定扇区
void SPI_FLASH_Read(u8 *data,u32 ReadAddr,u32 num);		//写入的数据指针  起始地址  长度




#endif		//__EEPROM_H
2、 bsp_flash.c文件
#include "bsp_flash.h"

void SPI_FLASH_config(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	SPI_InitTypeDef  SPI_InitStructure;
	
	SPI_GPIO_APBX_CLOCK(SPIX_GPIO_CLK,ENABLE);	        //打开GPIO时钟
	SPI_APBX_CLOCK(FLASH_SPI_CLK,ENABLE);			//SPI外设时钟
	
	GPIO_InitStructure.GPIO_Pin = SPIX_SCK_PIN;		//选择SCK线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	        //复用输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//输出速率
	GPIO_Init(SPIX_SCK_PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin =SPIX_MISO_PIN ;		//选择MISO线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	  //浮空输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//输出速率
	GPIO_Init(SPIX_MISO_PORT,&GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = SPIX_MOSI_PIN;		//选择MOSI线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	      //复用输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//输出速率
	GPIO_Init(SPIX_MOSI_PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = SPIX_CS_PIN;		//选择CS线
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //通用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//输出速率
	GPIO_Init(SPIX_CS_PORT,&GPIO_InitStructure);
	
	FLASH_SPI_CS_HIGH;		//CS高电平

	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //时钟分频因子
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;			    //奇/偶采样
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;			   //时钟极性
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据长度
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    //全双工
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		        //高位先行
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//软件控制片选信号
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;				//主机模式
	SPI_InitStructure.SPI_CRCPolynomial = 0;

	
	SPI_Init(SPI1, &SPI_InitStructure);

	SPI_Cmd(FLASH_SPIX,ENABLE);

}

uint8_t SendByte(uint8_t data)		                                    //发送并读取一个字节数据
{
	while(SPI_I2S_GetFlagStatus(FLASH_SPIX,SPI_I2S_FLAG_TXE)==RESET);    //检测TXE标置位
	
	SPI_I2S_SendData(FLASH_SPIX,data);
	while(SPI_I2S_GetFlagStatus(FLASH_SPIX,SPI_I2S_FLAG_RXNE)==RESET);    //检测RXNE标置位

	return SPI_I2S_ReceiveData(FLASH_SPIX);					//返回读取的数据

}


uint8_t ReadByte(void)		//读取一个字节数据
{
	return SendByte(0x00);

}
	
uint32_t Read_FlashID(void)		//读FLASH ID
{
	uint32_t FlashID;			//设备ID
	
	FLASH_SPI_CS_LOW;			//起始信号
	SendByte(0x9f);				//读ID指令
	
	FlashID=SendByte(0x00);			//接收高8位
	FlashID<<=8;
	FlashID|=SendByte(0x00);		//接收中8位
	FlashID<<=8;
	FlashID|=SendByte(0x00);		//低八=8位
	
	FLASH_SPI_CS_HIGH;			//结束信号

	return FlashID;				//返回读取到的ID
	
	
}

void FLASH_Read(uint32_t ReadAddr,uint8_t *data, uint32_t num)		//读flash数据  起始地址 读取的数据  长度
{

	FLASH_SPI_CS_LOW;											
	SendByte(READ_DATA);
	
	SendByte((ReadAddr&0xff0000)>>16);		        //高8位地址
	SendByte((ReadAddr&0xff00)>>8);				//中
	SendByte(ReadAddr&0xff);				//低
	
	while(num)						//循环读取数据
	{
		*data=SendByte(0x00);
		data++;
		num--;
		
	}
	FLASH_SPI_CS_HIGH;

}

void FLASH_WriteEn(void) 		//写入使能
{
	FLASH_SPI_CS_LOW;
	
	SendByte(WRITE_ENABLE); 	//写使能指令
	
	FLASH_SPI_CS_HIGH;
	
}

void FLASH_AwaitEnd(void)     //等待flash内部时序完成  擦除等
{
	u8 Stuartflag=0;						//
	
	FLASH_SPI_CS_LOW;
	SendByte(READ_STATUS);			    //发送读标志
	do
	{
		Stuartflag=SendByte(0x00);         //获取标志
	}
	while((Stuartflag&0X01)==1)                //最低位置 0 则内部时序完成 
	FLASH_SPI_CS_HIGH;
}
	
void FLASH_SectorErase(uint32_t SectorAddr)		//擦除指定扇区    擦除起始地址
{
	FLASH_AwaitEnd();				//等待时序完成
	FLASH_WriteEn();				//写使能
	FLASH_SPI_CS_LOW;									

	SendByte(0x20);					//发送擦除指令
	
	SendByte((SectorAddr&0xff0000)>>16);			
	SendByte((SectorAddr&0xff00)>>8);
	SendByte(SectorAddr&0xff);

	FLASH_SPI_CS_HIGH;
	FLASH_AwaitEnd();			//等待擦除完成
	
}


void SPI_FLASH_Read(u8 *data,u32 ReadAddr,u32 num)		//写入的数据指针  起始地址  长度
{
	FLASH_SectorErase(ReadAddr);				//擦除要写入的块数据
	
	FLASH_WriteEn();				        //写使能
	FLASH_SPI_CS_LOW;

	SendByte(0x02);						//写数据指令
	
	SendByte((ReadAddr&0xff0000)>>16);
	SendByte((ReadAddr&0xff00)>>8);
	SendByte(ReadAddr&0xff);
	
	while(num)						//循环写入数据
	{
		SendByte(*data);
		num--;
		data++;
	}
	
	FLASH_SPI_CS_HIGH;	
	FLASH_AwaitEnd();

}

3、main 函数

#include "stm32f10x.h"   
#include "bsp_led.h"
#include "usart.h"
#include "bsp_flash.h"

#define GPIOB_ODR_Addr      (GPIOB_BASE+0X0C)
#define PBout(n)   *(unsigned int *)((GPIOB_ODR_Addr & 0xF0000000)+0x02000000+((GPIOB_ODR_Addr&0x00FFFFFF)<<5)+(n<<2))
	
uint8_t ReadData[256]={0};
uint8_t writeData[256]={0};

void delay(uint32_t i)
{
	while(i--);
}
	
int main(void)
{	
	u16 i;
	
	u32 ID=100;			//定义FLASH  ID变量
	
	LED_GPIO_Config();
	PBout(0)=1;
	USART_config();

	SPI_FLASH_config();

	ID=Read_FlashID();   //读ID
	
	for(i=0;i<256;i++)		//数据填充
	{
		writeData[i]=i;
	}

	printf("\r\nID=0X%x\n",ID);			//读ID
	FLASH_SectorErase(0);
	
	SPI_FLASH_Read(writeData,0,256);		//写入的数据指针  起始地址  长度

	FLASH_Read(0,ReadData, 256);		        //读数据  地址  缓存指针  长度
	
	for(i=0;i<256;i++)				//循环串口输出
	{
		printf("%4d",ReadData[i]);
		if(i%10==0)		printf("\n");
	
	}
	
	PBout(0)=0;

  while(1);
}






猜你喜欢

转载自blog.csdn.net/qq_41985317/article/details/80718211
今日推荐