Análise da comunicação I²C entre um Arduino e um sensor MPU-6050
- Publicado em Eletrônica
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.
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:
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.
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):
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:
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:
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:
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:
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:
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:
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):
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).
No primeiro pacote de dados, visualizamos que o valor 0x0000 é lido para cada um dos sete 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).
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:
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:
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:
Conforme imagem abaixo, o clock também poderia ter sido elevado 1MHz, por exemplo:
Itens relacionados (por tag)
3 comentários
-
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 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 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.