LusoRobótica - Robótica em Português

Robótica => Iniciantes => Tópico iniciado por: marlon.tiedt em 04 de Dezembro de 2014, 01:37

Título: Comunicação I2C com Arduino
Enviado por: marlon.tiedt em 04 de Dezembro de 2014, 01:37
Pessoal estou estudando a comunicação I2C pelo Arduino. Estou querendo fazer a comunicação com o shield MPU-6050 e estou seguindo este tutorial http://playground.arduino.cc/Main/MPU-6050 (http://playground.arduino.cc/Main/MPU-6050) para entender a comunicação I2C.

As coisas que já entendi, é que todo componente com I2C tem o seu próprio endereço e os seus próprios registradores.

Neste exemplo tem estas linhas de código:

Código: [Seleccione]
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);/

O código
Código: [Seleccione]
Wire.write(0x6B); indica que quero acessar o endereço 0x6B? Se sim, como o controlador sabe que o próximo byte é valor que vai ser escrito? Ou o I2C por padrão é assim, mando o endereço o componente, um registrador e depois o valor.

Como sei se é escrita ou leitura?

Outra coisa, se eu tiver um segundo parâmetro em seguida tenho que mandar o endereço e depois o valor, ou posso mandar o valor direto? Se o valor para setar for igual a 0x6B, como ele vai entender que é um valor e não para ir no endereço?

Se eu tiver no minha rede I2C um parâmetro igual a um endereço, como os slaves se comportam?

Neste código
Código: [Seleccione]
Wire.beginTransmission(address);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(address, 6);


o requestFrom(address, 6); pede 6 próximos bytes a partir do 1 endereço?


Tentei colocar todas as dúvidas direto para não ficar perguntando por partes.
[/code]
Título: Re: Comunicação I2C com Arduino
Enviado por: Njay em 04 de Dezembro de 2014, 02:08
Bom, assim por alto:

O bus I2C em si apenas define como se faz a communicação (transmissão de dados) entre dispositivos; o que cada dispositivo faz com esses dados "é lá com ele", ou seja, está escrito na sua datasheet.

Na verdade o I2C destingue entre dispositivos mestre e dispositivos escravo, ou seja, há 2 tipos de dispositivo, sendo que apenas os do tipo mestre podem iniciar uma leitura ou escrita de dados de um dispositivo escravo (se 2 mestres pretenderem comunicar, um deles tem que se transformar em escravo temporariamente). O mestre é quem sempre controla a linha de clock (SCL), que regula o ritmo de transmissão de dados (os dados viajam na linha de dados, SDA). Quando falamos em "escrever" e "ler", é do ponto de vista do mestre, o mestre escreve ou lê dados do escravo.

Uma consequência da forma como o bus funciona é que um escravo não tem maneira de iniciar uma transmissão de dados para o mestre (excepto se se tornar num mestre!); se ele quiser enviar algo ao mestre, tem que o avisar de outra maneira (por exemplo por uma linha dedicada de "interrupção") e então o mestre é que faz a leitura dos dados do escravo.

O mestre tipicamente é um microcontrolador/processador e o escravo é um periférico/memória/sensor/etc.

O bus funciona por transmissão de "mensagens". Uma mensagem transporta um conjunto de bytes entre 2 dispositivos (sempre 1 mestre e 1 escravo), e começa com um "sinal especial" (ao nível eléctrico, chamado START CONDITION) que marca o inicio e outro sinal especial que marca o fim (STOP CONDITION). Existe ainda um bit especial de confirmação de recepção (acknowlege, ACK) depois de cada byte transmitido (quem recebe o byte confirma a recepção a quem o enviou), e uma forma de controlo de fluxo, em que o escravo pode dizer ao mestre "ei, espera aí um bocadinho, tás a falar/pedir muito depressa!", o chamado CLOCK STRETCHING (consiste no escravo "segurar" a linha de clock (SCL) a zero durante o bit de ACK, impedindo o mestre de transmitir clocks).

O 1º byte de cada mensagem é uma escrita (o mestre escreve para o escravo) que indica o endereço do escravo (7 bits) e se a operação é de leitura ou de escrita (1 bit); depois o mestre escreve ou lê dados conforme o tipo de operação escolhida no 1º byte.

Entendendo "por alto" como funciona o bus, tens que consultar a datasheet do dispositivo mestre e a do dispositivo escravo para saberes:

