клас I2C – двопровідний послідовний протокол#

I2C – це двопровідний протокол для зв’язку між пристроями. На фізичному рівні він складається з 2 дротів: SCL та SDA – лінії тактування і даних відповідно.

Об’єкти I2C створюються прив’язаними до конкретної шини. Їх можна ініціалізувати під час створення або пізніше.

Виведення об’єкта I2C відображає інформацію про його конфігурацію.

Існують апаратні та програмні реалізації I2C через класи I2C та SoftI2C. Апаратний I2C використовує підтримку апаратного забезпечення системи для виконання читання/запису і зазвичай є ефективним і швидким, але може накладати обмеження на те, які виводи можна використовувати. Програмний I2C реалізовано через побітне управління і може використовуватися на будь-якому виводі, але є менш ефективним. Обидва класи мають однакові доступні методи і відрізняються насамперед способом побудови.

Примітка

Шина I2C вимагає підтягуючих резисторів на лініях SDA та SCL для роботи. Зазвичай це резистори в діапазоні від 1 до 10 кОм, підключені від кожного SDA/SCL до Vcc. Без них поведінка невизначена і може варіюватися від блокування, непередбачуваного скидання за сторожовим таймером до просто неправильних значень. Часто ці підтягуючі схеми вже вбудовані в плату мікроконтролера або плати розширення датчиків, але жодного правила щодо цього не існує. Тому, будь ласка, перевіряйте у разі виникнення проблем. Дивіться також чудовий посібник з навчання від 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 має значення true, надсилається NACK; в іншому випадку надсилається ACK (і в цьому випадку периферійний пристрій очікує, що в подальшому виклику буде зчитано більше байтів).

write(buf: bytes) int#

Записати байти з buf на шину. Перевіряє, що після кожного байта отримується ACK, і припиняє передачу решти байтів при отриманні NACK. Функція повертає кількість отриманих ACK.

Стандартні операції шини#

Наступні методи реалізують стандартні операції читання та запису контролера I2C, спрямовані на заданий периферійний пристрій.

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

Прочитати nbytes з периферійного пристрою за адресою addr. Якщо stop має значення true, в кінці передачі генерується умова STOP. Повертає об’єкт bytes з прочитаними даними.

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

Зчитати в buf з периферійного пристрою за адресою addr. Кількість прочитаних байтів дорівнює довжині buf. Якщо stop має значення true, в кінці передачі генерується умова STOP.

Метод повертає None.

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

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

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

Записати байти, що містяться у vector, на периферійний пристрій за адресою addr. vector має бути кортежем або списком об’єктів з буферним протоколом. addr надсилається один раз, а потім байти з кожного об’єкта у vector записуються послідовно. Об’єкти у vector можуть мати нульову довжину в байтах, і в цьому випадку вони не вносять внесок у вихідний потік.

Якщо після запису байта з одного з об’єктів у vector отримується NACK, решта байтів і будь-які решта об’єктів не надсилаються. Якщо stop має значення true, в кінці передачі генерується умова 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.

клас SoftI2C – програмна емуляція шини I2C#

Клас SoftI2C реалізує I2C через побітне управління довільними виводами 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 в Гц (фактична частота зазвичай нижча через накладні витрати циклу побітного управління).

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 має значення true, в кінці передачі генерується умова STOP.

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

Прочитати len(buf) байтів з пристрою за адресою addr у buf. Якщо stop має значення true, в кінці передачі генерується умова STOP.

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

Записати buf на пристрій за адресою addr. Передача зупиняється при першому NACK. Якщо stop має значення true, умова STOP завжди генерується в кінці передачі (навіть при ранньому NACK). Повертає кількість отриманих ACK.

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

Записати конкатенацію буферів у vector на пристрій за адресою addr як одну транзакцію. Порожні буфери ігноруються. Поводиться як writeto() щодо семантики stop і значення, що повертається.

Операції з пам’яттю#

Деякі пристрої 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.