sábado, 19 de novembro de 2011

I2C com Java TC65i e ATMEGA 48/88/168 - Parte II

Continuação do post anterior.

Neste post, irei dar sequencia na comunicação I2C do TC65i como master com o ATMEGA 48/88/168 como slave.

Confesso que sofri um bocado com a IDE da Atmel baseada no visual studio, a mesma não tem a flexibilidade e agilidade comparada ao Netbeans e ao Eclipse, fora os bugs encontrados nos registradores do microcontrolador selecionado, portanto paciência!
Porém um ponto forte foi a melhoria da versão 4 para 5 que facilitou muito. Outro problema foi encontrar informações relevantes em comunidades, então para diminuir este gap vou colocar o código completo.
A versão da IDE utilizada foi o AVR Studio 5 podendo ser encontrado no site da ATMEL.

Não esqueçam, visitem a Gridtech para projetos diversos nas tecnologias:

  • Linux embedded ARM/x86
  • GPRS: TC65 e Telite
  • Zigbee
  • Softwares web de FrontEnd para controle de diversos módulos de comunicação e concentradores de dados.


PARTE II - Codificação do ATMEL 48 ou 88 ou 168

Para controle da I2C no microcontrolador implementei a seguinte regra de negócio:


  1. TC65i envia o comando de escrita de comandos para o endereço do microcontrolador ( no meu caso 0xAE). 
  2. Apos enviado o comando TC65i espera 200 ms antes de enviar o comando de leitura do status de execução do comando anterior. Isto é necessário pois a I2C só possui um canal de comunicação controlada pelo master e garanto que o microcontrolador trate o comando e formate a resposta.
  3. TC65i envia o comando de leitura para ler um numero de bytes específicos de acordo com o implementado no seu protocolo. Para o meu caso, espero sempre um comando contendo 8 bytes.
Segue abaixo dois aquivos (I2c.h e I2c.c) para serem executados no AVR Studio.

NOTA:  Devido ao erro de html que o código na integra gerou no blogspot, peço que quem tiver interesse na I2C do atmega me envie um e-mail para a Gridtech que irei encaminhar o código.


I2C com Java TC65i e ATMEGA 48/88/168 - Parte I

Olá pessoal.  
Recentemente tive que realizar uma integração entre o TC65i e um microcontrolador ATMEGA48/88/168. Encontrei várias dificuldades tanto no TC65i e tanto no ATMEGA. Logo, decidi contribuir com 2 posts que relacionam a comunicação via I2C entre o TC65i(master) com o ATMEGA(slave).
Não esqueçam, visitem a Gridtech para projetos diversos nas tecnologias:

  • Linux embedded ARM/x86
  • GPRS: TC65 e Telite
  • Zigbee
  • Softwares web de FrontEnd para controle de diversos módulos de comunicação e concentradores de dados.


PARTE I - Codificação TC65i para utilizar a I2C como Master.

NOTA:  Antes de qualquer condificação no TC65i, notei que não é possível utilizar eventos de listener nas portas de entrada em conjunto com a I2C ou SPI do modem. Quando é utilizado o listener das entradas digitais uma exceção fatal no modem ocorre. Até o momento não consegui informações sobre o erro da Cinterion. Portanto caso necessite utilizar leituras dos IOs do modem, faça um thread que fica checando a mudança de estados das entradas em cada 100ms por exemplo.

CÓDIGO TC65I - MASTER

A classe abaixo é a camada Control da I2C onde podemos encontrar os métodos já definidos de abertura/fechamento da I2C e da Leitura/Escrita na I2C. Para acessar esta classe fica como sugestão uma Thread contendo o método abaixo para acesso mais simplificado da classe:
...

private byte[] executeComandoI2C(byte[] comando) {

        if (!I2CComm.getInstance().IS_CONNECTED) {
            I2CComm.getInstance().openI2C();
        }

        if (I2CComm.getInstance().IS_CONNECTED) {
            retry = recarregaRetry;

            while (retry-- != 0) {
                if (I2CComm.getInstance().writeData(0xAE, comando) == 0) {
                    long l = System.currentTimeMillis() + 200;
                    while (l <= System.currentTimeMillis()) {
                        semaphore(50);
                    }
                    byte[] dados = I2CComm.getInstance().readData(0xAF, 8);
                    if (dados != null) {

                        if (dados.length == 8 && dados[0] == 0x02 && dados[7] == 0x03) {
                            //System.out.println("RXI2C = " + Util.byteToHexString(dados));
                            //I2CComm.getInstance().closeI2C();

                            return dados;
                        } else {
                            System.out.println("ERRO: DADOS INVALIDOS -> RXI2C = " + Util.byteToHexString(dados));
                        }
                    }
                }
            }
            //I2CComm.getInstance().closeI2C();
            System.out.println("ERRO: uC nao respondeu ao comando I2C");
        }



        return null;
    }

...


Não estou abordando neste Post o conceito da API java para comunicação da I2C no modem TC65i. Para isso consulte o javadoc da classe "I2cBusConnection" da Cinterion.


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gw.io.i2c;

