[2024.06.10.월] 인천인력개발원 하만 세미콘 아카데미
실습 1: UART_TX 설계
- 위 그림에 맞게 TX의 Input, Output 설정
module uart_tx( input RST, input CLK, input [7:0] DIN, input START, output reg TXD );
- 각 상태를 나타내는 idle, start, tx_send, stop을 local parameter로 선언하여 갑 지정 후 register와 wire 선언
localparam [1:0] idle = 2'b00, start = 2'b01, tx_send = 2'b10, stop = 2'b11; reg [1:0] curr_state, next_state; reg [3:0] over_sample_cnt; reg [3:0] bit_cnt; wire over_sample_cnt_done, bit_cnt_done; wire parity; reg [7:0] tx_data_in; wire [8:0] tx_data = {parity, tx_data_in}; wire baud_x16_en;
- 1clk마다 tx_data_in에 DIN을 넣어주고, 상태를 다음 상태로 변경하는 코드 작성
always @(posedge CLK) if(START) tx_data_in <=DIN; //1clk마다 다음 상태로 넘어가는 코드 always @(posedge CLK) begin if(RST) //RST이 1이면 초기 상태로 복귀 curr_state <= idle; else //RST이 0이면 1CLK마다 next_state로 curr_state 변경 curr_state <= next_state; end
- fsm 작동 코드 작성
//fsm 구문 always @(curr_state, START, over_sample_cnt_done. vit_cnt_done) begin case (curr_state) idle: //idle 상태에서 START가 1이 되면 curr_state를 start로 바꾸어 시작, 아니면 idle 유지 if(START) next_state = start; else next_state = idle; start: //start 상태에서 over_sample_cnt_done이 1이 되면 tx_send 시작, 아니면 start 유지 if(over_sample_cnt_done) next_state = tx_send; else next_state = start; tx_send: //tx_send 상태에서 over_sample_cnt_done과 bit_cnt_done이 모두 1이 되면 stop, 아니면 tx_send 유지 if(over_sample_cnt_done&&bit_cnt_done) next_state = stop; else next_state = tx_send; stop: //stop 상태에서 over_sample_cnt_done이 1이면 idle로 상태 복귀, 아니면 stop 유지 if(over_sample_cnt_done) next_state = idle; else next_state = stop; default: next_state = idle; endcase end
- over sample count 생성 코드 작성
//over_sample_cnt 생성 always @(posedge CLK) if(curr_state == idle) over_sample_cnt <= 5'd15; else if (baud_x16_en) over_sample_cnt <= over_sample_cnt-1; assign over_sample_cnt_done = (over_sample_cnt == 4'd0) & baud_x16_en;
- bit count 생성 코드 작성
//bit_cnt 생성 always @(posedge CLK) if(curr_state != tx_send) //tx_send 상태가 아니라면 bit_cnt <= 4'd0; else if(over_sample_cnt_done) bit_cnt <= bit_cnt+1; assign bit_cnt_done = over_sample_cnt_done & (bit_cnt == 4'd8);
- parity 생성 및 TXD(parallel -> serial) 코드 작성
//partiy 생성 assign parity = ^tx_data[7:0]; //parallel to serial(TXD) always @(curr_state, bit_cnt) if(curr_state == idle || curr_state == stop) TXD = 1'b1; else if(curr_state == start) TXD = 1'b0; else TXD = tx_data[bit_cnt];
- baud_gen 인스턴스화
//instantiation uart_baud_gen uart_baud_gen baud_gen_i0 ( .RST (RST), .CLK (CLK), .BAUD_X16_EN (baud_x16_en) );
실습 2: UART_TX Debug
1. Constraint 파일의 debug.xdc 내용 삭제
2. Uart_tx 모듈의 debug 할 신호를 mark debug
3. 포트 설정(constraints - uart_pin.xdc파일 편집)
- set_property IOSTANDARD LVCMOS33 [get_ports TXD]
- set_property PACKAGE_PIN K18 [get_ports TXD]
4. Run Synthesis - Open Synthesized Design - Layout Debug로 정의된 신호 확인
5. Setup Debug
6. Synthesized Design 종료 및 저장
7. Run Implementation - Generate Bitstream - Teraterm으로 확인
uart_top.v 전체 코드
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/05/24 12:25:55
// Design Name:
// Module Name: uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_top(
input RST,
input CLK,
input RXD,
output TXD
);
wire [7:0] rx_data;
wire empty, rx_data_rdy;
reg [7:0] dout;
wire [7:0] dout_reg;
always @(posedge CLK)
begin
if(!empty)
dout <= dout_reg;
end
uart_rx uart_rx_0 (
.RST (RST),
.CLK (CLK),
.RXD (RXD),
.RX_DATA (rx_data),
.RX_DATA_RDY (rx_data_rdy),
.FRM_ERR (FRM_ERR),
.PARITY_ERR (PAR_ERR)
);
my_fifo fifo_0(
.RST (RST),
.CLK (CLK),
.DIN (rx_data),
.WR_EN (rx_data_rdy),
.FULL (FULL),
.DOUT (dout_reg),
.RD_EN (~empty),
.EMPTY (empty)
);
//uart_tx instantiation
uart_tx uart_tx_0 (
.RST (RST),
.CLK (CLK),
.START (~empty),
.DIN (dout),
.TXD (TXD)
);
endmodule
uart_tx.v 전체 코드
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/06/10 09:42:17
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_tx(
input RST,
input CLK,
(* mark_debug = "true" *)
input [7:0] DIN,
(* mark_debug = "true" *)
input START,
(* mark_debug = "true" *)
output reg TXD
);
localparam [1:0] idle = 2'b00,
start = 2'b01,
tx_send = 2'b10,
stop = 2'b11;
(* mark_debug = "true" *)
reg [1:0] curr_state;
reg [1:0] next_state;
(* mark_debug = "true" *)
reg [3:0] over_sample_cnt;
(* mark_debug = "true" *)
reg [3:0] bit_cnt;
(* mark_debug = "true" *)
wire over_sample_cnt_done, bit_cnt_done;
(* mark_debug = "true" *)
wire parity;
(* mark_debug = "true" *)
reg [7:0] tx_data_in;
wire [8:0] tx_data = {parity, tx_data_in};
wire baud_x16_en;
always @(posedge CLK)
if(START)
tx_data_in <=DIN;
//1clk마다 다음 상태로 넘어가는 코드
always @(posedge CLK) begin
if(RST) //RST이 1이면 초기 상태로 복귀
curr_state <= idle;
else //RST이 0이면 1CLK마다 next_state로 curr_state 변경
curr_state <= next_state;
end
//fsm 구문
always @(curr_state, START, over_sample_cnt_done. vit_cnt_done)
begin
case (curr_state)
idle: //idle 상태에서 START가 1이 되면 curr_state를 start로 바꾸어 시작, 아니면 idle 유지
if(START)
next_state = start;
else
next_state = idle;
start: //start 상태에서 over_sample_cnt_done이 1이 되면 tx_send 시작, 아니면 start 유지
if(over_sample_cnt_done)
next_state = tx_send;
else
next_state = start;
tx_send: //tx_send 상태에서 over_sample_cnt_done과 bit_cnt_done이 모두 1이 되면 stop, 아니면 tx_send 유지
if(over_sample_cnt_done&&bit_cnt_done)
next_state = stop;
else
next_state = tx_send;
stop: //stop 상태에서 over_sample_cnt_done이 1이면 idle로 상태 복귀, 아니면 stop 유지
if(over_sample_cnt_done)
next_state = idle;
else
next_state = stop;
default: next_state = idle;
endcase
end
//over_sample_cnt 생성
always @(posedge CLK)
if(curr_state == idle)
over_sample_cnt <= 5'd15;
else if (baud_x16_en)
over_sample_cnt <= over_sample_cnt-1;
assign over_sample_cnt_done = (over_sample_cnt == 4'd0) & baud_x16_en;
//bit_cnt 생성
always @(posedge CLK)
if(curr_state != tx_send) //tx_send 상태가 아니라면
bit_cnt <= 4'd0;
else if(over_sample_cnt_done)
bit_cnt <= bit_cnt+1;
assign bit_cnt_done = over_sample_cnt_done & (bit_cnt == 4'd8);
//partiy 생성
assign parity = ^tx_data[7:0];
//parallel to serial(TXD)
always @(curr_state, bit_cnt)
if(curr_state == idle || curr_state == stop)
TXD = 1'b1;
else if(curr_state == start)
TXD = 1'b0;
else
TXD = tx_data[bit_cnt];
//instantiation uart_baud_gen
uart_baud_gen baud_gen_i0 (
.RST (RST),
.CLK (CLK),
.BAUD_X16_EN (baud_x16_en)
);
endmodule
uart_pin.xdc
더보기
set_property IOSTANDARD LVCMOS33 [get_ports CLK]
set_property IOSTANDARD LVCMOS33 [get_ports RST]
set_property IOSTANDARD LVCMOS33 [get_ports RXD]
set_property IOSTANDARD LVCMOS33 [get_ports TXD]
set_property IOSTANDARD LVCMOS33 K18 [get_ports TXD]
set_property PACKAGE_PIN H16 [get_ports CLK]
set_property PACKAGE_PIN D19 [get_ports RST]
set_property PACKAGE_PIN J18 [get_ports RXD]
set_property PACKAGE_PIN K18 [get_ports TXD]