Jump to content

    
Sign in to follow this  
KRUTOMER

Переход триггера в Z-состояние при приеме бита

Recommended Posts

Описываю поведение простого UART-передатчика на Verilog в среде Xiling Vivado 2018.2.

При присваивании D-триггеру значения с входного порта, он переходит в Z-состояние. Также при попытке присвоить этот сигнал цепи через оператор непрерывного присваивания assign, цепь также принимает высокоимпедансное состояние. В чем может быть причина такого поведения/симуляции, и как это можно исправить?

Описание модуля следующее:

Скрытый текст

`timescale 1ns / 100ps

module UART_rx
#(parameter FREQ = 24_000_000,
            BAUD_RATE = 9600)
(
    input wire clk, //reset,
    input wire DATA_serial,
    
    output reg data_bit, 
    output reg data_bit2,
    output reg [2:0] STATE,
    output reg [11:0] clk_counter,
    
    output reg done_tick = 0,
    output wire [7:0] DATA_byte

    );
    
//signal declaration
//reg [11:0] clk_counter = 0;
//reg data_bit, data_bit2;
reg [2:0] bit_index = 0;
reg [7:0] byte_bit = 0;
//reg [2:0] STATE = 0;

//dowble register body
always @(posedge clk)
  begin
    data_bit2 <= DATA_serial;
    data_bit <= data_bit2;
  end

    


//state declaration
localparam [2:0] IDLE = 3'b000,
                 START_BIT = 3'b001,
                 DATA_TRANSFER = 3'b010,
                 STOP_BIT = 3'b011,
                 CLEAN_UP = 3'b100;
                 
//------------FSM BODY---------------
always @(posedge clk)
  begin
    case (STATE) IDLE: begin
                       //waiting start_bit
                       done_tick <= 0;
                       clk_counter <= 0;
                       bit_index <= 0;
                         if (data_bit == 0) 
                           STATE <= START_BIT;
                         else
                           STATE <= IDLE;
                       end
                       
           START_BIT: begin
                      //check the midle of start_bit
                      done_tick <= 0;
                      clk_counter <= 0;
                      bit_index <= 0;
                        if (clk_counter == ((FREQ/2/BAUD_RATE)-1)) 
                          if (data_bit == 0) begin 
                            clk_counter <= 0; //midle of input_bit duration
                            STATE <= DATA_TRANSFER; end
                          else 
                            STATE <= IDLE; 
                        
                        else begin
                          clk_counter <= clk_counter + 1;
                          STATE <= START_BIT;
                        end
                      end
                      
       DATA_TRANSFER: begin
                      // receive 8 bit of data
                      done_tick <= 0;
                      bit_index <= 0;
                        if (clk_counter < ((FREQ/BAUD_RATE)-1)) begin
                          clk_counter <= clk_counter + 1;  
                          STATE <= DATA_TRANSFER; end
                        else begin
                          clk_counter <= 0;
                          byte_bit[bit_index] <= data_bit;
                            if (bit_index < 7) begin
                              bit_index <= bit_index + 1;
                              STATE <= DATA_TRANSFER; end
                            else begin
                              bit_index <= 0;
                              STATE <= STOP_BIT; end
                        end
                     end
                     
           STOP_BIT: begin
                     // receive stop-bit
                       if (clk_counter < ((FREQ/BAUD_RATE)-1)) begin
                         clk_counter <= clk_counter + 1;
                         STATE <= STOP_BIT; end
                       else begin
                         done_tick <= 1;
                         clk_counter <= 0;
                         STATE <= CLEAN_UP; end
                     end
                     
           CLEAN_UP: begin
                     //waiting 1 clk cycle
                     done_tick <= 0;
                     STATE <= IDLE;
                     end
                     
             default: STATE <= IDLE;
  endcase
end
   
   
assign DATA_byte = byte_bit;   
                                            
    
endmodule

 

 

Снимок.PNG

Share this post


Link to post
Share on other sites
2 hours ago, KRUTOMER said:

Описываю поведение простого UART-передатчика на Verilog в среде Xiling Vivado 2018.2.

При присваивании D-триггеру значения с входного порта, он переходит в Z-состояние. Также при попытке присвоить этот сигнал цепи через оператор непрерывного присваивания assign, цепь также принимает высокоимпедансное состояние. В чем может быть причина такого поведения/симуляции, и как это можно исправить?

 

Причина может быть в метастабильности

Share this post


Link to post
Share on other sites
3 minutes ago, =AK= said:

Причина может быть в том, что входной сигнал и клок находятся в разных time domains.

В симуляторе нет понятия мета-стабильность.  Скорее всего проблемы в самой логике  модуля или TB. 

Share this post


Link to post
Share on other sites
8 часов назад, Raven сказал:

А код тестбенча можете привести?

Вот код самого тестбенча:

`timescale 1ns / 1ps