import com.siemens.icm.io.I2cBusConnection;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;

/**
 *
 * @author possebon
 */
public class I2CComm {

    private static I2CComm instance = null;

    public static I2CComm getInstance() {
        if (instance == null) {
            instance = new I2CComm();
        }
        return instance;
    }
    private I2cBusConnection cc = null;
    private InputStream inStream = null;
    private OutputStream outStream = null;
    public boolean IS_CONNECTED = false;
    private String baudrate = "400";
    private String writeDelay = "800";
    private String readDelay = "800";
    private StringBuffer sb = new StringBuffer();
    private char[] hexArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    public I2CComm() {
    }

    public I2CComm(String baudrate, String writeDelay, String readDelay) {
        this.baudrate = baudrate;
        this.writeDelay = writeDelay;
        this.readDelay = readDelay;
    }

    public synchronized boolean openI2C() {


        try {
//            cc = (I2cBusConnection) Connector.open("i2c:" + "0" + ";baudrate=" + "100" + ";writeDelay=400" + ";readDelay=400");//+ ";writeDelay=1000" + ";readDelay=1000");
            cc = (I2cBusConnection) Connector.open(
                    "i2c:" + "0"
                    + ";baudrate=" + baudrate
                    + ";writeDelay=" + writeDelay
                    + ";readDelay=" + readDelay);
            inStream = cc.openInputStream();
            outStream = cc.openOutputStream();

            IS_CONNECTED = true;
             System.out.println("Conexao I2C aberta");
        } catch (Exception ex) {
            ex.printStackTrace();
             System.out.println("Erro ao abrir comunicação pela I2C");

            IS_CONNECTED = false;
        }

        return IS_CONNECTED;

    }

    public synchronized boolean closeI2C() {

        if (inStream != null) {
            try {
                inStream.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            inStream = null;
        }

        if (outStream != null) {
            try {
                outStream.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            outStream = null;
        }

        if (cc != null) {
            try {
                cc.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            cc = null;
        }

        IS_CONNECTED = false;
        System.out.println("Conexao I2C fechada");
        return IS_CONNECTED;
    }

    public int writeData(int address, byte[] data) {

        if (!IS_CONNECTED) {
            openI2C();
        }
        String s = toHex(data);
        //      System.out.println(s);


        try {
            outStream.write(("<0" + toHex(address) + s + ">").getBytes());
            outStream.flush();
            long l = System.currentTimeMillis() + 2000;
            while (System.currentTimeMillis() <= l) {
                if (inStream.available() > 0) {
                    byte[] b = new byte[inStream.available()];

                    inStream.read(b);

                    //  System.out.println(">>"+new String(b));
                    char flag = (char) b[2];
                    //  System.out.println(">>"+flag);
                    if (flag == '+') {
                        return 0;
                    } else {
                        return -1;
                    }
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }




        return -1;
    }

    public byte[] readData(int address, int num) {
        byte[] buff = new byte[num];

        try {

            byte[] numb = new byte[2];

            numb[0] = (byte) (num >> 8);
            numb[1] = (byte) (num & 255);

            outStream.write(("<0" + toHex(address) + toHex(numb) + ">").getBytes());
            outStream.flush();
            long l = System.currentTimeMillis() + 2000;
            while (System.currentTimeMillis() <= l) {
                if (inStream.available() > 0) {
                    byte[] b = new byte[inStream.available()];

                    inStream.read(b);

                    //System.out.println(">>"+new String(b));
                    char flag = (char) b[2];
                    //System.out.println(">>"+flag);
                    if (flag == '+') {
                        String s = new String(b, 3, b.length - 3 - 1);
                        // System.out.println(s);

                        b = fromHex(b, 3, b.length - 3 - 1);
                        return (b);

                    } else {
                        return null;
                    }
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }



        return "error".getBytes();
    }

    private String toHex(byte[] b) {
        int h = 0, l = 0;
        sb.setLength(0);
        int len = b.length;
        for (int i = 0; i < len; i++) {
            l = 15 & b[i];
            h = 15 & (b[i] >> 4);
            sb.append(hexArr[h]);
            sb.append(hexArr[l]);
        }


        return sb.toString();


    }

    private byte[] fromHex(byte[] s, int offset, int length) {


        byte[] b = new byte[length >> 1]; //rychle deleni 2
        int tmp = 0;
        length = offset + length;
        for (int i = offset, j = 0; i < length; i += 2, j++) {


            if (s[i] <= '9') {
                tmp = s[i] - '0';
            } else {
                tmp = (s[i] - 'A') + 10;
            }
            tmp = tmp << 4;
            if (s[i + 1] <= '9') {
                tmp += s[i + 1] - '0';
            } else {
                tmp += (s[i + 1] - 'A') + 10;
            }


            b[j] = (byte) tmp;


        }

        return b;
    }

    private String toHex(int i) {
        int h = 0, l = 0;
        sb.setLength(0);
        l = 15 & i;
        h = 15 & (i >> 4);
        sb.append(hexArr[h]);
        sb.append(hexArr[l]);
        return sb.toString();

    }
}