1) do lado do mestre, como endereçar um escravo e como efectuar escritas e leituras (no teu caso, tens a documentação da API do arduino do site do arduino)

2) do lado do escravo, que mensagens ele está preparado para receber/enviar e qual a sua composição (no caso, na datasheet desse MPU6050 (não sei o que é, não fui ver))
Título: Re: Comunicação I2C com Arduino
Enviado por: fergas em 04 de Dezembro de 2014, 08:55


Código: [Seleccione]

Wire.beginTransmission(MPU);



Aqui MPU deverá ser uma variável que tem o endereço do dispositivo com o qual o arduino vai comunicar.
A instrução Wire.write(x) envia valores para o dispositivo. Wire.write(0x6B) vai mandar o valor 0x68 para o dispositivo selecionado em Wire.beginTransmission(endereço); que já estará espera dele ou até de mais valores se fôr o caso.
Já a instrução Wire.requestFrom(address, x); indica ao dispositivo que tem o endereço "address" para enviar ao arduino x bytes, que serão colectados com as funções available() e read() .
Consulta a página do site do arduino que explica bem estas funções.
Título: Re: Comunicação I2C com Arduino
Enviado por: marlon.tiedt em 04 de Dezembro de 2014, 09:54
Valeu pelas dicas. Se eu fazer o código abaixo, vai escrever 0 no endereço 0x00 e 2 no endereço 0x01 ou vai escrever 0 no endereço 0x00 e depois 2 no mesmo endereço.

Código: [Seleccione]
Wire.write(0x00);
Wire.write(0);
Wire.write(2);

Ou tenho que fazer isto, para escrever nos dois endereços:

Código: [Seleccione]
Wire.write(0x00);
Wire.write(0);
Wire.endTransmission();
Wire.write(0x01);
Wire.write(2);
Wire.endTransmission();
Título: Re: Comunicação I2C com Arduino
Enviado por: Kristey em 04 de Dezembro de 2014, 11:00
Boa explicação Njay
Título: Re: Comunicação I2C com Arduino
Enviado por: jm_araujo em 04 de Dezembro de 2014, 11:07
Valeu pelas dicas. Se eu fazer o código abaixo, vai escrever 0 no endereço 0x00 e 2 no endereço 0x01 ou vai escrever 0 no endereço 0x00 e depois 2 no mesmo endereço.

Código: [Seleccione]
Wire.write(0x00);
Wire.write(0);
Wire.write(2);

Ou tenho que fazer isto, para escrever nos dois endereços:

Código: [Seleccione]
Wire.write(0x00);
Wire.write(0);
Wire.endTransmission();
Wire.write(0x01);
Wire.write(2);
Wire.endTransmission();


