stm32与FPGA通信代码实现方案spi(对初学者实用)

走远了吗. 提交于 2019-12-02 19:00:58

/*------------以下是FPGA与微控制器通信SPI模块的编程思路-分析----------------------------------------------

-----------------本文严禁抄袭和用于各种商业用途,违者必究------------------------------------------------------------------

---------------作者:熊楚华------------------------------------------------------------------------------------------------------------------

----------------------修改日期:2017/12/14-----------------------------------------------------------------------------------------------

*/

  模块结构框图

 

 

 

Spi_sclSPI通信时钟,由主机自行产生,跟一般意义的时钟不一样,上升沿32发数据,下降沿32接收数据

 

主要由SPI信号缓存模块,SPI时钟边沿检测,命令接收+数据接收,发送几部分构成:

 


Spi_sdo:MISO发给32处理

dout:[31:0]:这个数据通过dcm的选择发给其他从机

Cmd_done:从器件地址接收完毕标志,高电平有效

Data_done:FPGA数据收发完成标志,高电平有效

rst:FPGA复位

clk:FPGA时钟

Spi_sdi:MOSI

Spi_cs_data:低电平时开启SPI接收数据(接收数据片选信号)

Spi_cs_cmd:使能FPGA接收其他从器件地址的信号,低电平有效

Spi_scl:32提供的通信时钟

din[31:0]:FPGA并行数据接收端口,接收外界待测频率信号

 

 

程序分析:

程序一:SPI信号两级缓存部分程序设计

(为避免产生毛刺和方便信号边沿检测,SPI通信spi_scl(通信时钟),spi_cs_cmd(,FPGA从器件地址接收片选),spi_cs_data(,FP接收数据片选)这三个信号需要进行两级缓存)

 

 

 

这里只写spi_scl的二级缓存示例,其他两个方法一样

搞个always@(posedge clk )如同步复位的话就先清零spi_scl_reg1,else只是clk上升沿的话就让spi_scl_reg1<=spi_scl,这是一级缓存

在搞个always@(posedge clk)如同步复位的话就先清零spi_scl_reg,else只是clk上升沿的话就让spi_scl_reg<=spi_scl_reg1,这是二级缓存

 

程序二:SPI通信时钟边沿检测模块设计

//为什么要边沿检测,在SPI主从机通信中FPGAsclk上升沿接收数据,在sclk下降沿进行数据发送//

 

第一部分:sclk上升沿检测模块:存储在scl_up_flag

搞个always@(posedge clk )如同步复位的话就先清零spi_scl_flag,else只是clk上升沿的话就再判断if(spi_scl_reg1==1&&spi_scl_reg==0)//scl一级缓存为1scl二级缓存为零,  就令scl_up_flag<=1,标志这时sc刚刚有过上升沿现在还在高电平状态,   elsescl_up_flag <= 0

 

第二部分:sclk下降沿检测模块:存储在scl_down_flag

搞个always@(posedge clk )如同步复位的话就先清零spi_down_flag,else只是clk上升沿的话就再判断if(spi_scl_reg1==0&&spi_scl_reg==1)//scl一级缓存为0scl二级缓存为1,  就令scl_down_flag<=1,标志这时scl刚刚有过下降沿现在还在低电平状态,   elsescl_down_flag <= 0

 

注意(这里的updown信号个高电平会维持一个clk周期,称为高脉冲)

 

 

程序三:SPI通信接收模块设计

 

 

 

//这里只分析接收数据的方法,接收地址的方法不赘述地址为宽我们用8wei//

//手先需要spi_cs_data使能信号低电平有效,同时等到spi_scl上升沿时,接收模块将spi_sdi传入的串行数据经移位寄存器dout转成并行数据(注意没个上升沿只能传一位串行数据),经过数据位宽个spi_clk时钟后(我们用的是32位)数据片选使能才会拉高//

还是搞个always@(posedge clk )如同步复位的话就先清零spi_down_flag,else只是clk上升沿的话就再判断if(spi_cs_data_reg1==0&&spi_cs_data_reg==1)//scl一级缓存为0scl二级缓存为1, 说明数据片选信号有效,允许接收数据,这是在判断有没有if(scl_up_flag)通信时钟为高电平,刚有过上升沿,现在开始用移位寄存器dout接收spi_sdi的串行数据第一个数,

dout[31:0] <={dout[30:0],spi_sdi} //  dout左移让输入数据先占据最低位,依此。。。

再搞个else,如果以上三条件有一个不满足的话就让dout保持原值。

//再产生数据接收结束标志,搞个data_done触发器,当数据片选信号拉高之后表明数据串转并完毕,这时再让相应的接收完成标志寄存器data_done <= 1//

 

判断刚刚有过数据片选上升沿的语句:if(spi_cs_data_reg1 = = 1&& spi_cs_data_reg = = 0)

数据接收一开始也是先判断刚刚有过下降沿if(spi_data_reg1== 0&&spi_data_reg== 1),这个时候是给dout<=0,如果不是这样就dout保持,

 

程序四:SPI通信数据发送模块设计

//刚刚说了spi_cs_data为低时数据接收,发送的方法跟接收是对称的,所以在spi_cs_data为高的期间,一旦spi_scl的下降沿到来,就要将刚刚接收的数据存入数据发送寄存器进行din_reg中,仍然是等到spi_cs_data低电平期间一旦spi_scl下降沿到来时就将din_reg中并行数据转换成串行数据并经过spi_sdo端口输出给stm32,有事经过位宽个通信时钟后数据发送完毕,spi_cs_data拉高,//

 

先发送最高位,if(scl_down_flag)

Spi_sdo <= din_reg[31]

din_reg[31:0]={din_reg[30:0],1b0}//左移

//注意都别忘了当不满足条件时让spi_sdodin_reg[31:0]都保持前面都是这样的,这是一个默认的规则,还有那个复位也是//

这里在spi_cs_data拉高之后让din_reg[31:0]获取下一轮din[31:0]中接收的数据,else还是保持,切记!!

 

总结:din[31:0]中的数据是FPGA其他模块传来的,外界传来的信号加上测频部分的可能有好几路31位的数据,先通到一个mux8_to1selsel值由32发送过来)选择哪路进入到din[31:0]中,然后这个数据可以进入din_reg中再通过spi_sdo发送到stm3232收到这个数据信号后就可以进行各种处理,如显示在屏幕上等。然后32那边发送过来的数据或命令进入spi_sdi口,这个串行数据可以通过移位寄存器一个个移入dout[31:0]中从而传给FPGA其他模块

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!