你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】FPGA作为从机与STM32进行SPI协议通信---Verilog实现

[复制链接]
STMCU小助手 发布时间:2022-1-16 18:00
一.SPI协议简要介绍
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
  SPI总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU与各种外围器件进行全双工、同步串行通讯。SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。
SPI主模块和与之通信的外设时钟相位和极性应该一致。
以下是SPI时序图:
   主要讲解一下广泛使用的两种方式设置:
SPI0方式:CPOL=0,CPHA=0;SCK空闲状态为低电平,第一个跳变沿(上升沿)采样数据,无论对Master还是Slaver都是如此。
SPI3方式:CPOL=1,CPHA=1;SCK空闲状态为高电平,第二个跳变沿(上升沿采样数据,无论对Master还是Slaver都是如此。
其实对于SPI0和SPI1发送与接收数据,可以总结为一句话:上升沿采样数据,下降沿发送数据。全双工同时进行,当然,必须在CS拉低使能情况下。

二.FPGA作为Slaver实现SPI3方式与STM32通信
1.STM32方面:用库函数配置SPI1,设置CPOL=1,CPHA=1.
2.FPGA方面:
(1)通过边沿检测技术得出SCK上升沿与下降沿标志,用于下面状态机中的数据采样及发送。
(2)根据时序图,采用2个状态机分别在SCK上升沿实现数据采样,下降沿实现数据发送。无论是采样还是发送,都是高位在前,从Bit[7]到Bit[0],共8位数据。
(3)最后通过边沿检测技术得出数据采样完成标志,用于用户操作。
以下是SPI3的时序图:
三.Verilog代码部分
测试工程代码:实现了STM32每隔200ms发送流水灯数据给FPGA,使FPGA系统板上的4个LED灯实现流水操作;同时,FPGA每隔1s发送计数数据给STM32,并在STM32系统板上的LCD屏出来,即:显示0-9循环计数。
但下面的代码只是SPI作为从机的驱动部分,包括SPI发送数据与接收数据。

  1. /***********************************************************************
  2.      ****************** name:SPI_Slaver_Driver **************
  3.             ********** author:made by zzuxzt **********
  4.      ****************** time:2014.4.29 **********************
  5. ***********************************************************************/
  6. //use SPI 3 mode,CHOL = 1,CHAL = 1
  7. module spi(input clk,
  8.               input rst_n,
  9.               input CS_N,
  10.               input SCK,
  11.               input MOSI,
  12.               input [7:0] txd_data,
  13.               output reg MISO,
  14.               output reg [7:0] rxd_data,
  15.               output rxd_flag);   //recieve done,please transmit data

  16. //-------------------------capture the sck-----------------------------
  17. reg sck_r0,sck_r1;
  18. wire sck_n,sck_p;
  19. always@(posedge clk or negedge rst_n)
  20. begin
  21.     if(!rst_n)
  22.         begin
  23.             sck_r0 <= 1'b1;   //sck of the idle state is high
  24.             sck_r1 <= 1'b1;
  25.         end
  26.     else
  27.         begin
  28.             sck_r0 <= SCK;
  29.             sck_r1 <= sck_r0;
  30.         end
  31. end

  32. assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0;   //capture the sck negedge
  33. assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0;   //capture the sck posedge

  34. //-----------------------spi_slaver read data-------------------------------
  35. reg rxd_flag_r;
  36. reg [2:0] rxd_state;
  37. always@(posedge clk or negedge rst_n)
  38. begin
  39.     if(!rst_n)
  40.         begin
  41.             rxd_data <= 1'b0;
  42.             rxd_flag_r <= 1'b0;
  43.             rxd_state <= 1'b0;
  44.         end
  45.     else if(sck_p && !CS_N)
  46.         begin
  47.             case(rxd_state)
  48.                 3'd0:begin
  49.                         rxd_data[7] <= MOSI;
  50.                         rxd_flag_r <= 1'b0;   //reset rxd_flag
  51.                         rxd_state <= 3'd1;
  52.                       end
  53.                 3'd1:begin
  54.                         rxd_data[6] <= MOSI;
  55.                         rxd_state <= 3'd2;
  56.                       end
  57.                 3'd2:begin
  58.                         rxd_data[5] <= MOSI;
  59.                         rxd_state <= 3'd3;
  60.                       end
  61.                 3'd3:begin
  62.                         rxd_data[4] <= MOSI;
  63.                         rxd_state <= 3'd4;
  64.                       end
  65.                 3'd4:begin
  66.                         rxd_data[3] <= MOSI;
  67.                         rxd_state <= 3'd5;
  68.                       end
  69.                 3'd5:begin
  70.                         rxd_data[2] <= MOSI;
  71.                         rxd_state <= 3'd6;
  72.                       end
  73.                 3'd6:begin
  74.                         rxd_data[1] <= MOSI;
  75.                         rxd_state <= 3'd7;
  76.                       end
  77.                 3'd7:begin
  78.                         rxd_data[0] <= MOSI;
  79.                         rxd_flag_r <= 1'b1;  //set rxd_flag
  80.                         rxd_state <= 3'd0;
  81.                       end
  82.                 default: ;
  83.             endcase
  84.         end
  85. end


  86. //--------------------capture spi_flag posedge--------------------------------
  87. reg rxd_flag_r0,rxd_flag_r1;
  88. always@(posedge clk or negedge rst_n)
  89. begin
  90.     if(!rst_n)
  91.         begin
  92.             rxd_flag_r0 <= 1'b0;
  93.             rxd_flag_r1 <= 1'b0;
  94.         end
  95.     else
  96.         begin
  97.             rxd_flag_r0 <= rxd_flag_r;
  98.             rxd_flag_r1 <= rxd_flag_r0;
  99.         end
  100. end

  101. assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;

  102. //---------------------spi_slaver send data---------------------------
  103. reg [2:0] txd_state;
  104. always@(posedge clk or negedge rst_n)
  105. begin
  106.     if(!rst_n)
  107.         begin
  108.             txd_state <= 1'b0;
  109.         end
  110.     else if(sck_n && !CS_N)
  111.         begin
  112.             case(txd_state)
  113.                 3'd0:begin
  114.                         MISO <= txd_data[7];
  115.                         txd_state <= 3'd1;
  116.                       end
  117.                 3'd1:begin
  118.                         MISO <= txd_data[6];
  119.                         txd_state <= 3'd2;
  120.                       end
  121.                 3'd2:begin
  122.                         MISO <= txd_data[5];
  123.                         txd_state <= 3'd3;
  124.                       end
  125.                 3'd3:begin
  126.                         MISO <= txd_data[4];
  127.                         txd_state <= 3'd4;
  128.                       end
  129.                 3'd4:begin
  130.                         MISO <= txd_data[3];
  131.                         txd_state <= 3'd5;
  132.                       end
  133.                 3'd5:begin
  134.                         MISO <= txd_data[2];
  135.                         txd_state <= 3'd6;
  136.                       end
  137.                 3'd6:begin
  138.                         MISO <= txd_data[1];
  139.                         txd_state <= 3'd7;
  140.                       end
  141.                 3'd7:begin
  142.                         MISO <= txd_data[0];
  143.                         txd_state <= 3'd0;
  144.                       end
  145.                 default: ;
  146.             endcase
  147.         end
  148. end

  149. endmodule
复制代码




1 收藏 评论0 发布时间:2022-1-16 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版