bigbat 发表于 2022-5-8 12:26

SparkRoad测评(7)-FPGA串口测试

<p>安路的开发板上是带有USB2UART模块的,这个模块是通过板子上的单片机与USB转串口相连接的,打开自带的例程6_uart_loopback自接运行是不可以的。因为默认的引脚是不接在UART2USB的线上的,所以必须将引脚设定到USB2UART指定的引脚上。</p>

<p>1、打开项目uart.al,文件mini_EG4S20BG256.adc</p>

<p>&nbsp; 2、修改文件的指定资源。uart_tx E16、uart_rx F16</p>

<pre>
<code>set_pin_assignment {ext_clk_25m}    { LOCATION = K14;}
set_pin_assignment {ext_rst_n}{ LOCATION = L12;}   ##KEY_C

##set_pin_assignment {uart_tx} { LOCATION = C11; }         
##set_pin_assignment {uart_rx} { LOCATION = B15; }

set_pin_assignment {uart_tx} { LOCATION = E16; }      
set_pin_assignment {uart_rx} { LOCATION = F16; }

</code></pre>

<p>3、将项目综合后,烧入板子就可以实验了。</p>

<p>&nbsp;这个说明一下实验中的项目文件,speed_setting.v这个文件是用来修改波特率的。这里有两个文件对应的是收发两个设置</p>

<pre>
<code>module speed_setting
#(
    parameter BPS_SET      =   96,//波特率
    parameter CLK_PERIORD=   40   //时钟周期40ns(25MHz)
)
(
        input        clk,                //25MHz主时钟
        input        rst_n,                //低电平复位信号
        input        bps_start,        //接收到数据后,波特率时钟启动信号置位
        output        clk_bps                //clk_bps的高电平为接收或者发送数据位的中间采样点
);

`define BPS_PARA        (10_000_000/CLK_PERIORD/BPS_SET)        //10_000_000/`CLK_PERIORD/96;
`define BPS_PARA_2        (`BPS_PARA/2)                                                //BPS_PARA/2;       

