串口转axi_lite主机

Hello大家好,我是小黄。
最近工作上师傅要我自己写一个uart转axi_master的模块。一开始想xilinx应该有现成的ip核可以调用,没想到查了一下只有axi_uart做从机的ip。无奈之下,只能自己写一个。现在该模块已经写好了,接下来我将给大家展示一下我的工程。在这篇博客最后面我会将本工程的源码分享给大家。
首先给大家看下我对这个模块的划分。
模块的端口有串口输入输出,还有一个axi_master接口。相关rtl代码如下:

/***************************************************
*	Module Name		:	uart2axi_master	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
module	uart2axi_master #(
	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				//	设置最高位2为读操作
)(	
	//	Global Clock Signal
	input	wire							m_axi_aclk,			//	模块基准时钟,100MHz
	input	wire							m_axi_aresetn,		//	模块复位信号,低电平有效
	
	//	Master Write Addr Interface
	output	wire 							m_axi_awvalid,
	input	wire							m_axi_awready,
	output	wire [M_AXI_ADDR_WIDTH-1:0]		m_axi_awaddr,	
	
	//	Master Write Date Interface
	output	wire 							m_axi_wvalid,
	input	wire							m_axi_wready,
	output	wire [M_AXI_DATA_WIDTH-1:0]		m_axi_wdata,
	output	wire [M_AXI_DATA_WIDTH/8-1:0]	m_axi_wstrb,
	
	//	Master Read Addr Interface
	output	wire							m_axi_arvalid,
	input	wire 							m_axi_arready,
	output	wire [M_AXI_ADDR_WIDTH-1:0]		m_axi_araddr,
	
	//	Master Read Date Interface
	output	wire							m_axi_rready,
	input	wire							m_axi_rvalid,
	input	wire [M_AXI_DATA_WIDTH-1:0]		m_axi_rdata,
	input	wire [1:0]						m_axi_rresp,
	
	//	Master Response Interface
	output	wire							m_axi_bready,
	input	wire							m_axi_bvalid,
	input	wire [1:0]						m_axi_bresp,

	//	UART Interface
	input	wire							UART_RX,
	output	wire							UART_TX	
);

	//	wire define
	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_tx_en;
	wire	[M_AXI_DATA_WIDTH-1:0]	uart_tx_data;

	uart2axi_master_intf #(
		.M_AXI_ADDR_WIDTH	(	M_AXI_ADDR_WIDTH),
		.M_AXI_DATA_WIDTH	(	M_AXI_DATA_WIDTH),
		.RX_TOTAL_BYTE		(	RX_TOTAL_BYTE	),
		.TX_TOTAL_BYTE		(	TX_TOTAL_BYTE	)
	)uart2axi_master_intf(
		.m_axi_aclk			(	m_axi_aclk		),
		.m_axi_aresetn		(	m_axi_aresetn	),
		.m_axi_awvalid		(	m_axi_awvalid	),
		.m_axi_awready		(	m_axi_awready	),
		.m_axi_awaddr		(	m_axi_awaddr	),
		.m_axi_wvalid		(	m_axi_wvalid	),
		.m_axi_wready		(	m_axi_wready	),
		.m_axi_wdata		(	m_axi_wdata		),
		.m_axi_wstrb		(	m_axi_wstrb		),
		.m_axi_arvalid		(	m_axi_arvalid	),
        .m_axi_arready		(	m_axi_arready	),
        .m_axi_araddr		(	m_axi_araddr	),
		.m_axi_rready		(	m_axi_rready	),
        .m_axi_rvalid		(	m_axi_rvalid	),
        .m_axi_rdata		(	m_axi_rdata		),
		.m_axi_rresp		(	m_axi_rresp		),
		.m_axi_bready		(	m_axi_bready	),
		.m_axi_bvalid		(	m_axi_bvalid	),
		.m_axi_bresp		(	m_axi_bresp		),	
		
		.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    )
	);
	
	uart2axi_master_logic #(
		.M_AXI_ADDR_WIDTH	(	M_AXI_ADDR_WIDTH),
		.M_AXI_DATA_WIDTH	(	M_AXI_DATA_WIDTH),
		.BAUD_SET			(	BAUD_SET		),
		.RX_TOTAL_BYTE		(	RX_TOTAL_BYTE	),
		.TX_TOTAL_BYTE		(	TX_TOTAL_BYTE	),
		.WRITE_BIT			(	WRITE_BIT		),
		.READ_BIT			(	READ_BIT		)
	)uart2axi_master_logic(
		.sys_clk			(	m_axi_aclk		),
		.sys_rst_n			(	m_axi_aresetn	),
		.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_RX			),
		.uart_tx			(	UART_TX			)
	);

endmodule
//*****************文件结束***************************

接下来首先设计的是串口发送接收模块,这里我用1位起始位,8位数据位,1位停止位,波特率9600。模块基准时钟100MHz,用户使用时,可以根据模块的BAUD_SET参数修改波特率,计算时用100_000_000/波特率,将得到的数值取整赋值给BAUD_SET就可以了

module	uart_rx_logic #(
	parameter	BAUD_SET	= 16'd10416
)(
	input	wire			sys_clk,
	input	wire			sys_rst_n,
	output	reg [7:0]		rx_data,
	output	reg				rx_done,
	output	reg				uart_rx
);

这个是串口接收模块的端口,用来接收上位机发送的数据。为了提高该模块的抗干扰能力,首先将uart_rx信号进行消除亚稳态,在进行寄存得到下降沿,以此作为模块开始工作标志信号。接着将每一位数据分成16次采样,采中间6位做平均计算,若第二位数据是否为1,即累加的数大于等于4, 就认为接收到的是1,否则是0。

case(bps_clk_cnt)
	0:begin
			START_BIT <= 3'd0;
			r_rx_data[0] <= 3'd0;
			r_rx_data[1] <= 3'd0;
			r_rx_data[2] <= 3'd0;
			r_rx_data[3] <= 3'd0;
			r_rx_data[4] <= 3'd0;
			r_rx_data[5] <= 3'd0;
			r_rx_data[6] <= 3'd0;
			r_rx_data[7] <= 3'd0;
			STOP_BIT <= 3'd0;			
		end
	6,7,8,9,10,11:			START_BIT <= START_BIT + uart_rx_r[1];
	22,23,24,25,26,27:		r_rx_data[0] <= r_rx_data[0] + uart_rx_r[1];
	38,39,40,41,42,43:		r_rx_data[1] <= r_rx_data[1] + uart_rx_r[1];
	54,55,56,57,58,59:		r_rx_data[2] <= r_rx_data[2] + uart_rx_r[1];
	70,71,72,73,74,75:		r_rx_data[3] <= r_rx_data[3] + uart_rx_r[1];
	86,87,88,89,90,91:		r_rx_data[4] <= r_rx_data[4] + uart_rx_r[1];
	102,103,104,105,106,107:r_rx_data[5] <= r_rx_data[5] + uart_rx_r[1];
	118,119,120,121,122,123:r_rx_data[6] <= r_rx_data[6] + uart_rx_r[1];
	134,135,136,137,138,139:r_rx_data[7] <= r_rx_data[7] + uart_rx_r[1];
	150,151,152,153,154,155:STOP_BIT <= STOP_BIT + uart_rx_r[1];
	default:
	begin
		START_BIT <= START_BIT;
		r_rx_data[0] <= r_rx_data[0];
		r_rx_data[1] <= r_rx_data[1];
		r_rx_data[2] <= r_rx_data[2];
		r_rx_data[3] <= r_rx_data[3];
		r_rx_data[4] <= r_rx_data[4];
		r_rx_data[5] <= r_rx_data[5];
		r_rx_data[6] <= r_rx_data[6];
		r_rx_data[7] <= r_rx_data[7];
		STOP_BIT <= STOP_BIT;						
	end
endcase

//串口接收程序结束
接着是串口发送程序。
串口发送相对串口接收简单,这里我直接贴出相关代码。

always@(posedge	sys_clk or negedge sys_rst_n)
begin
	if(!sys_rst_n)
		uart_tx <= 1;
	else 
	begin
		case(bps_clk_cnt)
			0: uart_tx <= 1'b1;
			1: uart_tx <= START_BIT;
			2: uart_tx <= tx_data_t[0];
			3: uart_tx <= tx_data_t[1];
			4: uart_tx <= tx_data_t[2];
			5: uart_tx <= tx_data_t[3];
			6: uart_tx <= tx_data_t[4];
			7: uart_tx <= tx_data_t[5];
			8: uart_tx <= tx_data_t[6];
			9: uart_tx <= tx_data_t[7];
			10:uart_tx <= STOP_BIT;
			default:uart_tx <= 1'b1;
		endcase
	end 
end 

//未完待续
串口发送接收程序源码
完成了串口发送接收程序的测试,接下来对接收到的数据处理模块的编写。
数据接收、发送处理模块
因为是串口转axi_master,所以串口需要发送读写位,地址位,数据位,其中地址和数据是32位的,因此串口总共需要发送9byte数据才可以解析。这里为了方便,我将写入的数据返回给上位机作为应答,没有用CRC校验(因为我不会。。。)
串口发送数据格式
因为这个模块比较复杂一点,我用另一篇博客写好了代码给大家使用
串口发送接收模块顶层
到这里就很快啦,明天把axi_master接口搞定。
好了,忙前忙后,把整个模块搞定了。
先给大家看下波形图。
在这里插入图片描述
从图中可以看出,我首先是发起总线写命令,当传输完一帧数据后,地址、数据总线出现了目标数据,符合预期。接着发起读命令,发送读命令和读地址,发送完成后,可以看出读地址总线出现了预期的数据,接着我模拟从机,产生一个读有效脉冲和读数据,主机接收到信号后,产生串口发送信号,串口发送四次后,仿真停止。这一切看起来都很正常,实际……应该也是正常的。
老规矩,我在另一篇博客将源码分享给大家,希望大家使用后有什么不懂的地方或者模块有bug的地方能够告知一下我哈。
串口转axi主机总线接口程序源码
整个工程到这里就差不多结束啦。

  • 11
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值