历史上的今天

今天是:2024年11月03日(星期日)

2021年11月03日 | STM32F103ZET6 — SPI

发布者:电子思维 来源: eefocus关键字:STM32F103ZET6  SPI  时钟 手机看文章 扫描二维码
随时随地手机看文章

简介

SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。


SPI 具有信号线少,协议简单,数据率高等优点。数据传送速率达几MB/s


Pin 脚介绍

标准的 SPI 使用 4 Pin 进行数据传送:


(1)MOSI – 主器设备数据输出,从器件数据输入


(2)MISO – 主器设备件数据输入,从器件数据输出


(3)SCLK – 时钟信号,由主器件产生, 最大为fPCLK/2,从模式频率最大为fCPU/2


(4)NSS – 从器件使能信号,由主器件控制,有的 IC 会标注为 CS (Chip select)

数据时在 CLK 时钟的驱动下,在数据线上按照一个 bit 一个 bit 的进行传送,数据可以在时钟的上升沿或者下降沿改变(或者采样)。


SPI 传输的缺点是,没有数据完整性校验,也没有流控机制。


既然称 SPI 为总线,则 SPI 就可以支持多个设备相连接,通过 CS 片选信号来指定期望通讯的设备。(多机通讯)


SPI 模式

SPI 通讯有 4 中不同的通讯模式,通信双方需要配置成为一样的模式,才能够进行正常的数据传输,这里有两个概念:


CPOL:时钟极性


CPHA:时钟相位


CPOL:(时钟极性)控制在没有数据传输时,SPI 时钟的空闲状态电平。即,定义了总线空闲的工作状态(注意,和 UART 不同,SPI 是通过 CLK 的状态来表征当前的总线状态,即不发生任何数据交互的时候,时钟信号总是没有进行翻转的)


CPOL=0,表示当SCLK=0时处于空闲态


CPOL=1,表示当SCLK=1时处于空闲态


CPHA:(时钟相位)是用来配置数据采样是在第几个边沿。


CPHA=0,表示数据采样是在第1个边沿


CPHA=1,表示数据采样是在第2个边沿


所以 CPOL 和 CPHA 的不同组合,成为了 SPI 的四种传输模式:


SPI Mode

image.png

四种传输模式,定义了不同时刻的总线启动,以及数据发送和采样时间:


CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是 SCLK 由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。


CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是 SCLK 由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。


CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是 SCLK 由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。


CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是 SCLK 由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。


对应到波形上:

STM32 SPI 特性

STM32 上支持 3 路 SPI:


可以支持全双工的通信

支持硬件 CRC

可编程的数据顺序,MSB在前或LSB在前

主模式和从模式的快速通信

可编程的时钟极性和相位(CPOL,CPHA)

可触发中断的专用发送和接收标志

可触发中断的主模式故障、过载以及CRC错误标志

支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求


SPI 时钟

单板上使用 SPI2 进行 SPI FLASH 的操作,使用的是 APB1 的时钟,最大配置为 36MHz。


硬件连接

硬件上,通过单板的 SPI2 引脚,连接到外部的 SPI FLASH (W25Q64)

所以,在配置的时候,需要针对 SPI2 进行配置。


SPI Flash 简介

硬件单板上,连接的是 WinBond 的 W25Q64BV 的 SPI Flash,此款 Flash 的特性如下:


大小:64M-bit / 8M-byte

页 : 256B

支持 80MHz 的时钟

支持扇区擦除:Sector Erase (4K-bytes)

支持块擦除:Block Erase (32K and 64K-bytes)

支持页写入:0~256-bytes

软件/硬件写保护

由于暂时不需要硬件写保护和Hold功能,故,直接将 WP和HOLD引脚接到 VCC(3.3V)


(此款SPI FLASH 还支持双线和4线 QSPI 的读写,由于 STM32 不支持,所以不在多说)


