在FPGA设计中,线性序列机和状态机思想是十分重要的思想方法,用于实现各种时序要求。这次的内容是实现用FPGA,时钟周期为20ns,每间隔5000ns发送一个字节的数据,数据不从外部接入,而是内部给定。本着模块化设计原则,整体结构如下:

  • 子模块为ctrl和data_send,顶层为data_send_top。

  • data_send模块在en信号的同步下实现数据的发送,每50个时钟周期发送一个bit,发送完成后拉高一个时钟周期的tx_done。

  • ctrl模块根据tx_done信号来控制数据发送的间隔,同时指定要发送的数据data。

一、data_send设计与仿真

  1. 逻辑设计

对于data_send要求50个时钟周期发一个bit,采用线性序列机实现,实现一个最大值为50个时钟周期的计数器1,再实现一个对计数器1的溢出次数进行计数的计数器2,是个模8计数器(但为了生成tx_done以及不在0时刻发送data数据,这里实现的是模9计数器),后面的逻辑根据计数器2的计数值按时将数据放在数据线上即可。这就是线性序列机的思想,在实际应用中,往往要生成一组信号来满足某些控制器的时序,可以找到这些信号的变化最小时间单位,类似得实现计数器1,再实现计数器2,最后根据时序灵活安排数据发送得时刻即可。

module data_send
(input       wire                clk     ,input       wire                rst_n   ,input       wire                en      ,input       wire    [7:0]       data    ,output      reg                 tx      ,output      wire                tx_done
);reg     [7:0]   cnt;//计数器1
reg     [4:0]   cnt_add; //计数器2always@(posedge clk or negedge rst_n)if(!rst_n)cnt <= 8'd0;else if(en)if(cnt == 8'd49)cnt <= 8'd0;elsecnt <= cnt + 1'b1;elsecnt <= 8'd0;always@(posedge clk or negedge rst_n)if(!rst_n)cnt_add <= 5'd0;else if(en) beginif(cnt_add == 5'd9)cnt_add <= 5'd0;else if(cnt == 8'd49)cnt_add <= cnt_add + 1'b1;endelsecnt_add <= 5'd0;//序列机实现
always@(posedge clk or negedge rst_n)if(!rst_n)tx <= 1'b0;elsecase(cnt_add)5'd1 : tx <= data[0];5'd2 : tx <= data[1];5'd3 : tx <= data[2];5'd4 : tx <= data[3];5'd5 : tx <= data[4];5'd6 : tx <= data[5];5'd7 : tx <= data[6];5'd8 : tx <= data[7];default : tx <= 1'b0;endcase//tx_done信号生成
always@(posedge clk or negedge rst_n)if(!rst_n)tx_done <= 1'b0;else if(cnt_add == 5'd9)tx_done <= 1'b1;elsetx_done <= 1'b0;endmodule
  1. tb

`timescale 1ns/1ns
`define clk_period 20
module data_send_tb;//============================<端口>==============================
reg clk;
reg rst_n;
reg en;
reg [7:0] data;wire    tx;
wire    tx_done;
//================================================================
//==                         模块例化
//================================================================
data_send data_send_inst0
(.clk     (clk),.rst_n   (rst_n),.en      (en),.data    (data),.tx      (tx),.tx_done (tx_done)
);//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;//================================================================
//==                       设计输入信号
//================================================================
initial beginrst_n = 0;en = 0;data = 8'h00;#201;rst_n = 1;#201;data = 8'h23;en = 1;#20000;en = 0;#5000;data = 8'h56;en = 1;#20000;en = 0;#5000;$stop;endendmodule
  1. modelsim仿真

可以看到,发送完第八个字节后,拉高了一个时钟周期的tx_done,测量一个bit发送时间为50*20=1000ns,符合设计要求。

二、ctrl模块设计与仿真

  1. 逻辑设计

在这个模块中,由于tx_done信号需要data_send模块产生,而data_send需要ctrl的en信号来启动发送,故采用状态机来实现ctrl模块。

  • S0中en = 1,让data_send模块工作。

  • S1中等待tx_done信号有效。

  • S2中等待5000ns(250个时钟周期)。

