stm32—SPI

1. SPI 是什么

SPI (Serial Peripheral Interface):是由美国摩托罗拉公司(Motorala)最先推出的一种同步全双工串行传输规范,也是一种单片机外设芯片串行扩展接口

SPI 接口主要应用在 EEPROM,FLASH,实时时钟, AD转换器,数字信号处理器和数字信号解码器之间,等要求通讯速率较高的场合

SPI 是一种高速、全双工、串行、同步通信总线

        全双工意味着至少需要有两根数据线,串行意味着是按 bit 位一位一位的传输

        同步意味着通信双方共时钟线:

                SDO        Serial Data Output        串行数据输出

                SDI          Serial Data Input           串行数据输入

                SCLK       Serial Clock                   时钟线

SPI 采用的是主从架构,支持多 slave 模式:


Master:

        SCK  ---> 同时接所有的 Slave 的时钟线

        MOSI ---> 同时接所有的 Slave 的 MOSI 数据线

        MISO ---> 同时接所有的 Slave 的 MISO 数据线

        

        SS1 ---> 接第一个 Slave 的片选信号

        SS2 ---> 接第二个 Slave 的片选信号

        ......


当 Master 要和某个 Slave 通信时:

        enable 这个 Slave

        disable 其他的 Slave

2. SPI 物理层

SPI 总线上可以同时接多个 SPI 设备 (一主多从)

        那么总线上的时钟由谁产生呢?

                谁产生都可以,只要同一时刻没有多个设备同时控制总线就可以了

                同一时刻也只能有一个设备发送数据,但是可以有多个设备同时接收

        通过谁控制时钟线,我们人为的将 SPI 总线上的设备分为:

                Master        主设备:产生时钟信号的设备

                Slave          从设备:接收时钟信号的设备
一主一从:

一主多从:

