『FPGA通信接口』串行通信接口-SPI

news2024/11/25 3:07:38

在这里插入图片描述

文章目录

  • 1.SPI简介
  • 2.控制时序
  • 3.Dual、Qual模式
  • 4.例程设计与代码解读
  • 5.SPI接口实战应用
    • 5.1时序要求
    • 5.2仿真时序图
    • 5.3代码设计
  • 6.传送门

1.SPI简介

SPI是串行外设接口(Serial Peripheral Interface)的缩写,通常说SPI接口或SPI协议都是指SPI这一种串行外设接口规范。相对于串口,SPI是一种高速的(可达10Mb\s以上),全双工,同步的通信总线。串口是点对点的全双工的异步通信,因此要通信双方按照相同的约定(指起始、暂停位、波特率)才能在数据上同步,准确通信。而SPI是一种同步通信的总线结构,同步是指有专门时钟线用来同步源端和目的端,总线结构是指主从之分,通常是一个设备做主,可以多个设备做从,也正因为如此才有了CS片选线,指定所选从设备。
在这里插入图片描述
在实际的应用中,通常也只是一主一从。SPI接口多应用于Flash、ADC、LCD控制器,CMOS寄存器配置接口等场景。SPI在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议。

2.控制时序

SPI有四根线,如下,
在这里插入图片描述
(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;
(2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;
(3)SCLK – Serial Clock,时钟信号,由主设备产生;
(4)CS – Chip Select,从设备使能信号,由主设备控制。
SPI通信一般包括主设备(Master)和从设备(Slave),主设备负责发起通信并控制通信的时序,从设备则响应主设备的指令。SPI通信有四种模式,分别是模式0、模式1、模式2和模式3,不同的模式在时钟极性和相位上有所不同。这四种数据传输的时序模式,是由设备的属性的决定的,用CPOL和CPHA标识这四种时序。CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0(1),空闲电平为低电平(高电平)CPHA是用来决定采样时刻的,CPHA=0,在每个周期的第一个时钟沿采样,CPHA=1,则在每个周期的第二个时钟沿采样。 通常使用的是MODE0模式,即CPOL=CPHA=0,空闲时为低电平,在第一个时钟沿采样。其他几种模式如果需要可以上网搜索,资料很多。
使用SPI接口时需要注意,很多SPI接口的芯片并不是标准的SPI协议,可能是稍有变化,例如对哪个沿采样会有明确的说明。此外,还有一种可能是在SPI协议的基础上进一步做限制,例如要求一次读写过程结束后CS必须拉高等。SPI要求是高位在前,MSB的方式。还有就是SPI一个时钟周期必然要执行接收一位数据和发送一位数据。

3.Dual、Qual模式

上面描述的就是标准SPI,有4根引脚信号:clk , cs, mosi, miso。针对SPI Flash而言,有Dual SPI和Qual SPI两种模式,这是因为,Flash器件的全双工并不常用,因此扩展mosi和miso的用法,让它们工作在半双工,用以加倍数据传输。也就是对于Dual SPI Flash,可以发送一个命令字节进入dual mode,这样mosi变成SIO0(serial io 0),mosi变成SIO1(serial io 1),这样一个时钟周期内就能传输2个bit数据,加倍了数据传输。与Dual SPI类似,Qual SPI Flash增加了两根I/O线(SIO2,SIO3),目的是一个时钟内传输4个bit。

4.例程设计与代码解读

如图所示,把Spi_driver模块的输入输出分成两个部分,一个部分为图示左侧的与其他模块交互的接口,另一部分为图示右侧与物理管脚相连。Spi_en信号为外部的脉冲信号,收到该脉冲执行一次8Bit的发送动作,和8Bit的接收动作。通过VIO产生spi_en信号和要发送的数据信号data[7:0],将板卡上的mosi和miso管脚相连,判断发送数据和接收数据是否一致,若一致则点亮led。由于缺乏带SPI设备的板卡,故设计此例程。一次发送动作结束后会产生spi_done的脉冲信号,在发送动作执行过程中,spi_busy持续为拉高状态。另外,spi_sck作为同步时钟直接决定传输数据的速度,通常在10Mb/s以下,或者依据对端设备来指定。
在这里插入图片描述

在使用SPI设备时可以修改此驱动模块以满足需求,左侧信号与外部设备交互,当busy拉高的时候不允许发送spi_en信号;可以对data信号采用多路选择器,以完成某些固定的指令或者读写操作;同样,数据的位宽也可以扩展。另外,实际使用的时候应该使用cs管脚,按照相关设备的要求灵活运用该管脚。
下面代码在硬件板卡上完成测试。该代码使用MODE0,即CPOL=CPHA=0的模式。程序分为以下四步,第一步产生sck同步时钟,第二步依据en指示信号写数据,第三步依据en指示信号并发读数据,第四步产生ui交互信号。

module spi_wr(
    input        clk_i       ,
    //user interface
    // input        spi_en     ,//其他模块的spi使能信号
    // input    [7:0]data      ,
    output       spi_busy      ,//指示spi的状态,表示SPI过程
    output       spi_done      ,//指示spi结束一次动作
    output       led           ,
    // output       spi_cs        ,//SPI从机的片选信号,低电平有效。
    output       spi_clk       ,//主从机之间的数据同步时钟。
    output       spi_mosi      ,//数据引脚,主机输出,从机输入。
    input        spi_miso      //数据引脚,主机输入,从机输出。 
    );
// assign spi_cs = 0;
//1.同步时钟产生模块 用50MHz分频为50KHz
assign spi_clk = m_clk;
parameter [9:0] SPI_DIV    = 10'd499;//分频定为50KHz,50Mhz/50K/2- 1'b1=499
reg [9:0] clk_cnt = 10'd0;//分频计数器
always@(posedge clk_i)begin
    if(clk_cnt < SPI_DIV&&spi_busy)
        clk_cnt <= clk_cnt + 1'b1;
    else 
        clk_cnt <= 10'd0;
end
reg m_clk = 1'b0;
always@(posedge clk_i)begin
    if(spi_en)
        m_clk <= 1'b0;
    else if(clk_cnt==SPI_DIV) 
        m_clk <= ~m_clk;
end
//2.接收en信号和数据,执行spi mosi操作(写数据)
//计数发送个数
reg [3:0]tx_cnt = 0;
always@(posedge clk_i)begin
    if(spi_en)begin
        tx_cnt <= 0; 
    end else if((clk_cnt == SPI_DIV)&&(tx_cnt==4'd8))begin
        tx_cnt <= 0;
    end else if((clk_cnt == SPI_DIV)&&spi_clk==0)
        tx_cnt<=tx_cnt+1;
end
//移位寄存器发送
wire [7:0]data;
reg  [7:0]data_reg=8'b0;//数据源
always@(posedge clk_i)begin
    if(spi_en)
        data_reg <= data;
    else if(spi_done)
        data_reg <=8'b0;
    else if(clk_cnt == SPI_DIV&&spi_clk==1)
        data_reg[7:0] <= {data_reg[6:0],data_reg[7]};
end
assign spi_mosi = data_reg[7];
//3.接收en信号和数据,执行spi miso操作(读数据)
reg  [7:0]data_fifo=8'b0;
always@(posedge clk_i)begin
    if((clk_cnt == SPI_DIV)&&spi_clk==0)begin
        case (tx_cnt)
           0 : data_fifo[7] <= spi_miso;
           1 : data_fifo[6] <= spi_miso;
           2 : data_fifo[5] <= spi_miso;
           3 : data_fifo[4] <= spi_miso;
           4 : data_fifo[3] <= spi_miso;
           5 : data_fifo[2] <= spi_miso;
           6 : data_fifo[1] <= spi_miso;
           7 : data_fifo[0] <= spi_miso;
           default: ;
        endcase
    end else 
        data_fifo <= data_fifo;
end
//4.发出user interface相关指示信号
wire spi_en;
reg spi_busy =0;
assign spi_done = ((clk_cnt == SPI_DIV)&&(tx_cnt==4'd8)) ? 1'b1 : 1'b0;
assign led = (data_fifo==8'b11010111) ? 1'b1 : 1'b0;
//产生busy信号,指示spi进程
always@(posedge clk_i)begin
    if(spi_en)
        spi_busy<=1'b1;
    else if(spi_done)
        spi_busy<=1'b0;
    else
        spi_busy<=spi_busy;
end
vio_0 use_vio (
  .clk(clk_i),                // input wire clk
  .probe_out0(spi_en),  // output wire [0 : 0] probe_out0
  .probe_out1(data)  // output wire [7 : 0] probe_out1
);
ila_0 your_instance_name (
    .clk(clk_i), // input wire clk
    .probe0({data_reg,data_fifo}), // input wire [15:0]  probe0  
    .probe1(tx_cnt), // input wire [3:0]  probe1 
    .probe2({spi_en,spi_mosi,spi_miso,spi_busy}) // input wire [3:0]  probe2
);

5.SPI接口实战应用

给一款以SPI寄存器接口作为接口的芯片写一个SPI控制器大概需要三步,首先搞清楚芯片datasheet对于SPI接口的时序要求,每个芯片都可能有特殊的一面。然后,根据芯片要求设计程序完成仿真验证。最后,RTL设计,布局布线上板测试。

5.1时序要求

  1. 系统对于SPI读写发生的时隙做了规定,即上电之后经过一系列步骤等reset拉高之后的10us之后。

  2. 在使用PLL时钟的情况下,最大的SPI的时钟为10MHz,如下。为了精准的控制每一个上升沿和下降沿的数据,使用手动的方式生成这个时钟,用户时钟为50MHz,因此分频的时钟周期为20ns。
    在这里插入图片描述

  3. 根据datasheet提及的SPI时序,首先应该在按照上电时序要求的情况下把ss_n拉低。

  4. 手册要求,ss_n拉低之后需要保持一个spi的时钟周期才能给spi时钟。
    在这里插入图片描述

  5. 该芯片的SPI的时序是,第一个时钟边沿是上升沿,直接在第一个边沿就加载数据了。此处加载的是写入的9bit宽的地址值,注意此处是,MSB.
    在这里插入图片描述

  6. 注意读写之间的切换,与标准的SPI的时序不同,是在spiclk的下降沿抓取数据。

5.2仿真时序图

在这里插入图片描述

5.3代码设计

在这里插入图片描述
源码工程见文末
init模块完成系统对于上电时序的要求,上电后10us给时钟,时钟给到后的10us才开始复位拉高,控制SPI Upload在reset 10us之后开始;
②形成四个模块,各司其职。spi_ctrl模块控制读写寄存器的顺序以满足配置顺序要求;LUT模块将每个寄存器的将要写入的内容提前编辑好,配合ctrl完成读写配置;spi_driver模块根据ctrl模块的读写命令指示和lut的寄存器地址和写入数据驱动spi接口写入数据;top模块将三个子模块例化保持与design_top的通信。
③当开始spi upload后,spi_ctrl模块将按照预先编辑好的查找表,按顺序写入寄存器,其中需要注意有一个环节要读时钟管理寄存器的状态,状态正常后才能继续写,这点尤为重要。

6.传送门

  • 我的主页
  • SPI实战代码
  • FPGA通信接口专栏汇总导航
END

🔈文章原创,首发于CSDN论坛,我的主页。
🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。

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

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

相关文章

IBM SPSS Statistics for Mac中文激活版:强大的数据分析工具

IBM SPSS Statistics for Mac是一款功能强大的数据分析工具&#xff0c;为Mac用户提供了高效、精准的数据分析体验。 IBM SPSS Statistics for Mac中文激活版下载 该软件拥有丰富的统计分析功能&#xff0c;无论是描述性统计、推论性统计&#xff0c;还是高级的多元统计分析&am…

智能零售:引领购物新时代

智能零售通过整合人工智能、物联网、大数据和机器学习等技术&#xff0c;正在彻底改变传统的购物模式&#xff0c;为消费者和零售商提供前所未有的效率和个性化体验。 智能零售利用消费者数据分析来提供个性化的购物推荐。无论是在线平台或是实体店内&#xff0c;智能系统都能…

“中医显示器”是人体健康监测器

随着科技的进步&#xff0c;现代医学设备已经深入到了人们的日常生活中。然而&#xff0c;在这个过程中&#xff0c;我们不应忘记我们的医学根源&#xff0c;中医。我们将中医的望、闻、问、切四诊与现代科技相结合&#xff0c;通过一系列的传感器和算法将人体的生理状态以数字…

MyBatisPlus自定义SQL

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:MyBatisPlus自定义SQL 📚个人知识库: Leo知识库,欢迎大家访问 目录 1.前言☕…

机器学习方法在测井解释上的应用-以岩性分类为例

机器学习在测井解释上的应用越来越广泛&#xff0c;主要用于提高油气勘探和开发的效率和精度。通过使用机器学习算法&#xff0c;可以从测井数据中自动识别地质特征&#xff0c;预测岩石物理性质&#xff0c;以及优化油气储层的评估和管理。 以下是机器学习在测井解释中的一些…

华为配置路由式Proxy ARP示例

配置路由式Proxy ARP示例 组网图形 图1 配置路由式Proxy ARP组网图 路由式Proxy ARP简介配置注意事项组网需求配置思路操作步骤配置文件 路由式Proxy ARP简介 企业内部进行子网划分时&#xff0c;可能会出现两个子网网络属于同一网段&#xff0c;但是却不属于同一物理网络的情…

新a_bogus算法还原大赏

新a_bogus算法还原大赏 记得加我我们的学习群哦&#xff1a;529528142 1、本次新ab是继承之前旧ab的过程&#xff0c;新ab分为上半部分和下半部分&#xff0c;上半部分是之前的旧ab&#xff0c;下半部分我们开始讲解。 s.apply(l, u).length 172这是断住ab的条件&#xff0c;…

【介绍下负载均衡原理及算法】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

深入掌握k8s核心概念--Pod(二)

详解Pod的配置管理与调度特性等剖析 Kubernetes 中 Pod 的配置管理&#xff08;ConfigMap&#xff09;、调度策略、回滚与扩缩容详解一、Pod 配置管理&#xff1a;ConfigMap创建 ConfigMap 示例使用 ConfigMap 的 Pod 示例 二、玩转 Pod 调度&#xff1a;Kubernetes 高级调度策…

【笔记】ASP.NET Core Web API之Token验证

在实际开发中经常需要对外提供接口以便客户获取数据&#xff0c;由于数据属于私密信息&#xff0c;并不能随意供其他人访问&#xff0c;所以就需要验证客户身份。那么如何才能验证客户的身份呢&#xff1f;一个简单的小例子&#xff0c;简述ASP.NET Core Web API开发过程中&…

CTFHUB-技能树-Web前置技能-文件上传(前端验证—MIME绕过、00截断、00截断-双写后缀)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—MIME绕过、00截断、00截断-双写后缀&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—MIME绕过、00截断、00截断-双写后缀&#xff09;前端验证—MIME绕过有关MIMEMIME的作用 解题时有…

RACE IPEMD:构建安全基石的密码学原理与实践

title: RACE IPEMD&#xff1a;构建安全基石的密码学原理与实践 date: 2024/4/16 16:53:56 updated: 2024/4/16 16:53:56 tags: IPEMD哈希算法SHA-1SHA-2/3消息摘要数字签名安全分析 前言 在当今信息爆炸的时代&#xff0c;数据安全和隐私保护变得尤为重要。密码学作为信息安…

C语言100题练习打卡(2)

14&#xff0c;将一个正整数分解质因数。 例如&#xff1a;输入90&#xff0c;打印出902*3*3*5 #include<stdio.h> /*分析&#xff1a; * 1&#xff0c;如果这话质数恰巧等于&#xff08;小于的时候&#xff0c;继续执行循环&#xff09;n&#xff0c; 则说明分解质因数…

案例分析-redis

案例需求&#xff1a;在7002这个slave节点执行手动故障转移&#xff0c;重新夺回master地位 步骤如下&#xff1a; 1&#xff09;利用redis-cli连接7002这个节点 2&#xff09;执行cluster failover命令 如图&#xff1a; 效果&#xff1a; 4.5.RedisTemplate访问分片集群 …

Gitea是一个开源、轻量级的自托管Git解决方案

Gitea介绍 Gitea是一个由Go语言编写的、轻量级的、自托管的Git解决方案&#xff0c;类似于GitHub、GitLab等平台。它是用Go语言编写的开源软件&#xff0c;提供了Git版本控制系统的基本功能&#xff0c;包括代码托管、问题跟踪、代码审查、Wiki等。Gitea的设计目标是简单易用、…

ssm 体检预约管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 ssm 体检预约管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c; 系统主要采用B/S…

深度学习 Lecture 7 迁移学习、精确率、召回率和F1评分

一、迁移学习&#xff08;Transfer learning) 用来自不同任务的数据来帮助我解决当前任务。 场景&#xff1a;比如现在我想要识别从0到9度手写数字&#xff0c;但是我没有那么多手写数字的带标签数据。我可以找到一个很大的数据集&#xff0c;比如有一百万张图片的猫、狗、汽…

SD-WAN企业组网:多样化的应用场景

随着企业网络环境的快速发展&#xff0c;SD-WAN技术正成为实现站点间网络互通的关键所在。它不仅支持企业站点对因特网、SaaS云应用和公有云等多种业务的高效访问&#xff0c;更能满足多样化的业务需求。深入探讨SD-WAN的组网应用场景&#xff0c;我们能够发现其广泛的适用性和…

Day 14 网络协议

常见网络设备&#xff1a;交换机 路由器 中继器 多协议网关&#xff08;路由器的前身&#xff09; 交换机&#xff1a;用于连接统一网络的设备&#xff0c;实现内网设备通信。 从广义上分为&#xff1a;局域网交换机&#xff0c;广域网交换机 从网络构成分为&#xff1a;接…

UbuntuServer22.04安装docker

通过ubuntuserver安装docker是搭建开发环境最便捷的方式之一。下面介绍一下再ubuntu22.04上如何安装docker。相关内容参考官网链接&#xff1a;Install Docker Engine on Ubuntu 根据官网推荐&#xff0c;利用apt命令的方式安装&#xff0c;首先需要设置docker仓库&#xff0c…