SPI的通信很容易实现,相比之下,驱动FLASH反而耗费了我学习SPI整个过程的大部分时间。下面是我学习过程的一些记录。
硬件平台:秉火ISO_V2开发板
实现功能:STM32使用SPI协议读写板载NOR FLASH
1. 通讯引脚
SPI通讯需要4个引脚,nSS、SCK、MISO和MOSI,
以STM32的SPI1为例,其关联GPIO如上图标(摘自《STM32中文参考手册_V10.pdf》-P120)。AFIO_MAPR寄存器的BIT0(SPI1_REMAP)为0时则不重映射SPI1的4个GPIO,nSS、SCK、MISO和MOSI依次为PA4、PA5、PA6、PA7。我们使用寄存器的复位值为0x00,即我们不重映射SPI1关联引脚。开发板原理图的设计也确实如此:
另外,一般在实际工程中,nSS引脚不采用硬件SPI专用的nSS引脚,而是用STM32的一个普通GPIO功能来控制。
2. 软件设计
2.1 SPI初始化结构体
typedef struct
{
uint16_t SPI_Direction; //SPI的单双向模式
uint16_t SPI_Mode; //SPI的主/从机模式
uint16_t SPI_DataSize; //SPI的数据帧长度,8/16位可选
uint16_t SPI_CPOL; //空闲时钟极性,高低电平
uint16_t SPI_CPHA; //时钟相位,即奇偶边沿采样
uint16_t SPI_NSS; //片选引脚nSS是交由硬件控制还是软件控制
uint16_t SPI_BaudRatePrescaler; //时钟分频系数,FSCK = FCLK / 分频系数
uint16_t SPI_FirstBit; //MSB/LSB先行
uint16_t SPI_CRCPolynomial; //CRC校验表达式
}SPI_InitTypeDef;
2.2 操作函数
(1) 使能SPI的时钟
GPIO、SCK、MISO、MOSI都是PA组,且SPI外设跟GPIO外设一样,隶属于APB2总线:所以:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE);
(2) 初始化GPIO引脚
设置SPI1的相关引脚为复用输出,这样才会连接到SPI1上否则这些IO还是默认作为标准输入/输出。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
(3) 初始化SPI1,设置其工作模式
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位数据帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟悬空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //nSS信号软件控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的表达式
SPI_Init(SPI1, &SPI_InitStructure); //将上述设置信息初始化外设SPIx寄存器
(4) 使能SPI1
SPI_Cmd(SPI1, ENABLE);
(5) SPI接收数据
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
(6) SPI发送数据
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
(7) 查看SPI传输过程状态
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
在SPI的传输过程中,若要判断数据是否传输完成,发送缓冲区是否为空等状态,可通过此函数实现。以判断是否发送完成为例:
while (SPI_I2S_GetFlagStatus(SPI1, S
最低0.47元/天 解锁文章
1699

被折叠的 条评论
为什么被折叠?



