Project - TIM peripheral

Shaaqq·2023년 10월 21일
0

프로젝트(반도체)

목록 보기
3/4
post-thumbnail

▋ 개요

프로젝트명 : PWM 생성기
기획 및 제작 : 박순창
분류 : 메인 프로젝트 (개인)
시작/제작 기간 : 23.10.00 ~ 23.10.00 (1일)
진행상태: 스펙 정의 - 기능 검증 - RTL 생성 - 시뮬레이션 진행중 - 합성 및 배선
사용 툴: Vivado, Xcelium, Genus, Innovus
사용 도구: FPGA


▋ 설명

▶ 개발 동기

▶ 스펙

TIMER 구조

clk: 메인 클럭
50mhz

prescaler: 분주기
클럭을 나누는 역할
빠른 메인 클럭을 내려줄수 있음

50mhz / 1000 = 50khz
50khz마다 한번 카운트

counter mode: 카운터 상승/하강 선택

counter period: 카운터 주기 선택
주기를 1000으로 하면
50khz /1000 = 50hz
50hz마다 카운터가 초기화됨
상한선 같은 의미
카운터가 999가 넘어가면 다시 카운터가 0으로 돌아가고 이 상황을 반복

PWM: 일정 카운터에서 작동
주기를 100%로 잡았을 때

auto-reload preload : PWM 신호를 계속 반복해서 생성하고 싶으면 Enable, 아니면 Disable

  • 메모리 맵을 만들어 timer 제작
  • 메모리맵의 데이터에 따라 동작 변경
  • 기본 TIM clk를 내보내며 CH을 사용하여 PWM, Output compare 사용 가능

내부 구조

  • Baudrate Generator

▶ 메모리맵 구조

memory map
Address : 0000_0100 ~ 32'h0000_0108

1) ADDR_DATA [0000_0100]

  • reserved (dummy register)

2) ADDR_DATA [0000_0101]

  • Prescaler register
  • reserved(16bit) + register(16bit)

3) ADDR_DATA [0000_0102]

  • Counter_Period_register
  • (32bit)

4) ADDR_DATA [0000_0103]

  • CH1~4 mode select
  • reserved(16bit) + register(16bit)
  • 4bit씩 mode select
  • 4'b0000 = pwm mode, 4'b0001 = oc, 그외: function off

5) ADDR_DATA [0000_0104]

  • CH1 Pulse

6) ADDR_DATA [0000_0105]

  • CH2 Pulse

7) ADDR_DATA [0000_0106]

  • CH3 Pulse

8) ADDR_DATA [0000_0107]

  • CH4 Pulse