module ctrl
(input       wire            clk     ,input       wire            rst_n   ,input       wire            tx_done ,output      reg             en      ,output      reg    [7:0]    data
);reg [11:0]  cnt; //50us计数器
reg         cnt_en;
reg         dly_done;
reg [1:0]   state;
localparam  S0 = 3'd0;
localparam  S1 = 3'd1;
localparam  S2 = 3'd2;always@(posedge clk or negedge rst_n)if(!rst_n)beginstate <= S0;cnt_en <= 1'b0;en <= 1'b0;data <= 8'd0;endelse begincase(state)S0 : beginen = 1'b1 ;data <= 8'h12;state <= S1;endS1 : beginif(tx_done) beginstate <= S2;cnt_en <= 1;en <= 0;endelse beginen <= 1;cnt_en <= 0;state <= S1;endendS2 : beginif(!dly_done) beginstate <= S2;cnt_en <= 1;endelse begincnt_en = 0;state <= S0;endenddefault : beginstate <= S0;cnt_en <= 0;en = 0;endendcaseendalways@(posedge clk or negedge rst_n)if(!rst_n)cnt <= 12'd0;else if(cnt_en)beginif(cnt == 12'd249)cnt <= 12'd0;elsecnt <= cnt + 1'b1;endelsecnt <= 12'd0;always@(posedge clk or negedge rst_n)if(!rst_n)dly_done <= 1'b0;else if(cnt == 12'd249)dly_done <= 1'b1;elsedly_done <= 1'b0;endmodule
  1. tb

`timescale 1ns/1ns
`define clk_period 20
module ctrl_tb;//============================<端口>==============================
reg clk;
reg rst_n;
reg tx_done;wire    en;
wire    [7:0] data;
//================================================================
//==                         模块例化
//================================================================
ctrl ctrl_inst0
(.clk     (clk),.rst_n   (rst_n),.tx_done (tx_done),.en      (en),.data    (data)
);//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;//================================================================
//==                       设计输入信号
//================================================================
initial beginrst_n = 0;tx_done = 0;#201;rst_n = 1;#201;tx_done = 1;#20;tx_done = 0;#8000;tx_done = 1;#20;tx_done = 0;#8000;$stop;endendmodule
  1. modelsim仿真

可以看到,状态机可以正常工作。

三、ctrl模块设计与仿真

按照架构图在data_send_top例化即可。

  1. 逻辑设计

module data_send_top
(input       wire        clk         ,input       wire        rst_n       ,output      wire        tx
);wire    en;
wire    [7:0] data;
wire    tx_done;data_send data_send_inst0
(.clk     (clk),.rst_n   (rst_n),.en      (en),.data    (data),.tx      (tx),.tx_done (tx_done)
);ctrl ctrl_inst0
(.clk     (clk),.rst_n   (rst_n),.tx_done (tx_done),.en      (en),.data    (data)
);endmodule
  1. tb

`timescale 1ns/1ns
`define clk_period 20
module data_send_top_tb;//============================<端口>==============================
reg clk;
reg rst_n;wire    tx;
//================================================================
//==                         模块例化
//================================================================
data_send_top data_send_top_inst
(.clk         (clk),.rst_n       (rst_n),.tx          (tx)
);//================================================================
//==                         时钟信号
//================================================================
initial clk = 1'b1;
always #(`clk_period/2) clk = ~clk;//================================================================
//==                       设计输入信号
//================================================================
initial beginrst_n = 0;#201;rst_n = 1;#200000;endendmodule
  1. modelsim仿真

仔细观察,发现整体是可以正常工作的。

  1. 优化

在观察中,发现在ctrl中,从tx_done信号为高到发出en = 1信号,时间并不是严格的5000ns,而是多了3个时钟周期。

观察到dly_done信号是用时序逻辑实现会延迟一个时钟,但该信号的意义因该是计数到时立即有效,故用组合逻辑实现。结果优化了20ns。

但还是存在优化空间。

四、总结

  • 了解了线性序列机和状态机的思想和基本实现方法。

  • 写子模块时必须要仿真验证通过才能进行下一步工作,否则之后的步骤中的错误将很难排查。

  • 写代码之前最好将思路想好,模块分好,照图施工。

关于FPGA设计中的线性序列机和状态机相关推荐

  1. 小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计

    小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计 目标:学会使用线性序列机的思想设计常见的有串行执行特征的时序逻辑 实验现象:在QuartusⅡ软件中,使用ISSP工具,输入希望输出的电 ...

  2. 线性序列机与串口接口DAC驱动设计与验证

    线性序列机与串口接口DAC驱动设计与验证 TLV5618 型 DAC 内部工作原理 TLV5618 是一个基于电压输出型的双通道 12 位单电源数模转换器,其由串行接口.一个速度和电源控制器. 电阻网 ...

  3. 线性序列机与串行接口ADC驱动设计与验证

    线性序列机与串行接口ADC驱动设计与验证 ADC128S022 型 ADC 内部工作原理 在 AC620 开发板上使用的模数转换器为逐次逼近型的低功耗芯片 ADC128S022,其具有 8 通道以及 ...

  4. FPGA设计中,产生LFSR伪随机数

    今天给大侠带来在FPGA设计中,产生LFSR伪随机数,话不多说,上货. 一.概述 通过一定的算法对事先选定的随机种子(seed)做一定的运算可以得到一组人工生成的周期序列,在这组序列中以相同的概率选取 ...

  5. 基于线性序列机的SPI协议读写winbond公司flash芯片25Q16

    基于小梅哥所提的线性序列机思想设计读写该芯片的SPI协议,线性序列机简单来说就是用一个计数器对时钟计数,对于每一个计数值,按照时序要求对信号做出相应操作.简单写了一下 Read Manufacture ...

  6. 在FPGA设计中怎么应用ChatGPT?

    在FPGA设计中怎么应用ChatGPT? 科技即生产力,最近,OpenAI 发布了 ChatGPT,在各大论坛和许多网站上受到了广泛关注,ChatGPT是由 OpenAI 提出的大型预训练语言模型,使 ...

  7. (130)FPGA面试题-FPGA设计中波特率和比特率的区别

    1.1 FPGA面试题-FPGA设计中波特率和比特率的区别 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-FPGA设计中波特率和比特率的区别: 5)结束 ...

  8. (139)FPGA面试题-FPGA设计中的速度和面积互换原则

    1.1 FPGA面试题-FPGA设计中的速度和面积互换原则 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-FPGA设计中的速度和面积互换原则: 5)结束 ...

  9. 防止FPGA设计中综合后的信号被优化

    这不是一个新话题了,写这个也是当作自己的一个小小的笔记吧!觉得挺有用的. 一般在做前仿真(即功能仿真)时,不会考虑信号被优化的问题.最近做一个关于运算的小程序,前仿真的数据没有问题,但是实际出来的数据 ...

