一、编程要点
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);
}