9) ADDR_DATA [0000_0108]

  • reserved (dummy register)

    /
    ADDR_DATA[32'h0000_0100] : x
    ADDR_DATA[32'h0000_0101] : Prescaler register 16bit
    ADDR_DATA[32'h0000_0102] : Counter_Period_register 32bit
    ADDR_DATA[32'h0000_0103] : CH1~4 mode select
    ADDR_DATA[32'h0000_0104] : CH1 Pulse
    ADDR_DATA[32'h0000_0105] : CH2 Pulse
    ADDR_DATA[32'h0000_0106] : CH3 Pulse
    ADDR_DATA[32'h0000_0107] : CH4 Pulse
    ADDR_DATA[32'h0000_0108] : x
    /

▶ 블록도


▋Code

  • TIM_TOP.v
`timescale 1ns/1ps

module TIM_TOP #(parameter BIT_NUM = 32, parameter CHANNEL_NUM = 4) (
    input mclk,
    input rst,
    input [BIT_NUM-1:0] TIM_ADDR,
    input [BIT_NUM-1:0] TIM_DATA,
    input en,
    output reg prescaler_clk,
    output reg counter_period_clk,
    output wire [3:0] pin_out);
    

    reg [BIT_NUM-1 : 0] ADDR_DATA [32'h0000_0100 : 32'h0000_0108];
  
    wire [15:0] prescaler_val;
    wire [31:0] counter_period_val;
    wire [15:0] TIM_CH_mode_val;
    reg [15:0] prescaler_cnt;
    reg [31:0] counter_period_cnt;
    wire [31:0] pulse [0:3]; 
    reg [3:0] CH_wire;
    wire [3:0] CH_PWM;
    wire [3:0] CH_OC;

    TIM_CH TIM_CH1 (.cp_clk(counter_period_clk), .rst(rst), .pulse(pulse [0]), .cp_val(counter_period_val), 
                    .pwm_out(CH_PWM[0]), .oc_out(CH_OC[0]));
    TIM_CH TIM_CH2 (.cp_clk(counter_period_clk), .rst(rst), .pulse(pulse [1]), .cp_val(counter_period_val), 
                    .pwm_out(CH_PWM[1]), .oc_out(CH_OC[1]));
    TIM_CH TIM_CH3 (.cp_clk(counter_period_clk), .rst(rst), .pulse(pulse [2]), .cp_val(counter_period_val), 
                    .pwm_out(CH_PWM[2]), .oc_out(CH_OC[2]));
    TIM_CH TIM_CH4 (.cp_clk(counter_period_clk), .rst(rst), .pulse(pulse [3]), .cp_val(counter_period_val), 
                    .pwm_out(CH_PWM[3]), .oc_out(CH_OC[3]));

    assign prescaler_val = ADDR_DATA[32'h0000_0101] [15:0];
    assign counter_period_val = ADDR_DATA[32'h0000_0102] [31:0];
    assign TIM_CH_mode_val = ADDR_DATA[32'h0000_0103] [15:0];
    assign pulse [0] [31:0] = ADDR_DATA[32'h0000_0104] [31:0];
    assign pulse [1] [31:0] = ADDR_DATA[32'h0000_0105] [31:0];
    assign pulse [2] [31:0] = ADDR_DATA[32'h0000_0106] [31:0];
    assign pulse [3] [31:0] = ADDR_DATA[32'h0000_0107] [31:0];

    assign pin_out = CH_wire;

    always @(*) begin
        case (TIM_CH_mode_val[3:0])
            4'b0001: CH_wire[0] <= CH_PWM[0];   //pwm
            4'b0010: CH_wire[0] <= CH_OC[0];    //output compare    
            default: CH_wire[0] <= 1'bz;        //no output
        endcase
        case (TIM_CH_mode_val[7:4])
            4'b0001: CH_wire[1] <= CH_PWM[1];   //pwm
            4'b0010: CH_wire[1] <= CH_OC[1];    //output compare    
            default: CH_wire[1] <= 1'bz;        //no output
        endcase
        case (TIM_CH_mode_val[11:8])
            4'b0001: CH_wire[2] <= CH_PWM[2];   //pwm
            4'b0010: CH_wire[2] <= CH_OC[2];    //output compare    
            default: CH_wire[2] <= 1'bz;        //no output
        endcase
        case (TIM_CH_mode_val[15:12])
            4'b0001: CH_wire[3] <= CH_PWM[3];   //pwm
            4'b0010: CH_wire[3] <= CH_OC[3];    //output compare    
            default: CH_wire[3] <= 1'bz;        //no output
        endcase
    end

    always @(*) if(en) ADDR_DATA[TIM_ADDR] <= TIM_DATA;

    always @(posedge mclk or posedge rst) begin
        if(rst) begin
            prescaler_cnt <= 16'd0;
            prescaler_clk <= 1'b0;
        end
        else begin
            if(prescaler_cnt == (prescaler_val/2)-1) begin
                prescaler_cnt <= 16'd0;    
                prescaler_clk <= ~prescaler_clk;
            end
            else prescaler_cnt <= prescaler_cnt + 1'b1;
        end
    end

    always @(negedge prescaler_clk or posedge rst) begin
        if(rst) begin
            counter_period_cnt <= 32'd0;
            counter_period_clk <= 1'b0;
        end
        else begin
            if(counter_period_cnt == (counter_period_val/2)-1) begin
                counter_period_cnt <= 32'd0;
                counter_period_clk <= ~counter_period_clk;
            end
            else begin
                counter_period_cnt <= counter_period_cnt + 1'b1;
            end              
        end
    end
endmodule
  • TIM_CH.v
`timescale 1ns/1ps

module TIM_CH (
    input cp_clk,
    input rst,
    input [31:0] pulse,
    input [31:0] cp_val,
    output reg pwm_out,
    output reg oc_out);
    
    reg [31:0] cp_cnt;

    always @(posedge cp_clk or posedge rst) begin
        if(rst) begin
            cp_cnt <= 1'b0;
            pwm_out <= 1'b0;
            oc_out <= 1'b0;
        end
        else begin
            if(cp_cnt == cp_val-1) begin
                cp_cnt <= 1'b0;
                pwm_out <= 1'b0;
            end
            else begin
                cp_cnt <= cp_cnt + 1'b1;
                if(cp_cnt >= pulse-1) pwm_out <= 1'b1;
                if (cp_cnt == pulse-1) oc_out <= 1'b1;
                else oc_out <= 1'b0;
            end              
        end
    end
endmodule
  • TIM_TOP_tb.v
`timescale 1ns/1ps

module TIM_TOP_tb;

    parameter BIT_NUM = 32;
    parameter CHANNEL_NUM = 4;

    reg mclk, rst;
    reg [BIT_NUM-1:0] TIM_ADDR, TIM_DATA;
    reg en;
    wire prescaler_clk, counter_period_clk;
    wire [3:0] pin_out;


    TIM_TOP #(.BIT_NUM (BIT_NUM), .CHANNEL_NUM(CHANNEL_NUM)) 
        tim1 (mclk, rst, TIM_ADDR, TIM_DATA, en, 
              prescaler_clk, counter_period_clk, pin_out);


    always #0.5 mclk <= ~mclk;

    initial begin
        $display("TEST start");
        mclk <= 0; rst <= 0; 
        #10 TIM_ADDR <= 32'h0000_0100; TIM_DATA <= 32'h0000_0000; en <= 1;
        #10 en <= 0;
        #10 TIM_ADDR <= 32'h0000_0101; TIM_DATA <= 32'd20; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0102; TIM_DATA <= 32'd30; en <= 1;
        #10 en <= 0;
        #10 TIM_ADDR <= 32'h0000_0103; TIM_DATA <= 32'h0000_1111; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0104; TIM_DATA <= 32'd5; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0105; TIM_DATA <= 32'd10; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0106; TIM_DATA <= 32'd25; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0107; TIM_DATA <= 32'd29; en <= 1;
        #10 en <= 0; 
        #10 TIM_ADDR <= 32'h0000_0108; TIM_DATA <= 32'h0000_0000; en <= 1;
        #10 en <= 0; $display("check memory register");
        #10 rst <= 1;
        #10 rst <= 0;  
        #300000 $display("%0d, PWM fisnish", $time);
        #10 TIM_ADDR <= 32'h0000_0103; TIM_DATA <= 32'h0000_2222; en <= 1;
        #10 en <= 0; 
        #10 rst <= 1;
        #10 rst <= 0;
        #300000 $display("%0d, OC fisnish", $time);    
        #100 $display("TEST fisnish");
        $finish;
    end
endmodule

▋Test

▶ Simulation

  • Waveform
  • Block Diagram
  • Log

▶ Synthesis

▶ PnR


▋결론


  • Youtube:
  • github:
profile
개인 공부 겸 포트폴리오 사이트

0개의 댓글

관련 채용 정보