ack nack что это
NACK против ACK? Когда использовать один поверх другого?
Лично я даже не чувствую, что есть необходимость в ACK. Это быстрее, если мы просто отправим NACK (n) для потерянных пакетов вместо отправки ACK для каждого полученного пакета. Итак, когда / в каких ситуациях можно использовать ACK поверх NACK и наоборот?
Причиной ACK является то, что NACK просто недостаточно. Допустим, я отправляю вам поток данных из X сегментов (скажем, 10 для простоты).
У вас плохое соединение, и вы получаете только сегменты 1, 2, 4 и 5. Ваш компьютер отправляет NACK для сегмента 3, но не понимает, что должны быть сегменты 6-10, и не NACK их.
Итак, я пересылаю сегмент 3, но затем мой компьютер ошибочно полагает, что данные успешно отправлены.
ACK обеспечивают некоторую гарантию того, что сегмент прибыл в пункт назначения.
Если вы хотите, чтобы приложение обрабатывало порядок данных и повторных передач, вы можете просто выбрать использование протокола, такого как UDP (например, как TFTP).
Все сводится к распределению вероятности потерь и типу трафика.
Возьмем, к примеру, типичное беспроводное соединение с устойчивым уровнем потерь 10-30%. Если вы подтвердите каждый полученный кадр (например, 802.11abg), вы быстро обнаружите, когда кадр был потерян, поэтому вы не потеряете время для ожидания тайм-аута.
(угадайте, какое решение выберет 802.11n? и то и другое. Получатель отправляет битовую карту с переменной длиной кадра, которую он получил)
Теперь возьмем типичную сеть Интернет: у вас потеря пакетов близка к 0%, пока не случится что-то плохое, и у вас будет потеря пакетов, близкая к 100%, в течение определенного времени, следуя некоторому экспоненциальному закону распределения, от прерывания 200 мс до минуты и половина.
Захватывать каждый пакет в сети без потерь может показаться бессмысленным, пока вы не рассмотрите случай, когда связь разорвана: вы не будете получать ACK или NACK в течение возможно длительного промежутка времени, а получатель, как правило, не будет отправлять что-либо до соединения восстанавливается.
Если вы используете ACK, отправитель прекратит отправку и сохранит свое отставание до восстановления ссылки. Если вместо этого вы используете NACK, то получатель может в конечном итоге сказать вам, что он не получил пакет, который долгое время оставался в резерве отправителя, и соединение по существу невозможно восстановить.
ACK могут считаться более важными, чем NAK. NAK просто обеспечивают более быстрое восстановление в случае, когда пакет / блок, отправленный A, не принят B, и B каким-то образом обнаруживает, что пакет / блок отсутствует.
Совершенно возможно разработать протокол, поддерживающий надежную передачу и управление потоком только с ACK, без NAK (с повторной передачей передатчиком в случае, если передатчик не получает ACK, механизм повторной передачи, который необходим в любом случае).
Здесь я хотел бы добавить одну самую важную вещь: в TCP мы НЕ отправляем ACK для каждого полученного пакета.
Однако ACK отправляются только для ПОСЛЕДНЕГО ПОЛУЧЕННОГО ПАКЕТА.
Пожалуйста, поправьте меня, если я ошибаюсь.
Настройка Kafka для работы в режиме подтверждения о принятии сообщения (ack/nack)
единый тип реляционной базы данных
единый брокер сообщений
единый фреймворк в разрезе языка программирования
В этой статье пойдет речь о выборе брокера сообщений.
Kafka на данный момент уже используется в компании и эта технология является более масштабируемой чем тот же RabbitMQ, поэтому мы и смотрим в ее сторону. Перед тем как начать внедрять Kafka в наши проекты, мы протестируем закрывает ли эта технология наши потребности.
Предъявляемые требования к брокеру сообщений:
Совместимость с PHP
Стабильная работа, отказоустойчивость, высокий SLA(>99,95%)
Быстрая скорость отправки сообщения в очередь
Уверенность в доставке сообщения
Уверенность в получении и обработке сообщения(ack/nack)
По сути это все все и так есть и отлично работает(на малых и средних объемах) у RabbitMQ.
1. Выбор клиента для PHP
На официальном сайте Kafka есть несколько ссылок на репозиториев интеграции.
2. Сетап окружения
В 21м году Docker для разработчика это как кнут для Индианы Джонс.
После клонирования репозитория, запускаем:
С первого раза конечно же проект не собрался(как минимум у меня на MacOs BigSur). Для того чтобы испраить ошибку было достаточно просто убрать чётко заданую версию Kafka.
Все готово для работы приожения, но а как же без доп. бонуса? Для того чтобы лучше понимать что происходит с неизвестным мне инструментом, я решил сразу же поискать визуальный менеджер. Было несколько платных версий которые нужно устанавливать на ПК. Но это же не трушно. Поэтому я установил opensource admin panel
Для этого добавляем несколько строк в наш docker-compose.yml
На старт, внимание, пуск.
В консоли мы увидим наши сообщения.
Поздравляю вас теперь вы адепты Kafka.
3. Настраиваем конфигурацию под наши требования
Для этого нам потребуется отключить автоматическую синхронизацию кафки о сохраненном оффсете.
Для того чтобы севрвер мог сохранять offset мы должны назначить consumer’у уникальный идентификатор чтобы при переподключении кафка знала на каком месте мы остановлись.
Начинаем прослушивать очередь:
Получение сообщения из очереди
После успешной обработки сообщения(сохранения в БД или тп) помечаем сообщение как прочитанное(инкрементируем оффсет)
Вуаля, мы реализовали консистентную работу c Apache Kafka.
В поисках утерянного гигабита или немного про окна в TCP
Поводом для написания этой статьи послужила лень, которая, как известно, двигатель прогресса и свидетель появления на свет невероятно облегчающих жизнь вещей.
В моём случае это была лень объяснять в тысячный раз клиенту, почему он арендовал канал точка-точка и в договоре чёрным по белому написано Ethernet 1Гбит/с, а он как ни измеряет, но чуть-чуть да меньше получается.
Где остальное? Почему недобор? Куда девался интернет из провода? А может его и вовсе страшно обманули?
Ну что ж, давайте искать, а заодно напишем заметку, которую будет не стыдно показать тысяче первому клиенту, у которого будет недосдача скорости.
Важно
Если вы сетевой инженер, то не читайте эту статью. Она оскорбит все ваши чувства т.к. написана максимально простым и доступным языком с множеством упущений.
История про окна. Мир до окон
Итак, чтобы понять, где скорость, нам придётся разобраться в том, как работает TCP в плане обеспечения надежности соединения.
Как нам всем известно, у ТСР есть финт последней надежды, когда все ухищрения доставить кадр до получателя не сработали, он просто заново отправляет испорченный или утерянный кадр.
Как это выглядит в простейшем случае:
Графически этот алгоритм легко представляется на временной шкале:
Называется этот алгоритм методом простоя источника, что сразу даёт нам понять его главный минус: катастрофически неэффективное использование канала связи. Технически, ничего не мешает передатчику сразу после отправки первого кадра отправлять второй, но мы принуждаем его ждать прихода ACK/NACK или истечения таймера.
Поэтому важно понимать, что процессы отправки и получения ACKов могут идти независимо друг от друга. На этой идее и был рождён метод скользящего окна.
Окно первое. Скользящее. Теоретическое.
После осознания минусов предыдущего метода, в голову приходит идея разрешить источнику передавать пакеты в максимально возможном для него темпе, без ожидания подтверждения от приёмника. Но не бесконечное их количество, а ограниченное неким буфером, который называется окном, а его размер указывает на количество кадров которое разрешено передать без ожидания подтверждений.
Вернёмся к картинкам:
Для наглядности рассмотрим окно размером К кадров, в котором находятся пакеты (1. N) в некий момент времени, т.е. у нас была отправлена пачка кадров, каждый кадр по мере своей возможности достиг получателя, тот их обработал и отправил подтверждение для каждого.
Теперь усложняем ситуацию, включив время.
В момент прихода АСК на первый кадр, последний ещё не был даже отправлен, но поскольку мы знаем об успешности доставки, в окно можно добавить следующий по порядку кадр, т.е. окно сдвигается и теперь включает в себя кадры 2. N+1. Когда приходит ACK на 2-й кадр, окно снова сдвигается: 3. N+2. И так далее. Получается, что окно как-бы «скользит» по потоку пакетов. Или пакеты через него, тут кому как удобней представлять.
Таким образом, все кадры глобально делятся на три вида:
И как это влияет на скорость связи? – спросите вы.
Как мы видим из графика, необходимым условием для максимальной утилизации канала связи является регулярное поступление подтверждений в рамках действия окна. АСК не обязаны приходить в чётком порядке, главное чтобы АСК на первый кадр в окне пришёл раньше, чем будет отправлен последний кадр, иначе сработает таймер неответа, кадр будет отправлен заново, а движение окна прекратится.
Также, стоит отметить, что в большинстве реализаций алгоритма скользящего окна, подтверждения приходят не на каждый пакет, а сразу на всю принятую пачку (называется Selective Ack). Это позволяет ещё больше увеличить эффективную утилизацию канала за счёт снижения объёма служебной информации.
Итак, что же мы имеем в сухом остатке? Какие параметры имеют существенное влияние на эффективность передачи данных между двумя точками?
И мы не должны передать больше, чем готов принять получатель или пропустить сеть.
Давайте представим, что у нас супер надёжная сеть, где пакеты практически никогда не теряются и не бьются. В такой сети нам выгодно иметь окно максимально возможного размера, что позволит нам минимизировать паузы между отправкой кадров.
В плохой же сети ситуация обратная — при частых потерях и большом количестве битых пакетов нам важно доставить каждый из них в целости и сохранности, поэтому мы уменьшаем окно так, чтобы трафик как можно меньше терялся и мы избежали фатальных переотправок. Жертвовать в этом случае приходится скоростью.
И как нам всем известно, реальность — это смесь двух крайних случаев, поэтому в реальной сети размер окна величина переменная. Причём он может быть изменён, как в одностороннем порядке на любой стороне, так и по согласованию.
Промежуточное резюме. Как мы видим, даже без привязки к конкретным протоколам, чисто технически крайне сложно утилизировать канал на все 100%, т.к. хотим мы того или нет, но даже в лабораторных условиях между кадрами будут минимальные, но задержки, которые и не дадут нам достичь заветных 100% утилизации полосы пропускания.
А что уж говорить про реальные сети? Вот во второй части мы и рассмотрим одну из реализаций на примере TCP.
Окно второе. Реализация в TCP
Чем замечателен ТСР? На основе ненадёжных дейтаграмм IP, он позволяет обеспечить надежную доставку сообщений.
При установлении логического соединения модули ТСР обмениваются между собой следующими параметрами:
Сразу запоминаем важную особенность — в ТСР окно оперирует не количеством кадров, а количеством байт. Это значит, что окно представляет из себя множество нумерованных байт неструктурированного потока данных от верхних протоколов. Звучит громоздко, но проще написать не получается.
Итак, ТСР протокол дуплексный, а значит каждая сторона в любой момент времени выступает и как отправитель, и как получатель. Следовательно с каждой стороны должен быть буфер для приёма сегментов и буфер для ещё не отправленных сегментов. Но кроме того, должен быть ещё и буфер для копий уже отправленных сегментов, на которые ещё не получили подтверждения о приёме.
Кстати, отсюда следует упускаемая многими особенность: в двух направлениях условия сети могут быть разными, а значит разный размер окон и разная пропускная способность.
В такой ситуации пляска ведётся от возможностей получателя. При установлении соединения, обе стороны высылают друг другу окна приёма. Получатель запоминает его размер и понимает сколько байт можно отправить, не дожидаясь АСК.
Дальше включаются механизмы описанные в первой главе. Отправка сегментов, ожидание подтверждение, повторная отправка в случае необходимости и т.д. Важное отличие от теоретических изысканий — это комбинирование различных методик. Так например, получение нескольких сегментов, пришедших по порядку, происходит автоматически, прерываясь, только если сбивается очередность поступления. Это одна из функций буфера получателя — восстановить порядок сегментов. И то, если в потоке обнаруживается разрыв, ТСР модуль может повторить запрос потерянного сегмента.
Пара слов про буфер копий на отправителе. У всех сегментов, лежащих в этом буфере, работает таймер. Если за время таймера приходит соответствующий АСК, сегмент удаляется. Если нет — отправляется заново. Возможна такая ситуация, что по таймеру сегмент будет отправлен ещё раз до того, как придёт АСК, но в этом случае повторный сегмент просто будет отброшен получателем.
И вот от этого тайм-аута на ожидание и зависит производительность ТСР. Будет слишком короткий — появятся избыточные переотправки пакетов. Слишком длинный — получим простои из-за ожидания несуществующих АСК.
На самом деле ТСР определяет размер тайм-аута по сложному адаптивному алгоритму, где учитываются скорость, надежность, протяжённость линии и множество других факторов. Но в общих чертах он таков:
Но что-то мы всё больше про окно отправки, хотя окно приёма представляет из себя более интересную сущность. На разных концах соединения окна, обычно, имеют разный размер. В мире победивших клиент-серверных технологий, не приходится ожидать, что клиент будет готов оперировать окном того же размера, который может обрабатывать сервер.
Точно так же размер его может меняться динамически, в зависимости от состояния сети, но здесь неправильный выбор подразумевает уже “двойную” ответственность. В случае получения данных бОльших, чем может обработать ТСР модуль, они будут отброшены, на источнике сработает таймер, он переотправит данные, они опять не попадут в размер окна и т.д.
С другой стороны, установка слишком маленького окна приведёт к использованию канала на скорости равной скорости передачи одного сегмента.Поэтому разработчики ТСР предложили схему, в которой при установлении соединения размер окна устанавливается относительно большим и в случае проблем начинает сокращаться в два раза за шаг. Это действительно выглядит странно, поэтому были созданы реализации ТСР повторяющие привычную нам логику: начать с малого окна и, если сеть справляется, то начать его увеличивать.
Но на размер окна приёма может влиять не только принимающая сторона, но и отправитель данных. Если мы видим, что АСК регулярно приходят позже таймеров, что приходится часто переотправлять сегменты, то источник может выставить своё значение окна приёма и будет действовать правило наименьшего — будет принято самое маленькое значение, кто бы его ни назначил.
Остаётся рассмотреть ещё один вариант развития событий, а именно перегрузку ТСР-соединения. Это состояние сети характеризуется тем, что на на промежуточных и оконечных узлах возникают очереди пакетов. В данном случае у приёмника есть два варианта:
Хотя полностью закрыть соединение таким образом нельзя. Существует специальный указатель срочности, который принуждает порт принять сегмент данных, даже если для этого придётся очистить существующий буфер. А принявший нулевой размер окна отправитель не теряет надежды и периодически отправляет контрольные запросы на приёмник и, если тот уже готов для принятия новых данных, то в ответ он получит новый, не нулевой, размер окна.
Итого
Капитан подсказывает — если одна TCP сессия в принципе не может обеспечивать 100% утилизацию канала, то используй две. Если мы говорим про клиента, который взял в аренду канал точка-точка и поднял в нём GRE туннель, то пусть поднимет второй. Дабы они не дрались за полосу, заворачиваем в первый важный трафик, во второй — всякую ерунду и страшно зарезаем ему скорость. Этого как раз хватит на то, чтобы выбрать остатки полосы, которую первая сессия не может взять чисто технически.
Электроника для всех
Блог о электронике
Интерфейсная шина IIC (I2C)
Логический уровень
Как передаются отдельные биты понятно, теперь о том что эти биты значат. В отличии от SPI тут умная адресная структура. Данные шлются пакетами, каждый пакет состоит из девяти бит. 8 данных и 1 бит подтверждения/не подтверждения приема.
После адресного пакета идут пакеты с данными в ту или другую сторону, в зависимости от бита RW в заголовочном пакете.
Вот, например, Запись. В квадратиках идут номера битов. W=0
Задача решается так:
С записью все понятно — записали вначале адрес, а потом следом записали данные. А умная микросхема все прекрасно поняла и рассовала по ячейкам. А с чтением? А с чтением все через задницу, в смысле через запись.
Скриншот с осциллографа RIGOL 1042CD
Вроде бы все, практический пример с AVR будет потом, а пока помедитируйте над диаграммой работы конечного автомата TWI передатчика ATmega8. Скоро я вас буду этим грузить!
Страшна? 😉 На самом деле там все не так брутально. Можно обойтись вообще парой десятков строк кода на ассемблере.
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
200 thoughts on “Интерфейсная шина IIC (I2C)”
(1) OpenID работает криво. Я зашёл как blacklion.livejournal.com и всё равно справа-сверху «войти» (а не «выйти») и не даю комментировать. Пришлось регистрироваться и теперь тут два меня.
(2) Софтового мастера сделать не сложно. А вот слейва как-то просто не получается.
Щас попробую с опен ид поиграться.
Более того, многие предпочитают делать софтовый И2С мастер чтобы не заморачиваться с встроенным в TWI конечным автоматом.
Более того, многие предпочитают делать софтовый И2С мастер чтобы не заморачиваться с встроенным в TWI конечным автоматом.
Я когда первый раз подходил к электронике смотрел на PIC (зачем я это делал!? Зачем на PIC?!) так реализовал мастера в качестве упражнения за вечер. А вот слейва так и не осилил…
Я сделал софтового слейва на AT89C2051, но работало жутко медленно.
плюсадин. я уже раз 5 жаловался что логины глючат 😀 нашел выход, что залогинился, пару минуток подождал и рефреш. работает, но бесит :\
DI HALT спасибо за статью. Давно ждал рассказ про I2C. 🙂
У меня их почти полный аналог ICL12008 ваще работать не хотят — не отзываются на свой адрес, не дают ACK
и у тебя, Брут? я изъебался с их инициализацией — не пашут и все. взял ds, который считал сгоревшим и не рабочим, по по недоразумению не выкинул — и он заработал. в топку эти ISL, от лукавого они..
А у меня 5 штук их лежит — сэмплы. Надо бы в ST гневный мессадж накатать. МОл чо вы за говно нам подсунули?
Да, есть такое дело 🙂 Вообще при начале работы с IIC девайсом, желательно вдоль и поперек изучить Datasheet к нему. В свое время тоже поломал голову с m41 от ST. Вроде все пишется, все читается, но часы стоят и все тут. Оказалось там есть хитрый битик, который при пропадании всего питания — Vcc и Vbat, останавливает часы и пока его не сбросишь они не пойдут.
Ну и еще обычный прикол с часами, что не все могут работать при отключенной батарейке — даже если Vcc есть, внутри у них стоит контроль, который проверяет разницу между напругой и Vbat, и если Vbat нет, то часы просто ни на что не отвечают 🙂
p.s. а про NACK в конце чтения это да, самые популярные грабли наверно. Кстати для отлаживания шины если нет крутого осцила, можно прикрутить I2C Sniffer на Atmega8 — оч удобная штука, она в консоли показывает полностью весь обмен в удобоваримом виде.
А чё с ним было голову ломать? Кстати, m41t56 рекомендую, простые и удобные I2C часы. Про битик я давно знал — он у всех часовых изделий от ST присутствует. Наверное, как совместимость с m48t08 — который с батареей на борту. Чтобы батарею не сажать, пока таймкипер лежит на складе, они глушат часы.
О)) На самом деле классная тема! Мне бы сначала с простым UARTом разобраться, а потом только к творению Philips)) Буду ждать исходников…
Отличная статья! А есть последняя диаграмма только в чуть лучшем качестве? А то буквы трудно различить.
Красные пути — нормальная работа
Синие — возможные косяки.
Шина I2C. Подробности программной реализации
Освойте протокол I2C.
Дополнительная информация
Типовая транзакция
Устройства, связанные через I2C, должны поддерживать определенную последовательность событий. Каждое событие соответствует определенному способу управления линиями тактовой синхронизации (SCK) и данных (SDA); как обсуждалось в статьях, приведенных в списке «Вспомогательная информация», эти два сигнала являются единственным средством, с помощью которого устройства на шине могут обмениваться информацией. Мы будем рассматривать одну информационную последовательность как «транзакцию»; это слово более уместно, чем «передача», поскольку каждая транзакция включает в себя как переданные данные, так и полученные данные, хотя в некоторых случаях единственными полученными данными являются бит подтверждения (ACK) или не-подтверждения (NACK), детектируемые ведущим устройством. Следующая временная диаграмма показывает типовую транзакцию I2C.
Временная диаграмма типовой транзакции I2C
Обратите внимание на следующее:
Следующий список описывает последовательность событий в вышеуказанной транзакции:
Сколько байт?
Каждая транзакция начинается одинаково: стартовый бит, адрес, чтение/запись, ACK/NACK. После этого любое количество байт данных может быть отправлено от мастера к ведомому устройству или от ведомого к мастеру, причем после каждого байта следует ACK или NACK. NACK может быть полезен как способ сказать: «прекрати отправку данных!». Например, мастер может захотеть получать непрерывный поток данных от ведомого устройства (например, датчик температуры); за каждым байтом следует ACK, и если мастеру необходимо обратить внимание на что-то еще, он может послать ведомому устройству NACK и начать новую транзакцию, когда будет снова готов.
Многобайтовая транзакция
Старт без стопа
Протокол I2C допускает нечто, называемое условием «повторного старта». Это происходит, когда мастер инициирует транзакцию со стартовым битом, а затем инициирует новую транзакцию через другой стартовый бит без промежуточного стопового бита следующим образом:
Эта функция может использоваться всякий раз, когда одному ведущему устройству необходимо выполнить две или более отдельных транзакции. Однако есть ситуация, когда условие повторного старта особенно удобно.
Допусти, у вас есть ведомое устройство, которое хранит информацию в банке регистров. Вы хотите запросить данные из регистра с адресом 160, 0xA0 в шестнадцатеричном формате. Протокол I2C не позволяет мастеру отправлять данные и получать данные в одной транзакции. Следовательно, вы должны выполнить транзакцию записи, чтобы указать адрес регистра, а затем отдельную транзакцию чтения для извлечения данных. Хотя этот подход может привести к проблемам, поскольку мастер освобождает шину в конце первой транзакции, и, таким образом, другой мастер может занять шину и не дать первому мастеру получить нужные ему данных. Кроме того, второй мастер может взаимодействовать с тем же ведомым устройством и задать другой адрес регистра. Если первый мастер затем займет шину и прочитает данные без повторного указания адреса регистра, он будет считывать неправильные данные! Если второй мастер затем попытается выполнить транзакцию чтения в своей процедуре «запись и затем чтение», то это также закончится чтением неверных данных! Этого системного сбоя стоит ожидать, но, к счастью, условие повторного старта может предотвратить этот беспорядок, инициировав вторую транзакцию (чтение) без освобождения шины.
Пример использования повторного старта
Когда ведущие устройства не могут уживаться вместе
Часть того, что делает I2C настолько универсальной, – это поддержка нескольких ведущих устройств. Но, как показывает предыдущий раздел, ведущие устройства не всегда хорошо работают вместе. Логика I2C устройства должна быть в состоянии определить, свободна ли шина; если шину занял другой мастер, то устройство до запуска своей собственной транзакции ждет, пока не завершится текущая транзакция. Но что происходит, когда два (или более) мастера пытаются инициировать транзакцию одновременно? I2C обеспечивает эффективное и удивительно простое решение этой неприятной, если бы она случилась, проблемы. Этот процесс называется «арбитраж», и он полагается на гибкость схемы шины I2C с открытым стоком: если один мастер пытается привести сигнал к логической единице, а другой мастер пытаются привести сигнал к логическому нулю, то «выиграет» мастер с логическим нулем, и, кроме того, «проигравший» может обнаружить, что фактическое состояние на выходе отличается от состояния, которое он хотел установить:
Арбитраж на шине I2C
Эта схема показывает основу арбитража I2C; процесс происходит следующим образом:
Потратьте минутку, чтобы оценить простоту и эффективность этого механизма:
Заключение
В данной статье рассмотрены важные детали I2C, которые влияют на разработку программного или низкоуровнего аппаратного обеспечения. Если ваш микроконтроллер включает аппаратные модули I2C или SMBus, то некоторые детали реализации будут обрабатываться автоматически. Хотя это и удобно, но не оправдывает безграмотность потому, что вам всё равно нужно знать хотя бы немного (и, возможно, немного больше) о том, как на самом деле работает I2C. Кроме того, если вы когда-нибудь окажетесь на необитаемом острове без аппаратных модулей I2C, представленная здесь информация поможет вам на пути к разработке чисто программных I2C функций (с так называемой побитовой обработкой).