根据主从设备的区别,有时候两个数据接口命名也会有所不同:

                MOSI:Master Output Slave Input    主设备发送,从设备接收线

                MISO:Master Input Slave Output    主设备接收,从设备发送线
        MOSI 和 MISO 只是 SDO 和 SDI 的不同叫法而已

 
        SCLK:即时钟信号线,用于通讯同步

        另外,SPI 还有一根 NSS(Slave Select)线。因为SPI总线上的设备不像 IIC 总线上的设备有地址,所以我们需要一根额外的线来确定到底与谁进行通信

        这个NSS(CS)就是片选信号线,用于选择通讯的从设备,也可用CS表示,每个从设备都有一条独立的NSS信号线,主机通过将某个设备的NSS线置低电平来选择与之通讯的从设备。所以 SPI 通讯以NSS线电平置低为起始信号,以NSS线电平被拉高为停止信号,此线可以利用任何一个GPIO引脚,发送0/1进行片选 (比如#SS表示低电平有效,则发送0表示与该设备通信)

所以 SPI 一般需要 4 根线:SDO / SDI / SCLK / CS (单向传输时可以不需要 CS 线)

3. SPI 协议

协议就是规定数据是如何收发的,SPI 协议定义了通讯的起始和停止信号、数据有效性、时钟同步等内容,无应答机制


(1) 通信起始信号和停止信号

        NSS 信号线由高变低,是 SPI 通讯的起始信号,当从机检测到自己的NSS线为起始信号时,就 知道主机要与自己进行通讯了

        NSS 信号线由低变高,是 SPI 通讯的停止信号

(2) 数据有效性
        SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。MOSI 及 MISO 数据线在 SCLK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。数据传输时, MSB 先行或 LSB 先行并没有作硬性规定,但要保证两个 SPI 通讯设备之间使用同样的协定,一般都会采用 MSB 先行模式

(3) 通讯模式
      
  CPOL:Clock Polarity  时钟极性

                时钟极性决定不传任何数据时(SPI空闲时)时钟线的电平状态

                        CPOL = 1        不传数据(SPI空闲)时,时钟线保持高电平

                        CPOL = 0      不传数据(SPI空闲)时,时钟线保持低电平


        CPHA:Clock PHAse 时钟相位

                时钟相位决定 SPI 在何时锁定数据(决定数据采集的时刻)
                        CPHA = 1        在时钟线 SCLK 的第二个边沿锁存数据(数据采集)

                        CPHA = 0        在时钟线 SCLK 的第一个边沿锁存数据(数据采集)


也就是说CPOL和CPHA的组合决定数据采集和数据发送的时刻

        共四种通讯模式(Mode 0,Mode 1,Mode 2,Mode 3)


CPOL = 1,CPHA = 1 通讯模式:

(4) 数据帧格式
        SPI 数据的收发是按Frame为单位,那么一帧数据传送的 bit 位数由什么决定?

                DFF:Data Frame Format 数据帧格式

                        8bits        一帧数据 8 bits

                        16bits      一帧数据 16 bits

                        SPI 数据的收发是按 Frame 为单位

                那么一帧数据又是从LSB还是MSB开始发送?
                        LSBFIRST = 1     LSB(低bit)先发送

                        LSBFIRST = 0     MSB(高bit)先发送

(5) 传输速率
        传输速率由时钟频率决定,有一个原则:就低不就高

4. 模拟 SPI 时序收发数据

5. STM32 SPI 控制器

6. STM32 固件库 SPI 函数接口说明

SDO / SDI / SCLK都是复用自GPIO(无论是主从都没有区别)。如果作为从设备,则NSS(片选)也是复用自GPIO,如果是主设备,则不需要利用GPIO去复用为NSS


(1) 配置 SPI 的 GPIO 引脚
a. 使能 GPIO 时钟   RCC_APB1PeriphClockCmd();b. GPIO_Init();  ---> AFc. 配置具体的复用功能   GPIO_PinAFConfig();
(2) 配置 SPI 控制器
a. 使能 SPI 时钟RCC_APBxPeriphClockCmd();b. 配置 SPI 控制器void SPI_Init(SPI_TypeDef *SPIx, SPI_InitTypeDef *SPI_InitStruct);@SPIx:指定要配置的SPI控制器编号SPI1, SPI2 ... SP6@SPI_InitStruct:指向初始化信息结构体typedef struct{uint16_t SPI_Direction; 设置SPI的通信方式可以是半双工/全双工/串行发/串行收SPI_Direction_2Lines_FullDuplex	  全双工SPI_Direction_2Lines_RxOnly		  (两根线半双工)只收SPI_Direction_1Line_Rx			  (一根线半双工)串行接收SPI_Direction_1Line_Tx			  (一根线半双工)串行发uint16_t SPI_Mode;设置SPI的主从模式SPI_Mode_Master		主设备SPI_Mode_Slave		从设备uint16_t SPI_DataSize; 设置SPI传输的数据位长度(数据帧的bit位数)SPI_DataSize_16b   	数据位 16SPI_DataSize_8b		数据位 8uint16_t SPI_CPOL;设置SPI的时钟极性(在空闲时SCK时钟线的电平状态)SPI_CPOL_Low		空闲时SCK为低电平SPI_CPOL_High		空闲时SCK为高电平uint16_t SPI_CPHA;设置SPI的时钟相位(决定在SCK时钟线的第几个边沿采集数据)SPI_CPHA_1Edge	  在第一个边沿采集数据			SPI_CPHA_2Edge	  在第二个边沿采集数据CPOL和CPHA的组合决定数据采集和数据发送的时刻需要看从设备支持哪种模式,主模式和从模式必须统一uint16_t SPI_NSS;设置SPI的NSS信号是由硬件(NSS引脚)还是软件控制,可以理解为片选信号SPI_NSS_Hard   	由硬件NSS引脚控制SPI_NSS_Soft	由用户软件代码控制 ----> GPIO 引脚uint16_t SPI_BaudRatePrescaler;设置SPI波特率的预分频值SPI波特率(传输速率) = SPI输入时钟频率(APBx时钟) / SPI_BaudRatePrescalerSPI_BaudRatePrescaler_2		2分频SPI_BaudRatePrescaler_4     4分频...SPI_BaudRatePrescaler_256	256分频uint16_t SPI_FirstBit;指定SPI传输数据顺序是高位先发还是低位先发SPI_FirstBit_MSB		高位先发SPI_FirstBit_LSB		低位先发uint16_t SPI_CRCPolynomial; 指定CRC(循环冗余校验)校验多项式这个系数只需要大于1就可以了,为了提高通信可靠性} SPI_InitTypeDef;
(3) 使能 SPI
SPI_Cmd();
(4) 收发 SPI 数据,以及一些状态标志位
a. 读数据:只有 RXNE == 1 时才能读(可以利用中断去读也可以轮询)怎么去获取标志位:
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef *SPIx, uint16_t SPI_I2S_FLAG);返回值:SET ->1 /  RESET -> 0标志位有:#define SPI_I2S_FLAG_RXNE       ((uint16_t)0x0001)#define SPI_I2S_FLAG_TXE       	((uint16_t)0x0002)#define SPI_FLAG_CRCERR         ((uint16_t)0x0010)#define SPI_FLAG_MODF          	((uint16_t)0x0020)#define SPI_I2S_FLAG_OVR        ((uint16_t)0x0040)#define SPI_I2S_FLAG_BSY        ((uint16_t)0x0080)....怎么读:uint16_t SPI_I2S_ReceiveData(SPI_TypeDef *SPIx);
--------------------------------------------------------------------------
举例子:利用轮询去接收数据
unsigned char SPI1_Recv_Byte(void) {	while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) != SET);return SPI_ReceiveData(SPI1);
}
----------------------------------------------------------------------------
b. 发数据:只有 TXE == 1 时才能发送数据如何发:void SPI_I2S_SendData(SPI_TypeDef *SPIx, uint16_t Data);
-----------------------------------------------------------------------------
举例子:
Void SPI1_Send_Byte(unsigned char ch) {while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);SPI_I2S_SendData(SPI1, ch);
}

