LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: Capeleiro em 03 de Março de 2012, 20:18

Título: Implementar I2C a partir de USI
Enviado por: Capeleiro em 03 de Março de 2012, 20:18
Agradecia a ajuda de alguém que já tenha usado o USI de um ATtiny861 ou ATtiny85, ou qualquer coisa parecida.

Acontece que, sem muitas dificuldades, consegui pôr um ATtiny85 a comunicar por I2C, usando uma biblioteca conhecida, baseada nas AppNotes que a ATMEL criou.

http://code.google.com/p/attiny45-workshop/source/browse/twi_slave/firmware/?r=d8d7fc391a5414bfa09a5fed2630a4baf587818e (http://code.google.com/p/attiny45-workshop/source/browse/twi_slave/firmware/?r=d8d7fc391a5414bfa09a5fed2630a4baf587818e)

O problema é que não consigo de forma nenhuma fazer os outros ATtinys funcionarem. A biblioteca é exactamente a mesma, mas quando ligo o IC ao bus todos os outros slaves deixam de receber qualquer coisa, fica tudo parado.

Usando uma "espécie de osciloscópio" dá para perceber que quando ligo estes AVRs ao bus as duas linhas ficam a 0V, é esse o problema, mas não percebo o que pode estar a causar.
Título: Re: Implementar I2C a partir de USI
Enviado por: senso em 03 de Março de 2012, 21:30
Estás a usar esses micros como slaves?
Título: Re: Implementar I2C a partir de USI
Enviado por: Capeleiro em 03 de Março de 2012, 21:33
Sim, estou.
Título: Re: Implementar I2C a partir de USI
Enviado por: senso em 03 de Março de 2012, 21:38
A app Note tem uns erros, á uma pessoa que corrigiu isso..
Vê este tópico todo, se não está lá o código corrigido está lá o link para a outro tópico com isso
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467 (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467)
Título: Re: Implementar I2C a partir de USI
Enviado por: Njay em 04 de Março de 2012, 00:45
Há de facto uns problemas com o código exemplo e também já esbarrei nisso. Na altura ainda fiz uma correcção e ficou a funcionar mas continuava a ter um problema no arranque. Depois descobri uma outra lib e roubei-lhe umas partes na inicialização e dei mais uns toques. Isto que aqui deixo funciona de certeza com ATtiny26 porque é onde o uso, num bus com 2 ATtiny26, 2 outros dispositivos e um SoC como master. Também já o usei num bus com os 2 ATtiny26 e uma "consola I2C" baseada em Arduino. Este código simula um dispositivo com 2 a 8 registos, em que uns podem ser read-only. O número de registos é definido pela macro I2C_REGISTER_FILE_SIZE (por omissão é 8, mas podes passar ao compilador uma flag de macro para o definir). Esboço de utilização:

// The registers we support. Can be read, some written, through I2C:
enum {
    eI2cReg_Command         = 0,    // R/W   command
    eI2cReg_Status          = 1,    //   R   status
    eI2cReg_Speed           = 2,    // R/W   speed
    eI2cReg_Acceleration    = 3,    // R/W   acceleration
    eI2cReg_Temperature     = 4,    //   R   temperature
    eI2cReg_MotorCurrent    = 5,    //   R   motor current
    eI2cReg_MotorVcc        = 6,    //   R   motor Vcc
    eI2cReg_SwRevision      = 7,    //   R   sw revision
};

byte volatile gI2C_RegFile[I2C_REGISTER_FILE_SIZE];

static void twi_init (void)
{
    byte  my_i2c_addr = PortRead(A, eI2CaddrSel)? 0x22 : 0x23;

    i2c_Set_Reg(eI2cReg_SwRevision, 0x02);      // 0 x <major> <minor>
    // By default all registers are read-only. Set the read-write ones here.
    i2c_Set_Reg_Access(eI2cReg_Command, eI2c_RW);
    i2c_Set_Reg_Access(eI2cReg_Speed, eI2c_RW);
    i2c_Set_Reg_Access(eI2cReg_Acceleration, eI2c_RW);

    i2c_Slave_Initialise(my_i2c_addr);
}

int __attribute__((noreturn)) main(void)
{
    // Init i2c slave interface (do it while interrupts are disabled)
    twi_init();
    ...
    // Enable interrupts
    sei();

    while(1)
    {
        // Handle I2C commands
        byte  chg_mask = i2c_Get_Changed_Mask();
        // If there are any changes in the I2C registers...
        if (chg_mask)
        {
            if (chg_mask & _BV(eI2cReg_Command))        // Command register changed
            {
                byte  cmdVal = 0;
                byte  cmd = i2c_Get_Reg(eI2cReg_Command);
            }
            else if (chg_mask & _BV(eI2cReg_Speed))        // Speed register changed
            {
                ...
            }
        }
        ...
    }
}


O array gI2C_RegFile é onde a lib I2C vai colocar os valores dos registos e tens que o declarar no teu código; quando um master escreve, os valores são lá alterados e a função i2c_Get_Changed_Mask() retorna uma bitmask em que cada bit corresponde a um registo e o bit vem a 1 para os registos que foram alterados. O que escreveres num registo é o que o master vai ler. Isto foi feito para simular que o AVR é um dispositivo I2C tipico com registos. O endereço I2C é decidido pelo estado dum pino, daí aquela 1ª linha da função de inicialização.

Nota1: A lib tem as macros LON e LOFF que escrevem para o pino PA7. Isto pode ser removido, eu tenho lá isto para fazer piscar um LED quando há actividade no I2C dirigida ao dispositivo (se o LED ficar constantemente aceso é porque alguém ficou a prender o bus).

Nota2: A escrita e leitura de registos faz "wrap-around".
Título: Re: Implementar I2C a partir de USI
Enviado por: Capeleiro em 04 de Março de 2012, 04:10
A app Note tem uns erros, á uma pessoa que corrigiu isso..
Vê este tópico todo, se não está lá o código corrigido está lá o link para a outro tópico com isso
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467 (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467)
Pois, eu tinha ouvido falar destes erros, o que estava a fazer arrancar os cabelos era estar a usar precisamente este código corrigido... Mas depois de ver o código outra vez percebi o meu erro estúpido...

E muito obrigado, Njay, funcionou lindamente e é uma solução muito interessante, vai facilitar na hora de enviar e receber valores de diferentes sensores.
Título: Re: Implementar I2C a partir de USI
Enviado por: Njay em 04 de Março de 2012, 10:53
Esqueci-me de avisar que a lib tem as macros LON e LOFF que escrevem para o pino PA7. Isto pode ser removido, eu tenho lá isto para fazer piscar um LED quando há actividade no I2C dirigida ao dispositivo (se o LED ficar constantemente aceso é porque alguém ficou a prender o bus).

A escrita e leitura de registos faz "wrap-around".