一、編程要點
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);
}