Introdução ao Bit Banging: comunicação SPI via Bit Banging

Tempo de leitura: 5 minutes

As interfaces de comunicação são um dos fatores que são considerados ao selecionar um microcontrolador a ser usado para um projeto. O projetista garante que o microcontrolador selecionado tenha todas as interfaces necessárias para se comunicar com todos os outros componentes a serem usados para o produto. A existência de algumas dessas interfaces, como SPI e I2C no microcontrolador, invariavelmente aumenta o custo desses microcontroladores e, dependendo do orçamento do BOM, pode tornar o microcontrolador desejado não acessível. Em situações como essas, técnicas como o Bit Banging entram em cena.

O que é o Bit Banging?

O bit banging é uma técnica de comunicação serial em que todo o processo de comunicação é feito por software em vez de hardware dedicado. Para transmitir dados, a técnica envolve o uso de software para codificar os dados em sinais e pulsos que são usados para manipular o estado de um pino de I/O de um microcontrolador que serve como pino Tx para enviar dados para o dispositivo alvo. Para receber dados, a técnica envolve amostrar o estado do pino Rx após certos intervalos que são determinados pela taxa de transmissão de comunicação. O software define todos os parâmetros necessários para alcançar essa comunicação, incluindo sincronização, temporização, níveis, etc., que geralmente são decididos por hardware dedicado quando o bit banging não é usado.

 

Quando usar o Bit Banging

O bit-banging é geralmente usado em situações em que um microcontrolador com a interface necessária não está disponível ou quando mudar para um microcontrolador com a interface necessária pode ser muito caro. Assim, ele fornece uma maneira barata de permitir que o mesmo dispositivo se comunique usando vários protocolos. Um microcontrolador previamente habilitado apenas para comunicação UART pode ser equipado para se comunicar usando SPI e 12C via bit banging.

 

Algoritmo para comunicação serial via bit banging

Embora o código para implementar o bit banging possa ser diferente em diversos microcontroladores e também possa variar para diferentes protocolos seriais, o procedimento / algoritmo para implementar o bit banging é o mesmo em todas as plataformas.

Para enviar dados, por exemplo, o pseudo-código abaixo é usado;

  • Começar
  • Enviar bit inicial
  • Aguarde até que o tempo corresponda à taxa de transmissão do receptor
  • Enviar bit de dados
  • Espere que a duração corresponda à taxa de transmissão do receptor novamente
  • Verifique se todos os bits de dados foram enviados. Se não, vá para 4. Se sim, vá para 7
  • Enviar bit de parada
  • Pare

O recebimento de dados tende a ser um pouco mais complexo, geralmente uma interrupção é usada para determinar quando os dados estão disponíveis no pino do receptor. Isso ajuda a garantir que o microcontrolador não desperdice muito poder de processamento. Embora certas implementações usem qualquer um dos pinos de E / S dos microcontroladores, as chances de ruído e erros, se provavelmente não forem tratados, são maiores. O algoritmo para receber dados usando interrupções é explicado a seguir.

  • Começar
  • Ativar interrupção no pino Rx
  • Quando a interrupção é acionada, obtenha o bit de início
  • Aguarde o tempo de acordo com a taxa de transmissão
  • Leia o pin Rx
  • Repita de 4 até que todos os dados tenham sido recebidos
  • Aguarde o tempo de acordo com a taxa de transmissão
  • Verifique se há stop bit
  • Pare

 

Bit Banging sobre SPI

Como mencionado acima, o bit banging para diferentes protocolos funcionam de maneira diferente e, portanto, é importante ler sobre cada protocolo, para entender o enquadramento de dados e a temporização antes de tentar implementar. Tomando o modo SPI 1 como exemplo, o valor base do relógio é sempre 0 e os dados são sempre enviados ou recebidos na transição positiva do relógio. O diagrama de tempo para o protocolo de comunicação do Modo 1 SPI é mostrado abaixo.

