AXI-uartlite IP核快速使用


文章目录

  • 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