7. W25Q128

W25Q128 是一款 SPI 接口的 flash 存储器芯片

        内存:易失性存储器

        EEPROM:非易失性存储器,小容量

        FLASH:非易失性存储器,容量比较大

        磁盘:非易失性存储器

        ......

易失 / 非易失:指存储器断电后,它存储的数量内容是否会丢失

实现 在 SPI 串行Flash W25Q128 存储芯片的任意地址读写任意字节的数据
 

(1) 接口说明(见原理图)

  
        引脚:W25Q128                  MCU

                        CS       ----------     PB14

                       CLK     <----------    PB3   -----   SPI1_SCK
                        SO       ---------->   PB4   -----   SPI1_MISO
                        SI         <----------   PB5   -----   SPI1_MOSI

                物理上,全双工的

                        

        CS:片选引脚(低电平有效)

                当CS管脚为高电平时,芯片处在不选择的状态

                当CS管脚为低电平时,芯片处于被选择的状态(此时才能够与MCU通信)

(2) W25Q128 内部存储结构

内部存储地址是24bits,这24bits分为了4个部分:
        8bits                   4bits                      4bits                         8bits

block number      sector number        page number           byte number    

       块地址                 扇地址                    页地址                     字节地址

那么 W25Q128  共有              = 256      block(块)          一块65536个字节

                         每块 block     = 16        sector(扇)         一扇4096个字节(4K)

                         每扇 sector    = 16        page(页)           一页256个字节

                         每页 page       = 256      byte(字节)

1GB=1024MB,1MB=1024KB,1KB=1024Bytes,2^10 = 1024

所以 W25Q128 的存储大小 = 256 * 16 * 16 * 256 = 2^24 Bytes  = 16 M


反推可知,假设某个字节的地址为x,则该字节位于:

        (x >> 16) & 0xFF      块号

        (x >> 12) & 0xF        扇号

        (x >> 8) & 0xF          页码

         x & 0xFF                 字地址(页内偏移地址)

如果要往W25Q128中写入数据的话,需要分为两个步骤:

a. 擦除 (擦除区域被置位1)

        因为数据修改,二进制:1可以变成0,0不能变成1

        擦除:给存储单元充电 ----> 电压升高 ----> 写1 ----> 0xFF        放电:写0

        以 块 或者 半块 或者 扇区 或者整个芯片为单位,清除数据

b. 写入(编码)

        W25Q128芯片所有的操作,全部都是通过指令来进行的

        所以,我们的STM32要想控制W25Q128工作,只需要利用SPI总线,给W25Q128发送相应的指令就可以了(不能像内存一样直接寻址)

(3) W25Q128 的指令(详情见中文手册<9.2 指令>)

W25Q128一共有34个基本指令,指令都是以/CS下降沿开始的

        /CS下降沿开始:表示发送指令前,必须先将对应的片选引脚输出为低电平,也就是MCU要先将PB14拉低才能发送指令


第一个传输的字节是指令码

        指令其实就是一个字节的十六进制数(如手册表中所示)


在DI上传输的数据是在时钟的上升沿被锁存的
        MCU发给W25Q128的数据(指令),必须在时钟的上升沿锁存,也就是说W25Q128是在时钟的上升沿去采样

        所以这里就注定了CPOL和CPHA该如何配置
        英文版手册<6.1.1 Standard SPI Instructions>中介绍了W25Q128 SPI Bus支持Mode 0(0,0)和Mode 3(1,1)


MSB首先被传输 --->高位先发,SPI_FirstBit = SPI_FirstBit_MSB

/CS拉高(MCU将PB14拉高指令发送完成)

所有的读指令可以在任何时钟周期结束。但是,所有的擦写指令必须在 /CS 拉高之后还有一个8位的时钟间隔,否则前面的擦写指令将被忽略

