Home » Post » FPGA » UART Module Testbench Verilog로 다뤄보기

UART Module Testbench Verilog로 다뤄보기

UART Module Testbench 살펴보기

목차

  1. UART verilog Testbench 살펴보기(현재 포스팅)
  2. UART Tx Verilog Module 살펴보기
  3. UART Rx Verilog Module 살펴보기
  4. APB Bus 살펴보기
  5. APB Register 설계하기
  6. Vivado UART 모듈 설정 하기
  7. Xilinx Zynq Firmware Code 짜보기

UART Module Testbench Intro

UART Module Testbench 를 먼저 들여다보고 각 모듈을 보는 것을 이번 프로젝트 목표로 한다.

이번에서 다룰 코드는 아래 링크에서 참고가 가능하다.

https://github.com/dk-min/verilog_study/tree/master/05.UART

해당 깃허브 코드를 보면 알 수 있듯이, nandland의 코드를 icarus verilog로 구동될 수 있게 약간 수정한 정도밖에 안된다.
이번에는 UART 모듈을 다루고, 상세 코드를 리뷰하는 식으로 기술할 예정이다.

과거에 UART Module 에 대한건 여러번 다룬 적이 있다. 아래와 같은 링크가 대표적인 예시이다.

https://dkeemin.com/stm32f0xx-uart-cubemx%eb%a1%9c-%ec%84%a4%ec%a0%95%ed%95%98%ea%b8%b0/

이건 다만 펌웨어 단계에서 봤을 때 그런거고, 실제로 UART Module 이 어떤 파형이 나와야 하고, 통신을 시작하는 시점이 언제인지 파악하는 것은 별개의 일이다.
그래도 UART Module 이 어떤 동작을 하는 놈인지, 통신 규칙이 어떻게 되는지 파악하는 것은 위 링크와 구글링을 통해서 파악할 것을 권장한다.

하드웨어 관점에서 UART 보기

이번 기회에 UART 파형을 볼 일이 있었는데, nandland의 블로그를 퍼왔다.

UART Module Serial Data Stream

맨 처음에는 UART 통신을 하지 않을 경우 데이터 라인은 HIGH로 유지가 되고 있다가, 1bit Low로 내려가고, 그다음에 데이터 8비트를 보낸 뒤, HIGH로 올려주면 되는 식이다. 그전 블로그에서도 다룬 것처럼 패리티비트는 사용하지 않는다고 가정한다.

Async 통신이므로, 보내는 쪽과 받는 쪽의 속도를 정해야하고(9600, 115200 baud rate 등등..) 그거에 맞게 데이터를 보내주면 되는 식인거다.
이번 예제에서는 CPU, 혹은 버스의 clk이 25MHz, 보내는 통신 속도가 115200이라고 가정하고 프로젝트가 진행되었다. 그럼 테스트 벤치가 어떻게 되어 있는지 보자.

UART Module 에는 Rx와 Tx가 있고, 이번 테스트 벤치에서는 Tx가 Rx로 임의의 데이터를 보냈을 때 잘 수신되었는지를 확인하는 예제가 되겠다.

UART Module Testbench Code Review

module UART_TB ();

  // Testbench uses a 25 MHz clock
  // Want to interface to 115200 baud UART
  // 25000000 / 115200 = 217 Clocks Per Bit.
  parameter c_CLOCK_PERIOD_NS = 40;
  parameter c_CLKS_PER_BIT    = 217;

UART Module Testbench 에서 25MHz로 동작할 때 115200의 속도로 보내려고 하면 한 비트당 217의 사이클이 필요한 점을 눈여겨 볼 필요가 있다. clk이 변경되거나 baudrate가 변경된다면 UART Module 에서 설정해야하는 parameter value도 달라져야한다.

UART Rx, Tx Instance
UART Rx, Tx Instance

각 인스턴스에서는 테스트벤치에서 정의한 parameter가 입력으로 들어가고, 이는 c_CLKS_PER_BIT를 다른 값으로 지정할 경우 해당 instance 내부 parameter도 변경될 수 있음을 알 수 있다. 각 인스턴스는 보내거나 받는 데이터가 유효한지 알려주는 DV(Data Valid)가 있다.
해당 코드에서는 이에 대한 설명이 없는데, 나중에 bus를 포스팅하면 다뤄보겠다.

  // Keeps the UART Receive input high (default) when
  // UART transmitter is not active
  assign w_UART_Line = w_TX_Active ? w_TX_Serial : 1'b1;
    
  always
    #(c_CLOCK_PERIOD_NS/2) r_Clock <= !r_Clock;

위에 있는 assign 코드는 Tx가 동작 중이라는 신호를 Tx 인스턴스에서 발생하면 Tx 시리얼 데이터를 보내고 아니면 HIGH로 유지시키는데, 이는 UART Module Serial Data Stream 그림을 보면 그 이유를 쉽게 알 수 있다. Tx 인스턴스에서 보증할 수 있는 데이터가 아니면 동작하는 상태가 아니므로, HIGH로 유지시켜줘야 하기 때문이다.

그 밑에 있는 always 문은 clk generator라고 보면 될 것이다.

UART Module Testbench Code
UART Module Testbench Code

테스트 벤치에서 테스트 하는 방법을 서술해놓았다. Task로 만들어서 처리하는 것과 비슷하다. (별도의 verilog 파일을 만들어서 task를 만들어서 관리해도 된다는 뜻)
TX에서 보낼 임의의 데이터를 보내면서 DV를 high로 놓고, 그 다음 clk에서 low로 보낸 뒤, Rx 인스턴스에서 DV와 함께 값을 뱉으면 그 값이 보낸 값과 같은지를 보는 식이다.

UART Module Testbench dump waveform in GTKWave
UART Module Testbench dump waveform in GTKWave

결과 Waveform이 위와 같은데, 윈도우에서 대충 굴려봐서 그런건지 GTKWave가 좀 많이 버벅인다.
그래서 나중에 WSL 같은걸로 구현해보고 확인해봐야 할 것 같긴한데.. 그건 나중에 한번 시도해 보겠다.

일단 이번 포스팅은 이정도로 하고, 각 모듈 구성이 어떻게 되어 있는지는 다음 포스팅에서 다루겠다.

어쩌다보니 UART Module Testbench가 되어 버렸다.ㅎㅎ

댓글 남기기

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.