此系列文章是小白学习STM32的一些学习笔记。小白第一次写笔记文章,有不足或是错误之处,请多体谅和交流!
1.软件设计流程
SPI读写Flash流程:
- 初始化通讯引脚及端口时钟;
- 使能SPI时钟;
- 配置SPI结构体;
- 编写基本SPI按字节收发函数;
- 编写FLASH擦除及读写操作函数;
- 编写测试程序。
2.SPI初始化
其头文件如图:
根据定义的头文件可以写如下初始化程序,初始化SPI、端口时钟,引脚;配置SPI模式。
//SPI_FLASH_Init函数
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_initStructure;
GPIO_InitTypeDef GPIO_InitStructure;//SPI、GPIO结构体定义
FLASH_SPI_APBxClock_FUN(FLASH_SPI_CLK,ENABLE);
FLASH_SPI_CS_APBxClock_FUN(FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|FLASH_SPI_MISO_CLK|FLASH_SPI_MOSI_CLK,ENABLE);
//配置SPI的GPIO引脚
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
FLASH_SPI_CS_HIGH();//片选FLASH_CS为高电平
/*SPI模式配置********************************/
SPI_InitTypeDef SPI_InitStructure;
// FLASH 芯片 支持 SPI 模式 0 及模式 3,据此设置 CPOL CPHA
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
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_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(FLASH_SPIx, &SPI_InitStructure);
/* 使能 SPI */
SPI_Cmd(FLASH_SPIx, ENABLE);
}
3.SPI发送接收一字节函数编写
接下来编写SPI发送和接受一个字节数据的函数,如下:
#define Dummy_Byte 0xFF
u8 SPI_FLASH_SendByte(u8 byte)
{
SPITimeout = SPIT_FLAG_TIMEOUT;
//等待发送缓冲区为空,及TXE事件发生
while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_TXE) == RESET)
{
if((SPITimeout--)==0)
return SPI_TIMEOUT_UserCallback(0);
}
//把数据写入发送缓冲区
SPI_I2S_SendData(FLASH_SPIx,byte);
SPITimeout = SPIT_FLAG_TIMEOUT;
//等待接受缓冲区为非空,及RXNE事件发生
while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_RXNE) == RESET)
{
if((SPITimeout--)==0)
return SPI_TIMEOUT_UserCallback(1);
}
return SPI_I2S_ReceiveData(FLASH_SPIx);
//获取接受缓冲区数据
}
然后使用SPI读取一个字节数据
u8 SPI_FLASH_ReadByte(void)
{
return (SPI_FLASH_SendByte(Dummy_Byte));
}
由于SPI通讯模式配置为全双工模式,即收发是同步进行的。发送数据通过向发送缓冲区写数据即可;接收数据即调用发送数据函数,发送任意值,再返回收到的数据即可。
4.FLASH控制指令介绍
stm32作为主机,通过SPI向FLASH发送的数据过去,FLASH会将这些数据理解成不同指令,然后执行不同操作。
通过SPI依据指令表次序规律发送数据,即可完成相应操作。其中“A0~A23”指 FLASH 芯片内部存储器组织的地址;“M0~M7”为厂商号(MANUFACTURER ID);“ID0-ID15”为 FLASH 芯片的ID;“dummy”指该处可为任意数据;“D0~D7”为 FLASH 内部存储矩阵的内容。
通过指令“9F h”可以获得设备的生产厂商,存储器类型,容量。其通讯时序如下图:
本系列笔记内容和图片基于《【野火®】零死角玩转STM32—F103-MINI》