发送擦写指令后,必须再过8个 SPI 时钟周期才能发送下一个指令

a. 读状态寄存器指令(指令:0x05 / 0x35)

读取状态寄存器SR1 ---> 0x05

读取状态寄存器SR2 ---> 0x35

MCU向W25Q128发送读取状态寄存器指令完成后,W25Q128回复一个字节的状态寄存器SRx的状态码给MCU

SR1:<9.控制和状态寄存器>Bit7     Bit6     Bit5     Bit4     Bit3     Bit2     Bit1     Bit0SRP-0    SEC       TB      BP2      BP1      BP0      WEL      BUSYBUSY:为1表示W25Q128忙碌,为0表示空闲主机在发送指令之前,必须要先判断从设备的状态是否忙碌BUSY == 0时,才能发送指令WEL:为1表示写使能,可以写入为0表示写禁止,不能写入BP0-BP2:块保护(指定某些块只能读不能写)TB:顶部/底部块保护SEC:扇区/块保护SRP-0:保护的方法
举个例子:#define W25Q128_ENBALE()   GPIO_ResetBits(GPIOB, GPIO_Pin_14) // CS->0
#define W25Q128_DISBALE()  GPIO_SetBits(GPIOB, GPIO_Pin_14) // CS->1unsigned char Get_W25Q128_SR1(void) {// 使能片选,选中W25Q128W25Q128_ENBALE();// 发送读取SR1的指令Write_Bytes_To_W25Q128(0x05);/*     MCU向W25Q128发送读取状态寄存器指令完成后W25Q128回复一个字节的状态寄存器SRx的状态码给MCU*/// 接收SR1的值unsigned char status = Read_Bytes_From_W25Q128();// 禁止芯片W25Q128_DISBALE();return status;// if (status & 0x01 != 0) ---> 表示W25Q128忙碌
}
b. 读取 W25Q128 的 ID(指令:0x90)

                                               1            2               3            4                5                  6

Manufacturer/Device ID(2)   90h         00             00         00h      (MF7-MF0)     (ID7-ID0)

uint16_t Read_W25Q128_ID(void) {// 使能片选,选中W25Q128W25Q128_ENBALE();// 发送读取ID的指令Write_Bytes_To_W25Q128(0x90);Write_Bytes_To_W25Q128(0x00);Write_Bytes_To_W25Q128(0x00);Write_Bytes_To_W25Q128(0x00);// 厂商IDuint8_t idh = Read_Bytes_From_W25Q128();// 设备IDuint8_t idl = Read_Bytes_From_W25Q128();// 禁止芯片W25Q128_DISBALE();uint16_t id = idh << 8 | idl;printf(“厂商:%x  设备:%x\n”, id >> 8, id & 0xFF);return id;
}

     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/407180.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

树莓派5 笔记26:ollama大型语言模型_中文输入法_Python_espeak文字转语音

今日继续学习树莓派5 8G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 与 python 版本如下&#xff1a; 下载大语言模型&#xff0c;下载中文输入法&#…

