Интерфейс I2C по-русски: особенности аппаратной и программной реализации шины, плюсы и минусы
30.12.20
От автора
Третьего дня абсолютно неожиданно для себя накропал данную заметку про интерфейс I2C. История ее создания была такова. При описании интерфейсной шины I2C, используемой в КМПУ, мне потребовалось рассказать, каким образом можно выбрать номинал подтягивающих резисторов для линий SDA и SCL. Поскольку шина I2C является довольно древней (придумана она в 80-х годах прошлого века), и про нее уже́ написана гора статей, я, как обычно, просто хотел дать ссылку на одну из них, дабы не плодить лишних сущностей. Однако, беглый поиск показал, что путных статей на русском языке про интересующую меня тему сходу особо-то и не найдешь (хотя, например, про софтовые дела́ материала написано предостаточно). Поэтому я по традиции решил это исправить и запилить свою собственную небольшую заметку про выбор номинала подтягивающих резисторов. При этом пришлось подробно рассказывать о том, как вообще функционирует интерфейс I2C на уровне железа, и почему в нем были выбраны именно такие схемотехнические решения, так что небольшая заметка довольно сильно распухла. И в итоге оказалось, что в нее нужно добавить не так уж много информации, чтобы получилась более-менее полноценная статья про I2C. С одной стороны, перспектива была довольно интересной. С другой – наверное, я бы так и не взялся за написание «полновесной» заметки, ибо на нее даже с учетом уже́ написанного ушло бы много времени, ибо я привык копать глубоко. К тому же, для нормального оформления статьи мне потребовалось бы рисовать картинки, а я не особо люблю это дело. Но тут мне совершенно случайно попался на глаза цикл статей Роберта Кейма, посвященный интерфейсу I2C, где всё было расписано примерно так, как это сделал бы я сам, но главное – там были рисунки! Оставалось перевести на нормальный инженерный русский то, что уже́ есть в наличии, добавить туда свои собственные мысли и оформить всё это в виде одной заметки, что я незамедлительно и сделал.
Естественно, я совершенно не претендую на оригинальность. Более того, если бы мне захотелось написать «просто статью про I2C», я бы даже не стал приступать к оной – какой смысл в 1001-й раз мусолить то, что до тебя обсудили уже́ 1000 раз? Однако, как я уже говорил, в моей заметке довольно подробно рассмотрен вопрос выбора подтягивающих резисторов для линий SDA и SCL, ну и в целом аппаратная часть интерфейса тоже не обойдена вниманием. А вот такой информации, тем более на русском языке, мне попадалось намного меньше (конечно, я не особо продвинутый «искатель», но всё же). Поэтому я считаю, что данные, изложенные в этой заметке, в ряде случаев могут быть крайне полезны разработчикам электронной аппаратуры. Ну а то, что в ней вкратце рассказано еще и про софтовую сторону I2C – это просто приятный бонус, позволяющий найти всю «первичную» информацию в одном месте, а не переключаться постоянно между десятью вкладками браузера.
Для тех, кто с английским вполне дружит, вот ссылки на оригинальные статьи Роберта Кейма, использованные при написании данной заметки:
▪ Introduction to the I2C Bus
▪ The I2C Bus: Hardware Implementation Details1
▪ The I2C Bus: Firmware Implementation Details
1) – отмечу, что расчет номиналов подтяжек здесь не совсем корректен даже с учетом того, что это грубая оценка.
Правда, здесь нужно напомнить, что моя заметка не является тупым переводом данного цикла – минимум две трети этого документа были написаны лично мной, поэтому в оригинальных статьях некоторых вещей просто нет (ну это так, к слову). Но в целом, конечно, рассматриваемый документ имеет в своей основе именно цикл статей Роберта Кейма, поэтому ознакомиться с оригиналами будет нелишним.
И последнее. В отличие от многих простейших интерфейсов, шина I2C имеет нормальный стандарт (спецификацию). Это важно, поскольку стандартизация не позволяет двояко толковать многие моменты в работе интерфейса. Вот здесь находится самый свежий вариант спецификации шины I2C. На всякий случай я его сохранил и у себя (взять версию от 4 апреля 2014 года можно тут). И хочу заострить ваше внимание на том, что при разрешении каких-либо вопросов в первую очередь надо обращаться именно к официальному стандарту, а не к заметкам в Интернете, как бы хорошо они ни были написаны.
Понятие интерфейса
Одной из общих черт всех электронных систем является необходимость обмена информацией между двумя, тремя или десятью их отдельными компонентами. Для этих целей инженерами был разработан целый ряд стандартных протоколов (или интерфейсов), помогающих различным микросхемам успешно обмениваться данными (UART, USART, SPI, I2C, CAN и т.д.). Успех этот обусловлен тем, что структура и последовательность сигналов на линиях связи чипов, работающих по одному протоколу, жестко устанавливается соответствующими стандартами и/или соглашениями. В подавляющем большинстве случаев каждый стандарт для передачи информации предусматривает совместное использование сразу нескольких линий связи, объединяемых в интерфейсные шины или шины данных. Сам же конкретный способ передачи пачек данных называют интерфейсом, т.е. совокупностью правил взаимодействия между элементами системы.
Отметим, что у каждого из вышеперечисленных интерфейсов есть свои плюсы и минусы. Поэтому при разработке нового устройства нам важно знать хотя бы немного о каждом из них, чтобы принять обоснованное решение в пользу того или иного протокола. Данная статья посвящена интерфейсу I2C, который обычно используется для связи между отдельными микросхемами, расположенными на одной печатной плате или между модулями, входящими в состав одного устройства. Основной особенностью данного интерфейса можно назвать способность подключать к одной шине большое количество устройств (до 112 штук) при использовании всего двух линий связи. Однако, при этом I2C является сравнительно медленным протоколом, позволяющим обмениваться данными на скоростях, зачастую не превышающих 400кГц. Эти и другие особенности интерфейса I2C будут рассмотрены ниже.
Причины создания интерфейса I2C
Первым делом следует отметить, что интерфейс I2C является намного более сложным, чем другие простейшие шины (например, UART или SPI). Чтобы понять, для чего понадобились такие серьезные усложнения, представим, что нам нужно создать надежную, и в то же время универсальную систему связи между несколькими независимыми компонентами. Ситуация будет достаточно простой, если у нас есть одна микросхема, которая всегда является ведущей, и одна микросхема, которая всегда является ведомой. Но что, если у нас несколько ведомых? Что, если они не всегда знают, кто мастер? Что делать, если ведущих несколько? Что произойдет, если мастер запросит данные у ведомого устройства, которое по какой-то причине перестало работать? Что, если ведомый перестанет работать в середине передачи? Что, если мастер заявляет, что шина выполняет передачу, а затем отключается перед тем, как отпустить шину?
Очевидно, что в такой коммуникационной среде может возникнуть множество ошибок. И только дополнительное усложнение интерфейса может обеспечить создание надежной, гибкой и расширяемой шины, связывающей компоненты устройства, при этом используя минимум линий для передачи данных. В дальнейшем будет нелишним всегда помнить об этом, потому что в противном случае протокол I2C будет казаться вам необоснованно сложным и привередливым.
Особенности интерфейса I2C
Прежде чем мы углубимся в какие-либо подробности, необходимо перечислить основные особенности интерфейса I2C:
• шина I2C является синхронной (тактируемой);
• независимо от количества устройств на шине, для передачи информации всегда используется только две линии: линия данных SDA (Data Line) и линия тактовых импульсов SCL (Clock Line). Такты на линии SCL всегда генерирует мастер:
• обе линии должны быть подтянуты к «плюсу» питания через резисторы подходящего номинала;
• каждое устройство подключается к линиям SDA и SCL через выходные драйверы с открытым стоком (или открытым коллектором), см. ниже;
• каждое ведомое устройство идентифицируется с помощью 7-битного адреса, всего на одной шине может быть до 112 устройств (16 адресов являются зарезервированными). Мастер должен знать эти адреса для связи с конкретным ведомым устройством;
• начало любого обмена данными инициируется и завершается мастером. Мастер может как записывать данные в одно или несколько ведомых устройств, так и запрашивать у них данные. Обмен информацией между двумя ведомыми невозможен;
• понятия «Мастер» и «Ведомый» по своей природе непостоянны: в теории любое устройство на шине I2C может функционировать как ведущее или ведомое, если ему это позволяет сделать аппаратная часть и/или прошивка. Иными словами, рассматриваемая шина поддерживает режим мультимастера. Однако на практике системы на базе I2C чаще всего строятся по архитектуре, в которой есть только один мастер, отправляющий команды нескольким ведомым устройствам и собирающий с них данные;
• данные загружаются (Updated) на линию SDA по заднему фронту тактовых импульсов на линии SCL и считываются (Sampled) по переднему фронту SCL:
• данные передаются побайтово, за каждым байтом следует бит подтверждения, называемый битом ACK/NACK (подтверждено или не подтверждено).
Ну а после этого можно и объяснить, откуда берется большинство данных особенностей.
Аппаратная часть интерфейса I2C
Достоинства интерфейса I2C (возможность связи любого количества устройств всего по двум линиям, наличие нескольких ведущих и т.д.) связаны в основном с тем, что его линии SDA и SCL являются двунаправленными. Т.е. здесь вы не просто подключаете выход буфера соответствующего интерфейса ко входу (входам) других чипов, висящих на данной шине (как это было бы в случае UART или SPI) – интерфейс I2C требует, чтобы выводы SDA и SCL применяемых микросхем могли быть как входами, так и выходами. Далее мы рассмотрим несколько нюансов аппаратной реализации данного интерфейса, которые делают его довольно привлекательным (за счет надежности и универсальности) при построении канала связи между несколькими независимыми микросхемами.
Схема «Открытый сток»
С точки зрения железа основной отличительной особенностью микросхем, поддерживающих работу с интерфейсом I2C, является то, что к линиям SDA и SCL они должны подключаться через выходные драйверы с открытым стоком (или открытым коллектором). Чтобы понять смысл данной фразы, давайте сначала рассмотрим типичный выходной каскад современных чипов на полевых транзисторах:
Если на входе VIN присутствует высокий логический уровень, N-канальный транзистор (нижний по схеме) включен, а P-канальный транзистор (верхний по схеме) выключен. Таким образом, выход VOUT будет подключен к земле (сопротивление открытого канала полевиков на практике довольно мало, и в нашем случае его можно не учитывать). Если же на вход VIN подать низкий логический уровень, ситуация меняется на обратную, и выход VOUT будет подключен к «плюсу» питания VDD. Такая схема называется двухтактным выходным каскадом. При этом крайне важно понимать, что в общем случае вы не можете напрямую соединить два двухтактных выхода. Это связано с тем, что при наличии у одного из них на входе единицы (HIGH), а у другого – нуля (LOW), ток потечет от «плюса» питания VDD к земле, будучи ограниченным исключительно сопротивлением открытого канала полевиков:
Вследствие того, что данное сопротивление имеет крайне низкое значение, выходной ток микросхем будет весьма значительным – при питании VDD=+5,0В он может достигать единиц ампер. Ну и в итоге от этого тока выход чипа, естественно, сдохнет. Так вот, для того, чтобы при соединении двух и более выходов микросхем такой херни не происходило, часто используют схему «открытый сток» (ну, или «открытый коллектор», в зависимости от типа транзисторов, используемых в ней):
P-канальный транзистор здесь заменен резистором, причем важным является то, что этот резистор может быть внешним по отношению к микросхеме (т.е. может быть вынесен за ее пределы). Теперь если на вход VIN подать высокий логический уровень, N-канальный транзистор откроется и обеспечит низкоомное соединение выхода VOUT с землей. Если же на вход подать низкий логический уровень, полевик будет закрыт и представит из себя разомкнутую цепь. При этом выход VOUT будет подключен к «плюсу» питания VDD через внешний резистор. Такая логика работы выхода микросхемы приводит к двум важным особенностям. Во-первых, когда на выходе VOUT присутствует низкий логический уровень, схема потребляет дополнительный ток – он течет через внешний резистор, далее через открытый канал полевого транзистора и далее на землю. Это плохо, поскольку у двухтактного выходного каскада дополнительное энергопотребление практически отсутствует, ибо P-канальный полевик при этом будет закрыт. Но при этом (во-вторых) даже если на входе одного из полевых транзисторов будет присутствовать высокий логический уровень (HIGH), а на входе второго – низкий (LOW), то ничего страшного не произойдет. Как нетрудно видеть, при таком раскладе точка соединения выходов притянется к массе за счет первого полевика, а второй просто перестанет оказывать на работу схемы какое-либо влияние, т.к. будет представлять из себя разомкнутую цепь. При этом ток через выход микросхемы в любом случае будет ограничен за счет внешнего резистора (обычно имеющего номинал не ниже 1кОм):
Таким образом, применение схемы «открытый сток» или «открытый коллектор» позволяет безопасно соединять два (и более) выхода разных микросхем даже тогда, когда на одном из них присутствует единица, а на другом – нуль. Естественно, это является существенным плюсом данного схемотехнического решения, в принципе делающим возможным реализацию интерфейса I2C. Кроме безопасного соединения выходов нескольких чипов, применение «открытого стока» дает следующие бонусы:
• по умолчанию (т.е. когда выходные полевые транзисторы закрыты) сигналы на шине всегда имеют высокий логический уровень (а не какой попало). Поэтому если ведомое устройство вдруг заглючило и не может управлять сигналом на линии данных SDA, эта линия никогда не перейдет в неопределенное состояние – с нее будет считана логическая единица. Аналогично, если ведущий потеряет питание в середине передачи, сигналы SCL и SDA вернутся к высокому уровню. При этом если на линиях SCL и SDA в течение определенного промежутка времени присутствовала логическая единица, другие устройства на шине могут сделать вывод, что она доступна для новой передачи данных;
• любое устройство на шине может безопасно установить нуль на любой из линий SDA и SCL, даже если другое устройство в этот момент пытается установить единицу. Это основа функции «растяжения» тактовой частоты, часто применяемой «медленными» микросхемами I2C. Данная функция означает, что мастер может генерировать тактовые импульсы SCL на любой частоте, вплоть до максимально возможной – при необходимости ведомое устройство может удерживать линию SCL на низком уровне и тем самым уменьшать тактовую частоту;
• схема «открытый сток» автоматически приводит все сигналы на шине к одному уровню – к напряжению питания VDD. При этом данное напряжение может быть как больше, так и меньше напряжений питания отдельных микросхем на шине. Это происходит потому, что в реальности каждый чип может принудительно установить на линиях SDA и SCL лишь нуль – единица получается сама собой при выключении выходного транзистора, и уровень ее автоматически будет равен как раз значению VDD. Единственное условие безопасной работы здесь – полевики в выходном каскаде каждой микросхемы должны позволять работу с напряжением VDD (т.е. оно не должно превышать максимально допустимое значение «исток-сток» выходного транзистора). Таким образом, на шине I2C могут вполне нормально уживаться устройства с различным напряжением питания (например, трехвольтовый чип может взаимодействовать с пятивольтовым, если, конечно, его не убьют эти пять вольт).
Отметим, кстати, что точка соединения нескольких «открытых стоков» часто называется также «монтажным ИЛИ», поскольку для перевода ее в низкий уровень достаточно того, чтобы хотя бы на одном из объединяемых выходов был нуль.
Влияние емкости линий шины на скорость передачи данных
Несмотря на все свои достоинства, выходной драйвер с открытым стоком имеет и ряд недостатков. Одним из самых главных является существенное затягивание фронта выходного импульса при переводе линий SDA и SCL из низкого состояния в высокое.
Данное затягивание обусловлено наличием емкости линий шины. Легко заметить, что выводы SDA и SCL любой микросхемы имеют определенную входную емкость Ci (т.е. емкость между выводом и землей). Пусть эта емкость и невелика для каждого отдельного устройства (типовое значение Ci у большинства I2C-чипов составляет 10…20пФ), однако, по мере роста ведомых на шине суммарное значение емкости линий SDA и SCL будет увеличиваться. Сюда еще добавится и емкость между дорожками на печатной плате CPCB, зависящая, в том числе, от материала диэлектрика, из которого плата сделана:
И в итоге будем иметь, что результирующая емкость линий интерфейса I2C (CSDA и CSCL) будет состоять из суммы входных емкостей всех микросхем, висящих на шине (Ci+Ci+Ci+…), емкости соответствующей дорожки (CPCB), ну и еще емкости всякой паразитной херни, которую обычно можно не учитывать. Так вот, из логики работы схемы «открытый сток» следует, что при переходе линии SDA или SCL из единицы в нуль (HIGH to LOW, левая картинка ниже) разряд ее суммарной емкости CSDA или CSCL будет идти только через сопротивление открытого канала выходного полевого транзистора. А вот при переходе линии из нуля в единицу (LOW to HIGH, правая картинка ниже) емкости CSDA и CSCL смогут заряжаться только через резистор, подтягивающий шину к «плюсу» питания:
Длительность полного заряда или разряда емкости C через резистор R (а именно эти временны́е промежутки и определяют длительность фронтов на выходе микросхем) можно примерно оценить как t=5RC. При работе с реальными чипами это значение, конечно, будет меньше из-за наличия пороговых значений нуля и единицы на входе, но понять суть можно и при помощи этой простой формулы. Так вот, длительность полного разряда емкости линий SDA и SCL будет равна
tРАЗР. = 5CSDARDS_ON = 5CSCLRDS_ON,
где RDS_ON – сопротивление открытого канала выходного полевика.
Время же полного их заряда составит
tЗАР. = 5CSDARP = 5CSCLRP,
где RP – сопротивление внешнего резистора, подтягивающего линию к «плюсу» питания. И из-за того, что сопротивление RDS_ON обычно отличается от номинала внешней подтяжки минимум на три порядка (в лучшем случае – единицы Ом против единиц килоом), переход линий шины I2C от низкого уровня к высокому будет значительно медленнее, чем переход от высокого уровня к низкому. Это приводит к тому, что I2C-сигналы традиционно имеют не прямоугольную, а псевдо-пилообразную форму:
ну а их заваленные фронты, естественно, повлекут за собой ограничение максимальной скорости, на которой может работать шина. Отметим, что допустимые временны́е характеристики импульсов на линиях SDA и SCL, а также параметры выводов I2C-микросхем жестко регламентируются спецификацией для того, чтобы чипы разных производителей могли нормально общаться между собой. Основные данные из этой спецификации для удобства приведены ниже.
Электрическая спецификация шины I2C
Согласно стандарту I2C, на данный момент (декабрь 2020г.) существует пять режимов работы шины. Различаются они по максимально возможной скорости передачи данных, т.е. по максимальной частоте тактовых импульсов SCL:
Режим работы |
Макс. скорость |
Standard-Mode (SM) |
fSCL_MAX = 100кГц |
Fast-Mode (FM) |
fSCL_MAX = 400кГц |
Fast-Mode Plus (FM+) |
fSCL_MAX = 1000кГц |
High-Speed-Mode (HsM) |
fSCL_MAX = 3400кГц |
Ultra-Fast-Mode (UFM) |
fSCL_MAX = 5000кГц |
При этом исторически сложилось так, что наибольшее распространение получили лишь первые три из них. Почему так вышло, я не знаю, однако в дальнейшем будем рассматривать именно режимы «SM», «FM» и «FM+». Требуемые параметры выводов микросхем, поддерживающих режимы Standard-Mode, Fast-Mode и Fast-Mode Plus, приведены в Таблице 9 спецификации I2C (стр. 47):
а временны́е характеристики импульсов SDA и SCL – в Таблице 10 (стр. 48-49)
и на Рисунке 38 (стр. 50):
Отметим, что несмотря на наличие стандарта I2C, некоторые производители микросхем кладут на него хер. Например, стандартом оговорено, что входная емкость выводов SDA и SCL (Ci) не должна превышать 10пФ, а для всенародно любимого термометра LM75A в таблице указано 20пФ, и это, заметьте, не максимальное, а типовое значение. Еще бесит, когда емкость вывода не указывают вообще (типовой пример – АЦП ADS1110). Ну а уж не указывать максимально допустимый ток выходов SDA и SCL в нуле – это вообще традиция (видимо, в этом случае нужно брать IOL=3мА из спецификации). Правда, радует, что эти косяки касаются только параметров цифровых выводов – с временны́ми характеристиками всегда всё в ажуре. Однако, при расчете емкости линий шины I2C и выборе номиналов подтягивающих резисторов (см. ниже) вышеперечисленные ньюансы нужно учитывать.
Расчет номинала подтягивающих резисторов
Ранее было показано, что длительность фронтов сигналов на линии I2C напрямую зависит от емкости этой линии и от номинала резистора, который подтягивает ее к «плюсу» питания VDD. Например, на этих осциллограммах желтой линией показан переход линии SCL шины I2C из нуля в единицу и из единицы в ноль:
При этом использовался подтягивающий резистор довольно небольшого номинала (1кОм), а емкость линии была уменьшена до предела – на шине присутствовали только две микросхемы, соединенные между собой на печатной плате короткими дорожками. Отметим, что абсолютные значения фронтов сигнала (меньше 70нс) более чем приемлемы даже для устройств, работающих в режиме High-speed mode (fSCL до 3,4Мбит/с), однако с увеличением количества дывайсов на линии картина будет становиться всё менее и менее радостной. При этом формулы говорят (см. выше), что для улучшения переднего фронта сигналов шины I2C нам нужно уменьшать либо емкости линий SDA и SCL, либо сопротивление подтягивающих резисторов. Однако, как-либо уменьшить емкость линий чаще всего просто невозможно – они определяются в первую очередь количеством устройств на шине и характером взаимосвязей между этими устройствами. Поэтому зачастую единственным рычагом, позволяющим улучшить форму импульсов на линиях SDA и SCL, является сопротивление резисторов-подтяжек.
Очевидно, что чем меньше будет сопротивление подтягивающих резисторов, тем более крутые фронты импульсов мы получим. Однако, при этом будет расти энергопотребление устройства в целом, да и про предельно допустимый выходной ток микросхем забывать тоже не надо. Поэтому при выборе номинала подтягивающих резисторов каждый раз приходится искать компромисс между максимальной скоростью работы шины I2C и потребляемой ею мощностью. Понятно, что с точки зрения рабочей частоты сопротивление подтяжек должно быть как можно ниже, т.к. при этом фронты импульсов будут более крутыми. Но чем меньше взят номинал подтягивающих резисторов, тем больше будет ток, потребляемый от шины питания VDD при SCL=0 и SDA=0, а этот ток нередко ограничен требованиями к разрабатываемому устройству (например, у батарейных поделок). Поэтому минимально возможное сопротивление резисторов-подтяжек определяется максимально допустимым током IMAX, который может потребляться шиной I2C:
RP_MIN = VDD_MAX / IMAX      [1],
где VDD_MAX – максимально возможное напряжение питания шины (например, при питании +5,0В±5% значение VDD_MAX составит 105% от +5,0В, т.е. +5,25В). При этом нужно помнить, что ток IMAX, потребляемый линией I2C от источника, ни при каких обстоятельствах не должен превышать максимально допустимый ток соответствующего вывода микросхемы (ну а лучше предусмотреть хоть какой-то запас).
Отметим, что номиналу RP_MIN будет соответствовать максимально возможная частота работы шины. Однако, как сказано выше, зачастую нам гораздо важнее энергопотребление устройства, а особой скорости от шины I2C не требуется. Например, в приложениях, где по данной шине МК опрашивает исключительно датчик температуры LM75A, работать на частоте 400кГц (и даже 100кГц) обычно абсолютно бессмысленно, ибо температура не может столь быстро изменяться. Поэтому в данных приложениях стараются увеличить сопротивление подтяжек.
Для расчета максимально возможного номинала подтягивающих резисторов RP_MAX нам потребуется узнать емкость линий SDA и SCL. Понятно, что в идеале здесь надо было бы собрать всю систему вживую и тупо измерить данную емкость – так мы получим наиболее точное ее значение. Однако вполне естественно, что метод прямого измерения емкости разработчику обычно не подходит, ибо собирать всю систему ради одного номинала резистора – больно круто. Поэтому чаще всего на практике применяется приблизительная и довольно грубая оценка значений CSDA и CSCL. В этом случае сначала для каждой микросхемы, висящей на шине, из документации берется входная емкость выводов SDA и SCL (Ci), а затем они все суммируются. Обратите внимание на то, что в соответствии со стандартом I2C максимальное значение Ci должно составлять 10пФ. Однако, не каждый производитель четко придерживается спецификации, поэтому при просмотре даташытов надо быть крайне внимательным.
После того, как входные емкости всех микросхем просуммированы, нам останется учесть емкость проводников, которыми связаны между собой устройства на шине. В том случае, когда шина физически реализована в виде печатных проводников на плате, к сумме входных емкостей всех микросхем, рассчитанной ранее, надо добавить по 1,18пФ на каждый сантиметр дорожки (см. техасовский апнот, стр. 3). Если же для связи используются какие-либо «фирменные» провода, то их погонная емкость может быть напрямую взята из документации (например, в случае коаксиального кабеля RG-58 она составит около 100пФ на каждый метр). В итоге мы получим примерное значение CSDA или CSCL, которое уже́ можно использовать в дальнейших расчетах. Более подробно о составляющих суммарной емкости линий SDA и SCL, а также о том, как их вычислить, можно узнать здесь. Ну и не нужно забывать о том, что спецификация шины I2C прямо оговаривает максимально допустимую емкость этих линий: для режимов «Standard» и «Fast» предельное значение составляет Cb=400пФ, а для режима «Fast Plus» – Cb=550пФ (см. Таблицу 10 на стр. 48).
После того, как мы узнали значения емкостей линий SDA и SCL, можно, наконец-то, вычислить максимально допустимое сопротивление подтягивающих резисторов. Расчет их ведется исходя из того, что время нарастания сигналов на шине I2C (tr) не должно превышать значений, указанных в стандарте. Согласно Таблице 10 (см. стр. 48), время нарастания в режиме «Standard» должно быть не больше 1мкс, в режиме «Fast» – не больше 300нс, а в режиме «Fast Plus» – не больше 120нс. При этом под временем нарастания в спецификации понимается время, за которое сигнал успевает нарасти с 30% до 70% своего максимального значения (см. Рисунок 38 на стр. 50). И в соответствии с известной формулой для расчета времени заряда емкости до определенного уровня:
t=–RC∙ln(1-[U(t)/UMAX]),
получим, что до 30% напряжение на емкости линий SDA и SCL нарастет за интервал
t30% = –RP_MAXCb∙ln(1-[30%∙UMAX / UMAX]) = 0,36∙RP_MAXCb,
а до 70% – за интервал
t70% = –RP_MAXCb∙ln(1-[70%∙UMAX / UMAX]) = 1,20∙RP_MAXCb.
Поэтому можно считать, что время нарастания сигнала с 30% до 70% составит
tr = t70% – t30% = 1,20∙RP_MAXCb – 0,36∙RP_MAXCb = 0,84∙RP_MAXCb.
Отсюда мы можем найти максимально возможное сопротивление подтягивающего резистора для линии I2C:
RP_MAX = tr / (0,84∙Cb)       [2].
(Кстати, эти формулы я сначала вывел сам, а потом обнаружил, что они уже есть в стандарте I2C на стр. 55. С одной стороны, конечно, жаль потраченного времени, но с другой – я лично проверил, что в официальной спецификации всё верно, хе-хе. При этом крайне важным является то, что формула [2] может применяться лишь с определенными оговорками. Более подробно это рассмотрено ниже).
Из последней формулы следует, что максимально возможное значение сопротивления подтяжек определяется емкостью соответствующей линии шины I2C и допустимым временем нарастания сигнала. Поэтому для всех трех режимов работы интерфейса («Standard-Mode», «Fast-Mode» и «Fast-Mode Plus») максимальное значение RP_MAX будет отличаться – чем тормозней режим, тем больший номинал резистора можно использовать. В связи с этим, в приложениях, где крайне важна минимизация энергопотребления, наиболее выгодным будет использование режима «Standard». Однако, не нужно забывать, что данный режим сильно ограничен по скорости, поэтому, возможно, здесь придется с особой тщательностью подойти к разработке функциональной схемы устройства и выбору его элементной базы.
Отмечу, что в общем случае максимально и минимально возможное сопротивление подтягивающих резисторов шины I2C можно определить не только по формулам, но и по данным графикам:
(коричневая линия на верхнем рисунке – это прямая, а не кривая, как может показаться). Данные графики построены в соответствии с формулами для RP_MIN и RP_MAX, приведенными выше. Верхний график показывает зависимость минимально допустимого сопротивления подтягивающего резистора (RP_MIN) от напряжения питания шины I2C (VDD). Отмечу, что в стандарте на стр. 55 тоже есть подобный рисунок (более того, сама идея нахождения сопротивлений по графику взята мною именно оттуда), только мне не совсем понятны там два момента. Во-первых, почему-то при расчетах везде используется формула
RP_MIN = (VDD–0,4В) / IMAX,
где IMAX=IOL_WORST=3мА или 20мА (смотря в каком режиме работает шина, см. Таблицу 9 на стр. 47), а +0,4В – это максимально допустимое падение напряжения на выходах SDA и SCL, находящихся в нуле. При этом если на выходе упадет меньше +0,4В (а по стандарту там вообще может быть чистый нуль), то для того, чтобы не превысить заданный ток IMAX, нам понадобится резистор с номиналом больше расчетного. То есть, формула, учитывающая падение напряжения +0,4В на низком выходе SDA или SCL дает заниженное значение RP_MIN, поэтому лично я предпочитаю при расчетах использовать формулу [1] (см. выше). Она позволяет получить адекватную величину сопротивления подтягивающего резистора, поскольку в данной формуле сделано предельное допущение, что всё напряжение питания шины падает исключительно на подтяжке (а с точки зрения номинала RP_MIN хуже быть просто не может). Второй непонятный для меня момент – почему на графике в спецификации напряжение питания шины Vcc изменяется до +15,0В? Ведь в Таблице 9 на стр. 47 ясно сказано, что на входе SDA и SCL в любом случае не должно присутствовать напряжение выше +5,5В (см. примечание 2 после таблицы). А поскольку линии шины I2C являются двунаправленными, то и на выход, вроде, больше +5,5В давать нельзя. При этом предельное значение «+5,5В» вполне согласуется со всеми микросхемами I2C, встречавшимися мне до сих пор, а вот «+15,0В» – как-то не очень (правда, я не знаю – может и есть чипы, толерантные к такому напряжению). В общем, по моим понятиям, ось «Х» на верхнем графике должна изменяться от +1,0В до +6,0В, что я и отобразил. Ну а для бо́льших или меньших питаний данные линии можно будет легко продлить, благо это обычные прямые.
Нижний график показывает зависимость максимально возможного сопротивления подтяжки (RP_MAX) от суммарной емкости линии I2C (Cb). Этот график полностью совпадает с картинкой из спецификации (стр. 55) с той лишь разницей, что мне кажется более удобным логарифмический масштаб. Обратите внимание на то, что при работе в режиме «Standard» подтяжка номиналом в несколько десятков килоом – вовсе не фантастика. Понятно, что за это приходится платить снижением скорости обмена информацией, но тут уж ничего не поделаешь, ибо с физикой спорить – себе дороже. При этом если мы готовы и дальше жертвовать максимальной частотой работы шины, то сопротивление подтягивающих резисторов можно еще больше увеличить, поэтому использование шины I2C является крайне заманчивым для приложений, где требуется минимизация энергопотребления. В связи с этим, вопрос увеличения номиналов подтяжек сто́ит рассмотреть более подробно.
Крайне важно понимать, что формулы [1] и [2], а также оба графика, приведенные выше, позволяют вычислить диапазон номиналов подтягивающих резисторов, в котором на шину I2C можно вешать вообще любые микросхемы, удовлетворяющие данному стандарту. То есть при таких номиналах мы можем взять любой I2C-чип, повесить его на шину, и при этом он с гарантией а) не сгорит и б) сможет работать на максимально возможной частоте (100кГц, 400кГц и 1МГц для режимов Standard-Mode, Fast-Mode и Fast-Mode Plus соответственно). Однако, реальная жизнь не ограничивается одним только стандартом. Например, верхний график на последнем рисунке говорит, какое сопротивление должно быть у подтягивающих резисторов, чтобы ток выхода микросхемы не превысил значение, указанное в спецификации (3мА или 20мА). И вроде бы это логично, т.к. в общем случае мы должны ориентироваться именно на стандарт, но с другой стороны – есть куча микросхем, которые позволяют работать с бо́льшими выходными токами (те же LM75A или, например, камни AVR с включенным TWI). И если на шине присутствуют только такие микросхемы, то сопротивление подтяжки можно уменьшить, улучшив при этом фронты сигналов SDA и SCL. Я, конечно, понимаю, что рассматриваю сейчас ситуацию в сферическом вакууме, ибо абсолютно непонятно, зачем нужно улучшать форму импульсов, если она и так удовлетворяет всем требованиям. Однако всё же считаю нужным подчеркнуть:
значение IMAX в формуле [1] вовсе не обязательно должно быть «стандартным» (3мА или 20мА). Если микросхемы, подключенные к шине I2C, допускают работу с бо́льшими токами, то расчет минимально возможного сопротивления подтяжек можно вести, используя именно эти частные значения. Иными словами, в качестве величины IMAX в формуле [1] можно использовать предельно допустимый ток самого «слабого» чипа, висящего на шине.
А вот ситуация, при которой сопротивление подтягивающего резистора должно быть больше рассчитываемого по формуле [2] – это уже́ не сферические кони, а вполне реальная проблема. Чаще всего она встречается при разработке устройств с батарейным питанием, ибо в них иногда каждые 50мкА на счету. Поэтому в таких дывайсах потребление шины I2C стараются свести к минимуму, а для этого, напомню, нужно увеличивать сопротивление подтягивающих резисторов. Сопутствующее же снижение частоты работы шины обычно пытаются нивелировать за счет более тщательного продумывания алгоритма работы устройства (хотя нужно отметить, что зачастую это снижение не особо-то сильно и напрягает). При этом максимальную скорость обмена данными (fMAX), которая получится при выбранном номинале подтяжки, можно грубо оценить, используя следующие соображения.
Обычно тактовые импульсы, выдаваемые мастером, можно считать меандром, т.е. последовательностью прямоугольников, у которых время нахождения в единице и в нуле одинаково:
При этом, как было показано выше, за счет особенностей работы схемы «открытый сток» спадающий фронт у этого меандра будет достаточно крутым, а вот передний – затянутым:
И максимально возможная скорость шины I2C будет определяться именно степенью затянутости переднего фронта импульсов SCL, поскольку для нормальной работы интерфейса их амплитуда должна быть не ниже 0,7VDD (см. Таблицу 9 на стр. 47 спецификации). Иными словами, если передний фронт тактовых импульсов затянут настолько, что напряжение на линии SCL не успевает нарасти до 0,7VDD, то стабильная работа шины I2C не гарантируется. Более того – даже если уровень 0,7VDD и был достигнут, то перед тем, как начнется задний фронт меандра, обязательно должно пройти время tHIGH (см. Рисунок 38 на стр. 50 спецификации). В результате мы получаем, что длительность импульса SCL не может быть меньше величины
t70% + tHIGH = 1,20∙RP_MAXCb + tHIGH,
где значение tHIGH берется из Таблицы 10 на стр. 48 спецификации. Ну а поскольку тактовый сигнал на выходе мастера представляет собой меандр, то период его будет равен удвоенной длительности, и максимально возможная частота работы шины I2C составит
fMAX = 1 / TMIN = 1 / [2х(1,20∙RP_MAXCb + tHIGH)]
или
fMAX = 0,5 / (1,20∙RP_MAXCb + tHIGH)     [3]
(данное ограничение гарантирует, что длительность тактового импульса не превысит значения (1,20∙RP_MAXCb + tHIGH) при условии, что сигнал SCL является меандром).
Кстати, не нужно забывать, что согласно спецификации тактовый импульс должен оставаться в нуле как минимум в течение времени tLOW. При этом легко убедиться, что значение tLOW для любого режима работы шины и любых реальных RP_MAX и Cb будет меньше значения 1,20∙RP_MAXCb + tHIGH, поэтому формула [3] является корректной. Отмечу также, что 0,7VDD – это именно гарантированный уровень логической единицы, и в конкретном устройстве для конкретных чипов он запросто может быть ниже. Так что весьма велика вероятность, что в реальности частота работы шины I2C может быть несколько увеличена по сравнению с расчетным значением fMAX. Однако, это будет уже́ «тонкая настройка» под конкретный дывайс, в большинстве же случаев вполне хватает и формулы [3].
Ну и последнее. При взгляде на формулу [3] может показаться, что если нас устраивает низкая скорость работы шины I2C, то потребление тока по ней мы можем свести практически к нулю. В самом деле – пусть у нас есть крайне неспешное устройство, питающееся от +5,0В и опрашивающее некий датчик раз в 10 секунд (т.е. частота опроса составляет 0,1Гц). В этом случае, казалось бы, никто не мешает использовать в качестве подтяжек резисторы даже на 10МОм, ибо при этом максимальная скорость передачи данных в худшем случае составит fMAX=0,5/[1,2*10МОм*400пФ+4мкс]=104Гц (рассматриваем режим «Standard»), чего заведомо хватит для опроса нашего укуренного датчика. Но зато ток, отжираемый каждой линией шины I2C от источника питания, никогда не превысит 5В/10МОм=0,5мкА, а его среднее значение будет еще меньше (минимум в два раза), что для батарейных устройств – просто праздник. Так вот, реальность здесь нас жестко обламывает. Дело в том, что каждая микросхема (в том числе и I2C-чипы) имеет ток утечки как по входам, так и по выходам. И этот ток ILEAK, протекая по подтягивающему резистору, создает не нем падение напряжения, равное
VLEAK = ILEAK∙RP.
Напомню, что по стандарту I2C гарантированным уровнем единицы на входе является 0,7VDD. Это значит, что любой сигнал ниже данного уровня микросхема может принять за нуль. Поэтому нам нужно, чтобы падение напряжения, которое создает на подтягивающем резисторе ток утечки, не превысило VLEAK=VDD–0,7VDD=0,3VDD. В противном случае легко получить ситуацию, при которой I2C-линия вроде бы находится в исходном состоянии, а некоторые чипы, висящие на шине, считывают ее как нуль. Происходит это из-за того, что сигнал данной линии опустился ниже VDD–0,3VDD=0,7VDD, и эти микросхемы приняли его за низкое состояние. Поэтому когда в качестве подтяжки выбирается высокоомный резистор, крайне важно уделять пристальное внимание падению напряжения, создаваемому на нем токами утечки чипов. И исходя из того, что данное падение не должно превышать 0,3VDD, мы можем вывести формулу для «истинно» максимально возможного сопротивления подтяжки:
RP_MAX_HARD = 0,3VDD / IΣ_LEAK      [4],
где IΣ_LEAK – это суммарный ток утечки всех микросхем, подключенных к данной линии шины I2C. Отметим, что в соответствии со спецификацией I2C ток утечки чипа по входу/выходу не должен превышать 10мкА, поэтому формулу [4] можно переписать так:
RP_MAX_HARD[кОм] =0,3VDD[В] / (0,01∙N)      [4а],
где N – количество микросхем, висящих на шине I2C. В данной формуле напряжение питания VDD указывается в Вольтах, а сопротивление подтяжки получается в килоомах, что, на мой взгляд, гораздо удобнее Омов и микроамперов. При этом, для нашего устройства с медленным датчиком, которое было упомянуто чуть выше, формулы [4] и [4а] дадут
RP_MAX_HARD = 0,3VDD / (0,01∙N) = 0,3*5В / (0,01*2) = 75кОм,
то есть, если на шине I2C, питающейся от VDD=+5,0В, висят две микросхемы (N=2), удовлетворяющие соответствующей спецификации (ILEAK=10мкА), то сопротивление подтяжки в общем случае не может быть больше 75кОм. Таким образом, делать в этом случае частоту тактовых импульсов ниже fMAX=0,5/[1,2*75кОм*400пФ+4мкс]=1,38кГц особого смысла нет – всё равно подтяжку увеличить не получится.
Обращаю ваше внимание на то, что увеличение сопротивления подтягивающего резистора больше значения RP_MAX_HARD чревато появлением волшебных глюков при обмене информацией. Связано это с тем, что данное ограничение продиктовано уже́ не максимальной скоростью работы шины (которая зачастую может быть существенно ниже значения, указанного в спецификации), а правильной работой микросхем, висящих на той или иной ее линии. С другой стороны, нельзя не отметить, что в документации на чипы обычно указан только максимальный ток утечки, а реальное его значение запросто может быть в два раза ниже табличного. К тому же, повторюсь, у конкретных чипов, установленных в конкретное устройство, уровень единицы на входе вполне может оказаться не 0,7VDD, а ниже. А раз так, то и сопротивление подтягивающего резистора можно взять больше того, которое получается по формулам [4] и [4а]. Но это будет касаться именно конкретного дывайса, к тому же потребует дополнительных исследований. В общем же случае при разработке шины I2C категорически рекомендую пользоваться значением RP_MAX_HARD, рассчитываемому по формуле [4] или [4а].
Примеры расчета подтягивающих резисторов
В завершение данного пункта приведем несколько примеров расчета подтяжек для разных ситуаций. При этом сразу оговорим – поскольку требования к фронтам импульсов для сигналов SDA и SCL у стандарта одни и те же, то и номиналы подтягивающих резисторов мы будем брать одинаковыми. В принципе, это является общей практикой, и данное уточнение сделано с одной целью – заострить внимание на том, почему разработчики поступают именно так.
Ситуация №1. Имеем устройство, питающееся от сети и потребляющее по шине +5,0В 450мА. При этом встроенный источник рассчитан на 1А и никаких особых требований к энергопотреблению не предъявляется. На шине I2C присутствуют устройства, умеющие работать в режиме «Fast-mode» (т.е. понимающие часто́ты до 400кГц). Точность напряжения питания +5,0В составляет ±5%.
Поскольку никаких требований к энергопотреблению у нас нет, зато в наличии нехилый запас по току у источника питания, в данном случае я бы рекомендовал использовать подтяжку номиналом поменьше. Связано это с тем, что, повторюсь, в потреблении нас никто не ограничивает, а вот от модернизации устройства, при котором на шину I2C вполне может добавиться несколько микросхем, мы отнюдь не застрахованы. Ну а поскольку лишние чипы – это лишняя емкость, которая будет дополнительно заваливать передние фронты импульсов SDA и SCL, подтягивающий резистор в данном случае хотелось бы иметь поменьше. В связи с этим для расчета номинала подтяжек используем формулу [1], ибо именно она позволяет рассчитать минимальное значение RP. При этом учтем, что максимально возможное значение напряжения питания шины составляет VDD_MAX=+5,0В+5%=+5,25В, а допустимый выходной ток микросхем, рассчитанных на работу с шиной I2C, должен быть не ниже 3мА (см. Таблицу 9 на стр. 47 стандарта). Подставив данные значения в формулу [1] и взяв запас по выходному току 20% (ибо на полную катушку гонять электронику я не люблю), получим следующее минимально возможное сопротивление подтягивающих резисторов для линий SDA и SCL:
RP_MIN = VDD_MAX / IMAX = 5,25В / (80%*3мА) = 2,1758кОм.
Далее осталось лишь выбрать ближайшее значение из стандартного ряда номиналов, которое превышает расчетное RP_MIN. Единственное, на чем здесь хотелось бы заострить внимание – выбирать надо с учетом погрешности ряда. Например, если мы используем ряд E24 (точность ±5%), то брать ближайший больший номинал 2,2кОм нельзя, поскольку из-за разброса сопротивление такого резистора может составлять 2,2кОм–5%=2,09кОм, что меньше расчетного RP_MIN. В итоге приходится увеличить сопротивление до 2,4кОм, что слегка затянет фронты импульсов SDA и SCL и снизит максимально возможную рабочую частоту. А вот если используется 1%-й ряд, то здесь номинал 2,2кОм уже́ будет в тему, поскольку сопротивление такого резистора не может быть ниже 2,2кОм–1%=2,178кОм, а это нас вполне устраивает. Понятно, что ставить 1%-е резисторы на подтяжки шины I2C далеко не всегда разумно, но само по себе влияние используемого ряда номиналов вышеприведенный пример демонстрирует довольно хорошо. В нашем же случае выберем для подтягивающих резисторов номинал 2,4кОм±5%, и теперь осталось только прикинуть максимальную частоту, на которой сможет работать наша шина. Для этого воспользуемся формулой [3], куда подставим наихудшую комбинацию параметров: максимально возможное сопротивление подтягивающего резистора (2,4кОм+5%=2,52кОм) и максимально возможную емкость линии (для «Fast-Mode» по стандарту это будет 400пФ):
fMAX = 0,5 / [1,20∙RPCb + tHIGH] = 0,5 / (1,2*2,52кОм*400пФ + 0,6мкс) = 276,2кГц.
Отметим, что полученная величина меньше, указанной в спецификации I2C (400кГц). С другой стороны, частота 276,2кГц соответствует предельно допустимой емкости на линии шины, а такую емкость еще надо умудриться создать (например, если шина состоит из 16 устройств, то ее емкость, скорее всего, не будет превышать 150пФ). Ну и вообще говоря, сам стандарт I2C предусматривает, что из-за большой емкости могут возникнуть подобные ситуации и даже предлагает различные варианты выхода из них (см. п.7.2 на стр. 56). Поэтому лично я не вижу в снижении максимально возможной частоты ничего страшного. Ну а если уж прям вот кровь из носу надо именно 400кГц, тогда можно будет убрать запас по току выхода и снизить напряжение питания – в этом случае можно использовать подтяжки с меньшим сопротивлением, что увеличит предельную частоту работы шины. Вдобавок ко всему, номинал 2,4кОм был рассчитан для общего случая, т.е. когда на шине может висеть вообще любое устройство, удовлетворяющее спецификации I2C. Однако, существуют чипы, которые гарантированно могут пропускать через свой выход токи больше 3мА. И если вся шина состоит из подобных могучих микросхем, то в формулу [1] в качестве IMAX можно подставлять не 3мА, а вот этот увеличенный ток, что позволит еще больше уменьшить сопротивление подтяжек. Однако, следует учитывать, что при этом на шине смогут присутствовать только могучие микросхемы, ибо если там появится чип, рассчитанный всего на 3мА, уменьшенная подтяжка его запросто спалит.
Ситуация №2. Имеем устройство, питающееся от литиевого аккумулятора. При этом дывайс в целом довольно прожорливый, поэтому потребление линий I2C в нем хотелось бы минимизировать. С другой стороны, внутри устройства идет довольно активная жизнь, поэтому скорость обмена данными гарантированно должна быть не ниже 100кГц (т.е. работаем в «Standard-Mode»). При этом на шине находится 4 микросхемы и дывайс не подразумевает никаких модификаций. Напряжение питания камня и периферии составляет +3,3В±2%.
Очевидно, что здесь выдвинуты два требования, идущие вразрез друг с другом – для снижения энергопотребления сопротивление подтягивающих резисторов нужно увеличивать, однако, это приведет к ограничению максимальной рабочей частоты. С другой стороны, в данном примере первое требование – это больше пожелание, поскольку никаких конкретных цифр не приводится, а вот второе – это именно пункт ТЗ, поскольку в нем четко прописана частота, на которой шина должна уметь работать в любом случае. Поэтому и рассчитывать сопротивление подтягивающих резисторов нужно исходя из второго требования. А для этого нам нужно использовать формулу [2], ибо именно она позволяет рассчитать максимальный номинал подтяжек, при котором шина еще будет работать на стандартной частоте.
Для начала надо узнать емкость линий SDA и SCL. Поскольку на шине висит 4 устройства, а емкость входа/выхода каждого из них не должна превышать 10пФ (см. Таблицу 9 на стр. 47 стандарта), можем считать, что суммарная емкость выводов всех чипов шины составляет 4*10пФ=40пФ (кстати, обратите внимание, что есть I2C-микросхемы, емкость выводов которых больше 10пФ, поэтому при вычислении значения Cb надо крайне внимательно смотреть таблицы в даташытах). К данному значению необходимо добавить емкость соответствующей дорожки печатной платы (я беру по 1,18пФ на каждый сантиметр меди – см. техасовский апнот, стр. 3). Если предположить, что длина дорожки составляет 10см, то ее емкость составит 1,18пФ/см*10см=11,8пФ, и суммарная емкость линий SDA и SCL будет равна Cb=40пФ+11,8пФ=51,8пФ. Отсюда мы можем по формуле [2] найти максимальное сопротивление подтягивающего резистора для шины, работающей в режиме «Standard» (время нарастания импульсов не должно превышать tr=1000нс, см. Таблицу 10 на стр. 48 стандарта):
RP_MAX = tr / (0,84∙Cb) = 1000нс / (0,84∙51,8пФ) = 22,98кОм.
Ближайший меньший номинал – это 20кОм±5% (19кОм…21кОм) или 22кОм±1% (21,78кОм…22,22кОм). Однако, на мой взгляд, формула [2] дает корректный результат лишь в том случае, когда мастер умеет формировать тактовые импульсы хитрой формы – сначала он должен подождать, пока сигнал SCL нарастет до 0,7VDD, затем выдержать интервал tHIGH, после этого перевести линию в нуль и подождать еще tLOW. Тогда в нашем случае до 70% емкость линии успеет зарядиться за 1,2∙RP_MAXCb=1,42мкс, далее в режиме «Standard» надо дополнительно выждать tHIGH=4мкс, а затем сбросить линию и держать ее в нуле tLOW=4,7мкс. И в итоге мы получим, что период тактовых импульсов будет равен T=1,42мкс+4,00мкс+4,70мкс=10,12мкс, а частота их составит f=1/T=1/10,12мкс=98,8мкс, т.е. практически то, что надо. Но реальные микросхемы, имеющие возможность быть мастером шины I2C, далеко не всегда умеют формировать подобные импульсы. Например, в случае камней ATMega сигнал SCL – это обычный меандр, у которого время нахождения в высоком состоянии равно времени нахождения в низком состоянии. И если у нас длительность единицы равна 1,42мкс+4,00мкс=5,42мкс, то и длительность нуля тоже будет равна 5,42мкс. Поэтому период тактовых импульсов составит T=5,42мкс+5,42мкс=10,84мкс, а частота – f=1/T=1/10,84мкс=92,3кГц. Это уже́ существенно отличается от требуемых 100кГц, поэтому в данном случае для расчета сопротивления подтягивающего резистора я бы рекомендовал использовать формулу, которая учитывает, что тактовые импульсы могут быть только меандром (она легко получается из формулы [3]):
RP_MAX = (1–2f∙tHIGH) / (2,4f∙C) .
И если для расчетов сопротивления подтяжек использовать ее, то максимальное значение RP составит
RP_MAX = (1–2*100кГц*4мкс) / (2,4*100кГц*51,8пФ) = 16,27кОм,
поэтому в качестве подтягивающих резисторов здесь нужно выбрать 15кОм±5% (14,25кОм…15,75кОм) или 16кОм±1% (15,84кОм…16,16кОм). Естественно, это увеличит потребление тока по шине I2C, однако, с гарантией позволит работать на требуемой частоте даже в том случае, когда тактовый сигнал является меандром. Тем более, что абсолютные значения отжираемого тока будут не сильно отличаться. Если взять вариант «5%-й ряд», то в первом случае максимальное потребление тока составит
I1 = (3,3В+2%) / 19кОм = 177,1мкА,
а во втором
I2 = (3,3В+2%) / 14,25кОм = 236,2мкА,
и на фоне того, что литиевые аккумуляторы имеют собственный ток разряда в районе десятков микроампер, разницу между I1 и I2 можно считать равной нулю.
Ситуация №3. Имеем устройство, питающееся от батарейки типа «Крона» с емкостью 150мАч. При этом дывайс в целом не сильно жрущий, однако, находится он в труднодоступном месте, и часто менять батарейки в нем не получится. В связи с этим потребление линий I2C в нем необходимо сделать настолько низким, насколько это вообще возможно. При этом устройство крайне неспешно, и его практически единственная задача – опрашивать некий датчик раз в 30 секунд (т.е. частота опроса составляет 0,033Гц). На шине I2C кроме камня и датчика никого нет и никогда не будет. Напряжение питания камня и периферии составляет +5,0В±5%.
Данная ситуация почти один в один нам уже встречалась ранее (см. вывод формулы [4] выше). Для нее характерно стремление максимально снизить энергопотребление шины I2C за счет использования высокоомных подтягивающих резисторов. При этом то, на какой максимальной скорости сможет работать шина с такими подтяжками, нам вообще похер – при частоте опроса датчика один раз в 30 секунд эта скорость может быть практически любой. Поэтому в данном случае мы можем использовать самый большой номинал резисторов, который еще гарантирует приемлемые уровни сигналов на линиях SDA и SCL. Расчет этого номинала будем вести с помощью формулы [4], учитывающей токи утечки по входам/выходам I2C-микросхем. При этом учтем, что минимально возможное напряжение питания шины составляет VDD_MIN=+5,0В–5%=+4,75В, а суммарный ток утечки для двух чипов на шине не превысит IΣ_LEAK=20мкА (т.к. в соответствии со спецификацией I2C, у каждой микросхемы этот ток не должен превышать 10мкА – см. Таблицу 9 на стр. 47 стандарта):
RP_MAX_HARD = 0,3VDD_MIN / IΣ_LEAK = 0,3*4,75В / 20мкА = 71,5кОм,
Ближайший меньший номинал – это 68кОм±5% (64,6кОм…71,4кОм). При этом ток, отжираемый шиной I2C в худшем случае составит
I = (5,0В+5%) / 64,6кОм = 81,3мкА,
а скорость передачи данных можно будет с гарантией сделать не ниже
fMAX = 0,5 / [1,20∙RPCb + tHIGH] = 0,5 / (1,2*71,4кОм*25пФ + 4,0мкс) = 81,4кГц,
где 25пФ – емкость линии, на которой висят две микросхемы (по 10пФ на каждую), соединенные между собой дорожками длиной 4,2см (такое расстояние взято, чтобы суммарная емкость дорожки получилась 5пФ).
Что здесь можно сказать? Несмотря на то, что сопротивление подтягивающих резисторов получилось сравнительно большим, энергопотребление шины I2C оказалось далеко не на высоте. Чтобы это понять, достаточно сравнить полученное значение тока через подтяжки из этого примера (81,3мкА) и из предыдущего (236,2мкА). С одной стороны, снижение потребления налицо – цифры отличаются почти в три раза, к тому же в первом случае питание значительно ниже, чем во втором (а от этого напрямую зависит токопотребление шины). Но ведь, с другой стороны, и критерии, по которым рассчитывались подтягивающие резисторы, тоже существенно отличаются. Напомню, что в первом случае нам надо было уменьшить потребляемый ток, но при этом оставить возможность обмена данными на сравнительно большой скорости. Т.е. здесь улучшение энергопотребления априори было возможно только до уровня «как получится, так и получится», но при этом результат оказался вполне достойным (236мкА вместо «стандартных» 3мА, т.е. разница почти в 13 раз!). В втором же случае нам было абсолютно плевать на частоту работы шины, главным было уменьшить энергопотребление любой ценой – и разница всего в три раза. Да, если бы питание камня в медленном устройстве было равно +3,3В±2%, то эта разница составила бы четыре с половиной раза, однако это тоже, на мой взгляд, довольно мало. С третьей стороны, сама по себе цифра 81,3мкА – не сильно велика, особенно на фоне того, что связь с датчиком будет осуществляться раз в полминуты. Поэтому можно с ней «смириться», и оставить всё как есть. Однако, на всякий случай всегда нужно помнить, что расчет резисторов по формулам [4] и [4а] заведомо дает значение сопротивления с охереннейшим запасом, и если для нас важны каждые 10мкА, то всегда остается вариант прямого измерения суммарного тока утечки линии шины.
Как я уже́ говорил ранее, в документации на I2C-микросхемы чаще всего приводятся только максимальное значение тока утечки. И если в реальности он в два раза меньше, а на шине находится 3 устройства, то номинал подтягивающего резистора может быть увеличен в 2*3=6 раз без каких-либо ухудшений работы шины. Если ток в три раза меньше заявленного, а шина состоит из 5 микросхем, то подтяжку можно увеличить в 3*5=15 раз. И поскольку обычно значение утечки из таблицы минимум в 3 раза больше ее реальной величины, то на практике шина I2C вполне нормально работает с подтягивающими резисторами в несколько сотен килоом. Например, вот так выглядят тактовые импульсы в системе, образованной датчиком температуры LM75A и камнем ATMega328P, при использовании подтяжек номиналом 1,1МОм:
Питание шины составляет +5,0В. Обратите внимание на то, что в исходном состоянии (самый левый кусок осциллограммы) даже при использовании мегаомного резистора напряжение на линии SCL просаживается лишь на 0,5В относительно VDD . Это значит, что суммарный ток утечки по ней составляет всего IΣ_LEAK=0,5В/1,1МОм=0,46мкА вместо предельных 20мкА (2*10мкА), которые допускает спецификация (и которые, кстати, указаны в документации на вышеупомянутые микросхемы). Таким образом, в соответствии с формулой [4] сопротивление подтяжки линии SCL можно увеличивать вплоть до
RP_MAX_HARD = 0,3VDD_MIN / IΣ_LEAK = 0,3*4,75В / 0,46мкА = 3,09МОм,
т.е. более чем в 40 раз (!) по сравнению со значением, рассчитанным для предельных 20мА. Конечно, в серию такой резистор я бы не поставил, но в штучные дывайсы – почему бы и нет? Во всяком случае, в нескольких единичных поделках у меня на шину I2C чисто ради интереса установлены подтяжки номиналом 1МОм±5% и ничего – работают без нареканий несколько лет. Да и почему бы им не работать, если всё грамотно посчитано, а не взято с потолка? Вот, например, тактовые импульсы, показанные на последней осциллограмме. Большинство мега-гуру сразу же скажут: такие импульсы абсолютно неприемлемы. Извините, а почему? Потому, что эти импульсы не являются прямоугольниками? Так это не страшно – параметр tr в спецификации дан только для того, чтобы шина могла работать на максимально возможной частоте, а нам на это плевать. Или плохо то, что импульсы не доходят до напряжения питания? Так и на это тоже похер – главное, что они дотягивают до уровня 0,7VDD и после этого не сбрасываются еще минимум 4мкс. В итоге получаем, что шина отлично работает даже с треугольными сигналами SCL, если они сформированы в соответствии со стандартом, а все рассказы о их неправильной форме основаны на том, что рассказчик вообще не шарит в теме. То же самое касается и криков «на шине I2C не может быть мегаомных резисторов!» – вы сначала объясните, почему их там не может быть, а вот с этим возникают проблемы. Поэтому лично я считаю, что если надо прямо вот до усрачки предельно снизить потребление тока шиной I2C, то вполне допустимо не брать токи утечки микросхем из документации, а напрямую измерять их для конкретных чипов. Последовательность действий при этом будет такой:
• собираем устройство (ну, или хотя бы шину I2C);
• в качестве подтяжек вешаем резисторы номиналом 1МОм;
• измеряем, какое напряжение падает на этом резисторе в исходном состоянии шины (можно прямо тестером, только обмена данными во время измерений быть не должно, плюс некоторые тестеры имеют входное сопротивление 1МОм, и это нужно учитывать);
• получаем профит: реальный суммарный ток утечки данной линии (IΣ_LEAK) в микроамперах численно равен измеренному напряжению.
Далее можно вычислить максимально допустимое сопротивление подтягивающего резистора при помощи формулы [4]:
RP_MAX_HARD = 0,3VDD_MIN / IΣ_LEAK
и выбрать ближайший меньший стандартный номинал. При этом необязательно стремиться именно к расчетному значению, ибо даже 1МОм в случае цифровых микросхем с их питанием максимум +5,0В дает ток потребления линии не больше 0,5мкА (чего обычно более чем достаточно). Ну и в завершение нужно при помощи формулы [3] рассчитать, до какой частоты сможет без глюков работать наша шина:
fMAX = 0,5 / [1,20∙RPCb + tHIGH]
(как найти емкость Cb, было рассказано в прошлом примере). Например, для случая ATMega328+LM75A и подтяжки 1МОм, показанного на последнем рисунке, суммарная емкость составит Cb=10пФ+10пФ+11,8пФ+16пФ=47,5пФ (здесь 10пФ – емкость вывода I2C-микросхемы по стандарту, 11,8пФ – емкость линии связи длиной 10см и 16пФ – емкость щупа осциллографа при коэффициенте деления 1/10). Поэтому максимальная частота работы шины составит
fMAX = 0,5 / [1,20∙RPCb + tHIGH] = 0,5 / [1,20*1,1МОм*47,5пФ + 4мкс] = 7,5кГц,
и, как нетрудно видеть по последней картинке, при записи соответствующего значения TWBR в камень ATMega328 всё отлично работает. Там, кстати, даже побольше частота установлена (8,2кГц), потому что я при расчетах взял не 1,1МОм, а 1МОм, и всё равно шина пашет как надо, ибо 0,7VDD – это с запасом. Так что рассмотренный способ увеличения сопротивления подтяжек вполне работает, ну а уж пользоваться им или нет – решать вам.
Программная часть интерфейса I2C
Для того чтобы устройства могли общаться по шине I2C, должна быть соблюдена определенная последовательность битов на линиях синхронизации (SCL) и данных (SDA), поскольку кроме передачи непосредственно «полезной» информации шина предусматривает также наличие служебных битов. Обмен данными осуществляется пачками (посылками, транзакциями). Каждая пачка состоит из стартового бита, стопового бита, непосредственно передаваемой информации, а также битов подтверждения/неподтверждения:
Пунктирная линия, соответствующая высокому логическому уровню тактовых импульсов, заостряет наше внимание на том, что единица для линий SCL и SDA является рецессивным состоянием, т.е. сигнал естественным образом поднимается до высокого логического уровня через подтягивающий резистор безо всяких принуждений со стороны шины. Доминирующем же состоянием является низкий логический уровень, потому что сигнал будет притянут к массе только тогда, когда устройство принудительно устанавливает нуль на линии.
Любая посылка начинается со стартового бита, который определяется как задний фронт импульса на линии SDA, в то время как сигнал SCL установлен в единицу. Возникновение такого события воспринимается всеми устройствами, подключенными к шине, как признак начала процедуры обмена, и после фиксации старт-бита шина считается занятой. Обратите внимание на то, что формирование стартового бита – это обязанность мастера.
После того, как старт-бит сформирован, ведущий опускает линию SCL в нуль и выставляет на линию SDA старший бит первого байта сообщения, после чего линия SCL устанавливается в единицу. Обратите внимание на то, что данные, передаваемые по линии SDA, считаются действительными только во время высокого состояния тактового импульса (т.е. при SCL=1), а изменения на линии SDA допускаются исключительно при SCL=0. При этом данные с линии SDA считываются по переднему фронту тактового сигнала, а обновляются обычно по его заднему фронту. После отправки старшего бита передаваемого байта, на линию данных поочередно выставляются все остальные его биты, вплоть до младшего. Таким образом, обмен информацией по шине I2C происходит побайтово (количество байт в сообщении не ограничено). При этом за каждым байтом следует бит подтверждения («ACK») или не подтверждения («NACK»), выставляемый на шину приемником. Отметим, что «ACK» соответствует низкому логическому уровню, а «NACK» – высокому. Так сделано из-за того, что единица – это рецессивное состояние шины I2C, и если приемник заглючил, то сигнал сам по себе поднимется до «NACK». Поэтому подтверждение «ACK» может быть передано только в том случае, когда приемное устройство может прижать линию SDA к массе, что свидетельствует о его работоспособности.
Заканчивается транзакция стоповым битом, определяемым как передний фронт импульса SDA, в то время как сигнал SCL установлен в единицу. Любая I2C-посылка должна заканчиваться стоп-битом, однако может возникнуть ситуация, при которой стоповому биту предшествует не один, а несколько стартовых битов (см. ниже). Как и в случае стартового бита, формирование стоп-бита является обязанностью мастера. Через некоторое время после возникновения стопового бита шина считается освободившейся.
Последовательность событий при передаче данных по I2C будет такой:
• мастер генерирует стартовый бит, чтобы инициировать транзакцию;
• в первом байте сообщения мастер передает 7-битный адрес, соответствующий ведомому устройству, с которым он хочет связаться. Последний бит в этом байте – это индикатор чтения/записи. Если мастер хочет считать данные с ведомого устройства, он устанавливает данный бит в единицу, если же данные должны быть записаны, то последний бит первого байта сбрасывается;
• следующий байт – это байт данных. Он может исходить как от ведущего, так и от ведомого, в зависимости от состояния бита чтения/записи в первом байте. Напомним, что данные передаются по 8 бит, начиная со старшего;
• за байтом данных следует бит подтверждения, равный «ACK» или «NACK». Если осуществляется процедура считывания данных, то бит подтверждения генерируется мастером. Если же производится запись данных, то бит подтверждения должно генерировать ведомое устройство. Отметим, что процесс формирования бита ACK/NACK в случае шины I2C заслуживает особенного внимания, поэтому чуть ниже он будет рассмотрен более подробно;
• после формирования бита подтверждения по шине можно передавать следующий байт данных (напомним, что количество передаваемых байт неограниченно);
• посылка завершается стоп-битом, сгенерированным мастером;
• после этого шина считается готовой к осуществлению новой транзакции.
Как было сказано выше, процесс формирования бита подтверждения в случае шины I2C является нетривиальным. В том случае, когда мастером осуществляется запись данных в ведомое устройство, бит подтверждения генерирует ведомый. При этом на время импульса подтверждения мастер отпускает (переводит в высокое состояние) линию SDA, а ведомое устройство должно формировать сигнал «ACK», удерживая данную линию в низком уровне всё время, пока импульс синхронизации SCL равен единице. В том случае, когда ведомый не может ответить ведущему (например, когда он выполняет в данный момент какие-либо функции реального времени), линия данных SDA должна быть оставлена им в высоком состоянии, что будет соответствовать сигналу «NACK». При возникновении подобной ситуации у мастера остается возможность выдать стоповый бит для прерывания пересылки данных.
В случае, когда мастер считывает данные с ведомого, бит подтверждения после каждого принятого байта он должен формировать сам. При этом возможны два варианта. Если ведомый (по мнению мастера) передал еще не всю информацию, ведущий должен сгенерировать сигнал «ACK». Если же мастер считает принятый байт последним в посылке, то в этом случае вместо «ACK» выставляется сигнал «NACK», сообщающий ведомому об окончании транзакции и требующий от него освободить шину. Подобный подход является крайне эффективным в тех случаях, когда мастер получает от ведомого (например, от датчика температуры) непрерывный поток данных. В этом случае ведущему не нужно для считывания нового значения постоянно начинать новую транзакцию – достаточно просто не прерывать старую, раз за разом выставляя «ACK» в ответ на принятые данные. Если же мастеру нужно отвлечься на что-то еще, он может сформировать «NACK» после приема очередного байта и начать новую транзакцию только тогда, когда он будет к этому готов. Отметим, что для описанной работы интерфейса I2C ведомый, передающий данные мастеру, должен отпускать (т.е. переводить в высокое состояние) линию данных SDA на время формирования ведущим бита подтверждения.
Формирование нескольких стартовых битов
Протокол I2C допускает возможность формирования на шине так называемых «повторных запусков», когда мастер при помощи стартового бита начинает одну транзакцию, а затем объявляет начало новой транзакции без промежуточного стопового бита:
Данная фича введена для устранения возможных конфликтов между несколькими мастерами, присутствующими на шине. Чтобы понять, зачем она нужна, рассмотрим типичный пример – вычитывание данных с ведомого, в качестве которого выступает датчик температуры LM75A. Сначала мастеру надо сформировать стартовый бит для того, чтобы объявить начало транзакции. Затем нужно отослать датчику первый байт данных. В данном байте содержится адрес конкретного датчика (их на шине может висеть до восьми штук), последний же бит равен нулю – это означает, что мы будем записывать данные в датчик. Это может показаться странным, ведь, по идее, данные из датчика мы должны считывать, а не записывать их туда. Однако, из LM75 можно вытащить не только температуру, но и всякую служебную информацию, поэтому перед считыванием данных мы должны указать микросхеме, из какого регистра мы хотим их читать. Таким образом, вторым байтом данной транзакции будет выступать адрес регистра, в котором хранится измеренная температура (0х00). И в итоге первая посылка будет содержать адрес датчика, с которым мы хотим общаться (старшие 7 бит первого байта), плюс требование работать с регистром температуры (младший бит первого байта + второй байт). А вот далее можно уже́ считывать показания термометра – хоть непрерывно, хоть однократно. Однако, перед этим нужно объяснить датчику, что данные теперь должны именно считываться. Согласно стандарту I2C, это можно сделать только при помощи адресного байта, т.е. первого байта транзакции, в котором указывается адрес ведомого и направление передачи данных. Поэтому мастер будет вынужден объявить новую транзакцию на шине, для чего ему, по идее, надо было бы сначала сформировать стоповый импульс, а затем – стартовый. Так вот, функция «повторного запуска» позволяет ведущему сгенерировать стартовый бит, начинающий вторую транзакцию, без завершения первой посылки (т.е. без выдачи на шину стоп-бита).
На первый взгляд, данная фича абсолютно бесполезна, ибо сформировать стоповый бит для мастера – дело плёвое. Однако, смысл использования повторного запуска становится ясен, если вспомнить, что на шине I2C может присутствовать несколько мастеров. Дело в том, что при формировании стоп-бита мастер освобождает шину, поэтому любой другой ведущий тут же может ей воспользоваться. И нет никакой гарантии, что между первой и второй транзакцией не объявится мастер, который тоже захочет пообщаться с ведомыми, при этом помешав первому мастеру получить необходимые данные. Более того, второй ведущий может обратиться к тому же датчику и указать другой адрес регистра, из которого нужно вычитывать данные, после чего освободить шину для второй транзакции. И если в этот момент первый мастер захватит шину, то он будет читать неправильную инфу, поскольку исходить она будет не из регистра температуры, а из какого-то другого, запрошенного вторым ведущим. И именно для предотвращения подобной херни в стандарт I2C была введена возможность «повторного запуска», позволяющая начать вторую транзакцию (в нашем случае – чтение) без освобождения шины (т.е. без формирования стопового бита).
Арбитраж шины I2C
Одним из важных свойств интерфейса I2C является поддержка нескольких мастеров на шине (режим мультимастера). При этом во избежание конфликтов между ведущими, I2C-микросхемы должны уметь определять, свободна или нет в данный момент шина (см. предыдущий пункт). Если шина занята другим мастером, устройство должно ожидать завершения текущей транзакции, прежде чем инициировать свою собственную передачу. Но что происходит, когда два (или более) ведущих пытаются начать транзакцию одновременно? Шина I2C обеспечивает эффективное и простое решение данной проблемы при помощи процесса, называемым «арбитражем». Данный процесс основан на следующем свойстве выходного драйвера с открытым стоком: если один мастер пытается установить на линии высокий логический уровень сигнала, а другой – низкий, то установлен будет низкий логический уровень. В этом случае говорят, что второй мастер «выиграл», поскольку состояние шины будет определять именно он. Более того, если «проигравший» имеет возможность опрашивать свой выход, то он сразу обнаружит, что фактическое состояние линии не соответствует предполагаемому (т.е. на шине присутствует нуль, а не единица), и сможет прервать передачу данных:
Процесс арбитража на шине I2C происходит следующим образом. Сначала оба мастера генерируют стартовый бит, после чего они начинают последовательно выставлять данные на шину. При этом если логические уровни на линии SDA совпадают, процесс выдачи данных продолжается как обычно. Однако, при возникновении первого же несовпадения мастер, установивший низкий уровень сигнала, объявляется победителем и полностью захватывает шину, а проигравший должен прекратить передачу информации. При этом победитель может продолжать передачу без каких-либо прерываний (т.е. без необходимости перезапускать транзакцию), а это означает сохранность передаваемых данных и отсутствие конфликтов с другими устройствами. Однако, за такие плюхи приходится платить усложнением схемы выходного драйвера, т.к. он должен уметь одновременно как выставлять сигнал на линию SDA шины, так и считывать его фактическое состояние.
Поскольку после стартового бита на шину I2C должен выставляться «адресный» байт, то вполне очевидно, что большинство арбитражных конфликтов будет разрешено в течение его старших семи бит, ибо разные мастера обычно обращаются к разным ведомым. Однако, нельзя исключать ситуацию, при которой два ведущих захотят одновременно обратиться к одному и тому же устройству. В этом случае «адресный арбитраж» не будет выигран ни одним из мастеров, поскольку данные, которые они выставят на шину в течение семи старших бит «адресного» байта, будут идентичными. И далее в дело вступит «арбитраж по направлению передачи», при котором сравниваются младшие биты «адресного» байта. Напомним, что в соответствии со стандартом I2C, младший бит первого байта транзакции должен быть равен нулю, если инициируется процесс записи данных в ведомого, и единице, если инициируется процесс чтения. Таким образом, здесь возможны два варианта. Если оба мастера хотят считывать информацию с ведомого, то арбитраж по направлению не выиграет ни один из них, и оба ведущих начнут одновременное чтение данных с одного и того же устройства (что ничему не противоречит). Если же один мастер инициирует запись информации, а второй – ее считывание, то победителем будет ведущий, желающий записать что-то в ведомого (а второму мастеру придется подождать, пока процесс записи не будет завершен). Отметим, что если писа́ть данные на шину намереваются сразу два ведущих, то дальше вступит в дело «арбитраж по данным», который выиграет устройство, у которого в передаваемой информации раньше всех встретится нуль. Таким образом, наличие на шине адресного арбитража и арбитража по данным намекает нам, что самые «важные» адреса и данные должны быть как можно меньше (т.е. ближе всего к нулю), ибо они будут обработаны самыми первыми.
Плюсы и минусы шины I2C
Таким образом, основными достоинствами шины I2C (по мнению Роберта Кейса) являются следующие:
• поддержка сравнительного большого количества устройств (до 112 штук);
• даже при большом количестве устройств на шине для ее реализации достаточно всего двух линий – SDA и SCL;
• на шину легко повесить ведомые устройства разного типа;
• одновременная поддержка несколько мастеров на одной шине;
• наличие бита подтверждения (ACK/NACK), облегчающего обработку ошибок.
К недостаткам рассматриваемой шины можно отнести:
• увеличение сложности прошивки МК или усложнение аппаратной части;
• наличие битов подтверждения снижает максимальную пропускную способность шины;
• для нормальной работы шины требуются подтягивающие резисторы, которые ограничивают тактовую частоту и занимают место на печатной плате (что особенно критично в системах с ограниченным свободным пространством). Кроме того, подтягивающие резисторы увеличивают энергопотребление устройства в целом.
Отсюда видно, что интерфейс I2C особенно подходит для систем, имеющих сложную, разнообразную и/или разветвленную сеть исполнительных устройств. Однако, если пропускная способность шины является важным фактором, то от использования данного интерфейса часто приходится отказываться, либо шустрые элементы нужно выводить на отдельную шину, например, SPI или UART. При этом аппаратная реализация SPI/UART намного проще, чем I2C, и если вы работаете с FPGA и разрабатываете свой последовательный интерфейс с нуля, зачастую выбор падает именно на SPI/UART, а не на I2C. С другой стороны, по сравнению с USB или тем же самым Ethernet’ом интерфейс I2C является просто «игрушечным», и если требуемая элементная база для проекта (АЦП, датчики, ЧРВ и т.д.) существует только с интерфейсом I2C, принципиальных проблем с его реализацией даже в FPGA чаще всего не возникает. В любом случае – каждый раз при выборе шин данных, которые будут использованы разрабатываемом устройстве, приходится учитывать уйму «мелких» моментов, и в данной заметке я постарался заострить внимание именно на таких «мелочах» (в основном касающихся аппаратной части I2C).
А у меня на сегодня всё. Желаю удачи при работе с интерфейсом I2C!
Обсудить эту заметку можно здесь.