All for Joomla All for Webmasters

Análise da comunicação I²C entre um Arduino e um sensor MPU-6050

Neste texto, analisaremos a comunicação I²C entre um sistema embarcado Arduino e o circuito integrado MPU-6050 da empresa InvenSense, que consiste em uma Unidade de Processamento de Movimento, sensor giroscópio e um acelerômetro, ambos de três eixos e um termômetro por meio de um analisador lógico com decodificador I²C para facilitar a validação dos dados. Conforme demais artigos referentes a outras aplicações com o MPU-6050, o firmware foi desenvolvido por meio do Visual Studio com a extensão Visual Micro.

Considerações gerais

O chip MPU-6050 consiste praticamente em um processador combinado com um sensor giroscópio, sensor acelerômetro e sensor de temperatura, além de conversores analógico para digital (ADC) de 16 bits. A programação do dispositivo é realizada por meio da escrita de registradores de configuração e a comunicação entre os dispositivos mestre/escravo é efetuada pelo protocolo de comunicação I²C com clock de 100kHz.

Nesta aplicação, faremos uma breve análise da comunicação serial I²C por meio de um analisador lógico com respectivo decodificador conectado nesse barramento, que consiste em duas linhas bidirecionais, sendo uma para dados (denominado sinal SDA - Serial Data) e outro para o clock gerado pelo dispositivo mestre (SCL - Serial Clock).

Início comunicação I²C

Por meio de um analisador lógico, configuramos o sinal de dados SDA na cor laranja e o CLK de clock na cor vermelha, e o sinal superior representando a decodificação do sinal de dados (exibida a seguir). Na imagem a seguir demonstramos que o estado padrão do barramento (sem transferência de dados) é ambos estarem em estado alto.

 estado inicial barramento

Ainda, de acordo com o protocolo I²C, a transmissão de dados entre o mestre e o escravo é iniciada com a transição do sinal SDA para nível baixo, mantendo-se o SCL em nível alto, conforme imagem à esquerda e a transferência dos bytes (8 bits) é encerrada com a transição do sinal SDA para o nível alto, mantendo-se o sinal SCL também em nível alto:

start sequence i2c    stop sequence i2c

Com exceção dos processos de Start e Stop, o sinal SDA (dados) não deve ser alterado durante os pulsos positivos do sinal de clock e as alterações de estado do sinal de dados ocorrerão tão somente no intervalo em que o sinal de clock estiver em baixo.

Ainda, a transmissão de cada byte (8 bits) é encerrada com um bit de reconhecimento (ACK) estabelecido pelo dispositivo escravo, sinalizando ao dispositivo mestre que o byte foi recebido com sucesso e que o mesmo está pronto para o recebimento de outro byte, conforme imagem abaixo. Caso o dispositivo escravo estabelecesse o sinal SDA em nível alto (bit de não-reconhecimento NACK), isso indicaria ao mestre que o mesmo não estaria pronto para recebimento de outro byte, forçando o mestre a encerrar a transmissão por meio da emissão de uma sequência de stop.

acknowledge bit

Configuração inicial do MPU-6050

Abaixo, apresentamos a primeira linha de código em C do firmware referente à configuração do sensor/processador MPU-6050 da Invensense, que consiste na configuração dos bits FS_SEL[3:4] do registrador localizado no endereço 0x1B, com o valor 0x18 referente ao valor 0x03 (esse valor é deslocado para a esquerda em três bits uma vez que os dois bits referentes à configuração FS_SEL estão localizados nos bits 3 e 4):

codigo write 1b 0x18 5ms

Por meio do analisador lógico, constatamos que de fato houve a escrita (último bit do byte de enedereço em nível baixo, o que representa uma operação de escrita/"write") no endereço I²C do MPU-6050 "0xD0" do registrador de endereço "0x1B" com o valor 0x18, sendo que a cada byte transferido, o dispositivo escravo emite um sinal ACK de reconhecimento, mantendo-se o sinal SDA em nível baixo e após a transmissão dos três bytes, ocorre o término da transmissão por meio de um sinal de parada:

pacote1 d0 write 1b 18

pacote1 d0 write 1b 18

Ainda, podemos visualizar na imagem abaixo a pausa de 5ms estabelecida pelo Arduino (mestre) por meio do comando delay (5ms), momento em que o clock do barramento também é interrompido:

interrupcao 5ms

A seguir temos também o código-fonte do firmware para configuração dos bits AFS_SEL[4:3] registrador localizado no endereço 0x1C com a constante 0x03 nesses bits:

codigo write 1c 0x18 5ms

codigo write 1c 0x18 5ms

O código-fonte acima resulta, conforme imagem abaixo, em um comando START, uma operação de escrita no dispositivo I²C com endereço 0xD0 (MPU-6050), bit de reconhecimento ACK, endereço do registrador 0x1C, bit de reconhecimento ACK, a constante 0x18 (0x03 deslocado à esquerda em três posições), outro bit de reconhecimento ACK e, por fim, o comando STOP:

pacote2 d0 write 1c 18

pacote2 d0 write 1c 18

Por fim, temos a configuração reset, sleep, desativação do sensor de temperatura e a fonte de clock por meio do registrador PWR_MGMT_1 do MPU-6050 localizado no endereço 0x6B. Ao estabelecermos todos os seus bits como zero, estabelecemos a fonte de clock como sinal interno de 8MHz, modo sleep desativado, sensor de temperatura ativado e retiramos o dispositivo do reset caso o mesmo esteja assim configurado:

