Skip to content

Library for USI i2c slave mode in ATtiny compatible devices

License

Notifications You must be signed in to change notification settings

daguirrem/usi_i2c_slave

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

USI-I2C-Slave

Implementación del periferico USI de los ATtiny compatibles en modo I²C - Esclavo, Esta librería provee el funcionamiento básico del periférico, y un ejemplo de implementación.

Empezando

Para implementar la librería en su proyecto, se debe copiar los archivos /include/usi_i2c_slave.h y /src/usi_i2c_slave.c en la raíz del proyecto, y añadir la carpeta "include" en los directorios del compilador.

Prerequisitos

MPLAB X o Atmel Studio 7

AVR Toolchain o XC8 2.0 ++

MCU Compatible con USI de ATMEL

usi_i2c_slave.h

Configurar el modo I²C modificando los pines y puertos usados por el periférico USI en el respectivo MCU (ver datasheet)

#define SDAP  PIN0		/*#PIN correspondiente al SDA en el puerto*/
#define SCLP  PIN2		/*#PIN correspondiente al SCL en el puerto*/

#define I2CPN PINB		/*Registro PINx donde está el periférico I²C*/
#define I2CD  DDRB		/*Registro DDRx donde está el periférico I²C*/
#define I2CP  PORTB		/*Registro PORTx donde está el periférico I²C*/

y configurar el tamaño de registros internos (cantidad de direcciones) que va a manejar el modo esclavo

#define I2C_SLAVE_SZ_REG number_of_registers (Eg. 100)

Ejemplo de implementación

Ejemplo para ATtiny45

En el archivo principal se debe incluir el header con la función de inicialización

...
#include <usi_i2c_slave.h>
...
int main(void){
    ...
    i2c_slave_init(direction_of_slave);
    ...
    while(1){
    ...
    }

}

Si desea modificar registros del periferico:

...
#include <usi_i2c_slave.h>
...
int main(void){
...
    i2c_slave_init(direction_of_slave);
    ...
    //Usa un byte de los registros disponibles (IMPORTANTE **)
    i2c_slave_write_internalData(target_direction_in_registers, signed_or_unsigned_char_var,bit8);
    //Usa dos bytes de los registros disponibles (IMPORTANTE **)
    i2c_slave_write_internalData(target_direction_in_registers, signed_or_unsigned_int_var,bit16);
    //Usa cuatro bytes de los registros disponibles (IMPORTANTE **)
    i2c_slave_write_internalData(target_direction_in_registers, signed_or_unsigned_long_var,bit32);
    //Para guardar un flotante (Usa cuatro registros disponibles)
    i2c_slave_write_internalData_F(target_direction_in_registers, float_var);
    etc.
    ...
    while(1) {
        ...
    }
 }

**Los registros internos del esclavo están organizados de byte en byte por dirección:

    i2c_slave.registers: [0x00] (1 byte)
                         [0x01] (1 byte)
                         [... ] ...
                         [0x7F] (1 byte) (0x7F == 127 CONFIGURABLE)

                         donde: I2C_SLAVE_SZ_REG 128

Si se esribe una variable tipo DWORD (32bits) esta ocupará 4 bytes disponibles:

    -> i2c_slave_write_internalData(0x00,0xFFC90132,bit32);

    i2c_slave.registers: [0x00] 0xFF (1 byte)
                         [0x01] 0xC9 (1 byte)
                         [0x02] 0x01 (1 byte)
                         [0x03] 0x32 (1 byte)

Si desea leer constantemente registros (escritos por el maestro)

...
#include <usi_i2c_slave.h>
...
int main(void) {
    ...
    i2c_slave_init(direction_of_slave);
    ...
    long int signed_dword_var = 0;
    unsigned char unsigned_byte_var = 0;
    unsigned int unsigned_word_var = 0;

    while(1){
        signed_dword_var  = (long int) i2c_slave_read_internalData(direction_of_data_in_registers,bit32);
        unsigned_byte_var = (unsigned char) i2c_slave_read_internalData(direction_of_data_in_registers,bit8);
        unsigned_word_var = (unsigned int) i2c_slave_read_internalData(direction_of_data_in_registers,bit16);
    }

}

¿Cómo se envían los bytes leídos en mi I²C?

Ejemplo: El maestro desea leer un dword de los registros: 0x04, con el valor: 0xFFC90132 del esclavo con dirección: 0x1F

el paquete I²C se eviará de la siguiente manera:

    0011111| 0| 0| 00000100| 0|    0011111| 1| 0| 11111111| 0| 11001001| 0| 00000001| 0| 00110010| 1|
| S|   DIRE| W| A|     DIRR| A| RS    DIRE| R| A|     0xFF|A*|     0xC9|A*|     0x01|A*|     0x32|N*| ST|

El esclavo envía al maestro primero los bytes más significativos

¿Cómo se guardan los bytes escrios en mi I²C? (*Por un maestro)

Ejemplo: El maestro desea escribir un word en los registros: 0x01, con el valor: 0x51AC del esclavo con dirección: 0x1F

el paquete I²C se eviará de la siguiente manera:

    0011111| 0| 0| 00000001| 0| 10101100| 0| 01010001| 0|
| S|   DIRE| W| A|     DIRR| A|     0xAC| A|     0x51| A| ST|

El maestro debe enviar primero los bytes menos significativos

NOTA:

S = START
RS = REPEATED START
ST = STOP

DIRE = DIRECCIÓN ESCLAVO
DIRR = DIRECCIÓN REGISTRO

W = WRITE
R = READ

A = ACK
N = NACK
* = CONTROLADO POR EL MAESTRO (MASTER CONTROLLED)

Para mas información vea el archivo header: usi_i2c_slave.h

Para más información técnica vea el archivo: usi_i2c_slave.c

Autor

  • David Alejandro Aguirre Morales - daguirrem

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Buglist

  • 0x20_Bug: El dispositivo responde con un ack si se hace una petición con la dirección actual del esclavo y la siguiente de manera consecutiva (por ejemplo escaneando el BUS I²C), el bug aún no está arreglado, Thanks to favoritelotus for the report, más información en 0x20_Bug

Para tener en cuenta:

  • Velocidades máximas de comunicación probadas: -100KHz a 8MHz -200KHz a 16MHz
  • Esta librería hace uso de la interrupciones, por lo que las activa de manera global.