RTFM!
Os engenheiros perdem tanto tempo a escrever datasheets e depois ninguém lhes liga nenhum :(

Tens a resposta nas páginas 35 e 36 da datasheet do MPU 6050 : http://www.invensense.com/mems/gyro/documents/PS-MPU-6000A-00v3.4.pdf (http://www.invensense.com/mems/gyro/documents/PS-MPU-6000A-00v3.4.pdf)



Título: Re: Comunicação I2C com Arduino
Enviado por: marlon.tiedt em 04 de Dezembro de 2014, 11:49
Obrigado pela resposta jm_araujo.
Mas a minha dúvida é, o I2C se comporta assim ou depende do CI?

Título: Re: Comunicação I2C com Arduino
Enviado por: jm_araujo em 04 de Dezembro de 2014, 12:08
Tens sempre de ler as datasheets (é para isso que elas servem), cada IC implementa as partes que lhes interessa, e há alguns com umas manias bem estranhas: Recordo-me de memórias que se fizeres leituras(ou eram escritas?) sequenciais não mudavam de página de ?256bytes?, ficavam sempre na mesma, para alterar tinha-se de iniciar nova leitura.

Como já foi muito bem dito:
O bus I2C em si apenas define como se faz a communicação (transmissão de dados) entre dispositivos; o que cada dispositivo faz com esses dados "é lá com ele", ou seja, está escrito na sua datasheet.
Título: Re: Comunicação I2C com Arduino
Enviado por: senso em 04 de Dezembro de 2014, 12:42
Só escreve num endereço novo se fizer incrementação automática do endereço, mas tambem pode estar á espera de receber um valor de 16bits, ou 24, ou 32, ou mais bits para um só endereço e terás de fazer várias escritas para o mesmo endereço.

Se não queres ler, sacas uma biblioteca para esse chip, escreves chip.begin e chip.read e está feito, continuas é sem entender como é que funciona, mas mesmo a biblioteca i2c do arduino não é das melhores, esconde algumas coisas(ack's e nak's, o bit read/write do endereço, entre outros).
Título: Re: Comunicação I2C com Arduino
Enviado por: marlon.tiedt em 04 de Dezembro de 2014, 13:10
Só escreve num endereço novo se fizer incrementação automática do endereço, mas tambem pode estar á espera de receber um valor de 16bits, ou 24, ou 32, ou mais bits para um só endereço e terás de fazer várias escritas para o mesmo endereço.

Se não queres ler, sacas uma biblioteca para esse chip, escreves chip.begin e chip.read e está feito, continuas é sem entender como é que funciona, mas mesmo a biblioteca i2c do arduino não é das melhores, esconde algumas coisas(ack's e nak's, o bit read/write do endereço, entre outros).

Por isto estou tentando entender o padrão. Pois o Wire do Arduino esconde muita coisa mesmo. E vários post da internet, muitos são parecidos.
Título: Re: Comunicação I2C com Arduino
Enviado por: dropes em 04 de Dezembro de 2014, 14:17
Não há nada melhor do que ler um pdf de uma memória da Philips para entender o protocolo I2C.
Entretanto já consigo ler e escrever neste tipo de ICs como nos RTCs, sensores, etc..., através da porta paralela do pc ou de um microcontrolador programado em assembler.

http://www.nxp.com/documents/data_sheet/PCF8582C_2.pdf (http://www.nxp.com/documents/data_sheet/PCF8582C_2.pdf)
Título: Re: Comunicação I2C com Arduino
Enviado por: senso em 04 de Dezembro de 2014, 14:44
Podemos sempre ler o que uma das pessoas que criou o protocolo tem a dizer sobre o mesmo:
http://www.siliconvalleygarage.com/i2cfaq/i2cfaq_000_index.htm (http://www.siliconvalleygarage.com/i2cfaq/i2cfaq_000_index.htm)

Tambem conhecido como free_electron no eevblog.
Título: Re: Comunicação I2C com Arduino
Enviado por: Njay em 04 de Dezembro de 2014, 18:56
Uma das pessoas que criou o protocolo? Com o que ele diz na FAQ, não me parece:

Citar
Who put this FAQ together?
I put this FAQ together in response to my own frustration in searching for information about I2C. (...)

O I2C parece catita no papel, mas quando vamos realmente usar a coisa, as implementações de chips (principalmente mestres) por esse mundo fora estão "cheias" de bugs, dos AVR ao RaspberryPI*. Já tive que lidar com I2C em pelo menos 3 ou 4 projectos profissionais mais 1 pessoal e em absolutamente *todos* encontrei problemas com bugs do hardware e implementações de sw, que especialmente se traduzem em problemas que ocorrem esporádicamente (portanto, mesmo dos bons; uma vez passei uma bela noite no laboratório, eu, um analizador lógico e uma placa com um bus I2C). E foram só sistemas de 1 mestre, nem quero imaginar sistemas multi-mestre. Os locks de bus são os mais giros, quando há 3 ou mais dispositivos pendurados no bus; em geral é difícil ou quase impossível descobrir quem é que está a prender o bus**. A verdade é que a implementação do I2C é complexa, não passa pela cabeça de ninguém a quantidade de estados e casos possíveis que isto tem, para ser bem implementado. Admito que é um bus só uso se for "obrigado", eventualmente posso usar para aceder só a uma EEPROM ou chip simples mas mesmo assim... cuidado na escolha do hw mestre.


*O (SoC do) RaspberryPi tem um bug no clock stretching; em certas condições simplesmente ignora o pedido de stretching do escravo, resultando em locks temporários do bus e corrupção de mensagens. Sim, também já fui "mordido" por este.

**Uma dica: num sistema complexo, deixem no PCB maneira de poder desligar qualquer um dos dispositivos escravo do bus, ponham 2 jumpers/resistências de 0 Ohm em série com as linhas à entrada do dispositivo. Desta forma podem isolar o dispositivo do bus se tiverem problemas.
Título: Re: Comunicação I2C com Arduino
Enviado por: KammutierSpule em 04 de Dezembro de 2014, 20:06
Felizmente nunca tive que usar I2C :) Mas tenho encontrado testemunhos com o Njay dos problemas daquilo. Acho estranho principalmente porque ja devia ser um protocolo "maduro".
Tenho a impressão que a maior parte das erratas relacionadas com I2C, sao devido a novas expansões (plus plus plus...) ao protocolo original.
'E quando as leio que penso para mim "espero nunca vir a precisar disto!"  ???
Título: Re: Comunicação I2C com Arduino
Enviado por: senso em 04 de Dezembro de 2014, 20:52
Provavelmente estou a confundir com outro nome, sorry.

