自从08年开始学FPGA以来的一年,我都是从事VHDL的,当时写了uart第一版本,现在看来戳的不行了,而且有问题恶心,哇哇吐。。。
因为时代的潮流09年我也开始了Verilog,后来有学了SOCP,NIOS II,一直走。。。
10年暑假,因为准备比赛,再次写了Verilog 版本的uart,双向fifo协议收发,功能上可以,没多大问题。。。
11年寒假,因为家里没有宽带,饥渴难耐,我TMD受不了自己那么空了。。。觉得自己一直来是自由发挥的,代码规范都不咋地,于是拿出《华为verilog规范》,又拿出以前的代码,怎么看都不顺眼,于是,创作了verilog 版的uart 第三版本!!!
我用fifo测试收发文件,上万数据没出现过错误,而且比较稳定,比起网上那些随便搞搞的东西,左看右看都感觉自己的略胜一筹。。。
当然我知道完美是没有极限的,所以我拿出三个文件,希望大家能够提出宝贵意见,看看还有什么可以优化的!!!!!!!!!!!!!
首先我分了三个module:
(1)clk_generator.v 负责接收个发送的时钟,修改bps就在此处,没有用常规的方法分频,因为觉得从完美的角度考虑,这有损是新片的最佳发挥,当然也会不稳定,再次我采纳了DDS中0~2^N 步进寻址的思维,设计了是能时钟
(2)uart_receiver.v 负责uart的数据接收,相对于数据的发送稍微简单一点,因为此处为了达到数据的最稳定,不能一读取到有数据就采样,我设计在中间时刻采样,前后保持,用了16*bps的clk来工作
(3)uart_transfer.v 扶着uart数据的发送,clk = bps,这是比较简单的一个模块,用脚趾头想想都能实现
下面我贴出这几个代码,如果大家有时间希望能给我挑挑毛病,尤其是时钟模块,虽然我觉得直接偶数分频方法出来的不准确(为了数据的准确),但我的也不是很爽:
/**************************************************************
* File Name : clk_generator.v
* Author : Crazy Bingo
* Version : Quartus II 9.1
* CreateDate : 2011/01/31
* Description : To generator different bps
**************************************************************/
/***********************************
fc = 50*10^6
fo = fc*N/(2^32)
N = fo*(2^32)/fc
= fo*(2^32)/(50*10^6)
************************************/
module clk_generator
(
input clk,
input rst_n,
output clk_bps,
output clk_smp
);
//------------------------------------------
/************clk_smp = 16*clk_bps************
Freq_Word1 <= 32'd25770; Freq_Word1 <= 32'd412317; //300 bps
Freq_Word1 <= 32'd51540; Freq_Word2 <= 32'd824634; //600 bps
Freq_Word1 <= 32'd103079; Freq_Word2 <= 32'd1649267; //1200 bps
Freq_Word1 <= 32'd206158; Freq_Word2 <= 32'd3298535; //2400 bps
Freq_Word1 <= 32'd412317; Freq_Word2 <= 32'd6597070; //4800 bps
Freq_Word1 <= 32'd824634; Freq_Word2 <= 32'd13194140; //9600 bps
Freq_Word1 <= 32'd1649267; Freq_Word2 <= 32'd26388279; //19200 bps
Freq_Word1 <= 32'd3298535; Freq_Word2 <= 32'd52776558; //38400 bps
Freq_Word1 <= 32'd3693672; Freq_Word2 <= 32'd59098750; //43000 bps
Freq_Word1 <= 32'd4810363; Freq_Word2 <= 32'd76965814; //56000 bps
Freq_Word1 <= 32'd4947802; Freq_Word2 <= 32'd79164837; //57600 bps
Freq_Word1 <= 32'd9895605; Freq_Word2 <= 32'd158329674; //115200bps
Freq_Word1 <= 32'd10995116; Freq_Word2 <= 32'd175921860; //128000bps
Freq_Word1 <= 32'd21990233; Freq_Word2 <= 32'd351843721; //256000bps
*****************************************************/
//only want to generate beautiful clk for bsp and sample
reg [31:0] bps_cnt1;
reg [31:0] bps_cnt2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
bps_cnt1 <= 0;
bps_cnt2 <= 0;
end
else
begin
bps_cnt1 <= bps_cnt1+32'd10995116; //Bps=128000bps
bps_cnt2 <= bps_cnt2+32'd175921860; //Bps=128000bps*16
end
end
//------------------------------------------
//clk_bps sync bps generater
reg clk_bps_r0,clk_bps_r1,clk_bps_r2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_bps_r0 <= 0;
clk_bps_r1 <= 0;
clk_bps_r2 <= 0;
end
else
begin
if(bps_cnt1 < 32'h7FFF_FFFF)
clk_bps_r0 <= 0;
else
clk_bps_r0 <= 1;
clk_bps_r1 <= clk_bps_r0;
clk_bps_r2 <= clk_bps_r1;
end
end
assign clk_bps = ~clk_bps_r2 & clk_bps_r1;
//------------------------------------------
//clk_smp sync receive bps generator
reg clk_smp_r0,clk_smp_r1,clk_smp_r2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_smp_r0 <= 0;
clk_smp_r1 <= 0;
clk_smp_r2 <= 0;
end
else
begin
if(bps_cnt2 < 32'h7FFF_FFFF)
clk_smp_r0 <= 0;
else
clk_smp_r0 <= 1;
clk_smp_r1 <= clk_smp_r0;
clk_smp_r2 <= clk_smp_r1;
end
end
assign clk_smp = ~clk_smp_r2 & clk_smp_r1;
endmodule
/**************************************************************
* File Name : uart_receiver.v
* Author : Crazy Bingo
* Version : Quartus II 9.1
* CreateDate : 2011/01/31
* Description : rxd data Receiver
**************************************************************/
module uart_receiver
(
input clk,
input clk_smp, //clk_smp=16*clk_bps
input rst_n,
input rxd,
output rxd_flag, //the flag of receive over
output reg [7:0] rxd_data
);
//---------------------------------
//sync the data: rxd_sync
reg rxd_sync_r0,rxd_sync_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rxd_sync_r0 <= 1;
rxd_sync_r1 <= 1;
end
else if(clk_smp == 1)
begin
rxd_sync_r0 <= rxd;
rxd_sync_r1 <= rxd_sync_r0;
end
end
wire rxd_sync = rxd_sync_r1;
//---------------------------------
//sample data from pc to cpu
parameter R_IDLE = 1'b0; //>=7 clk_smp : receive flag
parameter R_SAMPLE = 1'b1; //sample data programmer
reg rxd_state;
reg [3:0] smp_cnt; //sample cycle counter
reg [2:0] rxd_cnt; //the lenth of data
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
smp_cnt <= 0;
rxd_cnt <= 0;
rxd_data <= 0;
rxd_state <= R_IDLE;
end
else if(clk_smp == 1)
begin
case(rxd_state)
R_IDLE:
begin
rxd_cnt <= 0;
if(rxd_sync == 1'b0)
begin
smp_cnt <= smp_cnt + 1'b1;
if(smp_cnt == 4'd7) //8 clk_smp enable
rxd_state <= R_SAMPLE;
end
else
smp_cnt <= 0;
end
R_SAMPLE:
begin
smp_cnt <= smp_cnt +1'b1;
if(smp_cnt == 4'd7)
begin
rxd_cnt <= rxd_cnt +1'b1;
if(rxd_cnt == 4'd7)
rxd_state <= R_IDLE;
case(rxd_cnt)
3'd0: rxd_data[0] <= rxd_sync;
3'd1: rxd_data[1] <= rxd_sync;
3'd2: rxd_data[2] <= rxd_sync;
3'd3: rxd_data[3] <= rxd_sync;
3'd4: rxd_data[4] <= rxd_sync;
3'd5: rxd_data[5] <= rxd_sync;
3'd6: rxd_data[6] <= rxd_sync;
3'd7: rxd_data[7] <= rxd_sync;
endcase
end
end
endcase
end
end
wire rxd_flag_r = (rxd_cnt == 4'd7) ? 1'b1 : 1'b0;
//---------------------------------
//the signal flag of rxd receive over
reg rxd_flag_r0,rxd_flag_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rxd_flag_r0 <= 0;
rxd_flag_r1 <= 0;
end
else
begin
rxd_flag_r0 <= rxd_flag_r;
rxd_flag_r1 <= rxd_flag_r0;
end
end
assign rxd_flag = ~rxd_flag_r1 & rxd_flag_r0;
endmodule
/**************************************************************
* File Name : uart_transfer.v
* Author : Crazy Bingo
* Version : Quartus II 9.1 SP2
* CreateDate : 2011/01/31
* Description : txd data Transfer
**************************************************************/
module uart_transfer
(
input clk,
input clk_bps,
input rst_n,
input txd_en, //txd data mark
input [7:0] txd_data,
output txd_flag, //txd data over mark
output reg txd
);
//-------------------------------------
//transfer data from cpu to pc
parameter T_IDLE = 1'b0; //test the flag to transfer data
parameter T_SEND = 1'b1; //uart transfer data
reg txd_state;
reg [3:0] txd_cnt; //txd data counter
reg txd_flag_r;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
txd_state <= T_IDLE;
txd_flag_r <= 0;
txd <= 1'b1;
end
else
begin
case(txd_state)
T_IDLE:
begin
txd <= 1;
txd_flag_r <= 0;
if(txd_en == 1)
txd_state <= T_SEND;
else
txd_state <= T_IDLE;
end
T_SEND:
begin
if(clk_bps == 1)
begin
if(txd_cnt < 4'd9)
txd_cnt <= txd_cnt + 1'b1;
else
begin
txd_cnt <= 0;
txd_state <= T_IDLE;
txd_flag_r <= 1;
end
case(txd_cnt)
4'd0: txd <= 0;
4'd1: txd <= txd_data[0];
4'd2: txd <= txd_data[1];
4'd3: txd <= txd_data[2];
4'd4: txd <= txd_data[3];
4'd5: txd <= txd_data[4];
4'd6: txd <= txd_data[5];
4'd7: txd <= txd_data[6];
4'd8: txd <= txd_data[7];
4'd9: txd <= 1;
endcase
end
end
endcase
end
end
//-------------------------------------
//Capture the falling of data transfer over
reg txd_flag_r0,txd_flag_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
txd_flag_r0 <= 0;
txd_flag_r1 <= 0;
end
else
begin
txd_flag_r0 <= txd_flag_r;
txd_flag_r1 <= txd_flag_r0;
end
end
assign txd_flag = txd_flag_r1 & ~txd_flag_r0;
endmodule
点击此处下载 ourdev_618188VEGAZ0.rar(文件大小:3K) (原文件名:uart_io_design.rar)
文件在此处上传,谁要用我没意见,反正XXX
但给我挑毛病,因为我看大部分人写的uart都不是很爽,所以 ,谢谢了
|