codigo write 6b 0x00 5ms

Os bytes correspondentes são apresentados abaixo e correspondem à escrita no registrador de endereço 0x6B do dispositivo I²C de endereço 0xD0 com o valor 0x00:

pacote4 d0 write 6b 00

Transmissão I²C

No código-fonte do firmware, temos posteriormente o início da leitura dos registradores de dados do MPU-6050, que possui conversor A/D de 16 bits, demandando 2 bytes para armazenar cada valor amostrado (ACCEL_XOUT_H, ACCEL_XOUT_L, ACCEL_YOUT_H, ACCEL_YOUT_L, ACCEL_ZOUT_H, ACCEL_ZOUT_L, TEMP_OUT_H, TEMP_OUT_L, GYRO_XOUT_H, GYRO_XOUT_L, GYRO_YOUT_H, GYRO_YOUT_L, GYRO_ZOUT_H e GYRO_ZOUT_L):

codigo write 3b

codigo request read 14 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48

As primeiras quatro linhas de comando iniciam a comunicação com o dispositivo com uma operação de escrita, define o endereço inicial 0x3B, sinaliza que a comunicação não deve ser interrompida e define que a transmissão do escravo deve conter os 14 registradores seguintes (2 bytes para cada um dos sete registradores de dados).

pacote5 d0 write 3b d1 read

No primeiro pacote de dados, visualizamos que o valor 0x0000 é lido para cada um dos sete registradores:

leitura inicial 14 registradores

Mas, conforme a imagem a seguir, no próximo pacote de dados, devido à alta precisão do MPU-6050, mesmo em estado estacionário alguns valores pequenos são lidos (ACCEL_XOUT = 0xF130; ACCEL_YOUT = 0x006C; ACCEL_ZOUT = 0xBBC4; TEMP_OUT = 0xF570; GYRO_XOUT = 0xF85B; GYRO_YOUT = 0x133D e GYRO_ZOUT = 0xF0E8), sendo cada um representado pelo complemento de 2 (números negativos).

pacote11 d0 write 3b d1 read visao geral pacote

Uma vez que os sensores de aceleração foram configurados com escala de leitura igual a mais ou menos 16 g (m/s²), cada valor deve ser dividido por 2048 para obtenção do valor real, os valores do giroscópios divididos por 16,4 e o de temperatura por 340 e somado por 36,53 conforme o datasheet do MPU-6050.

Fazendo essas operações e lembrando-se que são números com sinal, obtemos os seguintes valores:

Registrador        Valor lido      Valor convertido
ACCEL_XOUT 0xFF87  -0,059g
ACCEL_YOUT  0xFF06 -0,122g
ACCEL_ZOUT  0xF752  -1,085g
TEMP_OUT  0xF770  30,083°C
GYRO_XOUT  0x0332  -49,88°/s
GYRO_YOUT  0x0012  1,09°/s
GYRO_ZOUT  0xFFF6  -0,61°/s

 

Temporização I²C

Em loop, esse pacote de bytes são enviados continuamente a cada 10,58ms, conforme imagem abaixo, tempo necessário para o Arduino remeter as informações ao PC por meio da porta serial e demais comandos:

distancia pacotes

Por fim, demonstramos que a largura dos pulsos de clock gerados pelo Arduino é de 5 us (100kHz) com distância entre os bytes de 10,5 a 17,167 us, conforme imagem abaixo:

temporizacao

Ressaltamos que o clock é gerado pelo dispositivo mestre e poderíamos obter uma frequência de 400kHz (frequência nominal do sinal SCL) alterando-se a constante TWI_FREQ para 400000L no arquivo twi.h da biblioteca Wire.h no código-fonte do firmware:

temporizacao 400khz

Conforme imagem abaixo, o clock também poderia ter sido elevado 1MHz, por exemplo:

temporizacao 1MHz

3 comentários

  • WILLIAN
    WILLIAN Sábado, 26 Janeiro 2019 20:58 Link do comentário

    Olá tenho uma dúvida estou querendo enviar os valores dos eixos x,y,z através do protocolo TCP IP , no ethernet shield, para o matlab, como posso realizar o filtro do pacote enviado? Qual a quantidade de byte por eixo?

  • Fabrício Reinert
    Fabrício Reinert Quinta, 10 Agosto 2017 15:12 Link do comentário

    Bom dia, como faço para converter os valores, como você fez para converte GYRO_YOUT = 0x0012 em 1,09°/s?

  • Luiz Anselmo Junior
    Luiz Anselmo Junior Terça, 27 Outubro 2015 19:41 Link do comentário

    Parabéns pela matéria.
    Sou hobista em eletrônica, e costumo fazer alguns projetos utilizando Pic Basic Pro Compiler.
    Estou tentando atualmente fazer a comunicação entre o sensor GY-521 (MPU6050) e um Pic 16f84A.
    A comunicação é feita via I2C. Acontece que não estou conseguindo fazer essa comunicação,
    não estou conseguindo ler os dados que vem do GY-521.Tenho pesquisado bastante na
    internet, mas não tenho encontrado nada ligado a pic basic referente a esse sensor, tem muita coisa dele
    ligada à Arduino. Vocês teriam algum exemplo em picbasic, de como ler os dados do sensor, bem como desativar o modo sleep ?
    Pretendo visualizar os dados do sensor num LCD serial que possuo.
    Obrigado pela atenção.

Deixe um comentário

Certifique-se de preencher os campos indicados com (*). Não é permitido código HTML.