Até me sinto melhor ao saber que não é só comigo que sempre que há alguma coisa a falar i2c que há sempre algum problema inesperado, a ultima guerra foi com um PCA9685.

Título: Re: Comunicação I2C com Arduino
Enviado por: marlon.tiedt em 04 de Dezembro de 2014, 21:05
Como nunca mexi com I2C, estas informações são muito valiosas.

Estou querendo mexer com acelerômetros e giroscópios, e encontrei o MPU-6050. Mas o que me desanimou foi o I2C. Já vi acelerômetros com saidas digitais, que eu acho mais tranquilo de trabalhar, pois cada elemento tem uma saída analógica.

Porém não achei nenhum giroscópio com saída analógica, será que existe? E claro, outros componentes como magnétron e medidor de pressão e altitude, tudo usa I2C.

E minha singela opinião, ler 3 saídas analógicas é mais rápido do que ler 6 bytes.



 
Título: Re: Comunicação I2C com Arduino
Enviado por: senso em 04 de Dezembro de 2014, 21:09
Se for com um Arduino não, porque a ADC corre a pouco mais de 10Khz, e depois introduzes ruidos, problemas a desenhar filtros analógicos, bla bla bla.

Esses sensores são muito, muito usados, tens milhentas bibliotecas, quem não conhece, aqui fica uma boa base de dados de código comprovado e testado:
http://www.i2cdevlib.com/ (http://www.i2cdevlib.com/)
Título: Re: Comunicação I2C com Arduino
Enviado por: Njay em 07 de Dezembro de 2014, 15:37
Não senso, não é só de ti que o I2C não gosta :)

Não Kamm., não tem nada a ver com extensões ao I2C, são simplesmente bugs de implementação da funcionalidade básica.
Título: Re: Comunicação I2C com Arduino
Enviado por: senso em 07 de Dezembro de 2014, 15:42
A ultima coisa estranha foi mesmo o PCA ser um Plus(ou plus + ou lá o nome do i2c rápido esta semana) que devia funcionar a 1Mhz, mas acima de 400Khz e passa-se quando tento mudar o prescaler do clock, o sinal tem uma forma bonita, tem os devidos pull-ups e pistas curtas, mas nem me preocupei muito com aquilo, a 400Khz funciona rápido o suficiente.
Título: Re: Comunicação I2C com Arduino
Enviado por: Njay em 07 de Dezembro de 2014, 16:17
Na DiffTrike (http://myownhybrid.wordpress.com/) temos um RasPI ligado a 2 isoladores galvânicos I2C que ligam a 2 AVR (que controlam as pontes-H de potência), por um cabo "em Y" que terá cerca de 50cm entre o PI e cada AVR, e I2C a bombar a 500 kbps (a 3V3). Temos uma "checksum", mas nunca vimos nenhum erro. Agora bomba, mas não sem antes termos partido a cabeça com o bug no I2C do PI.

O isolador I2C foi crucial para detectar o bug do PI, porque pela forma como funcionam estes isoladores; o sinal "low" tem uma tensão ligeiramente diferente para o mestre e para o escravo, o que permitiu perceber quem é que estava a fazer o quê.

O cabo não foi escolhido à toa, é um cabo de rede, que escolhi por causa de ter vários pares entrançados; cada sinal (SDA, SCL) tem o seu próprio par, em que o GND é ligado nas 2 pontas. Por ser entrançado reduz a inductância do cabo (e logo distorções, emissões de EMI e susceptiilidade a EMI) e o crosstalk (por serem pares separados e viajarem com o seu próprio GND). A alimentação para o isolador I2C também viaja pelo cabo, no seu próprio par entrançado o que também ajuda a reduzir a inductância e logo problemas de alimentação (quando se tenta puchar corrente muito depressa através duma inductância, ela opõe-se fazendo baixar a tensão, e vice-versa).