文章目录
- AXI-uartlite IP核简介
- IP核用户接口
- 端口描述
- AXI-Lite接口基本使用
- 发送地址或数据
- 读数据
- AXI-uartlite IP核寄存器介绍
- 简单的AXI-uartlite控制模块
本文属于使用经验总结,未尽之处不必纠结
AXI-uartlite IP核简介
AXI-uartlite 是Xilinx提供的驱动串口的IP核,用AXI-Lite总线接口和用户进行交互,速度根据不同的芯片调整,总的来说使用比较简单,收发数据也比自己写的串口驱动程序要稳定。本文只介绍基本应用,不涉及中断等操作。
IP核用户接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | debug_uart your_instance_name ( .s_axi_aclk(s_axi_aclk), // input wire s_axi_aclk .s_axi_aresetn(s_axi_aresetn), // input wire s_axi_aresetn .interrupt(interrupt), // output wire interrupt //写地址端口 .s_axi_awaddr(s_axi_awaddr), // input wire [3 : 0] s_axi_awaddr .s_axi_awvalid(s_axi_awvalid), // input wire s_axi_awvalid .s_axi_awready(s_axi_awready), // output wire s_axi_awready //写数据端口 .s_axi_wdata(s_axi_wdata), // input wire [31 : 0] s_axi_wdata .s_axi_wstrb(s_axi_wstrb), // input wire [3 : 0] s_axi_wstrb .s_axi_wvalid(s_axi_wvalid), // input wire s_axi_wvalid .s_axi_wready(s_axi_wready), // output wire s_axi_wready //写应答端口 .s_axi_bresp(s_axi_bresp), // output wire [1 : 0] s_axi_bresp .s_axi_bvalid(s_axi_bvalid), // output wire s_axi_bvalid .s_axi_bready(s_axi_bready), // input wire s_axi_bready //读地址端口 .s_axi_araddr(s_axi_araddr), // input wire [3 : 0] s_axi_araddr .s_axi_arvalid(s_axi_arvalid), // input wire s_axi_arvalid .s_axi_arready(s_axi_arready), // output wire s_axi_arready //读数据端口 .s_axi_rdata(s_axi_rdata), // output wire [31 : 0] s_axi_rdata .s_axi_rresp(s_axi_rresp), // output wire [1 : 0] s_axi_rresp .s_axi_rvalid(s_axi_rvalid), // output wire s_axi_rvalid .s_axi_rready(s_axi_rready), // input wire s_axi_rready .rx(rx), // input wire rx .tx(tx) // output wire tx ); |
端口描述
端口 | 描述 |
---|---|
AWADDR | 写地址 |
AWVALID | 写地址有效标志 |
AWREADY | 写地址通道握手信号 |
WDATA | 写数据 |
WSTRB | 写数据选通信号,指明数据总线哪个字节有效,在AXI-uartlite中此信号不起作用 |
WVALID | 写数据有效标志位 |
WREADY | 写数据通道握手信号 |
BRESP | 写应答,指明发送是否被成功接收 |
BVALID | 写应答信号有效标志位 |
BREADY | 写应答通道握手信号 |
ARADDR | 读地址 |
ARVALID | 读地址有效标志位 |
ARREADY | 读地址通道握手信号 |
RDATA | 读数据 |
RRESP | 读应答,指明读操作的状态,是否成功 |
RVALID | 读数据有效标志位 |
RREADY | 读数据通道握手信号 |
AXI-Lite接口基本使用
AXI-Lite 总线使用valid+ready信号进行相互握手。
发送地址或数据
发送端提供数据或地址的同时提供同步的valid信号,等待接收端拉高ready信号,valid和ready同时为高时接收端采样数据或地址,即在上图中的T2时刻处开始采样。
AXI-uartlite写地址和写数据要同时进行
读数据
先发送读地址,同时拉高rready信号,表明可以接收数据,当valid信号拉高时采样数据。
AXI-uartlite IP核寄存器介绍
地址偏移 | 寄存器名称 | 描述 |
---|---|---|
0h | Rx FIFO | 接收数据FIFO |
04h | Tx FIFO | 发送数据FIFO |
08h | 状态寄存器 | IP核状态寄存器 |
0ch | 控制寄存器 | IP核控制寄存器 |
Rx FIFO和Tx FIFO都是低8bit有效,控制寄存器如下图所示:
状态寄存器如下图所示:
简单的AXI-uartlite控制模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | `timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // +------------------------------------------------------+ // | Address | Register Name | Description | // |---------|---------------|----------------------------| // | 0h | Rx FIFO | Receive data FIFO | // | 04h | Tx FIFO | Transmit data FIFO | // | 08H | STAT_REG | UART Lite status register | // | 0ch | CTRL_REG | UART Lite control register | // +------------------------------------------------------+ // // +———————————+—————————————+———————————+——————————————+——————————————+ // | 31:5 | 4 | 3:2 | 1 | 0 | // +———————————+—————————————+———————————+——————————————+——————————————+ // /\ /\ /\ /\ /\ // /\ /\ /\ /\ /\ // Reserved Enable Intr Reserved Rst Rx FIFO Rst Tx FIFO // // control Register // // +——————————+———————————————+—————————————+————————————————+———————————————+———————————————+————————————————+———————————————+——————————————————+ // | 31:8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // +——————————+———————————————+—————————————+————————————————+———————————————+———————————————+————————————————+———————————————+——————————————————+ // /\ /\ /\ /\ /\ /\ /\ /\ /\ // /\ /\ /\ /\ /\ /\ /\ /\ /\ // Reserved Parity Error Frame Error Overrun Error Intr Enabled Tx FIFO Full Tx FIFO Empty Rx FIFO Full Rx FIFO Valid Data // // status Register ////////////////////////////////////////////////////////////////////////////////// module uart_ctrl( input aclk, input aresetn, input tx_empty, input [31:0] tx_dout, output interrupt, output reg tx_rd_en, output reg [31:0] uart_o, output reg uart_o_v, input rx, output tx ); reg [3 : 0] awaddr; reg awvalid; wire awready; reg [31 : 0] wdata; wire [3 : 0] wstrb; reg wvalid; wire wready; wire [1 : 0] bresp; wire bvalid; reg bready; reg [3 : 0] araddr; reg arvalid; wire arready; wire [31 : 0] rdata; wire [1 : 0] rresp; wire rvalid; reg rready; reg [10:0] state_c; reg [10:0] state_n; parameter s0 = 11'b000_0000_0001; parameter s1 = 11'b000_0000_0010; parameter t1 = 11'b000_0000_0100; parameter s2 = 11'b000_0000_1000; parameter s3 = 11'b000_0001_0000; parameter s4 = 11'b000_0010_0000; parameter s5 = 11'b000_0100_0000; parameter t5 = 11'b000_1000_0000; parameter s6 = 11'b001_0000_0000; parameter s7 = 11'b010_0000_0000; parameter t7 = 11'b100_0000_0000; always @ (posedge aclk) begin if(!aresetn) begin state_c<=s0; end else begin state_c<=state_n; end end always @ (*) begin case(state_c) s0 : if(!tx_empty) begin state_n=s1; end else begin state_n=s4; end s1 : if(arready) begin state_n=t1; end else begin state_n=s1; end t1 : if(rvalid==1&&rdata[3]==0) begin state_n=s2; end else if(rvalid==1&&rdata[0]==1) begin state_n=s6; end else if(rvalid==1&&rdata[3]==1&&rdata[0]==0) begin state_n=s0; end s2 : state_n=s3; s3 : if(awready==1&&wready==1) begin state_n=s4; end else begin state_n=s3; end s4 : state_n=s5; s5 : if(arready) begin state_n=t5; end else begin state_n=s5; end t5 : if(rvalid==1&&rdata[0]==1) begin state_n=s6; end else if(rvalid==1&&rdata[0]==0) begin state_n<=s0; end s6 : state_n=s7; s7 : if(arready) begin state_n=t7; end else begin state_n=s7; end t7 : if(rvalid==1) begin state_n=s0; end else begin state_n=t7; end default : state_n=s0; endcase end always @ (posedge aclk) begin if(!aresetn) begin araddr<=4'h8; arvalid<=0; rready<=0; tx_rd_en<=0; awaddr<=4'h4; wdata<=32'd0; awvalid<=0; wvalid<=0; bready<=1; uart_o<=32'd0; uart_o_v<=0; end else case(state_c) s0 : begin uart_o<=uart_o; uart_o_v<=0; end s1 : begin rready<=1; if(arready) begin araddr<=4'h8; arvalid<=0; end else begin araddr<=4'h8; arvalid<=1; end end t1 : begin if(rvalid) begin rready<=0; end else begin rready<=1; end end s2 : begin tx_rd_en<=1; end s3 : begin tx_rd_en<=0; if(awready==1&&wready==1) begin awvalid<=0; wvalid<=0; end else begin awaddr<=4'h04; wdata<=tx_dout; awvalid<=1; wvalid<=1; end end s4 : begin araddr<=4'h8; arvalid<=1; rready<=1; end s5 : begin rready<=1; if(arready) begin araddr<=4'h0; arvalid<=0; end else begin araddr<=4'h8; arvalid<=1; end end t5 : begin if(rvalid) begin rready<=0; end else begin rready<=1; end end s6 : begin araddr<=4'h0; arvalid<=1; rready<=1; end s7 : begin rready<=1; if(arready) begin araddr<=4'h0; arvalid<=0; end else begin araddr<=4'h0; arvalid<=1; end end t7 : begin if(rvalid) begin rready<=0; uart_o<=rdata; uart_o_v<=1; end else begin rready<=1; uart_o<=uart_o; uart_o_v<=0; end end default : begin araddr<=4'h8; arvalid<=0; rready<=0; tx_rd_en<=0; awaddr<=4'h4; wdata<=32'd0; awvalid<=0; wvalid<=0; bready<=1; uart_o<=32'd0; uart_o_v<=0; end endcase end debug_uart debug_uart_inst ( .s_axi_aclk (aclk ), // input wire s_axi_aclk 100MHz .s_axi_aresetn(aresetn ), // input wire s_axi_aresetn .interrupt (interrupt ), // output wire interrupt .s_axi_awaddr (awaddr ), // input wire [3 : 0] s_axi_awaddr .s_axi_awvalid(awvalid ), // input wire s_axi_awvalid .s_axi_awready(awready ), // output wire s_axi_awready .s_axi_wdata (wdata ), // input wire [31 : 0] s_axi_wdata .s_axi_wstrb (wstrb ), // input wire [3 : 0] s_axi_wstrb .s_axi_wvalid (wvalid ), // input wire s_axi_wvalid .s_axi_wready (wready ), // output wire s_axi_wready .s_axi_bresp (bresp ), // output wire [1 : 0] s_axi_bresp .s_axi_bvalid (bvalid ), // output wire s_axi_bvalid .s_axi_bready (bready ), // input wire s_axi_bready .s_axi_araddr (araddr ), // input wire [3 : 0] s_axi_araddr .s_axi_arvalid(arvalid ), // input wire s_axi_arvalid .s_axi_arready(arready ), // output wire s_axi_arready .s_axi_rdata (rdata ), // output wire [31 : 0] s_axi_rdata .s_axi_rresp (rresp ), // output wire [1 : 0] s_axi_rresp .s_axi_rvalid (rvalid ), // output wire s_axi_rvalid .s_axi_rready (rready ), // input wire s_axi_rready .rx (rx ), // input wire rx .tx (tx ) // output wire tx ); endmodule |
配套testbench
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | `timescale 1ns / 1ps module tb_uartlite; logic srst; logic aclk ; logic aresetn; logic tx_empty; logic [31:0] tx_dout; logic interrupt; logic tx_rd_en; logic [31:0] uart_o; logic uart_o_v; logic rx; logic tx; integer finish_cnt; integer state; parameter s0 = 11'b000_0000_0001; parameter s1 = 11'b000_0000_0010; parameter t1 = 11'b000_0000_0100; parameter s2 = 11'b000_0000_1000; parameter s3 = 11'b000_0001_0000; parameter s4 = 11'b000_0010_0000; parameter s5 = 11'b000_0100_0000; parameter t5 = 11'b000_1000_0000; parameter s6 = 11'b001_0000_0000; parameter s7 = 11'b010_0000_0000; parameter t7 = 11'b100_0000_0000; always @ (*) begin case(uart_ctrl_inst.state_c) s0 : state = "s0"; s1 : state = "s1"; t1 : state = "t1"; s2 : state = "s2"; s3 : state = "s3"; s4 : state = "s4"; s5 : state = "s5"; t5 : state = "t5"; s6 : state = "s6"; s7 : state = "s7"; t7 : state = "t7"; endcase end assign rx = tx; initial aclk = 0; always #5 aclk = ~aclk; initial begin srst = 1; tx_empty = 1; #100 srst = 0; repeat (10) begin @(posedge aclk); end tx_empty = 0; wait(finish_cnt==10); #100 $stop; end always @ (posedge aclk) begin if(srst) begin aresetn<=0; end else begin aresetn<=1; end end always @ (posedge aclk) begin if(!aresetn) begin tx_dout <= 32'd0; end else if(tx_rd_en) begin tx_dout <= $urandom_range(255); end end always @ (posedge aclk) begin if(!aresetn) begin finish_cnt<=0; end else if(uart_o_v) begin finish_cnt<=finish_cnt+1; end end uart_ctrl uart_ctrl_inst( .aclk (aclk ), .aresetn (aresetn ), .tx_empty (tx_empty ), .tx_dout (tx_dout ), .interrupt (interrupt ), .tx_rd_en (tx_rd_en ), .uart_o (uart_o ), .uart_o_v (uart_o_v ), .rx (rx ), .tx (tx ) ); endmodule |