基于STM32与NOR FLASH的SPI通信

  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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值