인프런 커뮤니티 질문&답변
I2C SCL_Synched, SDA_Synched 질문
작성
·
29
0

안녕하세요 코드를 보다 의문점이 들어서 질문 드립니다. 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] 로 선언해서 사용해야 하는 것 아닌가요?? 감사합니다.
답변 1
0
안녕하세요, 답변 남겨드립니다.
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 이 되는 건
SCLSynch와SDASynch의 “새 값”인데,그 “새 값”은 다음 클럭에서야
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을 하나씩 밀어넣는 구조라서,
클럭이 지날 때마다 대략 이런 식으로 변합니다 (숫자 대신 말로 설명):
처음에는
SCLSynch가 예를 들어000이었다고 합시다. (SCL도 0)버스에서 SCL이 1로 바뀐다.
다음 clk 엣지에서
SCLSynch가001이 된다.
이때 상위 두 비트는00이므로SCL_posedge는 아직 0.그 다음 clk 엣지에서
SCLSynch가011이 된다.
이제 상위 두 비트2:1이01패턴이므로, 이 클럭에서SCL_posedge가 1이 된다.또 한 번 지나면
SCLSynch는111이 되고, 상위 두 비트는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로 바뀌었다고 해볼게요.
처음에는
SDASynch가000.SDA가 1로 바뀐다.
첫 번째 clk 이후:
001.
세 비트 AND는 아직 0.두 번째 clk 이후:
011.
세 비트 AND는 아직 0.세 번째 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_posedge와SDA_synched모두
이번 클럭에서 갱신되기 “직전”의 SCLSynch/SDASynch 값에 의해 결정됩니다.이번 클럭에서 막 metastable 이 된
SDASynch[0]의 상태는
아직SDA_synched계산에 사용되지 않습니다.
그건 다음 클럭에서야 반영됩니다.
그래서 “SCL_posedge==1 이 되는 그 클럭에서 SDA_synched AND 안에 metastable 비트가 끼어들어 와서 data_in이 메타 상태로 가는” 시나리오는
설계 구조상 성립하지 않습니다.






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