class I2C – двухпроводной последовательный протокол#

I2C – это двухпроводной протокол для обмена данными между устройствами. На физическом уровне он состоит из 2 проводов: SCL и SDA – линии тактирования и данных соответственно.

Объекты I2C создаются привязанными к конкретной шине. Они могут быть инициализированы при создании или позже.

Вывод объекта I2C на печать даёт информацию о его конфигурации.

Существуют как аппаратная, так и программная реализации I2C через классы I2C и SoftI2C. Аппаратный I2C использует встроенную аппаратную поддержку системы для выполнения чтения/записи и обычно эффективен и быстр, но может иметь ограничения на то, какие выводы можно использовать. Программный I2C реализован через bit-banging и может использоваться на любом выводе, но не так эффективен. Эти классы имеют одинаковый набор методов и отличаются главным образом способом создания.

Примечание

Для работы шины I2C требуются подтягивающие резисторы как на SDA, так и на SCL. Обычно это резисторы номиналом от 1 до 10 кОм, подключённые от каждой линии SDA/SCL к Vcc. Без них поведение не определено и может варьироваться от блокировки и неожиданного сброса по сторожевому таймеру до просто неверных значений. Часто такая подтягивающая схема уже встроена в плату MCU или в платы расширения с датчиками, но это не правило. Поэтому при возникновении проблем, пожалуйста, проверьте это. См. также это отличное руководство от Adafruit о подключении I2C.

Пример использования:

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. Этот параметр недоступен на некоторых портах.

Обратите внимание, что некоторые порты/платы имеют значения scl и sda по умолчанию, которые можно изменить в этом конструкторе. У других значения scl и sda фиксированы и не могут быть изменены.

Общие методы#

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

Инициализирует шину I2C с заданными аргументами:

  • scl – это объект вывода для линии SCL

  • sda – это объект вывода для линии SDA

  • freq – это тактовая частота SCL

В случае аппаратного I2C фактическая тактовая частота может быть ниже запрошенной. Это зависит от аппаратной платформы. Фактическую частоту можно определить, выведя объект I2C на печать.

scan() List[int]#

Сканирует все адреса I2C от 0x08 до 0x77 включительно и возвращает список тех, что ответили. Устройство отвечает, если оно притягивает линию SDA к низкому уровню после того, как на шину отправлен его адрес (включая бит записи).

Примитивные операции I2C#

Следующие методы реализуют примитивные операции контроллера шины I2C и могут комбинироваться для составления любой транзакции I2C. Они предоставляются на случай, если вам нужен больший контроль над шиной, в противном случае можно использовать стандартные методы (см. ниже).

Эти методы доступны только в классе SoftI2C.

start() None#

Генерирует условие START на шине (SDA переходит на низкий уровень, пока SCL находится на высоком уровне).

stop() None#

Генерирует условие STOP на шине (SDA переходит на высокий уровень, пока SCL находится на высоком уровне).

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#

Читает nbytes из периферийного устройства, заданного addr. Если stop истинно, в конце передачи генерируется условие STOP. Возвращает объект bytes с прочитанными данными.

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

Читает в buf из периферийного устройства, заданного addr. Количество прочитанных байтов будет равно длине buf. Если stop истинно, в конце передачи генерируется условие STOP.

Метод возвращает None.

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

Записывает байты из buf в периферийное устройство, заданное addr. Если после записи байта из buf получен NACK, то оставшиеся байты не отправляются. Если stop истинно, в конце передачи генерируется условие STOP, даже если получен NACK. Функция возвращает количество полученных ACK.

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

Записывает байты, содержащиеся в vector, в периферийное устройство, заданное addr. vector должен быть кортежем или списком объектов с буферным протоколом. addr отправляется один раз, после чего байты из каждого объекта в vector записываются последовательно. Объекты в vector могут иметь нулевую длину, и в этом случае они не вносят вклад в вывод.

Если после записи байта из одного из объектов в vector получен NACK, то оставшиеся байты и любые оставшиеся объекты не отправляются. Если stop истинно, в конце передачи генерируется условие STOP, даже если получен NACK. Функция возвращает количество полученных ACK.

Операции с памятью#

Некоторые устройства I2C работают как устройство памяти (или набор регистров), из которого можно читать и в которое можно записывать. В этом случае с транзакцией I2C связаны два адреса: адрес периферийного устройства и адрес памяти. Следующие методы являются удобными функциями для обмена данными с такими устройствами.

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

Читает nbytes из периферийного устройства, заданного addr, начиная с адреса памяти, заданного memaddr. Аргумент addrsize задаёт размер адреса в битах. Возвращает объект bytes с прочитанными данными.

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

Читает в buf из периферийного устройства, заданного addr, начиная с адреса памяти, заданного memaddr. Количество прочитанных байтов равно длине buf. Аргумент addrsize задаёт размер адреса в битах.

Метод возвращает None.

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

Записывает buf в периферийное устройство, заданное addr, начиная с адреса памяти, заданного memaddr. Аргумент addrsize задаёт размер адреса в битах.

Метод возвращает None.

class SoftI2C – программно-эмулируемая шина I2C#

Класс SoftI2C реализует I2C посредством bit-banging произвольных выводов GPIO. Он предоставляет тот же набор методов, что и I2C, плюс низкоуровневые примитивные операции шины (start(), stop(), readinto(), write()) для вызывающего кода, которому нужно собрать нестандартные транзакции. Используйте его, когда нужные вам выводы не подключены к аппаратному блоку I2C, когда вам нужно больше шин, чем предоставляет аппаратура, или для общения с устройствами, требующими необычных последовательностей (дополнительные такты, повторные старты после записи и т. д.).

Конструкторы#

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

Создаёт программную шину I2C, управляемую scl / sda.

freq – это целевая тактовая частота SCL в Гц (фактическая частота обычно ниже из-за накладных расходов цикла bit-banging).

timeout – это максимальное время в микросекундах ожидания растягивания тактового сигнала (когда SCL удерживается на низком уровне другим устройством на шине); по истечении вызывается OSError(ETIMEDOUT).

Общие методы#

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

Повторно инициализирует программную шину I2C с заданными выводами и частотой. Эквивалентно созданию нового SoftI2C на том же объекте.

scan() List[int]#

Сканирует все адреса I2C от 0x08 до 0x77 включительно и возвращает список тех, что ответили.

Примитивные операции I2C#

Следующие методы реализуют примитивные операции контроллера шины I2C и могут комбинироваться для составления любой транзакции I2C. Они доступны только в SoftI2C – аппаратный класс I2C их не предоставляет.

start() None#

Генерирует условие START на шине (SDA переходит на низкий уровень, пока SCL находится на высоком уровне).

stop() None#

Генерирует условие STOP на шине (SDA переходит на высокий уровень, пока SCL находится на высоком уровне).

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#

Читает nbytes из устройства с 7-битным адресом addr. Если stop истинно, в конце передачи генерируется условие STOP.

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

Читает len(buf) байтов из устройства с адресом addr в buf. Если stop истинно, в конце передачи генерируется условие STOP.

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

Записывает buf в устройство с адресом addr. Передача прекращается при первом 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#

Читает nbytes из устройства с адресом addr, начиная с регистра memaddr. addrsize – это ширина адреса регистра в битах (обычно 8 или 16).

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

Читает в buf из устройства с адресом addr, начиная с регистра memaddr.

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

Записывает buf в устройство с адресом addr, начиная с регистра memaddr.