Інтерфейс I2C (Inter Integrated Circuit) створювався як простий інтерфейс з мінімально кількістю ліній зв'язку. Він використовує всього дві лінії для зв'язку ведучого пристрою з веденим: двонаправлену лінію даних SDA (Serial DAta) та лінію тактування SCL (Serial CLock) для синхронізації прийому і передачі даних.
Основний режим роботи — 100 кбіт/с; 10 кбіт/с в режимі роботи із зниженою швидкістю. Після введення стандарту 1992 року стало можливим підключення більшої кількості пристроїв на одну шину (за рахунок 10-бітної адресації), а також зросла швидкість обміну до 400 кбіт/с у швидкісному режимі (реалізовано в Raspberry Pi). Відповідно, доступна кількість вузлів зросла до 1008. Версія стандарту 2.0, випущена в 1998 році, представила високошвидкісний режим роботи зі швидкістю до 3,4 Мбіт/с зі зниженим енергоспоживанням.
I2C використовується в таких додатках як, читання RTC (годинник реального часу), доступ до зовнішньої пам'яті EEPROM, в модулях таких сенсорів, як гіроскоп, магнітометр тощо.
Зв'язок пристроїв через інтерфейс I2C на рівні електричних сигналів здійснюється з урахуванням наступних 4 правил:
1. ВИСОКИЙ рівень на лінії даних SDA або на лінії тактування SCL не може бути встановлений безпосередньо пристроєм I2C. Всі пристрої I2C повинні мати виходи з відкритим колектором (або відкритим стоком). ВИСОКИЙ рівень напруги на лініях формується зовнішніми підтягуються резисторами.
2. Інформація на лінії даних SDA зчитується лише при ВИСОКОМУ рівні на лінії тактування SCL.
3. Інформація на лінію даних SDA виставляється тільки при НИЗЬКОМУ рівні на лінії тактування SCL.
4. Якщо шина I2C в даний момент не використовується, то на лініях повинен бути встановлений ВИСОКИЙ рівень сигналу (логічна 1).
Основний формат кадру обміну через I2C складається з 11 біт. Спочатку посилається старт-біт, потім 8 біт даних, далі біт підтвердження прийому, потім стоп-біт. Форма подання старт і стоп-бітів порушує записане вище правило 3. Старт-біт визначається наявністю спадаючого фронту на лінії SDA при ВИСОКОМУ рівні сигналу на лінії SCL. Цю комбінацію сигналів прийнято також називати стартовим станом, або станом Start. Стоп-біт (або стан Stop) визначається наявністю наростаючого фронту на лінії SDA при ВИСОКОМУ рівні на лінії SCL. Стани Старт і Стоп генеруються ведучим пристроєм.
Стани Start і Stop на шині I2C
Після формування стартового біта ведучий пристрій виставляє на лінію даних SDA 8 біт даних, починаючи зі старшого біта байта. Кожен біт супроводжується імпульсом синхронізації SCL. Потім приймач генерує біт підтвердження прийому ACK, встановлюючи лінію SDA в НИЗЬКИЙ стан на інтервалі дев'ятого імпульсу на лінії SCL.
Якщо приймач не впізнав прийняті дані, то генерується біт «непідтвердження» прийому NACK, просто не переводячи лінію SDA в НИЗЬКИЙ стан. В цьому випадку передавач закінчує поточний сеанс передачі даних і генерує стоп-біт. Згідно алгоритму прикладної програми передавач пробує передати інформацію пізніше. На рис. нижче показані часові діаграми на лініях I2C, які супроводжують передачу та прийом байта 11010000 (передача успішна, біт підтвердження ACK сформований).
Кадри передачі та приймання даних через інтерфейс I2C
Тривалість фронтів при перемиканні в реальних системах не настільки мала, як показано на рис., оскільки реальні лінії мають розподілену ємність і до них підключені підтягуючі резистори. Чим більші значення ємності і опору підтягуючих резисторів, тим більша тривалості фронтів сигналів. Великий час наростання і спаду сигналу може привести до помилок при обміні даними між пристроями.
При проектуванні шини I2C необхідно враховувати кількість пристроїв, що підключаються, величини їх вхідної ємності і опорів підтягуючих резисторів. Деякі виробники напівпровідникових приладів пропонують спеціальні конвертори для збільшення кількості пристроїв, що підключаються до шини I2C.
Врахуйте, що максимальна сумарна ємність підключених до лінії I2C пристроїв не повинна перевищувати 400 пФ!
Протокол I2C передбачає можливість примусового зниження швидкості передачі даних веденим пристроєм в процесі самої передачі. Коли лінія SCL знаходиться в НИЗЬКОМУ стані, ведений пристрій може примусово продовжити цей стан на лінії, поки він не буде готовий прийняти наступний біт даних. Ця функція називається «розширенням тактових імпульсів».
При необхідності взаємодії декількох пристроїв по шині I2C у кожного підключеного до шини пристрою повинна бути своя адреса. Відповідно до специфікації протоколу I2C адреса може бути 7- або 10-бітовою.
Структура кадру обміну через I2C при передачі 7-бітної адреси: тарт-біт, 7 біт адреси, біт напрямку передачі для наступного кадру R/W, біт підтвердження ACK. Перші 9 біт, включаючи старт-біт, генеруються ведучим пристроєм, а біт підтвердження прийому - веденим пристроєм, чия адреса збігається з адресою, яку виставив на лінію ведучий:
Структура кадру обміну через I2C
Зазвичай 7-бітова адреса складається з двох частин: перші 4 біта визначають тип веденого пристрою, а останні 3 - номер пристрою зазначеного типу в системі. У табл. нижче наведені деякі типи пристроїв та їх спеціальні зарезервовані адреси при організації зв'язку через протокол I2C.
Процедура адресації відбувається наступним чином:
1. Ведучий пристрій генерує стан Старт.
2. Ведучий пристрій виставляє на лінію адресу веденого пристрою.
3. В залежності від значення біта R/W, ведучий пристрій посилає дані веденому пристрою (якщо R/W = 0) або зчитує дані, виставлені на лінію веденим пристроєм (R/W = 1).
4. Як тільки всі дані надіслані, ведучий пристрій генерує на лінії стан Stop.
У специфікації протоколу описаний ще один режим, який називається «Повторний старт». В цьому режимі ведучий пристрій встановлює ще раз стан Start і передає один байт адреси без генерації стану Stop. Це буває корисно для зміни напрямку передачі даних.
Використання інтерфейсу I2C на Raspberry Pi розглянемо на прикладі цифрового компасу HMC5883L.
Модуль магнітометра HMC5883L:
• Магнітометр HMC5883L використовується для вимірювання напрямку та величини магнітного поля Землі в дешевих цифрових компасах та магнітометрах.
• Вимірює значення магнітного поля Землі вздовж осей X, Y та Z від мілігауса до 8 гаус.
• Допомагає знайти напрямок руху пристрою.
• Для з’єднання використовує протокол I2C.
Магнітометр HMC5883L
Raspberry Pi має виводи інтерфейсу I2C, які показані нижче:
Щоб отримати доступ до шини I2C в Raspberry Pi, ми повинні виконати певні налаштування. Перш за все, треба дозволити інтерфейс I2C на Raspberry Pi. Це можна зробити через меню, або використати термінал, ввівши команду
sudo raspi-config
Вибираємо Interfacing Configurations, а потім I2C. Дозволяємо його і перезавантажуємо Raspberry Pi.
Після перезавантаження Raspberry Pi, перевіряємо, який режим використовує порт I2C, ввівши команду:
ls /dev/*i2c*
RPi повинен повернути назву порта i2c:
Вище показане використання інтерфейсу I2C в режимі i2c-1. Старі версії Raspberry Pi можуть повертати режим i2c-0.
Тепер підключимо магнітометр до порта I2C:
Магнітометр HMC5883L з Raspberry Pi 3
Далі, можемо протестувати/сканувати пристрої I2C, підключені до нашої плати Raspberry Pi, попередньо встановивши i2c-tools. Ми можемо отримати i2c-tools за допомогою apt-менеджера пакетів. Використайте таку команду в терміналі Raspberry Pi:
sudo apt install -y i2c-tools
Скануємо порт I2C за допомогою команди:
sudo i2cdetect -y 1
У відповідь ми повинні отримати адресу пристрою. Наприклад, ми підключили HMC5883L I2C до Raspberry Pi і спробували виявити цей пристрій, як показано нижче:
Команда i2cdetect сканує порт I2C, щоб отримати адресу пристрою, якщо він підключений.
Якщо пристрій не підключений до порту I2C, то повернеться поле з (- -).
Ми можемо отримати або встановити дані пристрою I2C за допомогою команд i2cget, i2cset, тощо
Наприклад,
sudo i2cget -y I2C_user_mode_Port address_of_device Register_address
sudo i2cget -y 1 0x68 0x01
і отримаємо дані, що містяться в реєстрі з адресою 0x01.
Ми можемо отримати доступ до шини I2C на Raspberry Pi, використовуючи SMBus. SMBus - це підмножина шини/інтерфейсу I2C. SMBus надає підтримку пристроям з інтерфейсом I2C. При написанні програми для доступу до пристрою на базі I2C використовуйте команди SMBus.
При розробці програм для зв'язку з Raspberry Pi через інтерфейс I2C на Python також використовуйте пакет бібліотеки SMBus, який надає широку підтримку доступу до пристроїв I2C. Отже, ми повинні додати підтримку SMBus для Python за допомогою пакетного менеджера apt:
sudo apt install python-smbus
Програмування
• По-перше, ми повинні встановити реєстр конфігурації A для середнього значення з 8 вимірювань з швидкістю виведення даних за замовчуванням 15 Гц.
• Налаштувати Gain, використовуючи регістр конфігурації B, тут вибрано 0xA0. (можемо вибрати будь-який інший бажаний)
.• Вибираємо в регістрі режиму режим безперервного вимірювання. Отже, значення регістра режиму буде рівне 0x00.
Після ініціалізації прочитаємо рядки значень регістрів X, Y та Z-осей.
Обчислюємо значення напрямку за допомогою такої формули
Зверніть увагу, що необхідно врахувати магнітне відхилення для даного географічного місця. Відхилення можна знайти, скориставшись ресурсом http://magnetic-declination.com. Запустивши сценарій на сайті, отримаємо для м.Київ:
Програма на Python
“””
Знаходження напрямку з інтерфейсом HMC5883L за допомогою Raspberry Pi і Python
http://www.electronicwings.com
”””
import smbus #імпорт модуля SMBus інтерфейсу I2C
from time import sleep #імпорт sleep
import math
#деякі регістри та їх адреси
Register_A = 0 #Адреса регістра конфігурації A
Register_B = 0x01 #Адреса регістра конфігурації B
Register_mode = 0x02 #Адреса регістра режиму
X_axis_H = 0x03 #Адреса регістра старшого байта даних X-осі
Z_axis_H = 0x05 #Адреса регістра старшого байта даних Z-осі
Y_axis_H = 0x07 #Адреса регістра старшого байта даних Y-осі
declination = 0.135 #кут відхилення для даного місця в радіанах
pi = 3.14159265359 #значення pi
def Magnetometer_Init():
#Запис в регістр конфігурації A
bus.write_byte_data(Device_Address, Register_A, 0x70)
# Запис в регістр конфігурації B для gain
bus.write_byte_data(Device_Address, Register_B, 0xa0)
#Запис в регістр режиму для вибору режиму
bus.write_byte_data(Device_Address, Register_mode, 0)
def read_raw_data(addr):
#Читання рядка 16-бітового значення
high = bus.read_byte_data(Device_Address, addr)
low = bus.read_byte_data(Device_Address, addr+1)
#об’єднання старшого і молодшого байтів
value = ((high << 8) | low)
#отримання знаку значення з модуля
if(value > 32768):
value = value - 65536
return value
bus = smbus.SMBus(1) # або bus = smbus.SMBus(0) для старих версій плати
Device_Address = 0x68 # адреса магнітометра HMC5883L
Magnetometer_Init() # ініціалізація магнітометра HMC5883L
print (" Reading Heading Angle")
while True:
#Читання рядка значення акселерометра
x = read_raw_data(X_axis_H)
z = read_raw_data(Z_axis_H)
y = read_raw_data(Y_axis_H)
heading = math.atan2(y, x) + declination
#Через відхилення перевіряємо чи не більше >360 градусів
if(heading > 2*pi):
heading = heading - 2*pi
#перевірка знаку
if(heading < 0):
heading = heading + 2*pi
#перетворення в градуси
heading_angle = int(heading * 180/pi)
print ("Heading Angle = %d°" %heading_angle)
sleep(1)
Вирішення проблем
• Якщо результати команди i2cdetect видають помилку, то або не встановлено i2c-tools, або вам потрібно використати режим 0, а не 1
• Якщо пристрій не виявлений і ви не бачите адреси, то або ви неправильно підключили пристрій, або не включений інтерфейс i2c
• Двічі перевірте з’єднання і перезавантажте RPi
У рідкісних випадках може бути несправний пристрій, але набагато більш ймовірно, що має місце одна з перерахованих вище причин.