Para implementar isso, o seguinte algoritmo pode ser usado;

  • Começar
  • Defina o pino SS baixo para iniciar a comunicação
  • Defina o pino para Master Out Slave In (MOSI) para o primeiro bit dos dados a serem enviados
  • Defina o pino do relógio (SCK) alto para que os dados sejam transmitidos pelo mestre e recebidos pelo escravo
  • Leia o estado do Master in Slave Out (MISO) para receber o primeiro bit de dados do escravo
  • Defina SCK baixo, para que os dados possam ser enviados na próxima borda ascendente
  • Vá para 2 até que todos os bits de dados tenham sido transmitidos.
  • Defina o pino SS alto para interromper a transmissão.
  • Pare

 

Exemplo de Bit Banging: comunicação SPI no Arduino

Como exemplo, vamos implementar o algoritmo para comunicação SPI via bit banging no Arduino para mostrar como os dados podem ser bit-banging sobre SPI usando o código abaixo.

Começamos declarando os pinos do Arduino a serem usados.

const int SSPin = 11;
const int SCKPin = 10;
const int MISOPin = 9;
const int MOSIPin = 8;

byte sendData = 64;   // Valor a ser enviado
byte slaveData = 0;   // para armazenar o valor enviado pelo escravo

Em seguida, passamos para a função void setup() onde o estado dos pinos é declarado. Somente o pino de saída Master in Slave (MISO) é declarado como uma entrada, pois é o único pino que recebe dados. Todos os outros pinos são declarados como saída. Depois de declarar os modos de pino, o pino SS é definido como HIGH. A razão para isso é garantir que o processo esteja livre de erros e a comunicação só comece quando estiver definida como baixa.

void setup()
{
 pinMode(MISOPin, INPUT);
 pinMode(SSPin, OUTPUT);
 pinMode(SCKPin, OUTPUT);
 pinMode(MOSIPin, OUTPUT);
 digitalWrite(SSPin, HIGH);
}

Em seguida, iniciamos o loop para enviar dados. Observe que esse loop continuará enviando os dados repetidamente.

Começamos o loop escrevendo o pino SS baixo, para iniciar o início da comunicação, e chamamos a função bitbangdata que divide os dados predefinidos em bits e envia. Feito isso, escrevemos o pino SS HIGH para indicar o fim da transmissão de dados.

void loop()
{
  digitalWrite(SSPin, LOW);          // SS low
  slaveData = bitBangData(sendData); // transmissão de dados
  digitalWrite(SSPin, HIGH);         // SS alto de novo
}

A função bitbangdata() é escrita abaixo. A função recebe os dados a serem enviados e os divide em bits e os envia fazendo um loop sobre o código para a transmissão, conforme indicado na etapa 7 do algoritmo.

byte bitBangData(byte _send)  // Esta função transmite os dados via bitbanging
{
  byte _receive = 0;

  for(int i=0; i<8; i++)  // 8 bits em um byte
  {
    digitalWrite(MOSIPin, bitRead(_send, i));    // Definir MOSI
    digitalWrite(SCKPin, HIGH);                  // SCK alto
    bitWrite(_receive, i, digitalRead(MISOPin)); // Capture MISO
    digitalWrite(SCKPin, LOW);                   // SCK baixo
  } 
  return _receive;        // Retorna os dados recebidos
}

 

Desvantagens do Bit Banging

Adotar o bit banging deve, entretanto, ser uma decisão bem pensada, pois há várias desvantagens no bit banging que podem torná-lo não confiável para implementação em certas soluções. O bit banging aumenta a potência consumida pelo microcontrolador devido à alta potência de processamento consumida pelo processo. Comparado ao hardware dedicado, mais erros de comunicação, como falhas e jitters, ocorrem quando o bit banging é usado, especialmente quando a comunicação de dados está sendo realizada pelo microcontrolador ao mesmo tempo que outras tarefas. A comunicação via bit banging ocorre em uma fração da velocidade com a qual ocorre quando o hardware dedicado é usado. Isso pode ser importante em certas aplicações e pode fazer do bit banging uma escolha “não tão boa”.

O bit banging é usado para todos os tipos de comunicações seriais, incluindo; RS-232, comunicação serial assíncrona, UART, SPI e I2C.

 

UART via Bit banging no Arduino

Uma das implementações populares de bit banging é a biblioteca Arduino Software Serial, que permite que o Arduino se comunique pelo UART sem usar os pinos UART de hardware dedicados (D0 e D1). Isso oferece muita flexibilidade, pois os usuários podem conectar tantos dispositivos seriais quanto o número de pinos na placa Arduino pode suportar.