根据 W25Q64BV 的 Datasheet 描述,在操作这块 FLASH 的时候,需要配置主机为:


SPI Mode 0 或者 Mode 3

MSB 先传输

故,在 SPI2 配置的时候,需要进行对应的配置,才能够继续正常数据通信


W25Q64BV 存在两个寄存器可以被访问,为 Status Register-1 和 Status Register-2,其中描述的关于 Write-Protect 的部分,暂时不管。与读写相关的就是 BUSY 位了,因为对 SPI Flash 编程后,Flash 需要内部的 cylce 进行数据的写入,内部program的时候会将 BUSY 置成 1,写入完成后,会将 BUSY 位置 0,故,每次对 Flash 进行写(包括擦除)之前,均要进行 BUSY 位的判断。

好啦,现在就开始按照 DateSheet 进行配置我们的 STM32 了。


STM32 SPI2 配置

配置过程主要分为两步:GPIO 的配置,SPI2 的配置(如原理图所示,PB_12 的 GPIO 用于了 CS 片选,我们需要将其配置成为输出的 GPIO,拉低的时候,选中 Flash,拉高的时候释放 Flash 信号)


1. 开启 GPIO B 组的时钟


2. 开启 SPI2 的时钟


3. 按照 STM32 手册,配置 SCK 、MOSI 和 NSS 为复用推挽输出、MISO为浮空输入(有的代码将 MISO 配置成为的输出,虽然也可以运行,不过,您不觉得别扭么?还是遵循 Spec 的来吧)。同时将 GPIO_B _12配置为输出(CS信号)

4. 配置 SPI2 为全双工模式


5. SPI2 为 Master


6. SPI2 运行在 MODE3(按照 W25Q64BV 的 Timing 要求 )


7. SPI2 NSS 为软件模式(根本没用)


8. 预分频系数为 4 分频(APB1 为 36M,则 SPI2 的 SCK 为 9 MHz)


9. SPI2 传输 MSB(按照 W25Q64BV 的 Timing 要求)


10. 不启用 CRC


11. 开启 SPI 功能


此刻 SPI 的配置就基本完成了。接下来就是 按照 W25Q64BV 的 Timing 要求,写 FLASH 驱动咯.....


#define SK_SPI_FLASH_CS_HIGH()           GPIO_SetBits(GPIOB, GPIO_Pin_12)

#define SK_SPI_FLASH_CS_LOW()            GPIO_ResetBits(GPIOB, GPIO_Pin_12)

 

/*******************************************************************************

* Function Name  : SK_SPIPortInit

* Description    : Configure the I/O port for SPI2.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

static void _SK_SPI2PortInit(void)

{

    GPIO_InitTypeDef stGpioInit;

 

    /*!< Configure pins: SCK */

    stGpioInit.GPIO_Pin = GPIO_Pin_13;

    stGpioInit.GPIO_Speed = GPIO_Speed_50MHz;

    stGpioInit.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &stGpioInit);

 

    /*!< Configure pins: MISO */

    stGpioInit.GPIO_Pin = GPIO_Pin_14;

    stGpioInit.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOB, &stGpioInit);

 

    /*!< Configure pins: MOSI */

    stGpioInit.GPIO_Pin = GPIO_Pin_15;

    stGpioInit.GPIO_Speed = GPIO_Speed_50MHz;

    stGpioInit.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &stGpioInit);

 

    /*!< Configure pins: CS */

    stGpioInit.GPIO_Pin = GPIO_Pin_12;

    stGpioInit.GPIO_Speed = GPIO_Speed_50MHz;

    stGpioInit.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &stGpioInit);

}

 

