编写fpga的串口代码时遇到的一个大坑!

【编写fpga的串口代码时遇到的一个大坑!】
编写fpga的串口代码时遇到的一个大坑!

  • 1 warning 10240!!!
  • 2 代码
    • 2.1 uart_tx.v
    • 2.2 send_freq.v
    • 2.3 send_freq_top.v

1 warning 10240!!! ??在调试串口时遇到一个很诡异的问题。我打算用串口循环发送一个频率值,间隔为1s,然而下载到板子后只能发一次。我反复地检查我的时序设计图,然后用testbench仿真观察波形,都没有错!第一次遇到仿真正确然而下板验证时却出错的情况,值得纪念一下。不过难受的是我为这件事卡了一个星期,这一个星期里我反复地修改串口模块、发送频率模块和顶层模块,然而都无济于事,甚至还出现很多莫名其妙的情况,比如发送间隔为1s时只发了一次,改为10ms时就发送了两次,再改为1us时就什么也收不到了,完全不知道里面发生了什么……
??转机出现在今晚,我想起了以前看过的fpga开发分享贴,里面提到调试fpga时如果实在找不出bug所在,就看看warning。这一看不得了了!当我把下面这条10240警告改掉之后,程序就跑通了!!!
10240 Verilog HDL Always Construct warning at send_freq.v(38): inferring latch(es) for variable "r_next_state", which holds its previous value in one or more paths through the always construct

??这一条警告出现的原因是写了if没写else,或者写了case没写default,产生了锁存器。我在send_freq.v里面是这样写的:
always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_cur_state <= S_IDLE; else r_cur_state <= r_next_state; endalways @(*) begin case(r_cur_state) S_IDLE: if(i_freq_send_req) r_next_state <= S_SEND_TENTH; S_SEND_TENTH: ... default: r_next_state <= S_IDLE; endcase end

??我没有给r_next_state赋初值,复位后r_cur_state为S_IDLE,如果在紧接着的时钟沿到来前i_freq_send_req没有出现,那么r_cur_state就被赋值为r_next_state,一个未初始化的值。然后再次进入case判断时,因为有default的存在,r_next_state第一次被赋值为S_IDLE。接着r_cur_state又被赋值为S_IDLE,这个时候程序才走上正轨,该赋值的变量都赋值了。按理说不应该出现我遇到的问题,所以这个玄学我暂时没法解释。先记录在此,以后回过头来看也许就能一目了然。如果各位看官知道其中道理的,还望不吝赐教。
??以后要是要重视编程规范呀。
2 代码 ??这部分是可以运行的代码,分别是串口发送模块,频率发送控制模块和顶层模块。
2.1 uart_tx.v
module uart_tx( inputi_clk, inputi_rst_n, inputi_uart_send_req, input[7:0] i_uart_send_byte, outputo_uart_send_ack, outputo_uart_tx_pin ); localparam C_CYCLE = 50 * 1000000 / 115200; localparam S_IDLE= 5'b00001; localparam S_START= 5'b00010; localparam S_DATA= https://www.it610.com/article/5'b00100; localparam S_STOP= 5'b01000; localparam S_ACK = 5'b10000; reg[4:0] r_cur_state; reg[4:0] r_next_state; reg[31:0]r_cycle_cnt; reg[2:0] r_bit_cnt; reg[7:0] r_uart_send_byte; regr_uart_send_ack; regr_uart_tx_pin; assign o_uart_tx_pin = r_uart_tx_pin; assign o_uart_send_ack = r_uart_send_ack; always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_cur_state <= S_IDLE; else r_cur_state <= r_next_state; endalways @(*) begin case(r_cur_state) S_IDLE: if(i_uart_send_req) r_next_state <= S_START; else r_next_state <= S_IDLE; S_START: if(r_cycle_cnt == C_CYCLE - 1) r_next_state <= S_DATA; else r_next_state <= S_START; S_DATA: if((r_cycle_cnt == C_CYCLE - 1) && r_bit_cnt == 3'd7) r_next_state <= S_STOP; else r_next_state <= S_DATA; S_STOP: if(r_cycle_cnt == C_CYCLE - 1) r_next_state <= S_ACK; else r_next_state <= S_STOP; S_ACK: r_next_state <= S_IDLE; default: r_next_state <= S_IDLE; endcase endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_uart_tx_pin <= 1'b1; else case(r_next_state) S_IDLE: r_uart_tx_pin <= 1'b1; S_START: r_uart_tx_pin <= 1'b0; S_DATA: r_uart_tx_pin <= r_uart_send_byte[r_bit_cnt]; S_STOP, S_ACK: r_uart_tx_pin <= 1'b1; default: r_uart_tx_pin <= 1'b1; endcase endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_cycle_cnt <= 32'd0; else if(r_cur_state != r_next_state || (r_next_state == S_DATA && r_cycle_cnt == C_CYCLE - 1)) r_cycle_cnt <= 32'd0; else r_cycle_cnt <= r_cycle_cnt + 32'd1; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_bit_cnt <= 3'd0; else if(r_cur_state == S_DATA) if(r_cycle_cnt == C_CYCLE - 1) r_bit_cnt <= r_bit_cnt + 3'd1; else r_bit_cnt <= r_bit_cnt; else r_bit_cnt <= 3'd0; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_uart_send_byte <= 8'd0; else if(i_uart_send_req) r_uart_send_byte <= i_uart_send_byte; else r_uart_send_byte <= r_uart_send_byte; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_uart_send_ack <= 1'b0; else if(r_next_state == S_ACK) r_uart_send_ack <= 1'b1; else r_uart_send_ack <= 1'b0; endendmodule

