该模块处理接收到的数据,并对数据拼接,解析成读写位,地址,写数据。对axi_master读回来的数据进行处理,分成4byte数据经过串口发送都上位机。
下面是该模块的顶层,包含两个子模块,接收处理模块、发送处理模块。
/***************************************************
* Module Name : byte_matching
* Engineer : Huangruigui
* Target Device :
* Tool versions :
* Create Date :
* Revision : v1.0
* Description :
**************************************************/
module byte_matching #(
parameter M_AXI_ADDR_WIDTH = 8'd32,
parameter M_AXI_DATA_WIDTH = 8'd32,
parameter RX_TOTAL_BYTE = 8'd9, // 串口接收到9byte数据开始工作
parameter TX_TOTAL_BYTE = 8'd4, // 串口发送4byte数据给上位机
parameter WRITE_BIT = 5'd1, // 设置最高位1为写操作
parameter READ_BIT = 5'd2
)(
input wire sys_clk,
input wire sys_rst_n,
// uart_rx
input wire rx_done,
input wire [7:0] rx_data,
// uart->axi_master
output wire uart_write,
output wire [M_AXI_ADDR_WIDTH-1:0] uart_write_addr,
output wire [M_AXI_DATA_WIDTH-1:0] uart_write_data,
output wire uart_read,
output wire [M_AXI_ADDR_WIDTH-1:0] uart_read_addr,
input wire uart_tx_en,
input wire [M_AXI_DATA_WIDTH-1:0] uart_tx_data,
// uart_tx
output wire tx_en,
output wire [7:0] tx_data,
input wire tx_done
);
rx_conduct #(
.M_AXI_ADDR_WIDTH ( M_AXI_ADDR_WIDTH),
.M_AXI_DATA_WIDTH ( M_AXI_DATA_WIDTH),
.RX_TOTAL_BYTE ( RX_TOTAL_BYTE ),
.WRITE_BIT ( WRITE_BIT ),
.READ_BIT ( READ_BIT )
)rx_conduct(
.sys_clk ( sys_clk ),
.sys_rst_n ( sys_rst_n ),
.rx_done ( rx_done ),
.rx_data ( rx_data ),
.uart_write ( uart_write ),
.uart_write_addr ( uart_write_addr ),
.uart_write_data ( uart_write_data ),
.uart_read ( uart_read ),
.uart_read_addr ( uart_read_addr )
);
tx_conduct #(
.M_AXI_ADDR_WIDTH ( M_AXI_ADDR_WIDTH),
.M_AXI_DATA_WIDTH ( M_AXI_DATA_WIDTH),
.TX_TOTAL_BYTE ( TX_TOTAL_BYTE )
)tx_conduct(
.sys_clk ( sys_clk ),
.sys_rst_n ( sys_rst_n ),
.uart_tx_en ( uart_tx_en ),
.uart_tx_data ( uart_tx_data ),
.tx_en ( tx_en ),
.tx_data ( tx_data ),
.tx_done ( tx_done )
);
endmodule
//***************文件结束**************************
先给大家看下仿真时序
从图中,当发送的第一个字节是01,发送完一串数据后,uart_write会产生一个高脉冲,同时地址,数据总线出现要控制的数据。当发送的第一个字节是02,发送完一串数据后,uart_read会产生一个高脉冲。
使能一次uart_tx_en,串口在发送完4次数据后,tx_en信号不在使能。
符合预期效果。
下面对接收模块进行编写
/***************************************************
* Module Name : rx_conduct
* Engineer : Huangruigui
* Target Device :
* Tool versions :
* Create Date :
* Revision : v1.0
* Description :
**************************************************/
module rx_conduct #(
parameter M_AXI_ADDR_WIDTH = 8'd32,
parameter M_AXI_DATA_WIDTH = 8'd32,
parameter RX_TOTAL_BYTE = 8'd9, // 串口接收到9byte数据开始工作
parameter WRITE_BIT = 5'd1, // 设置最高位1为写操作
parameter READ_BIT = 5'd2 // 设置最高位2为读操作
)(
input wire sys_clk,
input wire sys_rst_n,
// uart_rx
input wire rx_done,
input wire [7:0] rx_data,
// uart->axi_master
output reg uart_write,
output reg [M_AXI_ADDR_WIDTH-1:0] uart_write_addr,
output reg [M_AXI_DATA_WIDTH-1:0] uart_write_data,
output reg uart_read,
output reg [M_AXI_ADDR_WIDTH-1:0] uart_read_addr
);
// parameter define
localparam HIGH_RW_ADDR = RX_TOTAL_BYTE*8-1,
LOW_RW_ADDR = RX_TOTAL_BYTE*8-8;
localparam HIGH_ADDR = (RX_TOTAL_BYTE-1)*8-1,
LOW_ADDR = (RX_TOTAL_BYTE-5)*8;
localparam HIGH_DATA = (RX_TOTAL_BYTE-5)*8-1;
// reg define
reg [5:0] rx_done_cnt; // 数据接收完成计数器
reg [RX_TOTAL_BYTE*8-1:0] uart_rx_data; // 串口接收到一帧数据
// wire define
wire one_frame_done; // 一帧数据接收完成
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
uart_write_addr <= 0;
uart_read_addr <= 0;
uart_write_data <= 0;
end
else if(uart_write)
begin
uart_write_addr <= uart_rx_data[HIGH_ADDR:LOW_ADDR];
uart_write_data <= uart_rx_data[HIGH_DATA:0];
end
else if(uart_read)
uart_read_addr <= uart_rx_data[HIGH_ADDR:LOW_ADDR];
else
begin
uart_write_addr <= uart_write_addr;
uart_read_addr <= uart_read_addr;
uart_write_data <= uart_write_data;
end
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
rx_done_cnt <= 6'd0;
else if(rx_done_cnt >= RX_TOTAL_BYTE)
rx_done_cnt <= 6'd0;
else if(rx_done)
rx_done_cnt <= rx_done_cnt + 1'b1;
end
assign one_frame_done = (rx_done_cnt == RX_TOTAL_BYTE);
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
uart_rx_data <= {(RX_TOTAL_BYTE*8-1){1'b0}};
else if(rx_done)
uart_rx_data <= {uart_rx_data[(RX_TOTAL_BYTE-1)*8-1:0],rx_data};
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
uart_write <= 0;
uart_read <= 0;
end
else if(one_frame_done)
begin
if(uart_rx_data[HIGH_RW_ADDR:LOW_RW_ADDR] == WRITE_BIT)
uart_write <= 1;
if(uart_rx_data[HIGH_RW_ADDR:LOW_RW_ADDR] == READ_BIT)
uart_read <= 1;
end
else
begin
uart_write <= 0;
uart_read <= 0;
end
end
endmodule
//*************文件结束***************************
接着对发送模块进行处理
/***************************************************
* Module Name : tx_conduct
* Engineer : Huangruigui
* Target Device :
* Tool versions :
* Create Date :
* Revision : v1.0
* Description :
**************************************************/
/***************************************************
* Module Name : tx_conduct
* Engineer : Huangruigui
* Target Device :
* Tool versions :
* Create Date :
* Revision : v1.0
* Description :
**************************************************/
module tx_conduct #(
parameter M_AXI_ADDR_WIDTH = 8'd32,
parameter M_AXI_DATA_WIDTH = 8'd32,
parameter TX_TOTAL_BYTE = 8'd4 // 串口发送4byte数据给上位机
)(
input wire sys_clk,
input wire sys_rst_n,
input wire uart_tx_en,
input wire [M_AXI_DATA_WIDTH-1:0] uart_tx_data,
// uart_tx
output reg tx_en,
output reg [7:0] tx_data,
input wire tx_done
);
// parameter define
localparam HIGH_ADDR = TX_TOTAL_BYTE*8-1,
LOW_ADDR = (TX_TOTAL_BYTE-1)*8;
// reg define
reg [4:0] tx_en_cnt;
reg tx_done_t;
reg [M_AXI_DATA_WIDTH-1:0] uart_tx_data_t;
// wrie define
wire uart_tx_done;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
tx_en_cnt <= 5'd0;
else if(tx_en_cnt == TX_TOTAL_BYTE)
tx_en_cnt <= 5'd0;
else if(tx_done)
tx_en_cnt <= tx_en_cnt + 1'b1;
end
assign uart_tx_done = (tx_en_cnt == TX_TOTAL_BYTE);
always@(posedge sys_clk) // 对tx_done打一拍
tx_done_t <= tx_done;
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
begin
tx_en <= 0;
end
else if(uart_tx_en)
tx_en <= 1;
else if(tx_done_t)
begin
if(uart_tx_done)
tx_en <= 0;
else
tx_en <= 1;
end
else
tx_en <= 0;
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
uart_tx_data_t <= 0;
else if(uart_tx_en)
uart_tx_data_t <= uart_tx_data;
else if(uart_tx_done)
uart_tx_data_t <= 0;
else if(tx_done)
uart_tx_data_t <= uart_tx_data_t << 8;
end
/*
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
tx_data <= 0;
else
begin
case(tx_done_cnt)
0:tx_data <= uart_tx_data_t[31:24];
1:tx_data <= uart_tx_data_t[23:16];
2:tx_data <= uart_tx_data_t[15:8];
3:tx_data <= uart_tx_data_t[7:0];
default:tx_data <= tx_data;
endcase
end
end
*/
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
tx_data <= 0;
else if(tx_en)
tx_data <= uart_tx_data_t[HIGH_ADDR:LOW_ADDR];
end
endmodule
//********************文件结束***********************
在这个发送模块中,我用的是每次发送完,对要发送的数据左移8位,下一次发送高8位的数据,这样做的好处是可以拓展模块发送的数据而不用修改代码,如果是用case语句的话,会出现穷举现象,不能很好的适配。
仿真测试文件
/***************************************************
* Module Name : uart2axi_master_logic_tb
* Engineer : Huangruigui
* Target Device :
* Tool versions :
* Create Date :
* Revision : v1.0
* Description :
**************************************************/
`timescale 1ns/1ns
module uart2axi_master_logic_tb;
// parameter define
parameter M_AXI_ADDR_WIDTH = 8'd32;
parameter M_AXI_DATA_WIDTH = 8'd32;
parameter BAUD_SET = 16'd10416; // 波特率设置,默认9600
parameter RX_TOTAL_BYTE = 8'd9; // 串口接收到9byte数据开始工作
parameter TX_TOTAL_BYTE = 8'd4; // 串口发送4byte数据给上位机
parameter WRITE_BIT = 5'd1; // 设置最高位1为写操作
parameter READ_BIT = 5'd2;
reg sys_clk;
reg sys_rst_n;
reg tx_en;
reg [7:0] tx_data;
reg uart_tx_en ;
reg [M_AXI_DATA_WIDTH-1:0] uart_tx_data ;
wire tx_done ;
wire uart_tx ;
wire uart_write ;
wire [M_AXI_ADDR_WIDTH-1:0] uart_write_addr ;
wire [M_AXI_DATA_WIDTH-1:0] uart_write_data ;
wire uart_read ;
wire [M_AXI_ADDR_WIDTH-1:0] uart_read_addr ;
wire uart_rx ;
initial sys_clk = 1;
always #5 sys_clk = ~sys_clk;
initial begin
sys_rst_n = 0;
tx_en = 0;
tx_data = 0;
uart_tx_en = 0;
uart_tx_data = 0;
#201;
sys_rst_n = 1;
#20;
@(posedge sys_clk)
#100;
tx_data = 0; // 测试写操作
repeat(9)
begin
tx_en = 1;
tx_data = tx_data + 1;
#10;
tx_en = 0;
wait(tx_done);
#100;
end
#100;
if(uart_write_addr == 32'h02030405)
$display("test success");
else
$display("test fail");
#1000;
tx_data = 1; // 测试读操作
repeat(9)
begin
tx_en = 1;
tx_data = tx_data + 1;
#10;
tx_en = 0;
wait(tx_done);
#100;
end
if(uart_read_addr == 32'h03040506)
$display("test success");
else
$display("test fail");
#1000;
uart_tx_en = 1;
uart_tx_data = 32'h12345678;
#10;
uart_tx_en = 0;
wait(uart2axi_master_logic.byte_matching.tx_conduct.uart_tx_done);
#1000;
$stop;
end
uart_tx_logic #(
.BAUD_SET ( BAUD_SET )
)uart_tx_logic(
.sys_clk ( sys_clk ),
.sys_rst_n ( sys_rst_n ),
.tx_en ( tx_en ),
.tx_data ( tx_data ),
.tx_done ( tx_done ),
.uart_tx ( uart_tx )
);
uart2axi_master_logic #(
.M_AXI_ADDR_WIDTH ( M_AXI_ADDR_WIDTH ),
.M_AXI_DATA_WIDTH ( M_AXI_DATA_WIDTH ),
.BAUD_SET ( BAUD_SET ), // 波特率设置,默认9600
.RX_TOTAL_BYTE ( RX_TOTAL_BYTE ), // 串口接收到9byte数据开始工作
.TX_TOTAL_BYTE ( TX_TOTAL_BYTE ), // 串口发送4byte数据给上位机
.WRITE_BIT ( WRITE_BIT ), // 设置最高位1为写操作
.READ_BIT ( READ_BIT )
)uart2axi_master_logic(
.sys_clk ( sys_clk ),
.sys_rst_n ( sys_rst_n ),
.uart_write ( uart_write ),
.uart_write_addr ( uart_write_addr ),
.uart_write_data ( uart_write_data ),
.uart_read ( uart_read ),
.uart_read_addr ( uart_read_addr ),
.uart_tx_en ( uart_tx_en ),
.uart_tx_data ( uart_tx_data ),
.uart_rx ( uart_tx ),
.uart_tx ( uart_rx )
);
endmodule
//*****************文件结束*************************
今晚终于把这个模块搞定啦,各位小伙伴可以放心食用了,明天把axi_master接口搞好,整个工程就算7788了。
//分割线*
在写主机接口的时候,发现一个问题,我串口读写地址有了,但是写数据呢?原来是疏忽大意了,忘记把写数据传过来,后面我写好了,也验证好了。大家这次可以放心使用啦嘿嘿。有什么错误或者有不懂的欢迎大家评论区留言哈