강의

멘토링

커뮤니티

Cộng đồng Hỏi & Đáp của Inflearn

Hình ảnh hồ sơ của rnjstns07212239
rnjstns07212239

câu hỏi đã được viết

Thực hành thiết kế mạch số : Thiết kế Computer Architecture và SoC protocol Digital IP

Bạn đã từng sử dụng Arduino chưa? Thiết kế giao thức truyền thông Serial Interface: I2C + SPI để truyền thông Chip-to-Chip

I2C SCL_Synched, SDA_Synched 질문

Viết

·

72

0

image.png

안녕하세요 코드를 보다 의문점이 들어서 질문 드립니다. input으로 들어오는 SCL 을 그대로 사용하는게 아니라 3단 F/F을 통해 slave 쪽의 clk에 맞춰서 SCL_posedge, SCL_negedge를 사용함으로써 동기화를 하여 Slave의 메인 clk에 맞춰 데이터를 채갈 수 있도록 하는 것은 이해했습니다! 근데 SCL_posedge 및 SCL_negedge 의 경우 '안정화 된' [2:1] 세번째, 두번째 F/F의 결과를 보고 posedge 및 negedge를 출력하기에 SCL은 안정화 된 값을 가지는 것을 이해하엿으나

SDA_synched의 경우 [2:0] 총 3개의 F/F 에 대해 AND 를 취한 결과를 사용하고 있습니다. 이렇게 하게 되면 만약 최악의 경우

SCL_posedge가 '1'이 되었을때

data_in 에다가 SDA_synched의 값을 넣어야 하는데

SCL_posedge가 1이됨과 동시에 SDA_syncehd[2], SDA_syncehd[1] 이 모두 1이고 SDA_synched[0] 이 0에서 1로 바뀌는 중이라면 결국 data_in에 무엇을 저장해야 할 지 몰라서 meta stable 한 상태에 빠질것이라고 생각됩니다.

이를 방지하려면,

wire SDA_synched = SDASynch[2] & SDASynch[1] 로 선언해서 사용해야 하는 것 아닌가요?? 감사합니다.

컴퓨터-구조verilog-hdlfpga임베디드amba

Câu trả lời 1

0

samcoach님의 프로필 이미지
samcoach
Người chia sẻ kiến thức

안녕하세요, 답변 남겨드립니다.

 

1. 이 코드에서 값이 언제 / 어떻게 보이는지

핵심 포인트 하나만 잡고 가면 됩니다:

always @(posedge clk)
    SCLSynch <= {SCLSynch[1:0], SCL};

always @(posedge clk)
    SDASynch <= {SDASynch[1:0], SDA};

여기서 <=논블로킹 할당이라서,

  • posedge clk 순간에

    • 레지스터 내부 값은 새 값으로 캡처되지만,

    • 클럭에서 조합논리(wire) 가 보는 값은 직전 클럭에 있던 값입니다.

즉,

  • SCL_posedge 는 “직전 클럭까지의 SCLSynch[2:1]”을 보고 계산되고,

  • SDA_synched 도 “직전 클럭까지의 SDASynch[2:0]”을 보고 계산됩니다.

  • 그리고 상태머신이나 data_in 레지스터는 그 두 신호를 보고 같은 posedge clk 에서 동작합니다.

그래서 질문하신 것처럼

“SCL_posedge가 1이 되는 바로 그 순간 SDASynch[0]이 0→1로 바뀌는 중이라서 둘이 섞여서 메타가 되는 것 아닌가요?”

라는 상황은 시간축 상으로 동시에 관측되지 않습니다.

  • SCL_posedge == 1 이라는 사실은 “한 클럭 이전까지 이미 결정돼 있던 SCLSynch[2:1]의 패턴” 때문이고,

  • 이번 클럭에서 막 metastable 이 되는 건 SCLSynchSDASynch의 “새 값”인데,

  • 그 “새 값”은 다음 클럭에서야 SCL_posedge / SDA_synched 계산에 쓰입니다.


2. metastability 자체는 어디서 생기고 어떻게 처리되나

진짜 메타가 생길 수 있는 곳은 여기뿐입니다:

always @(posedge clk)
    SDASynch[0] <= SDA;   // 비동기 입력을 첫 FF가 샘플링
  • SDA가 clk의 setup/hold 타이밍 근처에서 바뀌면 SDASynch[0]은 metastable 이 될 수 있습니다.

  • 하지만 한 클럭 주기 동안 시간이 지나면서 대부분 0 또는 1로 수렴하고,

  • 다음 클럭에서 SDASynch[1]가 그 값을 받고, 또 그 다음 클럭에서 SDASynch[2]가 받습니다.

