Notice
Recent Posts
Recent Comments
Link
관리 메뉴

거북이처럼 천천히

Verilog RTL 설계(7월 17일 - 5, Advanced Clock Mode - 2) 본문

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 17일 - 5, Advanced Clock Mode - 2)

유로 청년 2024. 7. 20. 22:17

1. Set 모드에서 시간을 설정한 뒤, 다시 Watch 모드로 가면 초와 분이 동기화되지 않는다.

 

1.1 문제 현상

  • Set 모드에서 시간을 세팅한 뒤, 다시 Watch 모드로 돌아가 시계로서 동작하면 초와 분 값이 동기화 되지 않고, 개별적으로 동작하는 문제점이 발생한다.
  • ex) 아직 59초에서 60초로 넘어가지 않았음에도 분 값이 증가하거나 59초에서 60초로 넘아갔음에도 분 값이 증가하지 않는다.

 

1.2. 문제의 원인

  • Set 모드로 돌아 왔을 경우, 분을 BCD 60진 카운터에서 기준 펄스가 되는 clk_min이 멈춰야 하지만, 멈추지 않고, 계속해서 진행하여 모드와 상관없이 계속해서 clk_min 기준 펄스가 Counting하다가 60초 되는 순간 One Cycle Pulse를 발생시켜 분 값을 증가 시키게 된다.
  • 예를 들어 설명하면 좀 더 이해하기 쉽다.
    - 시계가 0분 3초까지 출력한 뒤, Set mode에 들어 갔으면 분(minute)의 카운트는 멈춰야 한다.
    - 하지만, 분의 카운트는 멈추지 않고, 4초, 5초, 6초 .... 처럼 계속 카운트 된다.
    - 그리고, Set mode에서 10초 동안 대기한 뒤, 다시 Watch mode로 돌아오게 되면 이미 분의 카운터는 13까지 카운트한 상태이게 된다.
    - 따라서 초 값이 50되었을 때, 아직 59초에서 60초로 넘어 가지 않았음에도 분 값은 1씩 증가하게 된다.
    - 반대로 초 값이 59초에서 60초로 증가했음에도 분 값은 변화하지 않는다.

 

 

1.3. 문제 해결 방법

  • Watch mode에서 Set mode로 돌아갔을 때, 분의 카운트를 멈추면 문제를 해결 할 수 있다.
  • 따라서 1초를 주기로 갖는 Pulse Wave(clk_sec)를 1000분주하여 1분을 주기로 갖는 Pulse Wave(clk_min)을 생성하는  코드를 다음과 같이  수정함으로서 해결할 수 있다.

< 코드 수정 전 >

clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(clk_sec), .prescale(60), .clk_div_n(clk_min));

 

< 코드 수정 후 >

clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(inc_sec), .prescale(60), .clk_div_n(clk_min));

 

  • clk_sec 펄스 대신 inc_sec 펄스를 수정하였다.
  • 따라서 Set mode에서는 분 카운팅은 second button의 One Cycle Pulse인 btn_sec가 활성화 될 때만 카운팅하며, Watch mode에서는 주기가 1인 펄스파, clk_sec에 따라 카운팅할 수 있다.

 

 

1.4. 구현 영상

 

 

 

 

 

 

 

 

 

 

2. 초 값이 30초 이상일 때, btn_set 버튼을 누를 때마다 분 값이 1씩 증가한다.

 

 

2.1 문제 현상

  • 초 값이 30초 이상일 때, btn_set 버튼을 누를 때마다 분 값이 1씩 증가한다. 
  • 다음 영상를 통해 초 값이 30초 이상일 때, btn_set 버튼을 누를 때마다 분 값이 증가함을 확인할 수 있다.
  • chattering 문제 때문에 초 값이 증가하는 현상은 현재는 제외하며, 나중에 해결하자.

 

 

 

 

 

2.2. 문제의 원인

  • 문제의 현상인 "초 값이 30초 이상일 때"를 주의 깊게 생각하고, 다음 코드를 보자.
assign inc_min = (set_watch)? btn_min : clk_min;
  • clk_min 펄스파는 주기가 1min이며, Duty cycle이 50%인 펄스 파형이다.
  • 0 ~ 29초에서는 Low-Level, 30 ~ 59초에서는 High Level 값을 갖기 때문에 따라서 문제가 되는 30초 이상에서는 clk_min 값은 1을 갖는다, 
  • 이러한 상태에서 btn_set 버튼을 누른다면 set_watch 값이 변화하면서 inc_min 의 값은 clk_min 펄스파에서 btn_min 펄스파를 갖게 될 것이다.
  • 하지만, 아직 btn_min 버튼을 누르지 않은 상태이기 때문에 초 값이 30초 이상에서 inc_min 변수의 값은 1에서 0으로 바뀌게 될 것이다. 이 때, inc_min 변수 값이 1에서 0으로 바뀌면서 Negative edge를  발생 시켰다.
bcd_60_counter counter_min(.clk(clk), .reset_p(reset_p), .clk_source(inc_min), .bcd1(min_1), .bcd10(min_10));
  • inc_min 값에서 Negative edge가 발생하여 BCD 60 Counter는 이를 받아 분 값을 1씩 증가하게 되는 것이다.
  • 이는 의도된 Negative edge가 아닌 초 값이 30초 이상인 상태에서 clk_min 펄스 값이 1이여서 발생한 Negative edge이다.

 

 

 

2.3. 문제 해결 방법

  • 문제의 원인은 초 값이 30초 이상인 상태에서 clk_min 펄스 값이 1인 상태에서 mode의 변화가 생겨 inc_min 변수의 값이 1 → 0 으로 변화하여 Negative edge가 발생한 것이다.
  • 이를 해결하는 방법은 clk_min 펄스파가 1인 상태를 갖는 시간을 최대한으로 줄여주는 것이며, 이에 적합한 펄스파가 바로 " clk_min 펄스 파의 One Cycle Pulse"이다. 
  • BCD 60진 Counter는 외부로 부터 입력 받은 데이터의 One Cycle Pulse가 활성화 되었을 때, 카운트 할 뿐, 1 값인 상태에서 얼마만큼 유지되는지 여부는 중요하지 않다.
  • 따라서 다음과 같이 코드를 수정함으로서 문제를 해결 할 수 있다.

< 코드 수정 전 >

clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(inc_sec), .prescale(60), .clk_div_n(clk_min));

 

< 코드 수정 후 >

clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(inc_sec), .prescale(60), .clk_div_n_nedge(clk_min));
  • 코드 수정 이전에는 clk_min 변수는 Duty Cycle이 50%이고, 주기가 1min인 펄스파를 가졌다.
  • 하지만, 코드 수정 이후에는 clk_min 변수는 주기가 1min인 One Cycle Pulse를 갖는다.
  • 따라서 clk_min이 1인 상태가 고작 10ns에 불과하기 때문에 btn_set 버튼을 눌러 분 값이 증가할 확률은 대단히 줄어든다.
  • 물론, 매우 적은 확률로 One Cycle Pulse가 활성화 되었을 때, 버튼을 누를 경우 분 값이 증가할 수 있지만, 이는 대단히 매우 적은 확률이기 때문에 무시할 수 있다.

 

 

 

2.4. 구현 영상