데이터시트 분석
TCA9538은 I2C 및 SMBus를 지원하는 8채널 I/O Expander이다.
1. 주요 특징
- 주요 기능은 I2C to Parallel Port 확장 기능
- Open-Drain Active Low 인터럽트 출력 기능 제공
- Active Low 리셋 입력 기능 제공
- 공급 전압 : 1.65V~5.5V
- 5V tolerant I/O 포트
- 최대 400kHz(Fast Mode)의 I2C 통신 속도 지원
- 전원 공급 시 기본적으로 모든 채널이 Input으로 설정됨
- 2개의 하드웨어 주소 핀(A0, A1)을 통해 최대 4개의 디바이스 연결 가능
- 전원 인가 시 글리치 없음
- SCL/SDA 라인에 노이즈 필터 존
2. 블락 다이어그램
3. 핀아웃
4. 제어 방법
1) Supported I2C Mode
- Standard Mode : 100kHz
- Fast Mode : 400kHz
2) I2C Slave Address
기본 주소는 7h70부터 7h73까지이며 A0, A1 핀을 VCC에 연결하느냐 Ground에 연결하느냐에 따라 달라진다.
3) Control Register (= Command Byte)
Command Byte는 I2C 데이터 전송 시 Address Byte 다음으로 등장하는 두 번째 바이트로, 어떤 레지스터를 읽거나 쓸 것인지 선택하는 역할을 한다.
4) 레지스터 종류
- Input Port Register (0) : 읽기 전용, P0~P7 핀의 현재 입력 상태를 읽는 용도
- Output Port Register (1) : 읽기/쓰기, P0~P7 핀의 출력을 설정하는 용도
- Polarity Inversion Register (2) : 읽기/쓰기, 입력으로 설정된 핀의 입력 값의 논리 반전 여부를 설정하는 용도
- Configuration Register (3) : 읽기/쓰기, 핀을 입력 또는 출력으로 설정하는 용도
5) 인터럽트 동작 방식
인터럽트 설정을 위한 별도 레지스터가 존재하지 않으며, 인터럽트 기능은 입력 핀(P0~P7)의 상태 변화를 감지하는 하드웨어 로직에 의해 자동으로 동작한다.
- /INT 출력 핀은 Open-Drain 구조이므로 외부 풀업 저항이 필요하다.
- Input으로 설정된 P0~P7 핀에서 신호의 rising edge 또는 falling edge가 발생하면 /INT핀이 Low가 되어 활성화된다.
- 인터럽트 발생 이후 Input Port register(0)을 읽으면 인터럽트 상태가 해제되어 /INT핀이 다시 High 상태로 돌아간다.
- Output으로 설정된 핀은 인터럽트를 발생시키지 않는다.
- Output으로 설정된 핀을 도중에 Input으로 변경하는 경우 false interrupt가 발생할 가능성이 있다.
6) I2C Write 패킷 구조
[START] [Slave Address + W(0)] [ACK(S)] [Command Byte] [ACK(S)] [Data Byte] [ACK(S)] [STOP]
7) I2C Read 패킷 구조
Read 동작은 먼저 읽을 레지스터를 지정하고 그 다음 읽는 두 단계에 걸쳐 수행된다. 보통 I2C 트랜잭션은 START 조건으로 시작하고 STOP 조건으로 끝나는데, 이 경우에는 도중에 STOP을 발생시키지 않는 REPEATED START 방식을 사용하는 것을 볼 수 있다.
[START] [Slave Address + W(0)] [ACK(S)] [Command Byte] [ACK(S)]
[RESTART] [Slave Address + R(1)] [ACK(S)] [Data Byte] [ACK(M)] ... [Data Byte] [NACK(M)] [STOP]
Raspberry Pi 4B에서 테스트
1. 배선
Raspberry Pi 4 | TCA9538 |
3.3V | VCC |
GND | GND |
SDA (핀 3, GPIO2) | SDA (Pull-up to Vcc) |
SCL (핀 5, GPIO3) | SCL (Pull-up to Vcc) |
GND | A0 |
GND | A1 |
- | /RESET (Pull-up to Vcc) |
2. i2c 활성화 및 디바이스 트리 적용
/boot/firmware/config.txt 파일을 에디터로 열고 아래 항목을 편집한다.
$ sudo vim /boot/firmware/config.txt
# I2C 활성화를 위해 아래 라인 주석 해제 (기본적으로 I2C1 사용)
dtparam=i2c_arm=on
# 아래 문장 추가하여 디바이스 트리 적용
dtoverlay=pca953x,addr=0x70,pca9538
$ sudo reboot
3. 드라이버 로드 및 동작 확인
$ dmesg | grep pca
$ i2cdetect -y 1
libgpiod를 사용하면 TCA9538(i2c-1, 0x70) 장치가 gpiochip2 컨트롤러가 등록되었고 그 하위에 8개의 gpio line이 존재하는 것을 확인할 수 있다. 이렇게 된건 DT의 gpio-controller; 속성 때문인데 이 속성은 해당 노드가 gpio 컨트롤러임을 의미한다.
💡 참고.
- libgpiod는 기존 /sys/class/gpio/를 통한 GPIO방식이 deprecated 되면서 최신 커널에서 권장되는 GPIO 제어 방식이다.
- gpioget, gpioset 명령을 사용하면 내부적으로 핀 direction이 자동 설정된다. (라즈베리 파이에서는 가능한데 일부 플랫폼에서는 핀 입출력 방향을 시스템 동작 중에 못바꾸는 경우도 있다.)
$ gpiodetect
$ gpioinfo gpiochip2
# P0핀 읽기
$ gpioget gpiochip2 0
# P1핀 쓰기
$ gpioset gpiochip2 1=0
$ gpioset gpiochip2 1=1
💡 참고.
- 현재 gpiochip2의 line name이 unamed로 되어있는데 DT에서 gpio-controller; 속성 아래에 gpio-line-names 속성으로 문자열 리스트 값을 추가하면 line name을 지정할 수 있다.
- GPIO 컨트롤러 노드에 gpio-hog{}; 노드를 추가하면 line의 입출력 방향과 초기값을 설정할 수 있다. 다만, gpio-hog{}; 노드 추가 시 해당 리소스가 컨트롤러에 의해 선점된 상태이기 때문에 libgpiod로 제어하는데 제한이 있을 수 있다. 자세한 설정 방법은 /Documentation/devicetree/bindings/gpio/gpio.txt 문서를 참조한다.
- 예시.
gpio-controller@00000000 {
compatible = "foo";
reg = <0x00000000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <18>;
gpio-reserved-ranges = <0 4>, <12 2>;
gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
"LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
"Row A", "Row B", "Row C", "Row D", "NMI button",
"poweroff", "reset";
}
qe_pio_a: gpio-controller@1400 {
compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
reg = <0x1400 0x18>;
gpio-controller;
#gpio-cells = <2>;
line_b {
gpio-hog;
gpios = <6 0>;
output-low;
line-name = "foo-bar-gpio";
};
};
'임베디드 개발 > 리눅스 디바이스 드라이버' 카테고리의 다른 글
TCA9548A 데이터시트 및 리눅스 드라이버 분석 (Tested on Raspberry Pi 4) (0) | 2025.04.06 |
---|---|
LDD ] Device Tree (DT, 디바이스 트리) (0) | 2025.03.27 |
LDD ] PCIe 디바이스 드라이버 작성하기 - (4) with sysfs (0) | 2025.03.18 |
LDD ] 커널 메모리 할당 함수 (kmalloc, kzalloc 등) (0) | 2025.03.12 |
LDD ] PCIe 디바이스 드라이버 작성하기 - (3) with Interrupt (0) | 2025.03.03 |