그래서:

  • “아날로그적으로 애매한 중간값”이 조합로직을 타고 data_in까지 그대로 퍼지는 구조는 아니고,

  • 결국은 0 또는 1로 결정된 값만 논리 AND에 들어갑니다.

  • 문제가 될 수 있는 건 “언제 샘플링했느냐(타이밍)”이지,
    data_in이 ‘메타 상태 그 자체’를 받는 건 아닙니다.

3단 동기화 체인을 쓰는 이유는

  • metastability가 다음 스테이지까지 살아남을 확률을 쭉 떨어뜨리고,

  • 동시에 아주 짧은 글리치/스파이크도 여러 클럭 동안 반복되지 못하게 해서
    노이즈 필터 역할도 하려는 겁니다.


3. SCL_posedge 의 타이밍을 말로 풀어보기

SCL이 실제 버스에서 0에서 1로 올라갔다고 생각해봅시다.

SCLSynch는 매 클럭마다 오른쪽에서 SCL을 하나씩 밀어넣는 구조라서,
클럭이 지날 때마다 대략 이런 식으로 변합니다 (숫자 대신 말로 설명):

  1. 처음에는 SCLSynch가 예를 들어 000 이었다고 합시다. (SCL도 0)

  2. 버스에서 SCL이 1로 바뀐다.

  3. 다음 clk 엣지에서 SCLSynch001 이 된다.
    이때 상위 두 비트는 00 이므로 SCL_posedge는 아직 0.

  4. 그 다음 clk 엣지에서 SCLSynch011 이 된다.
    이제 상위 두 비트 2:101 패턴이므로, 이 클럭에서 SCL_posedge가 1이 된다.

  5. 또 한 번 지나면 SCLSynch111 이 되고, 상위 두 비트는 11 이므로 다시 SCL_posedge는 0.

즉:

  • 실제 SCL이 1이 된 뒤, 최소 두 번의 clk를 거쳐야만 SCL_posedge가 1로 올라옵니다.

  • I²C 규격상 SDA는 SCL rising 전에 어느 정도 setup time을 가져야 하기 때문에,
    내부 clk 기준으로 보면 우리가 데이터를 샘플하는 시점(SCL_posedge==1)에는 SDA가 굉장히 오래 전에 이미 안정적이었어야 합니다.


4. SDA_synched = [2] & [1] & [0] 이 의미하는 것

SDA도 똑같은 식으로 밀어 넣습니다.

SDA가 0에서 1로 바뀌었다고 해볼게요.

  1. 처음에는 SDASynch000.

  2. SDA가 1로 바뀐다.

  3. 첫 번째 clk 이후: 001.
    세 비트 AND는 아직 0.

  4. 두 번째 clk 이후: 011.
    세 비트 AND는 아직 0.

  5. 세 번째 clk 이후: 111.
    이때 비로소 세 비트 AND가 1이 된다.

즉,

  • SDASynch[2] & SDASynch[1] & SDASynch[0] 이 1이 되려면
    SDA가 최소 3클럭 동안 연속으로 1 이어야 합니다.

질문에서 제안하신

wire SDA_synched = SDASynch[2] & SDASynch[1];

로 바꾸면,

  • SDA가 1로 바뀌고 2클럭 연속 1일 때 1이 됩니다.

  • 그러니까 한 클럭 더 빨리 반응하는 대신, 필터링은 조금 약해집니다.

metastability 관점에서는

  • 둘 다 “이전 클럭까지의 레지스터 값”을 보기 때문에

  • 어떤 쪽도 “막 메타가 된 비트와 조합돼서 알 수 없는 상태로 가는” 위험성은 비슷합니다.

  • 차이는 “몇 클럭 연속 같은 값이어야 신뢰하겠냐” 라는 필터 강도입니다.


5. SCL_posedge 와 SDA_synched 을 같이 쓰는 순간

일반적인 슬레이브 수신부는 보통 이렇게 씁니다:

always @(posedge clk) begin
    if (SCL_posedge)
        data_in <= {data_in[6:0], SDA_synched};
end

이때도

  • SCL_posedgeSDA_synched 모두
    이번 클럭에서 갱신되기 “직전”의 SCLSynch/SDASynch 값에 의해 결정됩니다.

  • 이번 클럭에서 막 metastable 이 된 SDASynch[0]의 상태는
    아직 SDA_synched 계산에 사용되지 않습니다.
    그건 다음 클럭에서야 반영됩니다.

그래서 “SCL_posedge==1 이 되는 그 클럭에서 SDA_synched AND 안에 metastable 비트가 끼어들어 와서 data_in이 메타 상태로 가는” 시나리오는
설계 구조상 성립하지 않습니다.

rnjstns0721님의 프로필 이미지
rnjstns0721
Người đặt câu hỏi

친절한답변 덕분에 이해가 갔습니다. 감사합니다!!

Hình ảnh hồ sơ của rnjstns07212239
rnjstns07212239

câu hỏi đã được viết

Đặt câu hỏi