class I2C – 2선식 시리얼 프로토콜#

I2C는 장치 간 통신을 위한 2선식 프로토콜입니다. 물리 계층에서는 2개의 선, 즉 클럭 선인 SCL과 데이터 선인 SDA로 구성됩니다.

I2C 객체는 특정 버스에 연결되어 생성됩니다. 생성 시점에 초기화할 수도 있고, 나중에 초기화할 수도 있습니다.

I2C 객체를 출력하면 해당 구성에 대한 정보를 확인할 수 있습니다.

I2CSoftI2C 클래스를 통해 하드웨어와 소프트웨어 두 가지 I2C 구현이 모두 제공됩니다. 하드웨어 I2C는 시스템의 기본 하드웨어 지원을 사용하여 읽기/쓰기를 수행하며 일반적으로 효율적이고 빠르지만, 사용할 수 있는 핀에 제약이 있을 수 있습니다. 소프트웨어 I2C는 비트뱅잉(bit-banging)으로 구현되며 어떤 핀에서도 사용할 수 있지만 효율은 떨어집니다. 이 클래스들은 동일한 메서드를 제공하며, 주로 생성 방식에서 차이가 납니다.

참고

I2C 버스가 동작하려면 SDA와 SCL 모두에 풀업 회로가 필요합니다. 보통 각 SDA/SCL에서 Vcc로 연결되는 1 - 10 kOhm 범위의 저항을 사용합니다. 이러한 풀업이 없으면 동작이 정의되지 않으며, 블로킹이나 예기치 않은 워치독 리셋부터 단순히 잘못된 값까지 다양한 현상이 나타날 수 있습니다. 이 풀업 회로는 MCU 보드나 센서 브레이크아웃 보드에 이미 내장된 경우가 많지만 항상 그런 것은 아닙니다. 따라서 문제가 발생하면 확인해 보시기 바랍니다. I2C 배선에 대한 Adafruit의 훌륭한 학습 가이드 도 참고하세요.

사용 예시:

from machine import I2C

i2c = I2C(freq=400000)          # create I2C peripheral at frequency of 400kHz
                                # depending on the port, extra parameters may be required
                                # to select the peripheral and/or pins to use

i2c.scan()                      # scan for peripherals, returning a list of 7-bit addresses

i2c.writeto(42, b'123')         # write 3 bytes to peripheral with 7-bit address 42
i2c.readfrom(42, 4)             # read 4 bytes from peripheral with 7-bit address 42

i2c.readfrom_mem(42, 8, 3)      # read 3 bytes from memory of peripheral 42,
                                #   starting at memory-address 8 in the peripheral
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42
                                #   starting at address 2 in the peripheral

생성자#

class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)#

다음 매개변수를 사용하여 새 I2C 객체를 생성하고 반환합니다:

  • id 는 특정 I2C 주변장치를 식별합니다. 허용되는 값은 특정 포트/보드에 따라 다릅니다.

  • scl 은 SCL에 사용할 핀을 지정하는 핀 객체여야 합니다.

  • sda 는 SDA에 사용할 핀을 지정하는 핀 객체여야 합니다.

  • freq 는 SCL의 최대 주파수를 설정하는 정수여야 합니다.

  • timeout 은 I2C 트랜잭션에 허용되는 최대 시간(마이크로초 단위)입니다. 일부 포트에서는 이 매개변수가 허용되지 않습니다.

일부 포트/보드에는 sclsda 의 기본값이 있으며 이 생성자에서 변경할 수 있습니다. 다른 포트/보드에는 변경할 수 없는 고정된 sclsda 값이 있습니다.

일반 메서드#

init(scl: Pin, sda: Pin, *, freq: int = 400000) None#

주어진 인자로 I2C 버스를 초기화합니다:

  • scl 은 SCL 선에 대한 핀 객체입니다.

  • sda 는 SDA 선에 대한 핀 객체입니다.

  • freq 는 SCL 클럭 속도입니다.

하드웨어 I2C의 경우 실제 클럭 주파수가 요청한 주파수보다 낮을 수 있습니다. 이는 플랫폼 하드웨어에 따라 달라집니다. 실제 속도는 I2C 객체를 출력하여 확인할 수 있습니다.

scan() List[int]#

0x08부터 0x77까지(양 끝 포함)의 모든 I2C 주소를 스캔하고 응답한 주소의 목록을 반환합니다. 장치는 버스에 자신의 주소(쓰기 비트 포함)가 전송된 후 SDA 선을 로우로 끌어내리면 응답한 것으로 간주됩니다.

기본 I2C 동작#

다음 메서드들은 기본적인 I2C 컨트롤러 버스 동작을 구현하며, 이를 조합하여 임의의 I2C 트랜잭션을 만들 수 있습니다. 버스를 더 세밀하게 제어해야 할 때 제공되며, 그렇지 않으면 표준 메서드(아래 참조)를 사용할 수 있습니다.

