三大低速总线之SPI

news2024/9/23 16:43:12

三大低速总线之SPI


文章目录

  • 三大低速总线之SPI
  • 前言
  • 一、基本概念
    • 1.1 物理层
    • 1.2 协议
      • 1.3 传输过程
  • 二、实战FLASH芯片
    • 2.1 SPI-Flash 全擦除实验
      • 2.1.1 程序设计
    • 2.2 SPI-Flash 扇区擦除实验
      • 2.2.1 整体设计
    • 2.3 SPI-Flash 页写实验
      • 2.3.1 操作时序
    • 2.4 SPI_Flash 读数据实验
    • 2.4.1 时序
  • 总结


前言

SPI(串行外设接口)以其高速度而著称,使其成为快速通信的首选。与 I2C 不同,SPI 使用四线工作:MISO(主输入从输出)、MOSI(主输出从输入)、SCK(串行时钟)和 SS(从选择),允许全双工通信(发送和同时接收)。尽管简单且速度快,但 SPI 比 I2C 需要更多的引脚,这可能是电路设计中需要考虑的一个因素。优点:

高速:SPI通信速度较快,适用于对速度要求较高的应用。
**全双工:**SPI支持全双工通信,可以同时进行数据发送和接收。
**简单:**SPI的通信协议相对简单,适用于快速开发和实现。

SPI的模式选择可以通过查看设备的数据手册或通过软件设置来实现。 SPI通信协议支持多种模式,这些模式由‌时钟极性(‌CPOL)和‌时钟相位(‌CPHA)的不同组合定义。具体选择哪种模式,取决于设备的具体需求和设计

缺点:

连线复杂:SPI需要多根线进行连接,可能会增加硬件设计的复杂性。
长距离传输受限:SPI的传输距离受到限制,过长的线路可能导致信号衰减和干扰。
主从模式限制:SPI通常采用主从模式,主设备数量受限,不适用于多主设备场景。
应用案例:SPI 非常适合需要快速可靠的数据传输的情况,例如 TFT 显示器SD 存储卡无线通信模块。然而,在具有许多从站的复杂系统中,其有效性会降低。

一、基本概念

1.1 物理层

在这里插入图片描述
SPI 通讯协议包含 1 条时钟信号线、2 条数据总线和 1 条片选信号线, 时钟信号线为SCK,2 条数据总线分别为 MOSI(主输出从输入)、MISO(主输入从输出),片选信号线为CS(低有效),

1.2 协议

时钟极性和相位就是什么时候空闲,什么时候采样。
模式 0、模式 1、模式 2 以及模式 3,这 4 种模式分别由时钟极性(CPOL,Clock Polarity)和时钟相位(CPHA,Clock Phase)来定义。
有4中模式,具体使用哪种模式根据硬件需求来确定。
CPOL 比较好理解,就是表示设备未被选中的空闲状态时,串行时钟 SCK 的电平状态,CPOL = 0,空闲状态时 SCK 为低电平,CPOL = 1,空闲状态时SCK 为高电平;CPHA 的不同参数则规定了数据采样是在 SCK 时钟的奇数边沿还是偶数边沿,CPHA = 0,数据采样是在 SCK 时钟的奇数边沿,CPHA = 1,数据采样是在 SCK 时钟的偶数边沿,这里不使用上升沿或下降沿表示,是因为不同模式下,奇数边沿或偶数边沿

即CPOL = 0表示空闲时,SCK为低电平,CPHA 表示偶数或者奇数边沿采样。

在这里插入图片描述

1.3 传输过程

模式 0 为例:
在这里插入图片描述
此外,还需要确定一下几点:

  • 一次传输的bit
  • 先传高位还是低位(每次传输时不受限制的,一般是8/16bit)
  • 使用什么模式

二、实战FLASH芯片

2.1 SPI-Flash 全擦除实验

擦除方式有两种:

  • 通过 Quartus 软件的“programmer”窗口,将烧录到Flash 的*.jic 文件擦除
  • 编写全擦除程序
    实验目标:事先向 Flash 芯片中烧录流水灯程序,FPGA 上电执行流水灯程序,下载 Flash 芯片全擦除程序到 FPGA 内部 SRAM 并执行,擦除 Flash 芯片中烧录的流水灯程序,FPGA 重新上电后,无程序执行

