本工程板级支持包文件适用于野火stm32f429 开发板。
SPI 物理层
SPI 通讯使用3 条总线及片选线,3 条总线分别是SCK、MOSI、MISO,片选线为SS,其作用分别为:
SS:片选信号线,也称NSS、CS。当有多个SPI 从设备与SPI 主机相连时,设备的其他信号线 SCK、MOSI及 MISO同时并联到相同的 SPI总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。
I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。
SCK:时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为f pclk /2,两个设备之间通讯时,通讯速率受限于低速设备。
MOSI:主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。
MISO:主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。
协议层
SPI 基本通讯过程
SPI 的起始信号:NSS 信号线由高变低。
SPI 使用MOSI 及MISO 信号线传输数据,使用SCK 信号线进行数据同步。MOSI
及 MISO数据线在 SCK的每个时钟周期传输一位数据,且数据输入输出是同时进行的。数据传输时,MSB先行或 LSB先行并没有作硬性规定,但要保证两个 SPI通讯设备之间使用同样的协定。
MOSI及 MISO的数据在 SCK的上升沿期间变化输出,在 SCK的下降沿时被采样。即在 SCK的下降沿时刻,MOSI及 MISO的数据有效。
SPI每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制。
SPI 的停止信号:NSS 信号线由低变高。
CPOL/CPHA 及通讯模式
上面讲述的时序只是 SPI中的其中一种通讯模式,SPI一共有四种通讯模式,它们的主要区别是总线空闲时 SCK的时钟状态以及数据采样时刻。
为方便说明,在此引入“时钟极性 CPOL”和“时钟相位 CPHA”的概念。
时钟极性 CPOL是指 SPI通讯设备处于空闲状态时,SCK信号线的电平信号(即 SPI通讯开始前、 NSS 线为高电平时 SCK的状态)。CPOL=0时, SCK在空闲状态时为低电平,CPOL=1 时,则相反。
时钟相位 CPHA是指数据的采样的时刻,当 CPHA=0 时,MOSI或 MISO 数据线上的信号将会在 SCK时钟线的“奇数边沿”被采样。当 CPHA=1 时,数据线在 SCK的“偶数边沿”采样。
简单来说就是:
CPOL(0/1)控制时钟信号是正向脉冲还是反向脉冲;CPHA(0/1)控制采样信号是时钟脉冲起始还是时钟脉冲结束。
架构
通讯引脚
其中 SPI1、SPI4、SPI5、SPI6是 APB2 上的设备,最高通信速率达 45Mbtis/s,SPI2、SPI3 是 APB1上的设备,最高通信速率为 22.5Mbits/s。其它功能上没有差异。
时钟控制逻辑
SCK线的时钟信号,由波特率发生器根据“控制寄存器 CR1”中的 BR[0:2]位控制,该位是对 f pclk 时钟的分频因子,对 f pclk 的分频结果就是 SCK引脚的输出时钟频率。
其中的 f pclk 频率是指 SPI所在的 APB总线频率,APB1为 f pclk1 ,APB2为 f pckl2 。
通过配置“控制寄存器 CR”的“CPOL位”及“CPHA”位可以把 SPI设置成前面分析的 4 种 SPI模式。
3. 数据控制逻辑
SPI的 MOSI及 MISO 都连接到数据移位寄存器上,数据移位寄存器的内容来源于接收缓冲区及发送缓冲区以及 MISO、MOSI线。
当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。
通过写 SPI的“数据寄存器 DR”把数据填充到发送缓冲区中,通过 “数据寄存器 DR”,可以获取接收缓冲区中的内容。
其中数据帧长度可以通过“控制寄存器 CR1”的“DFF位”配置成 8 位及 16 位模式;置“LSBFIRST 位”可选择 MSB先行还是 LSB先行。
4. 整体控制逻辑
整体控制逻辑负责协调整个 SPI外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的 SPI模式、波特率、LSB先行、主从模式、单双向模式等等。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,我们只要读取状态寄存器相关的寄存器位,就可以了解 SPI的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生 SPI中断信号、DMA 请求及控制NSS 信号线。
实际应用中,我们一般不使用 STM32 SPI外设的标准 NSS 信号线,而是更简单地使用
普通的 GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。
通讯过程
此为STM32 作为SPI 通讯的主机端时的数据收发过程 ↑
主模式收发流程及事件说明:
控制NSS 信号线,产生起始信号(图中没有画出);
把要发送的数据写入到“数据寄存器 DR”中,该数据会被存储到发送缓冲区;
通讯开始,SCK时钟开始运行。MOSI把发送缓冲区中的数据一位一位地传输出去;MISO 则把数据一位一位地存储进接收缓冲区中(全双工);
当发送完一帧数据的时候,“状态寄存器 SR”中的“TXE 标志位”会被置 1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“RXNE标志位”会被置 1,表示传输完一帧,接收缓冲区非空;
等待到“TXE标志位”为 1 时,若还要继续发送数据,则再次往“数据寄存器DR”写入数据即可;等待到“RXNE标志位”为 1时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。
SPI 读写串行FLASH
FLASH(闪存)与EEPROM 都是掉电后数据不丢失的存储器,但FLASH 的容量普遍大于EEPROM;
存储控制上,最主要的区别是FLASH 芯片只能一大片一大片地擦写,而EEPROM 可以单个字节擦写。
STM32 的NSS 引脚是一个普通的GPIO,不是SPI 的专用NSS 引脚,需要用软件控制
控制FLASH 的指令
在与EEPROM 进行I²C 通讯时,第一个和第二个字节的数据分别会被视作硬件地址和内部存储矩阵地址。
但在与FLASH 进行SPI 通讯 时,FLASH 芯片自定义了很多指令,对于STM32 主机来说,这些字节就是普通的数据,而对于FLASH 来说,不同的数据将会被翻译成不同的指令。
其常用芯片指令有:
该表中的第一列为指令名,第二列为指令编码,第三至第 N 列的具体内容根据指令的不同而有不同的含义。
其中带括号的字节参数,方向为 FLASH 向主机传输,即命令响应,不带括号的则为主机向 FLASH 传输。
表中“A0~A23”指 FLASH 芯片内部存储器组织的地址;“M0~M7”为厂商号(MANUFACTURER ID);“ID0-ID15”为 FLASH 芯片的ID;“dummy”指该处可为任意数据;“D0~D7”为 FLASH 内部存储矩阵的内容。
编程要点:
初始化通讯使用的目标引脚及端口时钟;
使能SPI 外设的时钟;
配置SPI 外设的模式、地址、速率等参数并使能SPI 外设;
编写基本SPI 按字节收发的函数;
编写对FLASH 擦除及读写操作的函数;
编写测试程序,对读写数据进行校验。
以下是各个模块的分代码
==============总代码在这
bsp_spi_flash.h
/**
******************************************************************************
* @file bsp_spi_flash.h
* @author Waao
* @version V1.0.0
* @date 19-Jan-2019
* @brief This file contains some board support package's definitions for the SPI.
*
******************************************************************************
* @attention
*
* None
*
******************************************************************************
*/
#ifndef _BSP_SPI_FLASH_H_
#define _BSP_SPI_FLASH_H_
#include #include #include #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000) #define SPIT_LONG_TIMEOUT ((uint32_t)(10*SPIT_FLAG_TIMEOUT)) #define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256 #define FLASH_ERROR(fmt, arg...) printf("Error Code:"fmt"n", ##arg) //============================ SPI ================================= #define SPI_ SPI5 #define SPI_CLK RCC_APB2Periph_SPI5 //====================== Signal Line GPIO ========================== #define SPI_GPIO_CLK RCC_AHB1Periph_GPIOF #define SPI_GPIO_PORT GPIOF //=== NSS === #define SPI_NSS_GPIO_PORT GPIOF #define SPI_NSS_GPIO_PIN GPIO_Pin_6 #define SPI_NSS_GPIO_RCC RCC_AHB1Periph_GPIOF //=== SCK === #define SPI_SCK_GPIO_PORT GPIOF #define SPI_SCK_GPIO_PIN GPIO_Pin_7 #define SPI_SCK_GPIO_RCC RCC_AHB1Periph_GPIOF #define SPI_SCK_GPIO_PinSource GPIO_PinSource7 #define SPI_SCK_GPIO_AF GPIO_AF_SPI5 //=== MISO === #define SPI_MISO_GPIO_PORT GPIOF #define SPI_MISO_GPIO_PIN GPIO_Pin_8 #define SPI_MISO_GPIO_RCC RCC_AHB1Periph_GPIOF #define SPI_MISO_GPIO_PinSource GPIO_PinSource8 #define SPI_MISO_GPIO_AF GPIO_AF_SPI5 //=== MOSI === #define SPI_MOSI_GPIO_PORT GPIOF #define SPI_MOSI_GPIO_PIN GPIO_Pin_9 #define SPI_MOSI_GPIO_RCC RCC_AHB1Periph_GPIOF #define SPI_MOSI_GPIO_PinSource GPIO_PinSource9 #define SPI_MOSI_GPIO_AF GPIO_AF_SPI5 //=== CS/NSS Control === #define SPI_FLASH_CS_1 {SPI_NSS_GPIO_PORT->BSRRL=SPI_NSS_GPIO_PIN;} #define SPI_FLASH_CS_0 {SPI_NSS_GPIO_PORT->BSRRH=SPI_NSS_GPIO_PIN;} //================================================================ //=== Commonly Used Command === #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_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 WIP_Flag 0x01 /* Write In Progress (WIP) flag */ #define Dummy_Byte 0xFF void SPI_GPIO_Config(void); void SPI_Config(void); uint8_t SPI_FLASH_SendByte(uint8_t byte); uint8_t SPI_FLASH_ReadByte(void); uint32_t SPI_FLASH_ReadID(void); u32 SPI_FLASH_ReadDeviceID(void); void SPI_FLASH_WriteEnable(void); u8 SPI_FLASH_WaitForWriteEnd(void); void SPI_FLASH_SectorErase(u32 SectorAddr); void SPI_FLASH_PageWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite); void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite); void SPI_FLASH_BufferRead(u8 *pBuffer, u32 ReadAddr, u16 NumByteToWrite); uint8_t SPI_TIMEOUT_Callback(uint8_t errorcode); #endif bsp_spi_flash.c /** ****************************************************************************** * @file bsp_spi_flash.c * @author Waao * @version V1.0.0 * @date 19-Jan-2019 * @brief This file contains some board support package's functions for the SPI. * ****************************************************************************** * @attention * * None * ****************************************************************************** */ #include static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT; static uint32_t WAITING_TIME = SPIT_FLAG_TIMEOUT; /** * @brief Initialize the SPI_GPIO. * @param None * @retval None */ void SPI_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(SPI_GPIO_CLK, ENABLE); GPIO_PinAFConfig(SPI_SCK_GPIO_PORT, SPI_SCK_GPIO_PinSource, SPI_SCK_GPIO_AF);
上一篇:STM32F429 >> 12. I²C 通讯(Code)
下一篇:STM32F429 >> 13. SPI 通讯(code)
推荐阅读
史海拾趣
ACT(Advanced Crystal Technology)公司是一家专注于晶体技术的企业。以下是该公司发展的五个相关故事:
公司成立与起步阶段: ACT公司成立于1984年,总部位于美国加利福尼亚州。创始人致力于研究和开发高性能的晶体材料和晶振产品。公司最初是一家小型的研究型企业,致力于满足军事和航空航天领域对高精度晶振的需求。
技术创新和产品拓展: 随着市场需求的增长和技术进步,ACT公司不断进行技术创新,并扩展了产品线。公司推出了一系列高精度、高稳定性的晶振产品,覆盖了频率范围广泛的应用,包括通信、医疗、工业控制等领域。
市场拓展和国际化发展: ACT公司积极开拓国内外市场,并与全球各地的客户建立了合作关系。公司的产品不仅畅销于美国本土市场,还远销至欧洲、亚洲等国家和地区。通过与国际合作伙伴的合作,ACT逐步实现了国际化发展战略。
质量控制和技术支持: ACT公司注重产品质量和技术支持,建立了严格的质量控制体系和售后服务体系。公司拥有一支专业的研发团队和技术支持团队,为客户提供定制化的解决方案和技术支持,确保产品的稳定性和可靠性。
未来发展展望: ACT公司将继续致力于晶体技术领域的研发和生产,不断推出更先进、更高性能的晶振产品,以满足客户在不断变化的市场需求。公司将加强与客户的合作,深化技术创新,提升产品品质和服务水平,努力成为行业内的领先企业。
1957年,Charles A. Coolidge, Jr.和Marshall Kincaid共同创立了C&K Components公司,起初主要专注于磁芯记忆单元的制造。那个时代的电子行业刚刚起步,市场竞争激烈,技术更新换代迅速。C&K在初创时期就面临了诸多挑战,但两位创始人凭借对技术的热爱和对市场的敏锐洞察,坚持探索新的技术方向,为公司的发展奠定了坚实的基础。
背景:2008年全球金融危机爆发,电子行业受到重创,市场需求大幅下降。
发展:面对严峻的市场环境,HN Electronics迅速调整战略,削减非核心业务,加强成本控制,并加大在研发领域的投入,以技术创新为突破口,寻找新的增长点。
关键事件:在金融危机期间,HN Electronics成功开发出具有更高性价比的物联网传感器芯片,满足了市场对智能家居、智慧城市等新兴领域的需求,从而实现了业绩的稳步增长。
随着全球化进程的加速,Brainboxes逐渐将业务拓展至全球范围。公司在多个国家和地区设立分支机构或销售网络,以便更好地服务当地客户。同时,Brainboxes也在不断探索新的应用领域和市场机会,为公司的未来发展奠定坚实基础。展望未来,Brainboxes将继续致力于技术创新和市场拓展,为电子行业的发展贡献更多力量。
这五个故事分别展现了Brainboxes公司在电子行业中的创立与发展、技术创新与荣誉、内部制造与供应链、客户亲密度与工业连接以及全球布局与未来展望等方面的事实。通过这些故事,可以更加全面地了解Brainboxes公司在电子行业中的成长轨迹和发展成就。
Esc Electronics Corp(简称Esc)在成立的初期,以其独特的技术突破在电子行业中崭露头角。公司研发出一款高效能、低成本的电子元件,成功吸引了市场的注意。随着产品的不断迭代和技术的持续创新,Esc的产品线逐渐丰富,市场份额也逐步扩大。公司凭借技术优势和敏锐的市场洞察力,成功开拓了多个新的市场领域。
自1993年进入中国市场以来,伊顿公司凭借其先进的技术和丰富的经验,迅速在电网、石油化工、轨道交通、数据中心、商业楼宇等多个行业建立了市场地位。伊顿在中国的发展过程中,不仅带来了全球领先的产品和解决方案,还积极参与了本地市场的建设和创新。通过一系列的战略合作和收购活动,伊顿在中国市场的业务不断扩展,为中国经济和电气工业的发展做出了重要贡献。
音频系统应用中的“POP”噪声以其常用解决方法 “POP”噪声是指音频器件在上电、断电瞬间以及上电稳定后,各种操作带来的瞬态冲击所产生的爆破声。本文将讨论几种常用的解决方法及其工作原理,这些方法针对具体的集成电路具有各自特点,应用时 ...… 查看全部问答∨ |
|
我用T0接收脉冲,T1定时50ms(晶振的固有频率是11.0592MHZ),最后我把T0的高八位和低八位分别给A,B.那么我怎么显示所计的数据呢?我需要这个程序呢… 查看全部问答∨ |
|
各位老大: 在进入CE系统后,在桌面上单击右键(或长按触摸屏),会出现显示属性,显示属性的第二项为“背光灯” 在背光灯的显示框中有个“高级...”的按键,单击这个按键会显示调节背光的“背光设置”,点“OK”退出。 ...... ...… 查看全部问答∨ |
|
想在一个设备实现保存历史数据的功能,类似于pc机上的数据库,不知道用什么格式存放好。 谁知道手机的短信记录、通话记录等,是用什么格式保存的吗? 是自定义的二进制文件? 是纯文本文件? 是foxpro格式文件? 是嵌入式数据库?… 查看全部问答∨ |
关于Modelsim仿真Altera中LPM_ROM的问题做的是功能仿真,总是提示以下错误:# ** Error: (vsim-7) Failed to open VHDL file \"my_rom.hex\" in rb mode.# No such file or directory. (errno = ENOENT)# Time: 0 ns Itera ...… 查看全部问答∨ |
我们老师发了一块核心芯片型号为EPM570T144C5,这是一块cpld吧,我在quartus中定制LPM_ROM时,总是不成功,提示为MAX II不支持这个功能,请问一下,是不是这个芯片真的不支持LPM_ROM的 定制啊?谢谢了 , 如果我定制LPM_RAM,可不可代替呢,以 ...… 查看全部问答∨ |
如前面所述,HMI设备包括硬件与软件软件就是组态软件,我们也在第五讲里介绍了组态软件的相关情况。而硬件,我们在第六讲里提出了两个问题,分别是使用串口做接口和使用以太网做接口时谁是最好的HMI身子骨。… 查看全部问答∨ |