基于vue框架的比赛门票出售的系统12lh6(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,赛事类型,赛事信息,比赛队伍,比赛结果 开题报告内容 基于Vue框架的比赛门票出售系统开题报告 一、研究背景与意义 随着体育产业的蓬勃发展&#xff0c;各类体育赛事如雨后春笋般涌现&#xff0c;吸引了全球亿万观众的关注与参与…

【简历】25届西南某211JAVA简历:大厂面试官一看到DDD,肯定笑崩了

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 今天来看一份25届西南某大学211硕士的Java简历&#xff0c;学校这块就是一个正常的211&#xff0c;在大厂的话211和普通985&#xff0c;…

Java 3.1 - 计算机网络

目录 OSI 七层协议是什么&#xff1f;每一层的作用是什么&#xff1f; TCP / IP 四层模型是什么&#xff1f;每一层的作用是什么&#xff1f; 应用层&#xff08;Application Layer&#xff09; 传输层&#xff08;Transport Layer&#xff09; 网络层&#xff08;Network …

探索数据结构:图(二)之图的遍历,Kruskal与Prim算法

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 图的遍历 图的遍历方式一般分为两种&#xff1a;深度优先遍历与广度…

XSS游戏

目录 XSS游戏-WarmupsMa Spaghet!JefffUgandan KnucklesRicardo MilosAh Thats HawtLigmaMafiaOk, BoomerWW3 XSS游戏-Warmups Ma Spaghet! 1. 尝试注入&#xff0c;输入aaaaaaaa 2. 显示在<h2>标签内3. 输入标签&#xff0c;添加onmouseover属性值为alert(1337)&…

【数据库】MySql基本引擎InnoDB、MyISAM、MEMORY、CSV、ARCHIVE(详细说明)

文章目录 如何选择引擎存储引擎的作用修改引擎方式InnoDBMyISAMMEMORYCSVARCHIVE总结 更多相关内容可查看 如何选择引擎 合理选择数据库存储引擎对于系统的性能、数据完整性、维护成本等方面都具有重要影响 高并发的事务性应用&#xff1a;选择 InnoDB。以读操作为主的应用&a…

【python】Python中小巧的异步web框架Sanic快速上手实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【SQL】连续出现的数字

目录 题目 分析 代码 题目 表&#xff1a;Logs ---------------------- | Column Name | Type | ---------------------- | id | int | | num | varchar | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 id 是一个自增列。找出…

Langchain4J从AI Agent开始

前言 AI Agent是智能体的概念&#xff0c;以大模型为核心&#xff0c;集决策能力、记忆能力、工具调用能力为一体的智能体。 langchain框架是python写的&#xff0c;它是一个大语言模型智能框架&#xff0c;Langchain4J是langchain框架对应的java语言编写的。 langchain框架中…

Linux | vim编辑器的使用技巧:自动缩进、补全括号、光标定位、批量注释

文章目录 vim编辑器的使用技巧1、配置自动缩进、自动显示行号、自动补全括号2、光标定位3、批量注释、解除注释批量注释&#xff1a;批量解除注释 vim编辑器的使用技巧 1、配置自动缩进、自动显示行号、自动补全括号 打开vimrc配置文件 vim ~/.vimrc //如果没有编辑权限的&…

140页满分PPT | 一套完整的数字化转型+蓝图路线图规划项目案例

这份PPT文档是一个全面而深入的IT蓝图规划和实施路线图&#xff0c;为某大型制造企业的信息化建设和发展提供了详尽的框架和指导。 1. 业务战略与IT战略对接 在数字化转型过程中&#xff0c;应从企业的业务战略出发&#xff0c;强调了IT战略规划的重要性&#xff0c;指出IT战…

【计算机三级-数据库技术】数据库及数据库对象

数据库及数据库对象 第一节 创建及维护数据库 一、SQL server数据库分类 1&#xff09;系统数据库&#xff08;系统自动创建&#xff09;&#xff1a; master、msdb、tempdb、model、resource 2&#xff09;用户数据库 保存与用户业务有关的数据。 二、SQL server数据库组成…

一建证书哪个专业好?一建各专业含金量排行一览表

2024年一建考试将于9月7日、8日举行&#xff0c;距离现在已经不足五个月&#xff0c;今年一建考试大纲全新修订&#xff0c;教材也随之大改&#xff0c;加之一建考试难度较大&#xff0c;相信考生友友们都已经开启备考了吧&#xff1f; 近期也有小伙伴在跟小佑提问&#xff0c…

Is it possible to modify OpenAI environments?

题意&#xff1a;“是否可以修改 OpenAI 环境&#xff1f;” 问题背景&#xff1a; There are some things that I would like to modify in the OpenAI environments. If we use the Cartpole example then we can edit things that are in the class init function but with…

[数据集][目标检测]agvs仓储机器人检测数据集VOC+YOLO格式967张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;967 标注数量(xml文件个数)&#xff1a;967 标注数量(txt文件个数)&#xff1a;967 标注类别…

想要畅玩《黑神话:悟空》?上赞奇云工作站,仅需3步,直面天命!

全世界畅玩《黑神话&#xff1a;悟空》的时候 一批受害者们也迎来了属于他们的“九九八十一难” 这个时候&#xff0c;天命人才意识到 原来世界上最远的距离&#xff0c;不是天涯海角 而是《黑神话&#xff1a;悟空》就在我面前&#xff0c;旁边的电脑却带不动 作为被广泛视…

超维机器人在工业与能源领域的具身智能探索和应用

具身智能&#xff08;Embodied AI&#xff09;是指机器人能够通过其物理形态与环境的交互&#xff0c;进行感知、学习、决策和执行&#xff0c;从而完成复杂任务的能力。具身智能强调机器人不仅要具备感知环境和分析数据的能力&#xff0c;还要能够通过身体的行为和物理互动来适…

Cesium 视频纹理

Cesium 视频纹理 话不多说&#xff0c;直接上代码 <video id"video_dom"><source src"./video.mp4" type"video/mp4" /></video>var videoElement document.getElementById("video_dom");videoElement.play();vie…

145. 二叉树的后序遍历(递归法)

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 二&#xff1a;代码&#xff1a; /*** Definition for a bin…