Com referência às placas Arduino Uno, Mega2560, Leonardo e similares:
- Como o SPI funciona?
- Qual a velocidade do SPI?
- Como eu me conecto entre um mestre e um escravo?
- Como eu faço um escravo SPI?
Observação: isso é uma pergunta de referência.
arduino-uno
arduino-mega
c++
arduino-leonardo
spi
Nick Gammon
fonte
fonte
Respostas:
Introdução ao SPI
A interface SPI ( Serial Peripheral Interface Bus ) é usada para comunicação entre vários dispositivos em curtas distâncias e em alta velocidade.
Normalmente, existe um único dispositivo "mestre", que inicia as comunicações e fornece o relógio que controla a taxa de transferência de dados. Pode haver um ou mais escravos. Para mais de um escravo, cada um tem seu próprio sinal de "seleção de escravo", descrito mais adiante.
Sinais SPI
Em um sistema SPI completo, você terá quatro linhas de sinal:
Quando vários escravos são conectados ao sinal MISO, espera-se que eles tri-state (mantenha a alta impedância) que a linha MISO até que eles sejam selecionados pelo Slave Select sendo afirmados. Normalmente, a Seleção de Escravo (SS) fica baixa para afirmá-lo. Ou seja, é ativo baixo. Uma vez que um escravo específico é selecionado, ele deve configurar a linha MISO como uma saída, para que possa enviar dados ao mestre.
Esta imagem mostra a maneira como os dados são trocados quando um byte é enviado:
Observe que três sinais são saídas do mestre (MOSI, SCK, SS) e um é uma entrada (MISO).
Cronometragem
A sequência de eventos é:
SS
vai baixo para afirmar e ativar o escravoSCK
linha alterna para indicar quando as linhas de dados devem ser amostradasSCK
(usando a fase do relógio padrão)SCK
(usando a fase do relógio padrão), alterandoMISO
/MOSI
se necessárioSS
aumente a velocidade para desativá-laObserve que:
Como os dados são enviados e recebidos no mesmo pulso do relógio, não é possível que o escravo responda imediatamente ao mestre. Os protocolos SPI geralmente esperam que o mestre solicite dados em uma transmissão e obtenha uma resposta em uma transmissão subsequente.
Usando a biblioteca SPI no Arduino, fazer uma única transferência se parece com isso no código:
Código de amostra
Exemplo de envio apenas (ignorando quaisquer dados recebidos):
Fiação para SPI somente de saída
O código acima (que envia apenas) pode ser usado para conduzir um registro de deslocamento serial de saída. Como são dispositivos apenas de saída, não precisamos nos preocupar com nenhum dado recebido. No caso deles, o pino SS pode ser chamado de pino "armazenar" ou "trava".
Exemplos disso são o registrador de turno de série 74HC595 e várias faixas de LED, apenas para mencionar alguns. Por exemplo, este display LED de 64 pixels acionado por um chip MAX7219:
Nesse caso, você pode ver que o fabricante da placa usou nomes de sinal ligeiramente diferentes:
A maioria das placas segue um padrão semelhante. Às vezes, DIN é apenas DI (entrada de dados).
Aqui está outro exemplo, desta vez uma placa de LED de 7 segmentos (também baseada no chip MAX7219):
Isso usa exatamente os mesmos nomes de sinal que a outra placa. Nos dois casos, você pode ver que a placa precisa apenas de 5 fios, os três para SPI, além de potência e terra.
Fase e polaridade do relógio
Existem quatro maneiras de você experimentar o relógio SPI.
O protocolo SPI permite variações na polaridade dos pulsos do relógio. CPOL é a polaridade do relógio e CPHA é a fase do relógio.
Estes são ilustrados neste gráfico:
Você deve consultar a folha de dados do seu dispositivo para obter a fase e a polaridade corretas. Geralmente, haverá um diagrama que mostra como amostrar o relógio. Por exemplo, na folha de dados do chip 74HC595:
Como você pode ver, o relógio normalmente é baixo (CPOL = 0) e é amostrado na borda anterior (CPHA = 0), portanto, esse é o modo SPI 0.
Você pode alterar a polaridade do relógio e colocar o código da fase como este (escolha apenas um, é claro):
Este método foi descontinuado nas versões 1.6.0 em diante do IDE do Arduino. Para versões recentes, você altera o modo do relógio na
SPI.beginTransaction
chamada, assim:Ordem de dados
O padrão é o bit mais significativo primeiro, no entanto, você pode dizer ao hardware para processar o bit menos significativo primeiro assim:
Novamente, isso foi preterido nas versões 1.6.0 em diante do IDE do Arduino. Para versões recentes, você altera a ordem dos bits na
SPI.beginTransaction
chamada, assim:Rapidez
A configuração padrão para o SPI é usar a velocidade do clock do sistema dividida por quatro, ou seja, um pulso de clock do SPI a cada 250 ns, assumindo um clock da CPU de 16 MHz. Você pode alterar o divisor do relógio usando o
setClockDivider
seguinte:Onde "divisor" é um dos seguintes:
A taxa mais rápida é "dividir por 2" ou um pulso de clock SPI a cada 125 ns, assumindo um clock de CPU de 16 MHz. Portanto, isso levaria 8 * 125 ns ou 1 µs para transmitir um byte.
Este método foi descontinuado nas versões 1.6.0 em diante do IDE do Arduino. Para versões recentes, você altera a velocidade de transferência na
SPI.beginTransaction
chamada, assim:No entanto, os testes empíricos mostram que é necessário ter dois pulsos de clock entre os bytes, portanto a taxa máxima na qual os bytes podem atingir o tempo limite é de 1,125 µs cada (com um divisor de clock de 2).
Para resumir, cada byte pode ser enviado a uma taxa máxima de 1 por 1.125 µs (com um relógio de 16 MHz), fornecendo uma taxa de transferência máxima teórica de 1 / 1.125 µs ou 888.888 bytes por segundo (excluindo despesas gerais, como definir SS baixo e assim em).
Conectando ao Arduino
Arduino Uno
Conexão via pinos digitais 10 a 13:
Conectando através do cabeçalho ICSP:
Arduino Atmega2560
Conexão via pinos digitais 50 a 52:
Você também pode usar o cabeçalho ICSP, semelhante ao Uno acima.
Arduino Leonardo
O Leonardo e o Micro não expõem os pinos SPI nos pinos digitais, ao contrário do Uno e Mega. Sua única opção é usar os pinos do cabeçalho ICSP, conforme ilustrado acima para o Uno.
Escravos múltiplos
Um mestre pode se comunicar com vários escravos (no entanto, apenas um de cada vez). Isso é feito afirmando SS para um escravo e declarando-o para todos os outros. O escravo que o SS afirmou (geralmente significa LOW) configura seu pino MISO como uma saída para que o escravo, e esse escravo sozinho, possam responder ao mestre. Os outros escravos ignoram todos os pulsos de clock de entrada se SS não for afirmado. Portanto, você precisa de um sinal adicional para cada escravo, assim:
Neste gráfico, você pode ver que MISO, MOSI, SCK são compartilhados entre os dois escravos, mas cada escravo tem seu próprio sinal SS (seleção de escravo).
Protocolos
A especificação SPI não especifica protocolos como tal, portanto, cabe aos pares mestre / escravo individuais concordar com o que os dados significam. Embora você possa enviar e receber bytes simultaneamente, o byte recebido não pode ser uma resposta direta ao byte enviado (pois eles estão sendo montados simultaneamente).
Portanto, seria mais lógico para uma extremidade enviar uma solicitação (por exemplo, 4 pode significar "listar o diretório do disco") e depois fazer transferências (talvez apenas enviando zeros para fora) até receber uma resposta completa. A resposta pode terminar com uma nova linha ou caractere 0x00.
Leia a folha de dados do seu dispositivo escravo para ver quais seqüências de protocolos ele espera.
Como fazer um escravo SPI
O exemplo anterior mostra o Arduino como mestre, enviando dados para um dispositivo escravo. Este exemplo mostra como o Arduino pode ser um escravo.
Configuração de hardware
Conecte dois Arduino Unos juntamente com os seguintes pinos conectados um ao outro:
13 (SCK)
+ 5v (se necessário)
No Arduino Mega, os pinos são 50 (MISO), 51 (MOSI), 52 (SCK) e 53 (SS).
Em qualquer caso, o MOSI em uma extremidade está conectado ao MOSI na outra, você não os troca (ou seja, você não possui o MOSI <-> MISO). O software configura uma extremidade do MOSI (extremidade mestre) como uma saída e a outra extremidade (extremidade escrava) como uma entrada.
Exemplo mestre
Exemplo de escravo
O escravo é totalmente orientado a interrupções, portanto pode fazer outras coisas. Os dados SPI recebidos são coletados em um buffer e um sinalizador é definido quando um "byte significativo" (nesse caso, uma nova linha) chega. Isso diz ao escravo para continuar e começar a processar os dados.
Exemplo de conexão do mestre ao escravo usando SPI
Como obter uma resposta de um escravo
Seguindo o código acima, que envia dados de um mestre SPI para um escravo, o exemplo abaixo mostra o envio de dados a um escravo, fazendo com que ele faça algo com ele e retorne uma resposta.
O mestre é semelhante ao exemplo acima. No entanto, um ponto importante é que precisamos adicionar um pequeno atraso (algo como 20 microssegundos). Caso contrário, o escravo não tem chance de reagir aos dados recebidos e fazer algo com eles.
O exemplo mostra o envio de um "comando". Nesse caso, "a" (adicione algo) ou "s" (subtraia algo). Isso é para mostrar que o escravo está realmente fazendo algo com os dados.
Depois de afirmar a seleção do escravo (SS) para iniciar a transação, o mestre envia o comando, seguido por qualquer número de bytes e, em seguida, gera o SS para finalizar a transação.
Um ponto muito importante é que o escravo não pode responder a um byte recebido no mesmo momento. A resposta deve estar no próximo byte. Isso ocorre porque os bits que estão sendo enviados e os que estão sendo recebidos estão sendo enviados simultaneamente. Assim, para adicionar algo a quatro números, precisamos de cinco transferências, assim:
Primeiro, solicitamos ação no número 10. Mas não obtemos resposta até a próxima transferência (a de 17). No entanto, "a" será definido como a resposta como 10. Finalmente, acabamos enviando um número "fictício" 0, para obter a resposta para 42.
Mestre (exemplo)
O código para o escravo basicamente faz quase tudo na rotina de interrupção (chamada quando os dados SPI recebidos chegam). Ele pega o byte recebido e adiciona ou subtrai conforme o "byte de comando" lembrado. Observe que a resposta será "coletada" da próxima vez no loop. É por isso que o mestre precisa enviar uma transferência final "fictícia" para obter a resposta final.
No meu exemplo, estou usando o loop principal para simplesmente detectar quando o SS fica alto e limpar o comando salvo. Dessa forma, quando o SS é reduzido novamente para a próxima transação, o primeiro byte é considerado o byte de comando.
Mais confiável, isso seria feito com uma interrupção. Ou seja, você conectaria fisicamente o SS a uma das entradas de interrupção (por exemplo, no Uno, conectaria o pino 10 (SS) ao pino 2 (uma entrada de interrupção) ou usaria uma interrupção de troca de pino no pino 10.
A interrupção pode ser usada para perceber quando o SS está sendo puxado para baixo ou alto.
Escravo (exemplo)
Saída de exemplo
Saída do analisador lógico
Isso mostra o tempo entre o envio e o recebimento no código acima:
Nova funcionalidade no IDE 1.6.0 em diante
A versão 1.6.0 do IDE mudou a maneira como o SPI funciona, até certo ponto. Você ainda precisa fazer
SPI.begin()
antes de usar o SPI. Isso configura o hardware SPI. No entanto, agora, quando você está prestes a começar a se comunicar com um escravo, também fazSPI.beginTransaction()
para configurar o SPI (para este escravo) com o correto:Quando você terminar de se comunicar com o escravo, você liga
SPI.endTransaction()
. Por exemplo:Por que usar o SPI?
Esta é uma excelente pergunta. Minhas respostas são:
Ambos os métodos têm seu lugar. O I 2 C permite conectar muitos dispositivos a um único barramento (dois fios, mais terra), portanto, seria a escolha preferida se você precisasse interrogar um número substancial de dispositivos, talvez com pouca frequência. No entanto, a velocidade do SPI pode ser mais relevante para situações em que você precisa produzir rapidamente (por exemplo, uma faixa de LED) ou inserir rapidamente (por exemplo, um conversor ADC).
Referências
Minha página sobre o SPI - também possui detalhes sobre o SPI com interrupção de bits e o uso do USART para obter um segundo SPI de hardware no chip Atmega328.
Barramento de interface periférica serial - Wikipedia
Páginas de referência da biblioteca do Arduino SPI
Documentação SPI no PJRC
Protocolo SPI - Sparkfun
fonte
Are you going to cover the weirdness that is the Due's SPI?
- Não sei nada sobre o SPI do Due (além de presumir que o protocolo geral seja o mesmo). Você pode adicionar uma resposta que cubra esse aspecto.