此外,需要了解flash芯片需求的时序要求
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
片选信号自下降沿始到第一个有效数据写入时止,这一段等待时间定义为片选信号有效建立时间 tSLCH,由图 38-15 可知,这一时间段必须大于等于 5ns;片选信号自最后一个有效数据写入时始到片选信号上升沿止,这一段等待时间定义为片选信号有效保持时tCHSH,这一时间段必须大于等于 5ns;片选信号自上一个上升沿始到下一个下降沿止,这一段等待时间定义为片选信号高电平等待时间 tSHSL这一时间段必须大于等于 100ns。

即片选信号和有效数据写入之间的时序关系;和两个片选型号之间的时间间隔

2.1.1 程序设计

整体设计如下:
在这里插入图片描述
在这里插入图片描述
时序图如下:
在这里插入图片描述
设计要点:

  • flash芯片时钟频率选择为12.5MHz,即一个完整的bit指令输入为32个时钟周期
  • 为了节省计数器资源,统一规划片选和数据之间,片选和片选之间的等待时间也是32个时钟周期,因此只需要一个计数器,计数到32即可
`timescale  1ns/1ns

module  flash_be_ctrl
(
    input   wire            sys_clk     ,   //系统时钟,频率50MHz
    input   wire            sys_rst_n   ,   //复位信号,低电平有效
    input   wire            key         ,   //按键输入信号

    output  reg             cs_n        ,   //片选信号
    output  reg             sck         ,   //串行时钟
    output  reg             mosi            //主输出从输入数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//parameter define
parameter   IDLE    =   4'b0001 ,   //初始状态
            WR_EN   =   4'b0010 ,   //写状态
            DELAY   =   4'b0100 ,   //等待状态
            BE      =   4'b1000 ;   //全擦除状态
parameter   WR_EN_INST  =   8'b0000_0110,   //写使能指令
            BE_INST     =   8'b1100_0111;   //全擦除指令

//reg   define
reg     [2:0]   cnt_byte;   //字节计数器
reg     [3:0]   state   ;   //状态机状态
reg     [4:0]   cnt_clk ;   //系统时钟计数器
reg     [1:0]   cnt_sck ;   //串行时钟计数器
reg     [2:0]   cnt_bit ;   //比特计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_clk:系统时钟计数器,用以记录单个字节
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk  <=  5'd0;
    else    if(state != IDLE)
        cnt_clk  <=  cnt_clk + 1'b1;

//cnt_byte:记录输出字节个数和等待时间
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_byte    <=  3'd0;
    else    if((cnt_clk == 5'd31) && (cnt_byte == 3'd6))
        cnt_byte    <=  3'd0;
    else    if(cnt_clk == 31)
        cnt_byte    <=  cnt_byte + 1'b1;

//cnt_sck:串行时钟计数器,用以生成串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_sck <=  2'd0;
    else    if((state == WR_EN) && (cnt_byte == 1'b1))
        cnt_sck <=  cnt_sck + 1'b1;
    else    if((state == BE) && (cnt_byte == 3'd5))
        cnt_sck <=  cnt_sck + 1'b1;

//cs_n:片选信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
      cs_n    <=  1'b1;
    else    if(key == 1'b1)
        cs_n    <=  1'b0;
    else    if((cnt_byte == 3'd2) && (cnt_clk == 5'd31) && (state == WR_EN))
        cs_n    <=  1'b1;
    else    if((cnt_byte == 3'd3) && (cnt_clk == 5'd31) && (state == DELAY))
        cs_n    <=  1'b0;
    else    if((cnt_byte == 3'd6) && (cnt_clk == 5'd31) && (state == BE))
        cs_n    <=  1'b1;

//sck:输出串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        sck <=  1'b0;
    else    if(cnt_sck == 2'd0)
        sck <=  1'b0;
    else    if(cnt_sck == 2'd2)
        sck <=  1'b1;

//cnt_bit:高低位对调,控制mosi输出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_bit <=  3'd0;
    else    if(cnt_sck == 2'd2)
        cnt_bit <=  cnt_bit + 1'b1;

//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state   <=  IDLE;
    else
    case(state)
        IDLE:   if(key == 1'b1)
                state   <=  WR_EN;
        WR_EN:  if((cnt_byte == 3'd2) && (cnt_clk == 5'd31)) 
                state   <=  DELAY;
        DELAY:  if((cnt_byte == 3'd3) && (cnt_clk == 5'd31))
                state   <=  BE;
        BE:     if((cnt_byte == 3'd6) && (cnt_clk == 5'd31))
                state   <=  IDLE;
        default:    state   <=  IDLE;
    endcase

//mosi:两段式状态机第二段,逻辑输出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        mosi    <=  1'b0;
    else    if((state == WR_EN) && (cnt_byte == 3'd2))
        mosi    <=  1'b0;
    else    if((state == BE) && (cnt_byte == 3'd6))
        mosi    <=  1'b0;
    else    if((state == WR_EN) && (cnt_byte == 3'd1) && (cnt_sck == 5'd0))
        mosi    <=  WR_EN_INST[7 - cnt_bit];    //写使能指令
    else    if((state == BE) && (cnt_byte == 3'd5) && (cnt_sck == 5'd0))
        mosi    <=  BE_INST[7 - cnt_bit];       //全擦除指令

endmodule

2.2 SPI-Flash 扇区擦除实验

实验目标:
编写扇区擦除工程,擦除事先烧录到 Flash 中的流水灯程序所占的某个扇区,使流水灯程序不能正常工作。在此次实验工程,我们选择擦除第 0 个扇区,擦除地址为24’h00_04_25。

2.2.1 整体设计

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 SPI-Flash 页写实验

使用页写指令,向 Flash 中写入 N 字节数据,N 为整数,且大于 0 小于等于 256。在本本 实 验 中 我 们 向 Flash 芯 片 中 写 入 0-99 , 共 100 字 节 数 据 , 数 据 初 始 地 址 为24’h00_04_25

2.3.1 操作时序

由数据手册中页写操作介绍部分可知,页写指令是根据写入数据将存储单元中的“1”置为“0”,实现数据的写入。在写入页写指令之前,需要先写入写使能(WREN)指令,将芯片设置为写使能锁存(WEL)状态;随后要拉低片选信号,写入页写指令、扇区地址、页地址、字节地址,紧跟地址写入要存储在 Flash 的字节数据,在指令、地址以及数据写入过程中,片选信号始终保持低电平,待指令、地址、数据被芯片锁存后,将片选信号拉高;片选信号拉高后,等待一个完整的页写周期(tPP),才能完成 Flash 芯片的页写操作。读者还要注意的是,Flash 芯片中一页最多可以存储 256 字节数据,这也表示页写操作一次最多向 Flash 芯片写入 256 字节数据。页写指令写入后,随即写入 3 字节数据写入首地址,首地址为扇区地址、页地址、字节地址组成,扇区地址与页地址是确定数据写入 Flash的特定扇区的特定页,字节地址位再该页数据写入的字节首地址。当数据写入的字节首地址为该页的首地址,及字节首地址为 8’b0000_0000,数据写入个数为 0-256 字节,数据可以被正确写入 Flash 芯片;当数据写入的字节首地址不是该页的首地址,及字节首地址不是 8’b0000_0000,数据写入个数为 0-256 字节,若数据写入个数少于字节首地址地址到末地址之间的存储单元个数,数据可以被正确写入 Flash 芯片;若数据写入个数多于字节首地址地址到末地址之间的存储单元个数,等于字节首地址地址到末地址之间的存储单元个数的数据可以被正确写入 Flash 芯片,超出的那部分数据,会以 8’b0000_0000 为字节首地址顺序写入本页,覆盖改地址之前存储的数据。

2.4 SPI_Flash 读数据实验

使用页写或连续写操作向 Flash 芯片写入数据,再使用数据读操作读取之前写入数
据,将读取的数据使用串口传回 PC 机,使用串口助手传回数据并与之前写入数据比较,
判断正误。
*注意:在向 Flash 芯片写入数据之前,先要对芯片执行全擦除操作。

2.4.1 时序

要执行数据读指令,首先拉低片选信号选中 Flash 芯片,随后写入数据读(READ)指令,紧跟指令写入 3 字节的数据读取首地址,指令和地址会在串行时钟上升沿被芯片锁存。随后存储地址对应存储单元中的数据在串行时钟下降沿通过串行数据总线输出。数据读取首地址可以为芯片中的任何一个有效地址,使用数据读(READ)指令可以对芯片内数据连续读取,当首地址数据读取完成,会自动对首地址的下一个地址进行数据读取。若最高位地址内数据读取完成,会自动跳转到芯片首地址继续进行数据读取,只有再次拉高片选信号,才能停止数据读操作,否者会对芯片执行无线循环读操作

总结

其实对于spi协议来说就只需要确定时什么时候采样什么时候空闲,然后空闲的时候变化数据,每次传输的bit数和先传高还是低和了解从设备的硬件特性。

对于flash芯片来说需要注意的时序就是cs和有效数据之间的时序,cs和cs之间的时序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rasterization

在cityfm中有说道 Raster is a rasterization function that maps a closed polygon, represented as an ordered list of nodes, to a binary image 要在Python中实现一个将多边形映射到二值图像的光栅化函数&#xff0c;你可以按照以下步骤进行&#xff1a; 创建一个函数&…

网络安全 day3 --- WAFCDNOSS反向代理正向代理负载均衡

WAF&#xff08;网页防火墙&#xff09; 原理&#xff1a;Web应用防火墙&#xff0c;旨在提供保护 影响&#xff1a;常规Web安全测试手段会受到拦截 实验&#xff1a;Windows2022 IIS D盾 作用是防范网络安全入侵。 如下图&#xff0c;我们在网站目录下放一个简单的一句话木马…

JavaScript初级——文档的加载

1、浏览器在加载一个页面时&#xff0c;是按照自上向下的顺序加载的&#xff0c;读取到一行就运行一行&#xff0c;如果将 script 标签写到页面的上边&#xff0c;在代码运行时&#xff0c;页面还没有加载&#xff0c;页面没有加载DOM对象也没有加载&#xff0c;会导致无法获取…

一个计算勒让德多项式的HTML页面

效果如下 HTML代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>勒让德多项式</ti…

ZooKeeper体系架构、安装、HA

一、主从架构的单点故障问题 主从架构 Hadoop采用了主从架构&#xff0c;其中包含一个主节点和多个从节点。主节点负责管理整个集群的元数据、任务分配等关键任务&#xff0c;而从节点则负责执行具体的数据存储、计算等操作。 单点故障 在Hadoop主从架构中&#xff0c;主节点作…

Linux并发与竞争

一.概念 Linux 是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况,多个任务甚至中断都能访问的资源叫做共享资源。在驱动开发中要注意对共享资源的保护,也就是要处理对共享资源的并发访问。 Linux 系统并发产生的原因很复杂,总结一下有下面几个主要原…

wegege

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

使用 setResponseStatus 函数设置响应状态码

title: 使用 setResponseStatus 函数设置响应状态码 date: 2024/8/25 updated: 2024/8/25 author: cmdragon excerpt: 通过 setResponseStatus 函数,你可以轻松地在 Nuxt.js 中设置响应的状态码。这不仅能帮助用户更好地理解发生了什么,还能在需要时显示自定义的错误页面。…

深入探讨与优化:常见排序算法的原理、实现与应用场景分析

目录 引言 排序算法的重要性 排序的基本概念 常见排序算法 插入排序 交换排序 选择排序 归并排序 分配排序 排序算法的实现与优化 总结与应用 引言 排序算法在计算机科学中占据了重要位置&#xff0c;它不仅仅是数据处理的基础&#xff0c;也是优化许多复杂算法的关…

初识redis:Zset有序集合

Set作为集合&#xff0c;有两个特点&#xff1a;唯一且无序。 Zset是有序集合&#xff0c;在保证唯一的情况下&#xff0c;是根据什么来排序的呢&#xff1f;排序的规则是什么&#xff1f; Zset中的member引入了一个属性&#xff0c;分数&#xff08;score&#xff09;&#…

初识redis:类型补充

Redis最关键的五个数据类型&#xff1a;String List Hash Set Zset 我们已经学完了&#xff0c;接下来我们再了解一下不是那么重要的&#xff0c;但是仍然有用的类型。 Stream Redis Stream 是 Redis 5.0 版本引入的一种新的数据类型&#xff0c;它提供了一种存储时间顺序消息…

《机器学习》—— OpenCV 对图片的各种操作

文章目录 1、安装OpenCV库2、读取、显示、查看图片3、对图片进行切割4、改变图像的大小5、图片打码6、图片组合7、图像运算8、图像加权运算 1、安装OpenCV库 使用pip是最简单、最快捷的安装方式 pip install opencv-python3.4.2还需要安装一个包含了其他一些图像处理算法函数的…

智慧交通——铁路检测相关数据集

数据集列表 智慧交通系列数据集——铁路相关数据集&#xff0c;用于轨道交通、自动化、计算机等专业结合深度学习、目标检测、语义分割、实例分割相关技术实现应用型研究&#xff01;&#xff01;&#xff01; 下载链接&#xff1a;私信获取 目前已更新数据集类型如下&#x…

cola_os学习笔记(下)

cola_os学习笔记&#xff08;上&#xff09; os文件夹 cola_device.c ​ .h放在.c的同层级。作者采用了字符设备注册的方式&#xff0c;在.h中可以看到设备属性。也就是把LED这些设备抽象&#xff0c;外面传入"LED1"这样的参数&#xff0c;使我联想到java的new一个…

GoWeb 设置别名和多环境配置

别名 vite.config.ts中添加代码如下即可 //设置别名resolve: {alias: {"": path.resolve(process.cwd(),"src"),//用替代src}}随后即可使用 配置多环境 vite.config.ts中添加代码如下 envDir: ./viteenv,//相对路径随后在项目根目录创建对应的viteenv…

Flink内存调优

Flink内存调优 JVM 我们知道Flink是基于JobManager和TaskManager管理和运行任务&#xff0c;而他们都是以Java进程的形式运行的&#xff0c;所以在了解 Flink 内存时&#xff0c;我们需要先了解一下Java运行时环境Java虚拟机(JVM) 。 JVM 是可运行 Java 代码的假想计算机 &a…

Visio如何对自画的“不规则封闭图案”填充颜色?

Visio如何对自画的“不规则封闭图案”填充颜色&#xff1f; 当我们想要画一个如下所示的不规则图案时&#xff0c;可以根据Visio工具栏中的曲线/直线等进行拼接组成。 但是&#xff0c;画出来的图形即使是组合后也不能直接填充颜色&#xff0c;这是因为软件并不能识别其为一个…

Tomcat上传jsp木马

一、暴力破解 首先我们访问目标IP和端口 点击server status登录&#xff0c;直接burp进行爆破 我们输入tomcat 123 抓包&#xff0c;发现这个Basic是base64编码后的&#xff0c;解码是 tomcat:123 我们暴破时需要注意这里用的base64构成的&#xff0c;具体操作可以看http://…

【微服务】springboot整合对象映射工具MapStruct使用详解

目录 一、前言 二、实体对象映射概述 2.1 什么是实体对象映射 2.1.1 ORM的几个基本概念 2.1.2 ORM常用的框架 2.2 实体对象映射存在的问题 2.2.1 映射配置错误 2.2.2 性能问题 2.2.3 修改字段不一致问题 三、实体对象属性拷贝工具概述 3.1 什么是实体对象属性拷贝工具…

忘掉 Redux,拥抱 Zutand 和 Jotai 的全新世界

Redux 在现代 React 开发中存在着一些明显的局限性。 首先&#xff0c;Redux 的心智负担较重。它涉及到众多概念&#xff0c;如 Store、Reducer、Action 等&#xff0c;对于初学者来说&#xff0c;理解和掌握这些概念需要花费较多的时间和精力。而且&#xff0c;Redux 要求严格…