Как проверить шину i2c
Содержание
- 1 Как проверить шину i2c
- 1.1 Как настроить I2C-связь на Arduino
- 1.2 Что такое I2C?
- 1.3 Сеть I2C
- 1.4 Использование I2C
- 1.5 Скетч для мастера
- 1.6 Объяснение скетча для мастера
- 1.7 Скетч для наследника (ведомого)
- 1.8 Объяснение скетча для ведомого
- 1.9 Тестирование Arduino I2C
- 1.10 Радиолюбительские измерения: анализ сигналов шины I2C
- 1.11 Цифровой двухканальный осциллограф с памятью
- 1.12 Логический анализатор цифровых сигналов
- 1.13 Цифровой осциллограф vs логический анализатор
- 1.14 И такое программное обеспечение существует
- 1.15 Как проверить что I2C настроен и работает верно?
Как настроить I2C-связь на Arduino
В этом уроке мы обсудим, что такое протокол связи I2C, как он работает и как его использовать на Arduino. Для демонстрации мы построим проект, использующий I2C-соединение для обмена данными между двумя микроконтроллерами Arduino.
Что такое I2C?
c – это аббревиатура от Inter-Integrated Circuit (меж-интеграционная цепь или последовательная асимметричная шина).
I2C – низкоскоростной последовательный протокол связи, подходящий для передачи данных на короткие расстояния. Если вам необходимо передавать данные на большие расстояния, этот протокол не рекомендуется. Пример простой сети I2C показан ниже.
Как видно на диаграмме, преимущество использования I2C состоит в том, что для связи с несколькими устройствами требуется всего два провода.
Вся связь проходит по двум проводам к ведущему и ведомым устройствам и от них. Это очень полезно при выполнении проектов Arduino, так как Arduino имеет ограниченное количество входных/выходных контактов.
Многие датчики и модули, предназначенные для Arduino используют I2C для связи.
Сеть I2C
Сеть I2C состоит из ведущего и ведомого устройств, соединенных шиной. В сети I2C может быть несколько ведущих и ведомых устройств – мастеров и наследников.
Ведомое устройство (наследник)
Все ведомые устройства имеют I2C-адрес, который используется для идентификации устройства в сети. I2C-адрес позволяет ведущему устройству передавать данные конкретному ведомому устройству на шине.
Ведущее устройство (мастер)
Ведущие устройства могут отправлять и получать данные. Ведомые устройства реагируют на все, что посылает ведущее устройство. При отправке данных на шину только одно устройство может отправлять данные одновременно.
Шина в I2C – это просто два провода, которые соединяют все I2C-устройства в сети.
Эти два провода называются SDA и SCL. Провод SDA используется для связи между ведущим и ведомым устройствами.
Линия SCL несет тактовый сигнал, используемый для правильной синхронизации связи. Для поддержания обоих проводов в состоянии HIGH необходимы импульсные или подтягивающие (pull-up) резисторы.
Логические уровни
Будьте внимательны при подключении I2C устройств к Arduino.
Arduino выводит I2C-сигналы на 5В логическом уровне, но I2C-устройства работают с различными напряжениями логического уровня.
Таким образом, I2C устройство, которое работает на 3,3 В может быть повреждено при подключении к Arduino. В паспорте устройства должно быть указано напряжение логического уровня.
Если подтягивающие резисторы подключены к +5В, все устройства должны быть совместимы для работы с логическим уровнем +5В.
Использование I2C
Чтобы продемонстрировать, как использовать I2C в Arduino, давайте создадим проект, который посылает данные туда и обратно между двумя ардуинами.
Мы будем использовать I2C связи для изменения скорости мигания светодиода контакта 13 на одном Arduino, в зависимости от положения потенциометра, подключенного к другому Arduino.
Один Arduino будет выступать в качестве мастера, а другой Arduino будет выступать в качестве ведомого.
Пины I2C Arduino
Arduino имеет специальные контакты для I2C, которые имеют встроенные подтягивающие резисторы в соответствии с требованиями протокола I2C.
Для плат Arduino Uno это контакты A4 и A5. Пин A4 – это контакт SDA, а пин A5 – это контакт SCL. В версии Arduino Uno R3 есть еще один набор контактов I2C рядом с USB-разъемом:
Компоненты оборудования
Чтобы создать этот проект, вам понадобятся следующие компоненты:
- Arduino Uno – 2 шт.
- Потенциометр (10КОм) – 2 шт.
- Перемычки
Схема соединения
После того, как вы соберете все детали, пришло время собрать проект. Следуйте нижеприведенной электрической схеме, чтобы все подключить:
Вы могли заметить, что у нас нет подтягивающих резисторов на линиях SDA и SCL. Подтягивающие резисторы уже встроены в I2C контакты Arduino, так что они нам не нужны.
Скетч для мастера
У нас есть два Ардуино в нашей сети I2C, так что у нас есть два набора скетчей. Один для мастера Ардуино, а другой для наследника Ардуино. Между двумя эскизами нет большой разницы, как вы увидите позже.
Теперь откройте Arduino IDE и загрузите код ниже на мастер Arduino:
Объяснение скетча для мастера
Основная часть кода как для ведущего, так и для ведомых устройств – это то, что я называю логическим кодом мигания. Чтобы мигнуть светодиодом 13 на Ардуино, мы должны сделать следующее:
- Добавим глобальные переменные byte i2c_rcv , int time_start , stat_LED и byte value_pot в верхней части нашего скетча
- Инициализируйте значения глобальных переменных внутри функции setup()
- Инициализируйте контакт 13 Arduino как выходной контакт внутри setup() с помощью pinMode()
- Добавим код логики мигания внутри функции loop()
Библиотека Wire
Для использования встроенного интерфейса I2C Arduino мы будем использовать библиотеку Wire.
Эта библиотека поставляется в стандартной комплектации с Arduino IDE. Как и в других библиотеках Arduino, библиотека Wire имеет готовые I2C функции, чтобы сделать кодирование проще для нас.
Чтобы использовать функции библиотеки Wire, мы должны добавить его сначала в наш эскиз. В эскизе выше, у нас есть следующая строка в верхней части:
После включения библиотеки мы можем использовать встроенные функции библиотеки.
Первое, что нужно сделать, это подключить устройство к шине I2C. Синтаксис для этого – Wire.begin(address) . Адрес является необязательным для мастер-устройств. Итак, для эскиза мастера Arduino, мы просто добавляем код Wire.begin(); внутри setup() .
Теперь мы переходим к циклу loop() . Наш код заставит Arduino прочитать значение потенциометра, подключенного к контакту A0, и сохранить его в переменной value_pot .
Отправка данных
После сохранения значения с пина A0 в переменную value_pot , мы можем отправить значение по I2C. Отправка данных по I2C включает в себя три функции:
- Wire.beginTransmission()
- Wire.write()
- Wire.endTransmission()
Wire.beginTransmission()
Мы инициируем команду отправки, сначала информируя устройства на шине о том, что мы будем отправлять данные.
Для этого мы вызываем функцию Wire.beginTransmission(address) . Адрес – это I2C-адрес ведомого прибора, который будет принимать данные. Эта функция делает две вещи:
- Она информирует шину о том, что мы будем посылать данные.
- Он информирует предполагаемого получателя о том, что данные готовы к получению.
Wire.write()
А затем мы отправим значение переменной value_to_send с помощью функции Wire.write(value) .
Wire.endTransmission()
После отправки данных нам необходимо освободить сеть, чтобы позволить другим устройствам общаться по сети. Это делается с помощью функции Wire.endTransmission() .
Наше ведущее устройство также должно получить положение потенциометра от ведомого устройства. Мы делаем это с помощью Wire.requestFrom() , Wire.available() и Wire.read() .
Wire.requestFrom()
Полным синтаксисом запроса данных от ведомого устройства является Wire.requestFrom(адрес, количество).
Адрес – это I2C-адрес ведомого устройства, от которого мы должны получить данные, а количество – это количество байтов, которое нам нужно. Для нашего проекта, адрес ведомого устройства 0x08 и нам нужен один байт.
Внутри loop() мы используем Wire.requestFrom(0x08, 1); для запроса одного байта данных от ведомого устройства 0x08.
После выдачи команды Wire.requestFrom(0x08, 1) , за ней должна следовать команда чтения для получения ответа от шины I2C.
Write.available()
Сначала мы проверяем, есть ли данные на шине. Это делается с помощью функции Write.available() внутри условного оператора if() . Функция Write.available() возвращает количество байт, ожидающих чтения.
Wire.read();
Для получения доступных данных мы используем функцию Wire.read() и сохраняем возвращаемое значение в переменную i2c_rcv . Каждый вызов функции Wire.read() получает только один байт данных из шины I2C.
Скетч для наследника (ведомого)
Теперь загрузите этот код ведомому Ардуино:
Объяснение скетча для ведомого
Для ведомого устройства существует небольшая разница в кодировании I2C-связи. Первая разница заключается в адресе Wire.begin(address) .
Для ведомых устройств адрес является обязательным. Для нашего проекта адрес для ведомого устройства будет 0x08. Это может быть любой адрес, но убедитесь, что он уникален в сети I2C.
Некоторые I2C ведомые устройства также имеют определенные I2C-адреса, поэтому сначала проверьте спецификацию.
Мы присоединим I2C сеть в качестве ведомого устройства, добавив код Wire.begin(0x08); внутри setup() .
Обработчики событий
Следующая задача – добавить в наш код обработчики событий для управления данными, полученными с других устройств в I2C сети.
Обработчики событий – это части кода, которые управляют событиями, с которыми наше устройство, скорее всего, столкнется во время работы.
Wire.onReceive()
В части скетча setup() мы добавляем функцию Wire.onReceive(handler) для регистрации функции (обработчика), которая будет управлять полученными данными.
Мы вызываем нашу функцию-обработчик dataRcv() . Обратите внимание, что имя функции может быть любым. В приведенном выше эскизе Wire.onReceive(dataRcv); вызывается в секции setup() .
В конце эскиза находится код функции-обработчика. Он инициализируется как void dataRcv(int numBytes) . Параметр int numBytes содержит количество байт полученных данных.
Wire.onRequest()
Следующий обработчик события, который мы будем использовать – Wire.onRequest(handler) . Эта функция используется на подчиненных устройствах и работает аналогично Wire.onReceive() .
Единственное отличие заключается в том, что она обрабатывает события запроса данных. Запросы данных поступают от основных устройств.
В функцию setup() мы добавляем код Wire.onRequest(dataRqst); . А в конце нашего эскиза добавляем функцию void dataRqst() . Обратите внимание, что обработчики Wire.onRequest() не принимают никаких параметров. Функция dataRqst() содержит только Wire.write() .
Нам не нужны Wire.beginTransmission() и Wire.endTransmission() , потому что библиотека Wire уже обрабатывает ответы от ведомых устройств.
Тестирование Arduino I2C
А вот и самая захватывающая часть – включение питания и тестирование!
Используя Arduino IDE, загрузите эскиз мастера Arduino в одну из Ардуино. Затем загрузите скетч наследника в другую Arduino.
- Отрегулируйте потенциометр на ведущем устройстве, чтобы регулировать частоту мигания светодиода ведомого устройства.
- Отрегулируйте потенциометр на ведомом устройстве, чтобы контролировать частоту мигания светодиода ведущего устройства.
Наш код принимает положение потенциометра мастера и посылает его ведомому устройству через I2C. Затем ведомое устройство использует полученное значение для настройки времени задержки мигания светодиода. То же самое происходит и с положением потенциометра ведомого.
Радиолюбительские измерения: анализ сигналов шины I2C
Как я уже неоднократно упоминал в своих публикациях, любительские проекты финансируются из семейного бюджета, и радиолюбитель, обычно, не может себе позволить покупку дорогостоящего измерительного оборудования. Приходится довольствоваться тем, что есть. Или тем, что удаётся взять попользоваться «на время». А иногда от безысходности радиолюбителю приходится «сверлить пилой и пилить буравчиком».
Недавно я испытал потребность выяснить, что на самом деле передаётся в разрабатываемом мной устройстве по шине I2C. Это был тот счастливый момент, когда можно было себе позволить «пилить пилой».
Как происходит обмен данными между устройствами по протоколу I2C можно узнать здесь. Для анализа сигналов на шине I2C можно применить, как цифровой двухканальный осциллограф с памятью, так и логический анализатор.
Цифровой двухканальный осциллограф с памятью
При работе с радиоэлектронной аппаратурой осциллограф является наиболее универсальным инструментом. Современные цифровые осциллографы обладают рядом полезных свойств, позволяющих производить, в том числе, и анализ сигналов шины I2C.
В данном случае мне достался «на время» цифровой двухканальный осциллограф с памятью Rigol DS1102 (цена на сайте производителя $461). У этого прибора есть два канала измерения с полосой пропускания до 100 MHz и частотой выборки сигнала 1 GSa/s.
К сигналу SCL был подключен CH1. К сигналу SDA был подключен CH2. Для обоих каналов был установлен масштаб 1.00 V/дел. Масштаб развёртки – 10 us/дел. Для наглядности луч первого канала смещён в верхнюю половину экрана, а луч второго канала – в нижнюю.
В меню Trigger осциллограф был настроен на однократное измерение с запуском по достижению передним фронтом в канале CH1 уровня 1.00 V:
После включения тестируемого оборудования была нажата большая красная кнопка Run/Stop. Осциллограф встал в режим ожидания, затем запустился. Через несколько секунд запись была остановлена вручную.
Полученная осциллограмма записывалась на внешний носитель поэкранно:
Произведём разбор записанных сигналов. На первом экране мы видим отображение настроек прибора и осциллограмму сигналов SCL (верхняя часть) и SDA (нижняя часть экрана), на которой читаем слева направо:
- сигнал START: ведущее устройство выставляет низкий уровень сначала на шине SDA, а затем на шине SCL;
- 7-bit адрес: читаем 0x60 (1100000) на шине SDA по передним фронтам SCL;
- признак режима записи: читаем на шине SDA низкий уровень по следующему переднему фронту SCL;
- сигнал ACK: ведущее устройство после передачи байта переключается на приём по шине SDA, на SDA устанавливается высокий уровень, ведомое устройство по заднему фронту SCL выставляет на SDA низкий уровень (собственно, сигнал ACK), который ведущее устройство считывает по переднему фронту SCL;
- сигнал STOP: ведущее устройство выставляет высокий уровень сначала на шине SCL, а затем на шине SDA
Подобным образом, медленно, но верно, можно произвести вручную дешифровку остальных частей записи.
Логический анализатор цифровых сигналов
Дешифрацию протокола можно произвести более простым методом, используя логический анализатор и соответствующее программное обеспечение.
Для использования в качестве логического анализатора мне был любезно предоставлен коллегами Saleae Logic 8 (цена на сайте производителя $399). В качестве программного обеспечения использовалась демо-версия Saleae Logic 1.2.18, взятая с официального сайта. Устанавливая данное программное обеспечение, я принял лицензионное соглашение с условием, в том числе, не использовать данное программное обеспечение с оборудованием сторонних производителей.
В программе был включен анализатор протокола I2C. Для сигнала SCL был назначен канал CH0, а для сигнала SDA – канал CH1. Частота выборки сигнала 24 MSa/s.
Запуск был настроен по «переднему» фронту CH0. Для отображения данных был выбран шестнадцатеричный формат.
После включения тестируемого оборудования была нажата большая зелёная кнопка Start, и через несколько секунд на экран вывелась диаграмма:
Максимум пользы в применении логического анализатора я вижу в том, что программа сама дешифрует полученные данные. Результаты дешифровки заносятся построчно в окно Decoded Protocols. При выборе в окне строки данных, программа показывает расположение этих данных на диаграмме.
Цифровой осциллограф vs логический анализатор
Для сравнения вариантов я «склеил» в графическом редакторе четыре снимка экрана осциллографа и фрагмент диаграммы логического анализатора:
Start обозначен зеленым кружочком, Stop – красным кружочком. На диаграмме сначала происходит проверка наличия на шине устройства с адресом 0x60, а затем производится запись в регистр 0xB7 этого устройства значения 0x80.
Если подходить к сравнению вариантов «с пристрастием», то можно заметить, что на диаграмме логического анализатора (частота выборки 24 MSa/s) присутствует «джиттер» сигнала SCL, которого нет, как такового, на осциллограмме с частотой выборки 1 GSa/s. В остальном картина совпадает, а логическим анализатором ещё и производится правильная дешифрация данных в автоматическом режиме.
При выборе «или-или» в «сухом остатке» имеем, в случае осциллографа, дорогое универсальное устройство, не такое удобное для анализа шины, как логический анализатор, но за сопоставимые с ним деньги. В этих условиях лично я, как инженер «старой закалки», приобрёл бы цифровой осциллограф.
Однако, если бы существовало программное обеспечение с лицензионным соглашением, позволяющим использование недорогих клонов популярных логических анализаторов, типа Saleae Logic 8 или DSLogic Plus…
И такое программное обеспечение существует
Недорогие клоны популярных логических анализаторов, и не только их, поддерживает программное обеспечение open source проекта sigrok.
Было собрано рабочее место:
После чего начались «танцы с бубном». На Windows 10 запустилась только 32-разрядная версия PulseView. Наличие в системе недорогого китайского клона Saleae Logic (цена на сайте продавца $7) она не определила.
После этого, в Zadig для устройства Logic были установлены драйверы WinUSB, и после повторного сканирования оно определилось в Zadig, как устройство fx2latw:
После этого для устройства fx2latw в Zadig снова были установлены драйверы WinUSB, и только после этого PulseView увидела в списке устройство «Saleae Logic». Устройство было подключено.
После подключения устройства были произведены следующие настройки программы (слева направо по панели инструментов, начиная с надписи «Saleae Logic»):
- выставлено Pre-trigger capture ratio = 2% по нажатию кнопки с ключом и отвёрткой;
- отключены лишние входы по нажатию кнопки с красным щупом;
- выставлен объем записи 100 К выборок;
- выставлена частота выборки 24 MHz;
- включен анализатор протокола I2C по нажатию кнопки с жёлто-зелёным значком.
Далее в панели слева от каналов:
- каналам присвоены соответствующие сигналам текстовые метки;
- условием запуска назначен задний фронт сигнала SDA;
- сигналам I2C назначены соответствующие каналы.
После включения тестируемого оборудования была нажата кнопка Run. Получен уже знакомый результат:
Похоже, «танцы с бубном» того стоили!
UPD: После ручной установки в Диспетчере устройств для устройства USB Logic драйвера libusb-win32 программа PulseView начала стабильно определять наличие в системе «Saleae Logic» без манипуляций с Zadig.
Краткие выводы:
В статье была описана методика проведения анализа сигналов шины I2C с помощью цифрового осциллографа с памятью и логических анализаторов с пакетами прикладного программного обеспечения.
Универсальным методом анализа сигналов, но недешёвым и небыстрым, является применение цифрового осциллографа с памятью.
Быстрым и бюджетным методом анализа сигналов, но с нетривиальной задачей подключения оборудования, является применение недорогого клона логического анализатора в связке с PulseView.
Буду рад, если своей публикацией помог сэкономить читателям время и деньги.
В следующей публикации расскажу, как измерял частоту, на которой запустился кварцевый резонатор в синтезаторе частоты, без частотомера. Но это уже другая история…
Как проверить что I2C настроен и работает верно?
Как проверить, что I2C настроен и работает верно? Уже два дня не могу завести I2C на ADuC7024.
Схему подключения датчика проверял неоднократно. Датчик не откликается.
До этого с I2C не работал.
Как проверить, что ты верно нашел собственные числа и вектора матрицы?
Здравствуйте! Подскажите, пожалуйста, как можно проверить правильность найденных собственных чисел.
как проверить сгоревший I2C ?
Кажется что сгорел y2s, не знаю как проверить – осцилографа нет ;( Но в то же время оба вывода.
Может быть всё что угодно:
– неправильная инициализация TWI модуля (например частота)
– неправильные значения подтягивающих резисторов vs длина линии
– неправильная последовательность общения с TWI
Проверить – только цифровым осциллографом.
Тогда нужен код. Может быть что-то кто-нибудь и увидит.
Минимум – посмотреть в “покое” тестером – на SCL и SDA должны быть 1.
Правильно ли подключен сам датчик?
Чтобы выбрать режим обмена по I2С, нужно пин CS подключить к питанию.
Пин SDO в режиме I2C отвечает за адрес устройства. Если SDO сидит на земле, то адрес на чтение – 0x39, на запись – 0x38. Если подключен к питанию, то 0x3B и 0x3A соответственно.
Схема подключения взята из даташита. SDO на земле.
Возможно у нас недопонимание. В статье я указал как меняется адрес датчика в зависимости от SDO. Адрес в I2C это 7 бит, к которым добавляется еще один, обозначающий запись(0) или чтение (1).
Например чтобы считать значение регистра WHO_AM_I (0x0f) при SDO притянутом к VCC, надо (код просто как пример):
Если вы использовали именно эти адреса, то датчик откликаться не мог. У него совсем другие адреса.
На I2C забил. Аппаратно он реализован криво. Зато нашел простую рабочею софтварную реализацию http://www.robot-itistronics.co.uk/acat . orial.html.
2Mr_Pymk: Посмотрел твой код. Он рабочий?
output=SPI(0x0f,0xaa); // читаем “who am i” регистр .
Так прочитать значение регистра акселерометра невозможно. Все разобрался. Но все равно, код стремный.
Код я для примера привел, чтобы показать алгоритм чтения. Конечно у вас он бы не заработал, так как выдернут из моего проекта.
А теперь по поводу разногласий в адресах. Дело в том что я говорил про lis302dl. А у вас lis302dlH.
Скачал даташит и у них действительно разные адреса. Так что мы с вами про немного разные модели говорили.
SDO-MOSI
SDA-MISO. Это я правильно понял?
Акселерометр у меня возвращает какой то мусор. Наверное где то коротит((
Честно говоря не знаю, кто из них прав LUFA или LIS в следовании стандарту,
и что означает
return ((TWSR & TW_STATUS_MASK) == TW_MR_DATA_ACK);
но без неё всё работает
ЗЫ.
Спасибо Mr_Pymk за статью. Подсмотрел одну команду и всё заработало!
Проверить верно ли, что заданное число простое
1. Дано целое число N (> 1). Если оно простое, то вывести сообщение: «Число N простое», иначе.
Проверить, верно ли, что в числе нет цифр a
Дано натуральное число. Верно ли, что нет в нём цифр a.
Проверить, верно ли, что 3 элемента равны заданному числу k
В одномерном массиве х1,х2. Хn.Проверить верно ли 3 элемента равных заданному числу k
Проверить, верно ли, что наибольший член последовательности больше 1?
Вводится последовательность из n целых чисел (n задается с клавиатуры) Верно ли , что наибольший.