module UART_test;

reg clk; //reset;
reg DATA_serial;
wire done_tick, data_bit, data_bit2;
wire [2:0] STATE;
wire [7:0] DATA_byte;
wire [11:0] clk_counter;

UART_rx UART_uut
(.clk(clk),/* .reset(reset),*/ .done_tick(done_tick), .DATA_byte(DATA_byte),
.data_bit(data_bit), .data_bit2(data_bit2), .STATE(STATE), .clk_counter(clk_counter));

initial begin
clk = 0;
//reset = 1;
DATA_serial = 1'b1;
end
always #40 clk = ~clk;

initial begin
//#100 reset = 0;
#10000
#100_000 DATA_serial = 1'b1;
#100_000 DATA_serial = 1'b0; //start-bit
#100_000 DATA_serial = 1'b1; //0
#100_000 DATA_serial = 1'b0; //1
#100_000 DATA_serial = 1'b0; //2
#100_000 DATA_serial = 1'b0; //3
#100_000 DATA_serial = 1'b0; //4
#100_000 DATA_serial = 1'b0; //5
#100_000 DATA_serial = 1'b0; //6
#100_000 DATA_serial = 1'b0; //7
#100_000 DATA_serial = 1'b1; //stop-bit
#100_000
$stop;
end

endmodule

 

7 часов назад, Obam сказал:

 


Может для начала в schematic-е? Для ясности ;-)

 

Снимок.PNG

schematic.pdf

Share this post


Link to post
Share on other sites

 

12 hours ago, KRUTOMER said:

Описание модуля следующее:

1 hour ago, KRUTOMER said:

Вот код самого тестбенча:

Если уж  в модуле UART  есть вход  DATA_serial то  почему  в TB вы  его  не подключаете в модуль?  Висящий  в "воздухе" вход  имеет неопределённой состояние которое и распространяется по логике модуля. :cray:

 

Share this post


Link to post
Share on other sites
24 минуты назад, RobFPGA сказал:

 

Если уж  в модуле UART  есть вход  DATA_serial то  почему  в TB вы  его  не подключаете в модуль?  Висящий  в "воздухе" вход  имеет неопределённой состояние которое и распространяется по логике модуля. :cray:

 

Да, и вправду по невнимательности не добавил DATA_serial и инстанс. Сбасибо большое

Share this post


Link to post
Share on other sites
11 hours ago, RobFPGA said:

В симуляторе нет понятия мета-стабильность.

может придираюсь к словам, я же сейчас в timing simulation засел. Там если симулятор без спец ключа запустить, то при первом же слаке сигнал впадает в X. Не знаю, называется ли это мета-стабильность. Ну и понятно, что тут не этот случай, просто к слову

Share this post


Link to post
Share on other sites
1 minute ago, new123 said:

может придираюсь к словам, я же сейчас в timing simulation засел. Там если симулятор без спец ключа запустить, то при первом же слаке сигнал впадает в X. Не знаю, называется ли это мета-стабильность

В симе, при желании, можно симулировать поведение триггера при условиях возникновения  мета-стабильности. Но для этого нужны  специальные модели. Как раз для этого и служат библиотеки примитивов которые используются для timing simulation. Но в функциональной симуляции (и вообще в симе) как таковой мета-стабильности нет, так как значение триггеру присваивается за 0 время. 

Share this post


Link to post
Share on other sites

Еще раз спасибо большое всем, кто помог решить проблему и написал код ревью на мой UART-приемник. Все-таки решил чуть переписать модуль по заветам Понг П. Чу, а именно конечный автомат

Модуль:

`timescale 1ns / 100ps

module UART_receiver
#(parameter FREQ = 24_000_000,
            BAUD_RATE = 9600)
(
    input wire clk, //reset,
    input wire DATA_serial,
    
    output reg data_bit = 0, 
    output reg data_bit2 = 0,
    output reg [2:0] STATE_reg = 0,
   output reg [11:0] clk_counter_reg = 0,
   output reg [2:0] bit_index_reg = 0,
    
    output reg done_tick = 0,
    output wire [7:0] DATA_byte

    );
    
//signal declaration
//reg [11:0] clk_counter_reg;
reg [11:0] clk_counter_next;
//reg data_bit, data_bit2;
//reg [2:0] bit_index_reg;
reg [2:0] bit_index_next;
reg [7:0] byte_bit = 0;
//reg [2:0] STATE_reg;
reg [2:0] STATE_next;

//dowble register body
always @(posedge clk)
  begin
    data_bit2 <= DATA_serial;
    data_bit <= data_bit2;
    STATE_reg <= STATE_next;
    clk_counter_reg <= clk_counter_next;
    bit_index_reg <= bit_index_next;
  end

//state declaration
localparam [2:0] IDLE = 3'b000,
                 START_BIT = 3'b001,
                 DATA_TRANSFER = 3'b010,
                 STOP_BIT = 3'b011,
                 DONE = 3'b100;
                 
//------------FSM BODY---------------
always @*
  begin
    done_tick = 0;
    clk_counter_next = clk_counter_reg;
    bit_index_next = bit_index_reg;
    STATE_next = STATE_reg;
  
  
      case (STATE_reg) IDLE: begin
                           //waiting start_bit
                               if (data_bit == 0) 
                                 STATE_next = START_BIT;
                               else
                                 STATE_next = IDLE;
                             end
                       
           START_BIT: begin
                      //check the midle of start_bit
                        if (clk_counter_next == ((FREQ/2/BAUD_RATE)-1)) 
                          if (data_bit == 0) begin 
                            clk_counter_next = 0; //midle of input_bit duration
                            STATE_next = DATA_TRANSFER; end
                          else 
                            STATE_next = IDLE; 
                        else begin
                          clk_counter_next = clk_counter_reg + 1;
                          STATE_next = START_BIT;
                        end
                      end
                      
       DATA_TRANSFER: begin
                      // receive 8 bit of data
                        if (clk_counter_next < ((FREQ/BAUD_RATE)-1)) begin
                          clk_counter_next = clk_counter_reg + 1;  
                          STATE_next = DATA_TRANSFER; end
                        else begin
                          clk_counter_next = 0;
                          byte_bit[bit_index_next] = data_bit;
                            if (bit_index_next < 7) begin
                              bit_index_next = bit_index_reg + 1;
                              STATE_next = DATA_TRANSFER; end
                            else begin
                              bit_index_next = 0;
                              STATE_next = STOP_BIT; end
                        end
                     end
                     
           STOP_BIT: begin
                     // receive stop-bit
                       if (clk_counter_next < ((FREQ/BAUD_RATE)-1)) begin
                         clk_counter_next = clk_counter_reg + 1;
                         STATE_next = STOP_BIT; end
                       else begin
                        // done_tick = 1;
                         clk_counter_next = 0;
                         STATE_next = DONE; end
                     end
                     
           DONE: begin
                     //waiting 1 clk cycle
                     done_tick = 1;
                     STATE_next = IDLE;
                     end
                     
             default: STATE_next = IDLE;
  endcase
end
   
   
assign DATA_byte = byte_bit;   
                                            
    
endmodule

Тестбенч:

`timescale 1ns / 1ps

module UART_test;

reg clk; //reset;
reg DATA_serial;
wire done_tick, data_bit, data_bit2;
wire [2:0] bit_index;
wire [2:0] STATE;
wire [7:0] DATA_byte;
wire [11:0] clk_counter;

UART_receiver UART_uut
(.clk(clk),/* .reset(reset),*/ .done_tick(done_tick), .DATA_byte(DATA_byte), .DATA_serial(DATA_serial),
.data_bit(data_bit), .data_bit2(data_bit2), .STATE_reg(STATE), .clk_counter_reg(clk_counter), .bit_index_reg(bit_index));

initial begin
clk = 0;
//reset = 1;
DATA_serial = 1'b1;
end
always #40 clk = ~clk;

initial begin
//#100 reset = 0;
#200_000
#200_000 DATA_serial = 1'b1;
#200_000 DATA_serial = 1'b0; //start-bit
#200_000 DATA_serial = 1'b0; //0
#200_000 DATA_serial = 1'b1; //1
#200_000 DATA_serial = 1'b1; //2
#200_000 DATA_serial = 1'b0; //3
#200_000 DATA_serial = 1'b0; //4
#200_000 DATA_serial = 1'b1; //5
#200_000 DATA_serial = 1'b0; //6
#200_000 DATA_serial = 1'b0; //7
#200_000 DATA_serial = 1'b1; //stop-bit
#200_000
$stop;
end

 

Снимок.PNG

 

Снимок2.PNG

22.01.2022 в 01:25, Obam сказал:

Так всё-таки это приёмник УАППа (но до чего hardware "жирный") и проблема разрешиась?

Просто для симуляции сделал дополнительные выходы

Edited by KRUTOMER

Share this post


Link to post
Share on other sites
2 hours ago, KRUTOMER said:

Все-таки решил чуть переписать модуль по заветам Понг П. Чу, а именно конечный автомат

Модуль:

Совет - лучше вставлять код  в фрейм  Code <>,  так не слетает форматирование. А если код длинный, то заодно и в фрейм Spoiler чтобы была удобнее навигация по топикам.  

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this