/*******************************************************************************

* Function Name  : _SK_SPI2BusInit

* Description    : Configure the SPI2 Bus to adpte the W25Q64 Flash.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

static void _SK_SPI2BusInit(void)

{

    SPI_InitTypeDef  SPI_InitStructure;

 

    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; // PCLK = 36M, SPI2 CLK = PCLK/4 = 9M

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

    SPI_InitStructure.SPI_CRCPolynomial = 7;

 

    SPI_Init(SPI2, &SPI_InitStructure);

    SPI_Cmd(SPI2, ENABLE);

}

 

/*******************************************************************************

* Function Name  : SK_SPIInit

* Description    : Initializes the peripherals used by the SPI FLASH driver.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void SK_SPIFlashInit(void)

{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

 

    _SK_SPI2PortInit();

 

    SK_SPI_FLASH_CS_HIGH();

 

    _SK_SPI2BusInit();

}


W25Q64BV Flash 驱动

W25Q64BV 是 Flash 嘛,最主要的就是读和写。当然,除了这些,还有擦除功能,读 ID 等等。不着急,一步一步来,都是套路。


STM32 在进行 SPI 全双工数据传输的时候,在通过 MOSI 写出去数据后,可以立马进行 MISO 数据读取,通过轮询 TXE 标志来判断数据已经全部加载到移位寄存器,通过轮询 RXE 标志来得知本次 MISO 的数据已经全部到账。


针对  W25Q64BV Flash,Datasheet 中列出了支持的多种不同的命令:

对应上述表格,有不同的 Timing 进行描述,比如:Opcode 为 0x9F 的时候,是读取一个叫 JEDEC ID 的东西:

可以看到,主机首先将 CS 拉低,然后主机处在 Mode 0 或者 Mode 3 的时候,在 MOSI 信号上输出 0x9F 的数据(命令),然后接着写入 Dummy Data (随便写点东西),然后再 MISO 信号上就能够收到 manufacture ID 的信息(为 0xEF),在继续写入 Dummy Data,继续接收,继续写入,继续接收,这样便可以得到期望的数据了。


获取 Flash ID 信息

根据上述方式,便可以获取 ID 信息:


/********************** W25Q64 Flash Command Defination ***********************/

#define SPI_FLASH_PerWritePageSize      256

 

#define W25X_WriteEnable                0x06 

#define W25X_WriteDisable               0x04 

#define W25X_ReadStatusReg_1            0x05

#define W25X_ReadStatusReg_2            0x35 

#define W25X_WriteStatusReg             0x01 

#define W25X_ReadData                   0x03 

#define W25X_FastReadData               0x0B 

#define W25X_FastReadDual               0x3B 

#define W25X_PageProgram                0x02 

#define W25X_64K_BlockErase             0xD8 

#define W25X_32K_BlockErase             0x52 

#define W25X_4K_SectorErase             0x20 

#define W25X_ChipErase                  0xC7 

#define W25X_PowerDown                  0xB9 

#define W25X_ReleasePowerDown           0xAB 

#define W25X_DeviceID                   0xAB 

#define W25X_ManufactDeviceID           0x90 

#define W25X_JedecDeviceID              0x9F 

 

#define Busy_Flag                       0x01  /* Write In Progress (WIP) flag */

#define Dummy_Byte                      0xFF  /* Dummy Data */

 

typedef struct {

    uint8_t manufacturer_id;

    uint8_t memory_type_id;

    uint8_t capacity_id;

    uint8_t device_id;

} W25Q64_ID_t;

 

 

/*******************************************************************************

* Function Name  : SPI_FLASH_SendByte

* Description    : Sends a byte through the SPI interface and return the byte

*                  received from the SPI bus.

* Input          : byte : byte to send.

* Output         : None

* Return         : The value of the received byte.

*******************************************************************************/

static uint8_t SPI_FLASH_SendByte(uint8_t byte)