2.2 send_freq.v
module send_freq( inputi_clk, inputi_rst_n, inputi_freq_send_req, input[9:0] i_freq, outputo_freq_send_ack, outputo_uart_tx_pin ); localparam S_IDLE= 6'b000001; localparam S_SEND_TENTH = 6'b000010; localparam S_SEND_DOT= 6'b000100; localparam S_SEND_INT= 6'b001000; localparam S_WAIT= 6'b010000; localparam S_ACK= 6'b100000; reg[5:0] r_cur_state; reg[5:0] r_next_state; reg[5:0] r_last_state; reg[9:0] r_freq; reg[7:0] r_uart_send_byte; regr_freq_send_ack; regr_uart_send_req; wirer_uart_send_ack; assign o_freq_send_ack = r_freq_send_ack; always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_cur_state <= S_IDLE; else r_cur_state <= r_next_state; endalways @(*) begin case(r_cur_state) S_IDLE: if(i_freq_send_req) r_next_state <= S_SEND_TENTH; else // important!! r_next_state <= S_IDLE; S_SEND_TENTH,S_SEND_DOT,S_SEND_INT: r_next_state <= S_WAIT; S_WAIT: if(r_uart_send_ack) begin if(r_last_state == S_SEND_TENTH) r_next_state <= S_SEND_DOT; else if(r_last_state == S_SEND_DOT) r_next_state <= S_SEND_INT; else if(r_last_state == S_SEND_INT && (|r_freq)) r_next_state <= S_SEND_INT; else r_next_state <= S_ACK; end else r_next_state <= S_WAIT; S_ACK: r_next_state <= S_IDLE; default: r_next_state <= S_IDLE; endcase endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_freq_send_ack <= 1'b0; else if(r_next_state == S_ACK) r_freq_send_ack <= 1'b1; else r_freq_send_ack <= 1'b0; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_last_state <= S_IDLE; else if(r_next_state == S_SEND_TENTH || r_next_state == S_SEND_DOT || r_next_state == S_SEND_INT) r_last_state <= r_next_state; else r_last_state <= r_last_state; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_uart_send_req <= 1'b0; else if(r_next_state == S_SEND_TENTH) r_uart_send_req <= 1'b1; else if(r_next_state == S_ACK) r_uart_send_req <= 1'b0; else r_uart_send_req <= r_uart_send_req; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_freq <= 10'd0; else if(r_next_state == S_SEND_TENTH) r_freq <= i_freq / 10'd10; else if(r_next_state == S_SEND_INT && (|r_freq)) r_freq <= r_freq / 10'd10; else r_freq <= r_freq; endalways @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_uart_send_byte <= 8'hff; else if(r_next_state == S_SEND_TENTH) r_uart_send_byte <= i_freq % 10'd10 + "0"; else if(r_next_state == S_SEND_DOT) r_uart_send_byte <= "."; else if(r_next_state == S_SEND_INT && (|r_freq)) r_uart_send_byte <= r_freq % 10'd10 + "0"; else r_uart_send_byte <= r_uart_send_byte; enduart_tx uart_tx_inst( .i_clk(i_clk), .i_rst_n(i_rst_n), .i_uart_send_req(r_uart_send_req), .i_uart_send_byte(r_uart_send_byte), .o_uart_send_ack(r_uart_send_ack), .o_uart_tx_pin(o_uart_tx_pin) ); endmodule

2.3 send_freq_top.v
module send_freq_top( inputi_clk, inputi_rst_n, output o_uart_tx_pin ); localparam S_IDLE = 4'b0001; localparam S_SEND = 4'b0010; localparam S_WAIT = 4'b0100; localparam S_SEND2= 4'b1000; reg[3:0]r_next_state; reg[31:0] r_clk_cnt; reg[9:0]r_freq; regr_freq_send_req; wirer_freq_send_ack; always @(posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_next_state <= S_IDLE; r_freq <= 10'd1021; r_freq_send_req <= 1'b0; r_clk_cnt <= 32'd0; end else case(r_next_state) S_IDLE: r_next_state <= S_SEND; S_SEND: begin r_clk_cnt <= 32'd0; if(r_freq_send_req && r_freq_send_ack) begin r_freq_send_req <= 1'b0; r_next_state <= S_WAIT; end else if(!r_freq_send_req) r_freq_send_req <= 1'b1; end S_WAIT: begin r_clk_cnt <= r_clk_cnt + 32'd1; if(r_clk_cnt >= 32'd50000000) r_next_state <= S_SEND; end default: r_next_state <= S_IDLE; endcase endsend_freq send_freq_inst( .i_clk(i_clk), .i_rst_n(i_rst_n), .i_freq_send_req(r_freq_send_req), .i_freq(r_freq), .o_freq_send_ack(r_freq_send_ack), .o_uart_tx_pin(o_uart_tx_pin) ); endmodule

    推荐阅读