모듈 -verilog 구현 -VCS 시뮬레이션을 보내는 직렬 포트 (UART)

1. 주요 포인트

1. 구조 : TTL 레벨 직렬 포트는 두 개의 신호 라인으로 연결됩니다. 하나는 수신단 RX이고 다른 하나는 송신단 TX입니다. UART는 클록 라인이없고 배선이 간단한 직렬 인터페이스입니다.

2. 타이밍 : 정보 흐름의 시간 순서. 다음 그림은 직렬 포트의 타이밍 다이어그램입니다.

       직렬 데이터는 프레임 단위로 전송됩니다. 프레임의 데이터 비트, 체크 비트 및 정지 비트를 구성 할 수 있습니다. 일반적으로 데이터 비트는 체크 비트가없는 8 비트이고 정지 비트는 1 비트입니다. 데이터 프레임에는 1 + 8이 포함됩니다. + 0 + 1 = 10 비트 (비트).

      유휴 상태에서 버스는 하이이고 시작 비트는 로우 레벨로 고정됩니다. 유휴 상태에서 로우 레벨이 전송되면 데이터 프레임이 전송되기 시작하고 정지 비트가 하이 레벨로 고정되어 데이터 프레임의 끝을 나타냅니다.

3. Baud rate : 데이터 전송 속도, 즉 초당 전송할 수있는 비트 수입니다. 예를 들어, 115200의 전송 속도에서 즉, 초당 최대 115200 비트의 데이터 (시작 비트, 중지 비트 및 패리티 비트 포함)를 전송할 수 있으며, 데이터의 각 비트를 유지하는 데 필요한 시간은 1s / 115200≈8.68055us입니다.

둘째, 실현

1. 아키텍처 : 송신 모듈은 주로 세 부분으로 구성됩니다. 1. 카운터를 사용하여 보드 속도 타이밍을 실현합니다. 2. 모듈 상태를 전송합니다. 3. 송신 데이터를 입력합니다.

2. Verilog 언어 설명

새 uart_tx.v 파일 만들기

module uart_tx
(
    input clk,
    input nrst,
    input tx_en,
    input [7:0]tx_data,
    output tx_pin,
    output tx_done
);

위에서 설명한 모듈의 포트는 클럭, 재설정, 활성화, 데이터 전송, 핀 전송 및 완료 플래그 전송입니다.

parameter INPUT_CLK = 125000000 , BUDO = 115200;
localparam B_CNT_MAX = (INPUT_CLK/BUDO)-1;//波特率计数器最大值

reg [3:0]CS;    //状态
reg [10:0]b_cnt; //用来产生波特率时钟
reg [10:0]tx_buf;//包含起始位与停止位的数据缓冲区

reg r_tx_pin;
reg r_txdone;

위는 모듈의 매개 변수, 로컬 매개 변수 및 사용 된 레지스터를 정의합니다. 모듈의 기본 입력 클럭은 125MHz이고 전송 속도는 115200입니다.