最新文章

  1. 海康威视 | AI算法实习生招聘(3D检测/分割/多模态融合)
  2. 程序设计语言常见面试题
  3. php删除文件指令,php – Symfony cache:清除命令更改文件夹所有者
  4. 如何学习WPF技术?
  5. HDU 6428 Problem C. Calculate(积性函数)
  6. mysql 转换编码方式
  7. 顺序表Sqlist.cpp
  8. substr php,PHP substr() 函数
  9. 搞了多年管理软件,总算说清楚了什么是好软件
  10. vba 正则表达式_VBA中正则表达式与数组结合的应用案例!
  11. Mysql 优化(学习笔记二十)
  12. Vue中插槽slot的使用
  13. 机器人“病患”会流血会休克,魔鬼训练从斯坦福医院开始 |准医生的噩梦
  14. ADO.NET实体框架Entity Framework模型-基于元数据解析
  15. java 解析ttf字体文件_stb_truetype解析ttf字体并将其保存到图片中
  16. python实现气象数据分析实验报告_Python 气象数据分析
  17. Unity WebView 插件 | 浏览器插件3D WebView 专栏介绍
  18. linux patch 给文件打补丁,Linux补丁工具patch生成使用补丁用法示例
  19. 摄氏温度转化为华氏温度代码
  20. struck.unpack

热门文章

  1. 2022-2028全球临床前医疗设备检测服务行业调研及趋势分析报告
  2. STC-Seg:首个超越PointTrack的弱监督视频MOTS算法
  3. 服务器显示 未安装失败,生成失败!原因:可能服务器未安装Adobe Arcobat软件!...
  4. Java实现为手机号码或身份证号码打星号
  5. 如何在iPhone上使用Chrome扫描QR码
  6. 一加8t和小米10pro哪个好?对比有什么区别?
  7. 北航计算机科学与技术专业河北投档线,北京航空航天大学2020录取分数线(附2017-2020年分数线)...
  8. 曼昆宏观经济学第8版课后答案
  9. stream relocation truncated to fit
  10. 【C++】输入输出流(IO流)