reg        cnt;                  //分频计数
reg clk_bps_r;                //波特率时钟寄存器
reg        uart_ctrl;        //uart波特率选择寄存器

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
      cnt &lt;= 13'd0;
        else if((cnt == `BPS_PARA) || !bps_start)
      cnt &lt;= 13'd0;          //波特率计数清零
        else
      cnt &lt;= cnt + 1'b1;//波特率时钟计数启动
end

always@(posedge clk or negedge rst_n)
begin
        if(!rst_n)
      clk_bps_r &lt;= 1'b0;
        else if(cnt == `BPS_PARA_2)
      clk_bps_r &lt;= 1'b1;                        //clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点
        else
      clk_bps_r &lt;= 1'b0;
end

assign clk_bps = clk_bps_r;

endmodule
</code></pre>

<p>只要修改parameter BPS_SET = 96, //波特率 其中的96就可以了,其实的参数行是:`define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET) //10_000_000/`CLK_PERIORD/96;</p>

<p>别的就不要动了。其实主要的就是一个&ldquo;分频器&rdquo;</p>

<p>下面我们来分析一下串口的发送文件,my_uart_tx.v</p>

<pre>
<code>module my_uart_tx
(
        input                        clk,
        input                        rst_n,
        input                rx_data,
        input                        rx_int,
        output                        uart_tx,
        input                        clk_bps,
        output                        bps_start
);

//---------------------------------------------------------
reg         rx_int0,rx_int1,rx_int2;        //rx_int信号寄存器
wire         neg_rx_int;                                        //rx_int下降沿标志位

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                rx_int0 &lt;= 1'b0;
                rx_int1 &lt;= 1'b0;
                rx_int2 &lt;= 1'b0;
        end
        else
    begin
                rx_int0 &lt;= rx_int;
                rx_int1 &lt;= rx_int0;
                rx_int2 &lt;= rx_int1;
        end
end

assign neg_rx_int =~rx_int1 &amp; rx_int2;        //捕捉到下降沿后,neg_rx_int拉高保持一个主时钟周期

//---------------------------------------------------------
reg                tx_data;                //待发送数据的寄存器
reg                 bps_start_r;
reg                 tx_en;                        //发送数据使能信号,高有效
reg                num;

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                bps_start_r &lt;= 1'bz;
                tx_en                 &lt;= 1'b0;
                tx_data         &lt;= 8'd0;
        end
        else if(neg_rx_int)
    begin                                    //接收数据完毕,准备把接收到的数据发回去
                bps_start_r &lt;= 1'b1;
                tx_data         &lt;= rx_data;                //把接收到的数据存入发送数据寄存器
                tx_en                 &lt;= 1'b1;                //进入发送数据状态中
        end
        else if(num == 4'd10)
    begin                                    //数据发送完成,复位
                bps_start_r &lt;= 1'b0;
                tx_en                &lt;= 1'b0;
        end
end

assign bps_start = bps_start_r;

//---------------------------------------------------------
reg uart_tx_r;

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                num                 &lt;= 4'd0;
                uart_tx_r         &lt;= 1'b1;
        end
        else if(tx_en)
    begin
                if(clk_bps)       
      begin
                        num &lt;= num+1'b1;
                        case (num)
                                4'd0: uart_tx_r &lt;= 1'b0;                 //发送起始位
                                4'd1: uart_tx_r &lt;= tx_data;        //发送bit0
                                4'd2: uart_tx_r &lt;= tx_data;        //发送bit1
                                4'd3: uart_tx_r &lt;= tx_data;        //发送bit2
                                4'd4: uart_tx_r &lt;= tx_data;        //发送bit3
                                4'd5: uart_tx_r &lt;= tx_data;        //发送bit4
                                4'd6: uart_tx_r &lt;= tx_data;        //发送bit5
                                4'd7: uart_tx_r &lt;= tx_data;        //发送bit6
                                4'd8: uart_tx_r &lt;= tx_data;        //发送bit7
                                4'd9: uart_tx_r &lt;= 1'b1;                //发送结束位
                               default: uart_tx_r &lt;= 1'b1;
                        endcase
                end
                else if(num == 4'd10)
                num &lt;= 4'd0;               
        end
end

assign uart_tx = uart_tx_r;

endmodule
</code></pre>

<p>这个文件让人看了有点疑惑,主要是这里面多了一步,将收到的数据转出到tx_data的过程,这个过程真不应该写到这个模块中,我的建议是写到顶层的文件中的状态机当中。</p>

<pre>
<code>always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                bps_start_r &lt;= 1'bz;
                tx_en                 &lt;= 1'b0;
                tx_data         &lt;= 8'd0;
        end
        else if(neg_rx_int)
    begin                                    //接收数据完毕,准备把接收到的数据发回去
                bps_start_r &lt;= 1'b1;
                tx_data         &lt;= rx_data;                //把接收到的数据存入发送数据寄存器
                tx_en                 &lt;= 1'b1;                //进入发送数据状态中
        end
        else if(num == 4'd10)
    begin                                    //数据发送完成,复位
                bps_start_r &lt;= 1'b0;
                tx_en                &lt;= 1'b0;
        end
end</code></pre>

<p>接下来是输出的主要部分。</p>

<pre>
<code>//---------------------------------------------------------
reg uart_tx_r;

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                num                 &lt;= 4'd0;
                uart_tx_r         &lt;= 1'b1;
        end
        else if(tx_en)
    begin
                if(clk_bps)       
      begin
                        num &lt;= num+1'b1;
                        case (num)
                                4'd0: uart_tx_r &lt;= 1'b0;                 //发送起始位
                                4'd1: uart_tx_r &lt;= tx_data;        //发送bit0
                                4'd2: uart_tx_r &lt;= tx_data;        //发送bit1
                                4'd3: uart_tx_r &lt;= tx_data;        //发送bit2
                                4'd4: uart_tx_r &lt;= tx_data;        //发送bit3
                                4'd5: uart_tx_r &lt;= tx_data;        //发送bit4
                                4'd6: uart_tx_r &lt;= tx_data;        //发送bit5
                                4'd7: uart_tx_r &lt;= tx_data;        //发送bit6
                                4'd8: uart_tx_r &lt;= tx_data;        //发送bit7
                                4'd9: uart_tx_r &lt;= 1'b1;                //发送结束位
                               default: uart_tx_r &lt;= 1'b1;
                        endcase
                end
                else if(num == 4'd10)
                num &lt;= 4'd0;               
        end
end

assign uart_tx = uart_tx_r;
</code></pre>

<p>这个程序使用了一个计数器,而不是一个标准状态机,这点根据个人的喜好了,计数器的优点是资源占用少,但是可配置性差,不是很灵活,状态机的缺点是结构复杂。这就是看各自的喜好了。本次测试到此为止,希望大家多多指正。</p>

Jacktang 发表于 2022-5-9 08:08

<p>将收到的数据转出到tx_data的过程,写到顶层的文件中的状态机当中建议很好,收藏</p>
页: [1]
查看完整版本: SparkRoad测评(7)-FPGA串口测试