//CS依据波特率计数器自增,实现状态转移
task CS_increase;
    if(CS == 'd10) begin    //一帧完成,复位
        CS <= 'd0;
        b_cnt <= 'd0;
    end
    else if (b_cnt == B_CNT_MAX) begin//计数满1bti的发送时间,转移到下一个bit,计数器清零
        CS <= CS + 1'b1;
        b_cnt <= 'd0;
    end
    else //计数中
        b_cnt <= b_cnt + 1'b1;
endtask

위는 다른 코드에서 호출되는 태스크를 정의하고 상태 천이를 실현하기 위해 보레이트 카운터에 따라 상태 레지스터 CS의 자체 증가를 실현합니다. 이 섹션은 전송 속도 타이밍과 상태 전환의 두 부분을 결합합니다.

always @(posedge clk) begin
    if (!nrst) begin//复位
        CS <= 'd0;
        b_cnt <= 'd0;
        tx_buf <= 'd0;
        r_tx_pin <= 1'b1;
        r_txdone <= 1'b1;
    end
    else if (tx_en) begin
        //状态转移
        CS_increase;

        //各状态输出
        if (CS == 'd0) begin
            r_txdone <= 1'b0;//开始发送,发送完成标志置0
            tx_buf <= {2'b11,tx_data,1'b0};
        end
        else if (CS == 'd10) begin
            r_txdone <= 1'b1;//发送完成标志置1
            tx_buf <= tx_buf;
        end
        else begin           //正在发送数据位、停止位
            r_txdone <= 1'b0;
            tx_buf <= tx_buf;
        end
    
        r_tx_pin <= tx_buf[CS];//输出引脚数据更新
    end
    else
        r_tx_pin <= 1'b1;
end

 위의 부분은 송신 모듈의 주요 구조로, 클럭 상승 에지 이후에 리셋이 있는지 감지합니다. (nrst = 0 일 때 리셋) 리셋 태스크가없고 송신 모듈이 활성화되면 두 가지 태스크가 완료됩니다 : 1. 상태 전이 태스크 호출 CS_increase는 상태 천이를 실현합니다 .. 2. 상태 레지스터 CS에 따라 송신 레지스터 r_tx_pin과 송신 완료 레지스터 r_txdone에 값을 할당합니다.

상태 레지스터 CS의 각 값은 TX 라인의 각 전송 상태에 해당합니다 .CS = 0이면 시작 비트 전송을 시작 함을 의미합니다.이 때 전송할 데이터를 tx_buf에 채우고 1'b0이 시작 비트이고 tx_data가 데이터입니다. , 2'b11은 1 개의 정지 비트와 1 개의 종료 상태 (또는 정지 비트와 유휴 상태)를 합칠 때 전송되는 데이터입니다.

CS = 10은 정지 비트가 전송 된 후 다음 상태를 의미하며, 이때 tx 라인은 유휴 상태로 들어가 정지 비트처럼 1을 전송합니다. 이때 전송 완료 플래그 r_txdone은 1로 설정됩니다. (다음 맨 위 파일에서 전송 완료 플래그가 1로 설정되면 tx_en이 비활성화되어 상태 레지스터 CS를 전송할 수 없게됩니다. 달성 된 효과는 r_tx_pin <= 1'b1, 즉, tx 라인 고정 출력 1)입니다.

//驱动输出声明
assign tx_pin = r_tx_pin;
assign tx_done = r_txdone;

endmodule // uart_tx

마지막으로 출력 레지스터가 출력 네트워크로 구동되고 송신 모듈 정의가 완료됩니다.

3. 테스트 파일 작성, VCS 시뮬레이션 테스트

1. 테스트 파일 작성 : 클럭 생성, 활성화 신호 관리 및 전송 포함

새 uart_tb.v 파일 생성

`timescale 1ns/1ps

module uart_tb();
reg nrst;
reg clk;

reg en_tx;
reg [7:0] tx_data;
wire tx_pin,tx_done;
reg [7:0]tx_cnt;

//实例化
uart_tx uart_tx(
    .clk(clk),
    .nrst(nrst),
    .tx_en(en_tx),
    .tx_data(tx_data),
    .tx_pin(tx_pin),
    .txdone(tx_done)
);

테스트를위한 uart_tb 모듈을 정의하고, 관련 신호를 정의하고, uart_tx 모듈을 인스턴스화합니다.

//产生125Mhz的时钟
initial begin
    clk = 0;
    forever begin
        #4;
        clk = ~clk; 
    end
end

initial begin
    en_tx = 0;
    tx_data = 8'b0;
    tx_cnt = 'd0;
    nrst = 1;
    #100;
    nrst = 0;//复位信号
    #103;
    nrst = 1;

    tx_data = 'd64;
end

125MHz 클록 생성 및 각 신호의 값 초기화

//产生循环发送的信号
always @(negedge clk) begin
    if (nrst) begin
        if (tx_done) begin
            if (en_tx)//刚刚发送完成
                en_tx <= 1'b0;
            else begin//发送完成一段时间
                if (tx_cnt == 'd250) begin
                    tx_cnt <= 'd0;
                    en_tx <= 1'b1;//重启发送
                end
                else
                    tx_cnt <= tx_cnt + 1'b1;
            end
        end
        else begin
            en_tx <= en_tx;
            tx_cnt <= tx_cnt;
        end
    end
end

endmodule // usart_tb

tx_done이 high로 설정되면 전송이 완료되고 en_tx가 비활성화됨을 의미합니다. 그런 다음 tx_cnt를 사용하여 카운트하고 일정 시간 후에 en_tx를 다시 활성화하고 새 프레임 전송을 시작합니다.

2. VCS 시뮬레이션

uart_tx.v 및 uart_tb.v 파일을 같은 폴더에 넣고 디렉토리 경로에서 터미널을 열고 vcs -full64 * .v -debug_all 명령을 사용하여 컴파일합니다.

그런 다음 ./simv -gui 명령을 사용하여 GUI 그래픽 인터페이스를 열고 시뮬레이션을 위해 오실로스코프에 관련 신호를 추가합니다. 

시뮬레이션 파형은 그림과 같습니다. 빨간색 라인에서 tx_done 신호는 상승하고 en_tx 신호는 하강합니다. 카운터에서 계수 한 기간이 지나면 en_tx가 다시 High로 설정됩니다.

추천

출처blog.csdn.net/a1254484594/article/details/100190162