이 메서드들은 SoftI2C 클래스에서만 사용할 수 있습니다.

start() None#

버스에 START 조건을 생성합니다(SCL이 하이인 동안 SDA가 로우로 전환됨).

stop() None#

버스에 STOP 조건을 생성합니다(SCL이 하이인 동안 SDA가 하이로 전환됨).

readinto(buf: bytearray, nack: bool = True, /) None#

버스에서 바이트를 읽어 buf 에 저장합니다. 읽는 바이트 수는 buf 의 길이입니다. 마지막 바이트를 제외한 모든 바이트를 수신한 후에는 버스에 ACK가 전송됩니다. 마지막 바이트를 수신한 후, nack 이 참이면 NACK가 전송되고, 그렇지 않으면 ACK가 전송됩니다(이 경우 주변장치는 이후 호출에서 더 많은 바이트를 읽을 것으로 가정합니다).

write(buf: bytes) int#

buf 의 바이트를 버스에 씁니다. 각 바이트 후에 ACK가 수신되는지 확인하고 NACK가 수신되면 나머지 바이트의 전송을 중단합니다. 이 함수는 수신된 ACK의 수를 반환합니다.

표준 버스 동작#

다음 메서드들은 주어진 주변장치를 대상으로 하는 표준 I2C 컨트롤러 읽기 및 쓰기 동작을 구현합니다.

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes#

addr 로 지정된 주변장치에서 nbytes 만큼 읽습니다. stop 이 참이면 전송 끝에 STOP 조건이 생성됩니다. 읽은 데이터를 담은 bytes 객체를 반환합니다.

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None#

addr 로 지정된 주변장치에서 buf 로 읽어 들입니다. 읽는 바이트 수는 buf 의 길이입니다. stop 이 참이면 전송 끝에 STOP 조건이 생성됩니다.

이 메서드는 None 을 반환합니다.

writeto(addr: int, buf: bytes, stop: bool = True, /) int#

addr 로 지정된 주변장치에 buf 의 바이트를 씁니다. buf 의 한 바이트를 쓴 후 NACK가 수신되면 나머지 바이트는 전송되지 않습니다. stop 이 참이면 NACK가 수신되더라도 전송 끝에 STOP 조건이 생성됩니다. 이 함수는 수신된 ACK의 수를 반환합니다.

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int#

vector 에 담긴 바이트를 addr 로 지정된 주변장치에 씁니다. vector 는 버퍼 프로토콜을 가진 객체들의 튜플 또는 리스트여야 합니다. addr 은 한 번만 전송되고, 이어서 vector 의 각 객체의 바이트가 순차적으로 기록됩니다. vector 의 객체는 길이가 0바이트일 수 있으며, 이 경우 출력에 기여하지 않습니다.

vector 의 객체 중 하나의 바이트를 쓴 후 NACK가 수신되면 나머지 바이트와 남은 객체들은 전송되지 않습니다. stop 이 참이면 NACK가 수신되더라도 전송 끝에 STOP 조건이 생성됩니다. 이 함수는 수신된 ACK의 수를 반환합니다.

메모리 동작#

일부 I2C 장치는 읽고 쓸 수 있는 메모리 장치(또는 레지스터 집합)처럼 동작합니다. 이 경우 I2C 트랜잭션에는 두 개의 주소, 즉 주변장치 주소와 메모리 주소가 연관됩니다. 다음 메서드들은 이러한 장치와 통신하기 위한 편의 함수입니다.

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes#

memaddr 로 지정된 메모리 주소부터 시작하여 addr 로 지정된 주변장치에서 nbytes 만큼 읽습니다. addrsize 인자는 주소 크기를 비트 단위로 지정합니다. 읽은 데이터를 담은 bytes 객체를 반환합니다.

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None#

memaddr 로 지정된 메모리 주소부터 시작하여 addr 로 지정된 주변장치에서 buf 로 읽어 들입니다. 읽는 바이트 수는 buf 의 길이입니다. addrsize 인자는 주소 크기를 비트 단위로 지정합니다.

이 메서드는 None 을 반환합니다.

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None#

memaddr 로 지정된 메모리 주소부터 시작하여 addr 로 지정된 주변장치에 buf 를 씁니다. addrsize 인자는 주소 크기를 비트 단위로 지정합니다.

이 메서드는 None 을 반환합니다.

class SoftI2C – 소프트웨어로 에뮬레이션된 I2C 버스#

