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讀寫時序


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);
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章