(editar: Para ficar claro, muitas das preocupações a seguir têm a ver com a integridade do sinal causada pelo uso placa-a-placa de dispositivos I2C / SPI, como Olin corretamente indica.)
A menos que você tenha restrições que o empurrem fortemente em direção a menos fios (tivemos um projeto com um conector hermeticamente fechado que cada contato adicional era bastante caro), evite o I2C sempre que possível e atenha-se ao SPI.
É fácil lidar com o SPI com base em hardware e software. No hardware, existem duas linhas de dados compartilhadas, Master In Slave Out (MISO ou SOMI) e Master Out Slave In (MOSI ou SIMO), um relógio compartilhado gerado pelo mestre e uma seleção de chip por dispositivo. A linha CS fica baixa, o relógio alterna e muda essencialmente nos bits de entrada e desloca os bits de saída, até a transação terminar, quando a linha CS fica alta. Quando a linha CS é alta, os dispositivos escravos não se comunicam: eles ignoram as linhas CLK e MOSI e colocam o pino MISO em um estado de alta impedância para permitir que outras pessoas o usem.
Se você possui um microcontrolador usando vários dispositivos SPI e ele possui um periférico SPI interno, envie a saída CS do microcontrolador para um desmultiplexador (por exemplo, 74HC138) e controle as linhas de endereço para selecionar o dispositivo entre as transações SPI; você escreve palavras em um registro para enfileirá-las para saída e as lê novamente depois que o pino CS é elevado.
Como os sinais SPI são todos unidirecionais, eles podem ser armazenados em buffer, usados através de uma barreira de isolamento com isoladores digitais e podem ser enviados de placa para placa usando drivers de linha como LVDS. Você só precisa se preocupar com o atraso na propagação de ida e volta, o que limitará sua frequência máxima.
I2C é uma história completamente diferente. Embora seja muito mais simples do ponto de vista da fiação, com apenas dois fios SCL e SDA, ambas as linhas são linhas bidirecionais compartilhadas que usam dispositivos de drenagem aberta com uma tração externa. Há um protocolo para I2C que começa transmitindo um endereço de dispositivo, para que vários dispositivos possam ser usados se cada um tiver seu próprio endereço.
Do ponto de vista do hardware, é muito difícil usar o I2C em sistemas com ruído significativo. Para armazenar em buffer ou isolar linhas I2C, você precisa recorrer a CIs exóticos - sim, eles existem, mas não existem muitos: usamos um em um projeto e percebemos que você poderia usar um isolador, mas não podia use dois em série - ele usou pequenas quedas de tensão para descobrir de que lado era o fim das coisas e duas quedas em série eram duas.
Os limites do nível lógico do I2C dependem do Vcc, portanto, você deve ter muito cuidado ao usar dispositivos de 3V / 3,3V e 5V no mesmo sistema.
Quaisquer sinais que usem um cabo de mais de um pé ou dois precisam se preocupar com a capacitância do cabo. A capacitância de 100pf / metro não é incomum para cabos multicondutores. Isso faz com que você tenha que desacelerar o barramento ou usar resistores de pullup inferiores, para poder lidar adequadamente com a capacitância extra e atender aos requisitos de tempo de subida.
Então, digamos que você tenha um sistema que tenha projetado bem e que possa lidar com a maioria dos problemas de integridade do sinal, e o ruído é raro (mas ainda presente). Com o que você precisa se preocupar?
Há várias condições de erro que você precisa estar preparado para lidar:
O dispositivo escravo não reconhece um byte específico. Você precisa detectar isso e parar e reiniciar a sequência de comunicações. (Com o SPI, você geralmente pode ler novamente os dados que enviar, se quiser ter certeza de que foram recebidos sem erros.)
Você está lendo um byte de dados de um dispositivo escravo, e o dispositivo é "hipnotizado" por causa do ruído na linha do relógio: você enviou os 8 relógios necessários para ler esse byte, mas por causa do ruído, o dispositivo escravo pensa que recebeu 7 relógios e ainda está transmitindo um 0 na linha de dados. Se o dispositivo tivesse recebido o oitavo relógio, teria liberado a linha de dados alta, para que o mestre pudesse aumentar ou diminuir a linha de dados para transmitir um bit ACK ou NACK, ou o mestre poderia transmitir uma condição de parada (P). Mas o escravo ainda mantém a linha de dados baixa, esperando em vão por outro relógio. Se um mestre não estiver preparado para experimentar relógios extras, o barramento I2C ficará preso em um impasse. Embora eu tenha usado vários microcontroladores que lidam com as condições normais do ACK / NACK,
O caso realmente terrível é quando um mestre está gravando dados em um dispositivo escravo, e outro escravo interpreta o endereço do dispositivo incorretamente e pensa que os dados transmitidos são para ele. Tivemos dispositivos I2C (expansores de E / S) que ocasionalmente têm registros configurados incorretamente por causa disso. É quase impossível detectar esse caso e, para ser robusto ao ruído, é necessário definir todos os registros periodicamente, para que, se você encontrar esse erro, pelo menos ele seja corrigido após um curto período de tempo. (A SPI nunca tem esse problema - se ocorrer uma falha na linha CS, ela nunca persistirá por muito tempo e você não obterá dados lidos acidentalmente pelo dispositivo escravo errado.)
Muitas dessas condições poderiam ser tratadas corretamente no protocolo se houvesse detecção de erro (códigos CRC), mas poucos dispositivos possuem isso.
Acho que tenho que criar um software complexo no meu dispositivo mestre I2C para lidar com essas condições. Na minha opinião, não vale a pena, a menos que as restrições na fiação nos forcem a usar o I2C e não o SPI.