您的位置 首页 软件

零根底学FPGA(十一)一步一足迹之根据FIFO的串口发送机规划全流程及常见过错详解

记得在上几篇博客中,有几名网友提出要加进去错误分析这一部分,那我们就从今天这篇文章开始加进去我在消化这段代码的过程中遇到的迷惑,与大家分享。今天要写的是一段基于FIFO的串口发送机设计,之

  记住在上几篇博客中,有几名网友提出要加进去过错剖析这一部分,那咱们就从今日这篇文章开端加进去我在消化这段代码的进程中遇到的利诱,与咱们共享。

  今日要写的是一段依据FIFO的串口发送机规划,之前也写过串口发送的电路,这次写的与前次的有几分相似。这段代码也是我看过他人写过的之后,消化一下再依据自己的了解写出来的,下面是我写这段代码的悉数流程和思路,期望对刚开端触摸的朋友来说有一点点的协助,也期望有经历的朋友给予名贵的主张。

  首先来解说一下FIFO的意义,FIFO便是First Input First Output的缩写,便是先入先出的意思,依照我的了解便是,先进去的数据先出,例如一个数组的高位先进,那么读出来的时分也就高位先出。下面是百度百科的解说。

  FIFO一般用于不同时钟域之间的数据传输,比方FIFO的一端是AD数据收集,另一端是计算机的PCI总线,假定其AD收集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为1056Mbps,在两个不同的时钟域间就能够选用FIFO来作为数据缓冲。别的关于不同宽度的数据接口也能够用FIFO,例如单片机位8位数据输出,而DSP或许是16位数据输入,在单片机与DSP衔接时就能够运用FIFO来到达数据匹配的意图。

  下面咱们开端规划。

  这次规划咱们要规划一个串口发送机,想一下的话,咱们要发送数据,总得有一个数据发生模块和数据发送模块吧。好,那么在咱们的脑海里就呈现了这两个模块。由于咱们这次是借用Altera公司供给的IP核FIFO来完结,所以要参加这个模块,这个模块作为一个数据缓冲器,需求咱们例化,等会咱们依照思路来例化它。

  好,模块出来了,咱们将这三个模块别离界说为dataoutput块,fifo_ctrl块和uart_ctrl块。现在考虑连线。我个人感觉在规划之前,把要规划的东西在草稿纸大将大体框图画出来,详细到每一根连线,这样依据图来写代码要比直接用脑子构图要便利的多。三个模块,先考虑时钟和复位信号线,三个模块都有,然后,数据发生模块要将发生的数据发给FIFO模块,所以要有数据写入线,咱们界说它为wr-datain,数据写入FIFO块后总要输出,这些数据便是咱们要发送的数据,所以界说输出数据线tx_data,先不论FIFO,咱们再来界说数据发送模块的连线,数据发送总要有个发动信号,所以咱们界说变量tx_start,之后,还要有一个输出端给PC机,咱们界说这个输出端位rs232,关于FIFO模块的例化进程很简单就不做过多的阐明,只把接口说一下,FIFO模块除了时钟,复位信号外,还有数据输入端口,这个端口要和之前的数据发生模块的数据输出端口相连,还有写恳求端口,高电平有用,数据发送模块每隔1秒钟发生一个16位的数据,并发送写恳求指令给FIFO,还有读恳求指令,高电平有用数据发送模块在发送数据时要发送一个读恳求给FIFO,从中读取数据后再发送给PC机,还有空信号empty,只需检测到FIFO中有数据,empty就为低电平,咱们可用这个信号来发动数据发送模块。这样一来,咱们的全体结构就出来了有了这个全体结构,再写代码就简单多了。

  下面是RTL视图

360桌面截图20140714200658.jpg

  下面咱们来写代码

  依照这个结构,先把接口界说出来,中心的连线用wire型

360桌面截图20140714202033.jpg

  规划完端口之后咱们就来规划底层模块,先规划数据发生模块dataoutput

  这个部分主要是发生数据,可用一个分频电路完成每1s发送一次的数据,发生这16位数据的时分,需求16个时钟,每个时钟数据自加1,整体来说比较简单

360桌面截图20140714202504.jpg

  写完一个模块之后养成好习气,立刻把端口例化

