Q&A 게시판

리눅스 커널에 대한 Q&A 게시판 입니다. (비밀글 체크는 꼭 필요한 경우에만)

I2C 파형 문의 드립니다.

작성자
Harv
작성일
2021-06-01 16:34
조회
174
안녕하세요.

운영자님의 블로그를 보면서 많이 공부하고 있습니다.
임베디드 보드를 개발 중에 있는 개발자입니다.
I2C사용중에 문제가 생겨서 문의 드립니다.
커널은 3.14.79를 사용하고 있습니다.
ADC용 IC(max11600)를 사용하여 I2C 통신으로 2초마다 전압값을 가져오고 있습니다.
통신이 잘되다가 하루에 4~5번씩 time out error 로고가 kern.log에 남아 있습니다.
그러다가 일주일 또는 한달만에 아에 먹통이 됩니다.
블로그에서 알려주신것처럼 SCL 핀에 외부핀을 연결하여 수동으로 클럭을 입력해 주면 다시 살아나는 것은 확인 했습니다.
저는 근본 원인을 찾고 싶어서 문의 드립니다. pull-up은 1K~4.7K까지 다양하게 사용해봤으나
증상은 동일합니다.
첨부한 파형에서 보면 SCL이 SDA보다 약 0.4us 먼저 Low로 떨어 지는 것을 알수 있습니다.
제가 알기로는 이론상으로 SDA가 출력 후 SCL은 약 1/4 Clock(100khz 기준, 2.5us) 딜레이 후에 출력이 나가는 것으로 알고 있습니다.
현재 출력 파형은 SCL이 약 5us후에 출력이 나가는데 slave 쪽에서 데이타를 읽을 때 문제가 발생하지 않을까 해서요.
파형이 정상인지 확인 부탁드립니다.
감사합니다.
첨부파일 : SDS00004.bmp
첨부파일 : SDS00005.bmp
전체 5
  • 2021-06-02 10:30
    안녕하세요? Harv님

    I2C 표즌 100Khz 스탠다드 모드로 범위를 좁혀 말씀드립니다.

    sda와 scl의 상승 에지 타이밍이 너무 완만하군요. 표준에서는 1us 이내입니다.
    하강 에지 타이밍은 좋아 보이며, 표준에서는 0.3us 이내입니다.

    scl의 LOW 시간은 최소 4.7us 이상이어야 하고, HIGH 시간은 최소 4us를 유지해야 합니다.
    상승 에지 시간이 길어지는 바람에 scl의 HIGH 시간이 4.7us보다 짧아질 수 있어 보입니다.

    scl이 HIGH에 있을 때, sda는 변하면 안됩니다. 이렇게 변하면 일반 적인 비트 전송이 아니라
    start 및 stop condition을 전송하는 것으로 바뀝니다. 조금 아슬 아슬해보입니다.

    sda 출력 후 2.5us 딜레이하고 scl이 나가야하는 것이 아니라, sda 출력 후 최소 0.25us 딜레이하고 scl이 나가야 합니다.
    이것은 data set-up 타이밍을 의미합니다.
    그런데 보내주신 파형을 보니 방금 조건은 만족하지만, 그 보단 훨씬 더 늦게 나가는 군요.

    ----

    위의 내용은 spec 적인 부분이고, 실전에서는 위와 같은 환경을 만족시키기 힘든 경우는 얼마든지 있습니다.
    그 때문에 i2c 통신이 불안정한 시스템들이 꽤 많이 있습니다.

    최대한 매칭(마스터와 슬레이브 측의 풀업, 드라이버 전류, 버스 Capacity(pF)) 등을 맞춰 안정화시키시고,
    상황이 더 이상 개선되지 않으면 통신 에러시 커널의 드라이버 제어를 통해 리커버리가 잘 되도록 하는 수 밖에 없겠죠.

    참고로 pull up 저항등의 크기는 spec 문서를 통해 갸늠을 해보시고,
    아래 참고 문서는 다른 분의 경험을 담았으므로 첨부합니다.
    - I2C 통신의 풀업저항 크기 - https://www.basic4mcu.com/bbs/board.php?bo_table=p1&wr_id=20&device=mobile

    감사합니다.

    문영일 드림.

  • 2021-06-02 13:47
    운영자님 답변 감사 드립니다.
    맨땅에 해딩하는 저로써는 정말 도움이 많이 될 것 같습니다.
    이 문제로 몇달동안 고생하고 있습니다. 우선 파형 개선부터 시도를 해야 겠습니다.
    추가로 한가지 문의 드릴 사항은 제가 너무 초보라서 DTS설정에 대해 한가지 문의 드리고자 합니다.
    커널 3.14를 사용하고 있고 드라이버는 i2c-pnx.c를 사용하고 있습니다.
    scl-recovery 함수를 사용할려고 하는데 DTS설정에서 scl-gpios = < gpio 포트번호 > 만
    설정해주면 되는 건지요? 아니면 추가로 설정해야 할 부분이 있을까요?
    확인 부탁 드립니다.

  • 2021-06-03 15:39
    대부분의 32비트 arm 아키텍처를 사용한 SoC들은 리눅스 커널 v3.x 후반대 버전에서 최조 디바이스 트리에 연결되었습니다.
    이 떄 당시 해당 플랫폼 디바이스들은 일부만 디바이스 트리를 사용하고, 대부분은 custom specific한 코드들을 사용하고 있었습니다.
    참고로 lpc32xx의 경우 arch/arm/mach-lpc32xx 디렉토리에 SoC의 플랫폼 디바이스들의 구동 및 초기화에 대해 사용되고 있습니다.

    이후 arm64 부터 플랫폼 디바이스에 대해서 위와 같은 custom 코드의 지원을 원천적으로 봉쇄하였고,
    custom 코드 추가 없이 플랫폼 디바이스들은 모두 디바이스 트리를 통해서 잘 연동되게끔 하였습니다.
    이를 통해 리눅스 커널 v4.x 이후 부터는 변화가 생겼습니다.
    i2c 칩과 같은 해당 장치의 제조사만 장치 드라이버를 작성하고, 이를 사용하는 SoC 제조사 또는 보드 제조사들은 별도의 장치 드라이버를 작성하지 않고, 디바이스 트리로 지정하여 사용할 수 있는 편리한 단계에 이르렀습니다.

    서론이 길었습니다만 i2c 리커버리를 사용하려면 다음과 같은 복잡한 준비가 필요합니다.

    1) i2c에 사용하는 scl핀과 sda핀이 gpio와 pinctrl 제어가 되어야 i2c 장애시 gpio 모드로 전환하여 recovery를 시도할 수 있습니다.
    - lpc32xx의 경우 해당 pin들이 gpio 전환이 안되는 것으로 보입니다. 데이터 시트를 확인해보세요.

    2) 위와 같은 지원이 불가능한 경우 보드에서 hw 수정이 필요합니다.
    - 리커버리시 pulse를 만들어내는 라인을 추가하여 제어한다. (gpio 등으로 평소에는 open 되어 있어야 합니다)
    - 위의 방법이 번거로우면 i2c 슬레이브 장치를 리셋시킬 수 있는 회로를 추가합니다.

    3) i2c host 드라이버에 i2c recovery 코드들을 구현하여야 합니다.
    - lpc32xx에서 사용하는 i2c-pnx.c는 준비되어 있지 않습니다.
    - 보통 i2c recovery 코드가 준비된 i2c 드라이버들의 경우 디바이스 트리에서 지정하는 것으로 준비가 완료됩니다.
    - 다음 디바이스 트리 파일에서 gpio, pinctrl, i2c 등을 참고하시기 바랍니다.
    arch/arm64/boot/dts/marvell/armada-3720-uDPU.dts
    arch/arm64/boot/dts/marvell/armada-37xx.dtsi
    - 위의 i2c 디바이스 트리가 사용하는 i2c 드라이버 코드는 다음을 참고하시기 바랍니다.
    drivers/i2c/busses/i2c-pxa.c

    끝으로 lpc32xx에서 i2c recovery를 준비하려면 2)번과 3)번을 모두 준비하여야 하므로 많은 노력이 필요할듯해 보입니다.

  • 2021-06-03 21:26
    답변 감사드립니다. Recovery 도 쉬운게 아니었군요. I2C가 이렇게 어려운건지 10년을 넘게 사용하고서도 이제서야 알았네요.
    운영자님이 알려주신 방법으로 좀더 공부해야겠습니다.
    감사합니다.

  • 2021-06-04 09:31
    좋은 결과 얻으시길 바랍니다. 좋은 하루 되세요 ^^