SoftI2C 클래스는 임의의 GPIO 핀을 비트뱅잉하여 I2C를 구현합니다. I2C 와 동일한 메서드 인터페이스에 더해, 비표준 트랜잭션을 조립해야 하는 호출자를 위한 저수준 기본 버스 동작(start(), stop(), readinto(), write())을 노출합니다. 필요한 핀이 하드웨어 I2C 블록에 연결되어 있지 않을 때, 하드웨어가 제공하는 것보다 더 많은 버스가 필요할 때, 또는 비정상적인 시퀀스(추가 클럭, 쓰기 후 반복 시작 등)를 요구하는 장치와 통신할 때 사용하세요.

생성자#

class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)#

scl / sda 로 구동되는 소프트웨어 I2C 버스를 생성합니다.

freq 는 목표 SCL 클럭 속도(Hz 단위)입니다(비트뱅 루프 오버헤드 때문에 실제 속도는 일반적으로 더 낮습니다).

timeout 은 클럭 스트레칭(버스의 다른 장치가 SCL을 로우로 유지하는 것)을 기다리는 최대 시간(마이크로초 단위)입니다. 만료되면 OSError(ETIMEDOUT) 이 발생합니다.

일반 메서드#

init(scl: Pin, sda: Pin, *, freq: int = 400000) None#

주어진 핀과 주파수로 소프트웨어 I2C 버스를 다시 초기화합니다. 같은 객체에 대해 새 SoftI2C 를 생성하는 것과 동등합니다.

scan() List[int]#

0x08부터 0x77까지(양 끝 포함)의 모든 I2C 주소를 스캔하고 응답한 주소의 목록을 반환합니다.

기본 I2C 동작#

다음 메서드들은 기본적인 I2C 컨트롤러 버스 동작을 구현하며, 이를 조합하여 임의의 I2C 트랜잭션을 만들 수 있습니다. 이들은 SoftI2C 전용이며, 하드웨어 I2C 클래스는 이를 노출하지 않습니다.

start() None#

버스에 START 조건을 생성합니다(SCL이 하이인 동안 SDA가 로우로 전환됨).

stop() None#

버스에 STOP 조건을 생성합니다(SCL이 하이인 동안 SDA가 하이로 전환됨).

readinto(buf: bytearray, nack: bool = True, /) None#

버스에서 buf 로 바이트를 읽습니다. len(buf) 바이트가 읽히며, 마지막을 제외한 모든 바이트 후에 ACK가 전송됩니다. 마지막 바이트 후 nack=True (기본값)는 전송을 종료하기 위해 NACK를 전송하고, nack=False 는 ACK를 전송하여 이후의 readinto() 를 위해 장치를 선택된 상태로 유지합니다.

write(buf: bytes) int#

buf 를 버스에 쓰며, 모든 바이트 후에 ACK를 확인합니다. 첫 번째 NACK에서 전송이 중단됩니다. 수신된 ACK의 수를 반환합니다.

표준 버스 동작#

다음 메서드들은 주어진 주변장치를 대상으로 하는 표준 I2C 컨트롤러 읽기 및 쓰기 동작을 구현합니다.

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes#

7비트 주소 addr 의 장치에서 nbytes 만큼 읽습니다. stop 이 참이면 전송 끝에 STOP 조건이 생성됩니다.

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None#

addr 의 장치에서 len(buf) 바이트를 buf 로 읽습니다. stop 이 참이면 전송 끝에 STOP 조건이 생성됩니다.

writeto(addr: int, buf: bytes, stop: bool = True, /) int#

addr 의 장치에 buf 를 씁니다. 첫 번째 NACK에서 전송이 중단됩니다. stop 이 참이면 전송 끝에 항상 STOP 조건이 생성됩니다(이른 NACK가 발생하더라도). 수신된 ACK의 수를 반환합니다.

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int#

vector 에 담긴 버퍼들을 이어 붙인 것을 단일 트랜잭션으로 addr 의 장치에 씁니다. 빈 버퍼는 무시됩니다. stop 의 의미와 반환값은 writeto() 와 동일하게 동작합니다.

메모리 동작#

일부 I2C 장치는 읽고 쓸 수 있는 메모리 장치(또는 레지스터 집합)처럼 동작합니다. 이 경우 I2C 트랜잭션에는 두 개의 주소, 즉 주변장치 주소와 메모리 주소가 연관됩니다. 다음 메서드들은 이러한 장치와 통신하기 위한 편의 헬퍼입니다.

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes#

addr 의 장치에서 레지스터 memaddr 부터 시작하여 nbytes 만큼 읽습니다. addrsize 는 레지스터 주소의 너비(비트 단위, 일반적으로 8 또는 16)입니다.

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None#

addr 의 장치에서 레지스터 memaddr 부터 시작하여 buf 로 읽어 들입니다.

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None#

addr 의 장치에 레지스터 memaddr 부터 시작하여 buf 를 씁니다.