2016-07-08 1 views
0

저는 일반적으로 fpgas를 처음 사용합니다. SCK가 상승 에지를 볼 때마다 반복되는 카운터를 만들고 싶습니다. 내 코드에 문제가 있다는 것은 두 번 계산되는 것 같습니다. 상승하는 전환점이있을 때마다 두 개의 LED가 점등됩니다. 단 하나의 LED가 켜지는 것과 반대입니다. 이게 어디에서 오는 것일까?상승 에지 카운터

module spi_slave(pcEn, LED, clk, SCK); 
input clk, SCK; 
output reg pcEn; 
output reg [7:0] LED = 8'h00; 
reg r1 = 0; 
reg r2 = 0; 
reg r3 = 0; 
reg [3:0] cnt = 4'b0000; 

always @(posedge clk) 
begin 

    r1 <= SCK;    
    r2 <= r1; 
    pcEn <= r1 && !r3; 
    if (pcEn == 1) begin 
     cnt = cnt + 4'b0001; 

     if (cnt == 4'b0001) begin 
      LED[0] = 1'b1; 
      end 
     else if (cnt == 4'b0010) begin 
      LED[1] = 1'b1; 
      end 
     else if (cnt == 4'b0011) begin 
      LED[2] = 1'b1; 
      end 
     else if (cnt == 4'b0100) begin 
      LED[3] = 1'b1;  
      end 
     else if (cnt == 4'b0101) begin 
      LED[4] = 1'b1;  
      end 
     else if (cnt == 4'b0110) begin 
      LED[5] = 1'b1; 
      end 
     else if (cnt == 4'b0111) begin 
      LED[6] = 1'b1; 
      end 
     else if (cnt == 4'b1000) begin 
      LED[7] = 1'b1; 
      end 
     else 
      LED = 8'h00; 
     end 
    else 
     #100; 

    r3 <= r2; 
    end 

endmodule 

답변

1

r1 & !r3을 비교하므로 카운터가 두 번 계산됩니다.

r1-> r2-> r3. r1이 1과 같을 때 r3을 설정하려면 2 클럭이 필요합니다. 이는 r1&!r3 조건이 2 클록 동안 유효하게 유지됨을 의미합니다. pcEn은 2 클럭 동안 생성되므로 카운터는 두 번 계산됩니다.

r1 && !r2 또는 지연을 원할 경우 r2 && !r3이 정상적으로 작동합니다.

파형에서이 동작을보고 디버깅 할 수 있어야합니다. 시뮬레이션에서 $dumpvars;을 사용하여 파형을 확인하십시오.

또한 코드를 개선하기 위해 몇 가지 변경 사항이 있습니다.

  1. 리셋의 사용.
  2. 은 일관되게 비 차단 할당을 사용합니다.
  3. # 100 지연이 필요 없습니다. # 지연

    module spi_slave(pcEn, LED, clk, SCK,rst_n); 
    input clk, SCK,rst_n; 
    output reg pcEn; 
    output reg [7:0] LED ; 
    reg r1 ; 
    reg r2 ; 
    reg r3 ; 
    reg [3:0] cnt ; 
    
    always @(posedge clk or negedge rst_n) 
    begin 
    
        if (rst_n == 0) 
        begin 
         r1 <=0 ; 
         r2 <= 0 ; 
         r3 <= 0 ; 
         cnt <= 0 ; 
         LED <=0 ; 
         pcEn <=0 ; 
        end 
        else 
        begin 
         r1 <= SCK; 
         r2 <= r1; 
         r3 <= r2; 
         pcEn <= r2 && !r3; 
         if (pcEn == 1) begin 
          cnt <= cnt + 4'b0001; 
    
          if (cnt == 4'b0001) begin 
           LED[0] <= 1'b1; 
           end 
          else if (cnt == 4'b0010) begin 
           LED[1] <= 1'b1; 
           end 
          else if (cnt == 4'b0011) begin 
           LED[2] <= 1'b1; 
           end 
          else if (cnt == 4'b0100) begin 
           LED[3] <= 1'b1; 
           end 
          else if (cnt == 4'b0101) begin 
           LED[4] <= 1'b1; 
           end 
          else if (cnt == 4'b0110) begin 
           LED[5] <= 1'b1; 
           end 
          else if (cnt == 4'b0111) begin 
           LED[6] <= 1'b1; 
           end 
          else if (cnt == 4'b1000) begin 
           LED[7] <= 1'b1; 
           end 
          else 
           LED <= 8'h00; 
         end 
        end 
    end 
    
    endmodule 
    
1

먼저 그들은 단지 시뮬레이션을위한 지연되어, 합성 수 없습니다.

일반적으로 블록 및 논 블로킹 논리를 다른 항상 블록으로 분리하는 것이 가장 좋습니다. combinational (차단 할당)의 경우 always @*이고 순차적 (차단없는 할당)의 경우 always @(posedge clk)입니다. FYI : Verilog는 코딩 값을 더 쉽게 비교하고 else-if를 중첩하는 case-statements를 지원합니다. 라훌도

always @* begin 
    if (pcEn == 1'b0) begin 
    next_cnt = cnt; 
    next_LED = LED; 
    else begin 
    next_cnt = cnt + 4'b0001; 
    next_LED = 8'h00; // Rest all to 0s 
    if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles 
    case(cnt) 
    4'b0000 : next_LED[0] = 1'b1; 
    4'b0001 : next_LED[1] = 1'b1; 
    // ... 
    4'b0111 : next_LED[7] = 1'b1; 
    endcase 
    end 
end 
always @(posedge clk) begin 
    r1 <= SCK; 
    r2 <= r1; 
    r3 <= r2; 
    pcEn <= r2 && !r3; 
    cnt <= next_cnt; 
    LED <= next_LED; 
end 
을 지적

나는 것은 당신이 r1 && !r3 대신 r2 && !r3을 사용할 수 있습니다