360桌面截图20140714203301.jpg

  数据发生今后就要进入缓冲器FIFO,由于这段代码咱们是调用的,所以只需例化接口就好了,只需求将发生的fifo_ctrl_inst文件中例化好的代码复制张贴就好

360桌面截图20140714203514.jpg

  最终咱们要写数据发送部分

  之前现已讲过,数据发送部分还要包含两个子模块,一个是波特率匹配模块,一个是发送模块,已然又包含两个子模块,那么咱们还要构建一个框图

  依照之前的比方,当FIFO傍边有数据时empty就会拉低,咱们把它取反后送给发送模块,告知发送模块预备发送,这样,发送模块就会发生一个波特率计数器发动信号bps_start给波特率匹配模块,波特率匹配模块收到信号后立马开端匹配计数,并发生收集信号,将收集信号传给发送模块,发送模块依据收集信号,将数据一位一位发送出去。知道了这个原理之后,咱们构建起这样一个结构

360桌面截图20140714204221.jpg

  依据这个框图,咱们界说端口和线

360桌面截图20140714204322.jpg

  界说完端口之后,开端写发送模块,用边缘脉冲检测法检测发动信号tx_start信号的上升沿来发动发送部分,波特率装备模块详细代码在前面也文章中有给出,就不在阐明,写完之后例化端口,这两个模块作为数据发送模块的子模块,要在数据发送模块下例化

360桌面截图20140714205127.jpg

360桌面截图20140714204858.jpg

  这样一来,咱们整个规划就完结了,看上去很简单,可是从我自己实践的视点来说仍是有点应战的,包含中心呈现的各种问题,下面就来共享一下我在做这个规划时遇到的问题

  1.例化问题

  在例化端口时,要注意括号里边的才是本层模块的端口,也便是说在本层模块上面现已界说过的变量,括号外面的才是被调用模块的端口,也在基层模块的顶部被声明,我在写这段程序的时分将二者倒置了,导致连线不成功,最终是经过检查RTL视图知道了哪根线有问题才修正成功的

360桌面截图20140715130721.jpg

  2.同一个变量不能在多个always句子中被赋值

  咱们或许习气这么写

  always @ (posedge clk or negedge rst_n)

  if(!rst_n) num <= 1'b0;

  else num <= num+1'b1;

  那么,num的值在其他always句子中就不允许再被赋值或许清零,我在写的时分在其他always句子中将num 清零了,导致编译不成功

  3. 界说变量之前不要呈现该变量,即便后边又界说了

  例如,我先进性num的运算,之后再界说num,reg [3:0] num,这样写的话尽管编译没有过错,可是在调用modelsim仿真的时分它会呈现编译过错,所以为了标准,不要这样写

  4. 在边缘脉冲检测的时分,我习气于检测下降沿,而这里是检测tx_en 的上升沿,所以我在复位清零的时分过错的将两级寄存器赋值为0,实际上在检测上升沿时要对两级寄存器复位时置一,再把最终一级寄存器取反后与上一级相与。

360桌面截图20140715131444.jpg

  5. 在发送数据部分,由于遭到前次写接纳部分程序的影响,没有将开端位发送出去,由于在接纳部分,是不需求接纳开端位的,是从第一位开端,而在发送部分只要先发送开端位才干和上位机握手通讯,还有在发送完数据后要发送中止位,其他情况下都发送高电平来阻挠通讯的进行

360桌面截图20140715132338.jpg

  6.最终一个问题是最扎手的问题,我找了好大一半天也没发现,最终仍是依据源代码找出来的,不过我仍是不知道将这两条句子倒置了对程序有什么影响,只知道倒置后数据会一直在发送,不会像预设相同,每隔一秒发送一次,至今仍是搞不清楚,期望大神指点迷津

360桌面截图20140715132953.jpg

  总归我觉得语法上的过错到不至于太难,写的多了就不会出错了,关键是逻辑上的过错很荫蔽,也很难发现,能够经过RTL视图来检测连线上是否正确,还能够凭借仿真东西,可是我现在仿真东西用的还不熟,就比方这段代码,在板子上运行时正确的,可是我用软件仿真时输出端一直是高电平不变,也不知道为什么。反正要学的东西还许多,这点水平仍是远远不够,持续加油吧!

  今日就到此为止了,谢谢咱们!

树莓派文章专题:树莓派是什么?你不知道树莓派的常识和使用

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/ruanjian/117154.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部