(Правка: для ясности, многие из следующих проблем связаны с целостностью сигнала, вызванной межплатным использованием устройств I2C / SPI, как правильно указывает Олин.)
Если у вас нет ограничений, которые сильно подталкивают вас к меньшему количеству проводов (у нас был один проект с герметичным разъемом, чтобы каждый дополнительный контакт был довольно дорогим), по возможности избегайте I2C и придерживайтесь SPI.
С SPI довольно легко работать на аппаратном и программном уровне. В аппаратном обеспечении имеется две общие линии данных: Master In Slave Out (MISO или SOMI) и Master Out Slave In (MOSI или SIMO), общие часы, генерируемые мастером, и один выбор микросхемы для каждого устройства. Линия CS снижается, тактовые циклы и, по существу, сдвигаются во входных битах и сдвигают выходные биты до тех пор, пока транзакция не завершится, и в этот момент линия CS становится высокой. Когда их CS-линия высока, подчиненные устройства не обмениваются данными: они игнорируют линии CLK и MOSI и переводят свой вывод MISO в высокоимпедансное состояние, чтобы позволить кому-то еще использовать его.
Если у вас есть микроконтроллер, использующий несколько устройств SPI, и он имеет встроенное периферийное устройство SPI, отправьте выход CS микроконтроллера на демультиплексор (например, 74HC138) и управляйте адресными линиями, чтобы выбрать устройство между транзакциями SPI; вы записываете слова в регистр, чтобы поставить их в очередь для вывода, и читаете их обратно после того, как вывод CS поднялся высоко.
Поскольку все сигналы SPI являются однонаправленными, их можно буферизовать, использовать через изолирующий барьер с цифровыми изоляторами и отправлять с платы на плату с помощью линейных драйверов, таких как LVDS. Единственное, о чем вам нужно беспокоиться, это задержка распространения в оба конца, которая ограничит вашу максимальную частоту.
I2C - это совсем другая история. Хотя это намного проще с точки зрения проводки, с двумя проводами SCL и SDA, обе эти линии являются общими двунаправленными линиями, которые используют устройства с открытым стоком с внешним подтягиванием. Существует протокол для I2C, который начинается с передачи адреса устройства, поэтому можно использовать несколько устройств, если у каждого есть свой собственный адрес.
С аппаратной точки зрения очень трудно использовать I2C в системах, которые имеют какой-либо значительный шум. Чтобы буферизовать или изолировать линии I2C, вы должны прибегнуть к экзотическим микросхемам - да, они существуют, но их не много: мы использовали один на один проект и поняли, что вы можете использовать один изолятор, но вы не могли использовать два последовательно - он использовал небольшие падения напряжения, чтобы выяснить, какая сторона была движущей силой, и два последовательных падения были два очень.
Пороги логического уровня I2C зависят от Vcc, поэтому вам следует быть очень осторожным, если вы используете устройства 3V / 3.3V и 5V в одной системе.
Любые сигналы, в которых используется кабель длиной более одного или двух футов, должны беспокоиться о емкости кабеля. Емкость 100 пф / м не является необычной для многожильного кабеля. Это заставляет вас замедлять шину или использовать более низкие подтягивающие резисторы, чтобы иметь возможность правильно обрабатывать дополнительную емкость и соответствовать требованиям времени нарастания.
Допустим, у вас есть система, которую вы считаете хорошо спроектированной, и вы можете справиться с большинством проблем с целостностью сигнала, а шум встречается редко (но все еще присутствует). О чем вам беспокоиться?
Есть куча состояний ошибок, которые вы должны быть готовы обработать:
Ведомое устройство не распознает определенный байт. Вы должны обнаружить это и остановить и перезапустить коммуникационную последовательность. (С помощью SPI вы обычно можете прочитать отправленные данные, если хотите убедиться, что они были получены без ошибок.)
Вы читаете байт данных с ведомого устройства, и устройство «загипнотизировано» из-за шума на линии синхронизации: вы отправили необходимые 8 часов, чтобы прочитать этот байт, но из-за шума ведомое устройство думает, что это получил 7 часов и все еще передает 0 на линии данных. Если бы устройство получило 8-й такт, оно высвободило бы линию данных высоко, чтобы мастер мог поднять или опустить линию данных, чтобы передать бит ACK или NACK, или мастер мог передать условие останова (P). Но ведомый по-прежнему удерживает линию данных на низком уровне, тщетно ожидая очередных часов. Если мастер не готов попробовать дополнительные часы, шина I2C застрянет в тупике. Хотя я использовал несколько микроконтроллеров, которые обрабатывают нормальные условия ACK / NACK,
Действительно ужасный случай, когда ведущий записывает данные на одно подчиненное устройство, а другой ведомый неправильно интерпретирует адрес устройства и считает, что передаваемые данные предназначены для него. У нас были устройства I2C (расширители ввода / вывода), которые из-за этого иногда неправильно устанавливали регистры. Почти невозможно обнаружить этот случай, и чтобы быть устойчивым к шуму, вы должны периодически устанавливать все регистры, чтобы, если вы столкнетесь с этой ошибкой, по крайней мере она будет исправлена через короткий промежуток времени. (SPI никогда не сталкивается с этой проблемой - если у вас случится сбой в линии CS, он никогда не будет длиться долго, и вы не получите данные, случайно прочитанные неправильным ведомым устройством.)
Многие из этих условий можно было бы правильно обработать в протоколе, если бы было обнаружение ошибок (коды CRC), но лишь немногие устройства имеют это.
Я считаю, что мне нужно создать сложное программное обеспечение в моем главном устройстве I2C, чтобы справиться с этими условиями. На мой взгляд, это того не стоит, если только ограничения на проводку не заставят нас использовать I2C, а не SPI.