{

  /* Loop while DR register in not emplty */

  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

 

  /* Send byte through the SPI2 peripheral */

[1] [2] [3]
关键字:STM32F103ZET6  SPI  时钟 引用地址:STM32F103ZET6 — SPI

上一篇:STM32 DMA外设地址的计算问题
下一篇:STM32F103ZET6 — SDIO (Mirco SDCard)

推荐阅读

        芯科技消息(文/雷明正),大陆福建晋华集成电路公司和台湾联华电子公司2日遭美方起诉共谋窃取美国半导体厂美光的商业机密。联电一早公告声明,表示美国政府起诉内容实际上与先前美光对公司提起民事诉讼所主张的内容相同。对于美国检察官办公室未事先通知联电,并未给予讨论事件始末机会表示遗憾。联电特别强调,针对此类指控,都将严正...
南方电网公司始终坚持推进核心技术创新和商业模式创新,提早布局区块链技术在能源领域的应用。 在珠海,广东电网公司珠海供电局开展了基于区块链技术的绿证交易平台试点示范。在深圳,南网电动汽车公司于今年1月31日开出全国首份充电电费区块链电子发票,截至昨日,已累计开具5000余张。 据了解,在国内外能源领域中,区块链技术多用于解决可再生能...
CPE这个东东,对于我们国内用户来说,算是一个新鲜且少见的玩意。 它的全称叫做Customer Premise Equipment,业内喜欢称之为“客户终端设备”。其实,Premise有“前提、假设”的意思,更准确的翻译应该是“客户前置设备”。 所谓“前置”,是指它总是站在用户设备的“前面”。它的作用,是将移动通信信号(4G、5G等)或有线宽带信号,转换成本地局域网信...

史海拾趣

问答坊 | AI 解惑

protel

哪位兄弟有可以实现仿真的电路原理图,请提供!能够实现将微弱小信号放大为0——5V的标准信号…

查看全部问答∨

谁闲着呢?看一个很奇怪的C问题

最近做个东西写了个小程序但是就出现了费解的问题.仅仅是改动下面的几句 程序就出现非常不正常的现象,看不出问题出那里了.....只有把if(a-b >1)改为if(--a != b)(后面有a的修正a++) 程序才能正常运行.....很是纳闷.....这俩句子没区别吧??? ...…

查看全部问答∨

18b20

问一下各位:           18b20在发送64为序列号时是8位产品类型号在前还是8位CRC码在前?     期待高手回复…

查看全部问答∨

数模转换

急急急,求数模转换设计…

查看全部问答∨

大家有没有使用过HT1620/21?

我正在做一个温度计,需要使用到HT1620/21,前一段搭了一个电路,使用的HT1621,但是无论如何调整驱动程序(示波器观察基本是正确的),HT1621就是没有动静:振荡器没有波形;COM、seg没有波形。   谁遇到过这样的问题? 下面是硬件原理图 ...…

查看全部问答∨

dxp原件的封装大小是不是可以改变的!

dxp原件的封装大小是不是可以改变的!…

查看全部问答∨

PCB参考层

在PCB的设计向导中,会出现如图所示对话框,问你要不要指定电源或者地参考层的数目,老师教的时候没提到这个,我也一直是按默认做的,但看见网上好多设计都涉及到接地参考层,所以想请教一下设置参考层与否有什么区别? [ 本帖最后由 zzbaizhi 于 ...…

查看全部问答∨

新手上路

msp430单片机怎么学啊,求大神指导…

查看全部问答∨

ZIGBEE2007的串口通信(转)

此篇文章为转载,谢谢原著者分享 就跟我自己承诺的一样,我会发一篇关于zigbee串口通信的。虽然这个是我五月份就做的东西,但是现在看来,还是有那么一群人对这个纠缠不清。但是,这个其实很简单。 事实上zigbee协议栈2006是有自己集成好 ...…

查看全部问答∨

【WEBENCH设计】基于TPS54229E设计的12V转5V电源设计(实物测试)

【转】 【方案介绍】          在使用51单片机做开发设计的年代,一个7805电源管理芯片是比不可少的东西,这个最大输出电流可达1A的线性稳压器是我们刚开始学51时最先接触到的电源芯片,另外一个就是赫赫有名的117 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved