1nnocent 发表于 2022-7-31 10:14

07、安路SparkRoad国产FPGA测评【学习篇】串口回环实验

本帖最后由 1nnocent 于 2022-7-30 09:10 编辑

<p>&nbsp; &nbsp; 该例程实现串口回环实验,FPGA 实时监测 uart_rx 信号是否有数据, 若接收到 PC 端发送的数据, 则把接收到的数据通过 uart_tx 返回给 PC 端。先下载程序试下效果,发现PC端发送数据时,没有现象,检查了原理图和管脚约束文件发现是管脚约束时例程使用的不是USB对应的引脚,通过原理图可知TX_RX对应的引脚分别为F16_E16。</p>

<p> &nbsp; &nbsp;</p>

<p>&nbsp; 修改引脚后功能正常。</p>

<p>&nbsp; &nbsp; 先看下一步串口通讯的数据格式:首先是起始位,空闲时为高电平,起始位时拉低电平,之后是数据位,校验位和停止位,停止位时拉高电平。 &nbsp;</p>

<p>&nbsp; &nbsp; 例程顶层模块的输入接口为25MHz时钟,外部复位(对应中间的按键)、输入引脚(rx_引脚)、输出引脚(tx_引脚)。</p>

<p>&nbsp; &nbsp; 波特率设置模块(波特率为9600,时钟周期40ns_):其中bps_start是uart_tx引脚捕获的起始位信号,clk_bps位波特率采样中点。</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                // 波特率采样中点脉冲信号
);

`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;                // 接收过程标志信号 寄存器

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;                        // 波特率采样中点标志
        else
      clk_bps_r &lt;= 1'b0;
end

assign clk_bps = clk_bps_r;

endmodule

</code></pre>

<p>&nbsp; &nbsp; rx_接收模块:该模块捕获下降沿时使用的四个寄存器uart_rx0、uart_rx1、uart_rx2、uart_rx3,捕获的下降沿用于产生波特率模块。该模块主要功能是接收数据,把rx_引脚上的数据进行串转并的功能。</p>

<pre>
<code>module my_uart_rx
(
        input                        clk,                // 25MHz 系统时钟
        input                        rst_n,                // 系统复位
        input                        uart_rx,        // uart_rx 输入引脚
        output                rx_data,        // uart_rx 接收数据
        output                        rx_int,                // 接收过程标志信号
        input                        clk_bps,        // 波特率采样中点
        output                        bps_start        // 捕获的起始位脉冲信号
);

//----------------------------------------------------------------
reg                uart_rx0,uart_rx1,uart_rx2,uart_rx3;        // 起始位下降沿信号寄存器
wire        neg_uart_rx;                                                       

always @ (posedge clk or negedge rst_n)        // 起始位下降沿信号寄存
begin
        if(!rst_n)
    begin
                uart_rx0 &lt;= 1'b0;
                uart_rx1 &lt;= 1'b0;
                uart_rx2 &lt;= 1'b0;
                uart_rx3 &lt;= 1'b0;
        end
        else
    begin
                uart_rx0 &lt;= uart_rx;
                uart_rx1 &lt;= uart_rx0;
                uart_rx2 &lt;= uart_rx1;
                uart_rx3 &lt;= uart_rx2;
        end
end

assign neg_uart_rx = uart_rx3 &amp; uart_rx2 &amp; ~uart_rx1 &amp; ~uart_rx0;        // 捕获起始位下降沿信号

//----------------------------------------------------------------
reg                 bps_start_r;        // 起始位脉冲信号寄存器
reg                num;       
reg                 rx_int;                // 接收过程标志信号

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                bps_start_r &lt;= 1'bz;
                rx_int                 &lt;= 1'b0;
        end
        else if(neg_uart_rx)
    begin                            // 捕获起始位下降沿
                bps_start_r &lt;= 1'b1;        // 起始位脉冲信号置一   
                rx_int                 &lt;= 1'b1;        // 接收过程标志信号置一
        end
        else if(num == 4'd9)
    begin                            // 接收到停止位
                bps_start_r &lt;= 1'b0;        // 起始位脉冲信号置零
                rx_int                 &lt;= 1'b0;        // 接收过程标志信号置零
        end
end

assign bps_start = bps_start_r;

//----------------------------------------------------------------
reg                rx_data_r;                // 接收数据寄存器
reg                rx_temp_data;        // 临时接收数据寄存器

always @ (posedge clk or negedge rst_n)
begin
        if(!rst_n)
    begin
                rx_temp_data         &lt;= 8'd0;
                num                         &lt;= 4'd0;
                rx_data_r                 &lt;= 8'd0;
        end
        else if(rx_int)
    begin                      // 接收过程标志信号为一时
                if(clk_bps)                 // 波特率采样中点时,寄存接收数据
      begin                           
                        num &lt;= num+1'b1;
                        case (num)
                                4'd1: rx_temp_data &lt;= uart_rx;        //寄存接收数据0bit
                                4'd2: rx_temp_data &lt;= uart_rx;        //寄存接收数据1bit
                                4'd3: rx_temp_data &lt;= uart_rx;        //寄存接收数据2bit
                                4'd4: rx_temp_data &lt;= uart_rx;        //寄存接收数据3bit
                                4'd5: rx_temp_data &lt;= uart_rx;        //寄存接收数据4bit
                                4'd6: rx_temp_data &lt;= uart_rx;        //寄存接收数据5bit
                                4'd7: rx_temp_data &lt;= uart_rx;        //寄存接收数据6bit
                                4'd8: rx_temp_data &lt;= uart_rx;        //寄存接收数据7bit
                                default: ;
                        endcase
                end
                else if(num == 4'd9)
      begin               
                        num                        &lt;= 4'd0;                        // 停止位时,清零接收数据计数器
                        rx_data_r        &lt;= rx_temp_data;        // 寄存临时接收数据寄存器的数据
                end
        end
end

assign rx_data = rx_data_r;       

endmodule
</code></pre>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; 发送模块,该模块的功能主要是将接收的数据进行并转串,并发送给PC端。发送模块与接受模块不同的地方是需要发送起始位和停止位。</p>

<pre>
<code>module my_uart_tx
(
        input                        clk,                // 系统时钟
        input                        rst_n,                // 复位信号
        input                rx_data,        // 接收到的数据
        input                        rx_int,                // 接收过程标志信号
        output                        uart_tx,        // uart_tx 输出引脚
        input                        clk_bps,        // 波特率采样中点
        output                        bps_start        // 捕获的结束位脉冲信号
);

//---------------------------------------------------------
reg         rx_int0,rx_int1,rx_int2;        // 接收过程标志信号寄存器
wire         neg_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;        // 捕获接收过程标志信号

//---------------------------------------------------------
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>&nbsp;</p>

<p>&nbsp; &nbsp; 历程运行效果:</p>

<p> &nbsp;</p>

lugl4313820 发表于 2022-8-3 07:12

uart是最常用的通信方式,感谢分享!

xutong 发表于 2023-1-26 08:48

<p>感谢分享</p>
页: [1]
查看完整版本: 07、安路SparkRoad国产FPGA测评【学习篇】串口回环实验