empezando con el I2C sdcc

Ir abajo

empezando con el I2C sdcc

Mensaje por tony8a87 el Jue 15 Sep 2011 - 3:41

Hola de vuelta al foro, estoy interesado en realizar algunas aplicaciones con el protocolo I2C para lectura de memorias eeprom, sensores con ese protocolo, etc. Encontre una libreria que realizó Felixls que me pareció bastante buena. Pero para ser sinceros no se como ocupar este código al 100%.
Código:

#include <pic/pic16f877a.h>
#define SDA RC4
#define SCL RC3
#define TSDA TRISC4
#define TSCL TRISC3
void i2c_delay(void)
{
   delay_us(133);
}
void SDALow()
{
   TSDA = 0;
   SDA = 0;  
}
void SDAHigh()
{
   TSDA = 1;
}
void SCLLow()
{
   TSCL = 0;
   SCL = 0;
}
void SCLHigh()
{
   TSCL = 1;
   while(SCL==0);
}
void i2c_clock(void)
{
        i2c_delay();
        SCLHigh();             /* Start clock */
        i2c_delay();    
        SCLLow();                     /* Clear SCL */
        i2c_delay();    
}
void i2c_start(void)
{
        if(SCL)
        SCLLow();                  /* Clear SCL */
        SDAHigh();        /* Set SDA */
        SCLHigh();                /* Set SCL */
        i2c_delay();
        SDALow();        /* Clear SDA */
        i2c_delay();
        SCLLow();        /* Clear SCL */
        i2c_delay();
}
void i2c_stop(void)
{
        if(SCL)
        SCLLow();                      /* Clear SCL */
        SDALow();                      /* Clear SDA */
        SCLHigh();                      /* Set SCL */
        i2c_delay();
        SDAHigh();                      /* Set SDA */
        i2c_delay();
}
unsigned char i2c_write(unsigned char dat)
{
        unsigned char data_bit;       
        unsigned char i;       
        for(i=0;i<8;i++)                /* For loop 8 time(send data 1 byte) */
        {
                data_bit = dat & 0x80;  /* Filter MSB bit keep to data_bit */
    if (data_bit==0)
      SDALow();            /* Send data_bit to SDA */
    else
      SDAHigh();   
          dat = dat<<1;  
         SCLHigh();
         i2c_delay(); 
         SCLLow();
         i2c_delay(); 
        }
        SDAHigh();
        SCLHigh();
        i2c_delay();   
        data_bit = SDA;        /* Check acknowledge */
        SCLLow();                      /* Clear SCL */
        i2c_delay();
        return data_bit;         /* If send_bit = 0 i2c is valid */                   
}
unsigned char i2c_read(void)
{
        unsigned char i, dat;
        dat = 0x00;   
  SDAHigh();
        for(i=0;i<8;i++)                /* For loop read data 1 byte */
        {
                SCLHigh();                      /* Set SCL */
                dat = dat<<1;         
                if (SDA)
                    dat = dat | 0x01; // if port pin = 1, set LSB (bit position)
                else
                    dat = dat & 0xFE; // else port pin = ,clear LSB (bit position)
  SCLLow();
        i2c_delay(); 
        }
        return dat;
}
void i2c_ack()
{
        SDALow();              /* Clear SDA */
        i2c_delay();    
        i2c_clock();    /* Call for send data to i2c bus */
}
void i2c_noack()
{
        SDAHigh();              /* Set SDA */
        i2c_delay();
        i2c_clock();    /* Call for send data to i2c bus */
}

Tengo dudas de como realizar la escritura y lectura a las memorias, en este caso tengo una 24LC22A de 2Kbits y un 24LC1025 de 1024Kbits.

Me gustaria saber como puedo guardar más de un solo dato en el programa principal. Este código más o menos me orienta pero no se con exactitud como implementarlo.
Código:

                                        http://memoria24xx256.c
unsigned char EEPROM_get(unsigned int addr)
{
        unsigned char dat;     
        i2c_start();            /* Start i2c bus */
        i2c_write(EEPROMS_ID); /* Connect to EEPROM */
        i2c_write(addr&0xF0); /* Request RAM address (Hight byte) */
        i2c_write(addr&0x0F); /* Request RAM address (Low byte) */
        i2c_start();            /* Start i2c bus */
        i2c_write(EEPROMS_ID+1);/* Connect to EEPROM for Read */
        dat = i2c_read();              /* Receive data */
        i2c_noack();
        i2c_stop();                            /* Stop i2c bus */
   return dat;                 
}
void EEPROM_set(unsigned int addr, unsigned char val)
{
        i2c_start();
        i2c_write(EEPROMS_ID);/* Connect to EEPROM */
        i2c_write(addr&0xF0); /* Request RAM address (Hight byte) */
        i2c_write(addr&0x0F); /* Request RAM address (Low byte) */
        i2c_write(val);  /* Write sec on RAM specified address */
        i2c_stop();            /* Stop i2c bus */
}
La addr en mi programa principal con que valor empieza y donde termina??
alguien me puede explicar esto:
addr&0xF0
addr&0x0F
Saludos cordiales!!!
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Pikitin el Jue 15 Sep 2011 - 17:01

La addr en mi programa principal con que valor empieza y donde termina??

Empieza en 0 y termina según lo grande que sea la memoria, por ejemplo una memoria de 2k:

Decimal:0000 a 2048

Hexadecimal: 0x008 a 0x800

Binario: 000000000000 a 100000000000

(el conversor de base me ha sido util Smile )


alguien me puede explicar esto:
addr&0xF0
addr&0x0F
Aquí hay algo que no me cuadra, addr se supone que es un Int de 16 bits y debería de ser:

addr&0xFF00 ( y coger sólo byte alto )
addr&0x00FF

O no lo he entendido...

En cualquier caso:
addr&0xF0 pone a 0 los 4 bits bajos de addr
addr&0xF0 pone a 0 los 4 bits altos de addr

Por ejemplo si addr = 01101100
addr&0xF0
ahora addr = 01100000



Saludos.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Jue 29 Sep 2011 - 1:32

Holo aun no he podido simular a la perfeción y creo que existe un problema en esta parte del codigo

Código:

unsigned char i2c_write(unsigned char dat)
{
        unsigned char data_bit;       
        unsigned char i;       
        for(i=0;i<8;i++)  /* For loop 8 time(send data 1 byte) */
        {
                data_bit = dat & 0x80;  /* Filter MSB bit keep to data_bit */
    if (data_bit==0)
      SDALow();            /* Send data_bit to SDA */
    else
      SDAHigh();   
          dat = dat<<1; 
          SCLHigh();
          i2c_delay(); 
          SCLLow();
          i2c_delay(); 
        }
        SDAHigh();
        SCLHigh();
        i2c_delay();   
        data_bit = SDA;        /* Check acknowledge */
        SCLLow();                      /* Clear SCL */
        i2c_delay();
        return data_bit;    /* If send_bit = 0 i2c is valid */
}

Porque se recorre un bit, adjunte una imagen. Para ejemplificar envio en la dirección 0xF1=1111 0001 pero solo alcanza a enviar 0x78=0111 1000 el ultimo bit lo coloca en Nack y el bit que le corresponde a Nack lo coloca en otra palabra más.

Imagen:
mediafire.com i/?6eff15nw6wp6d75

Espero contar con su ayuda para arreglar esto.

Saludos cordiales!!!
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Sáb 1 Oct 2011 - 1:43

Hola no encontre solución con el anterior código, por lo cual segui buscando y viendo otros ejemplos con el uso de Master Synchronous Serial Port (MSSP) Module. La cual ya puedo leer y escribir en mi 24LC22A. Los códigos fueron obtenidos de los ejemplos de iearobotics.
Código:
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f877a.h>
#include <delay.h>
/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word at 0x2007 CONFIG = _XT_OSC & _WDT_ON & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF;
void i2c_SendAck();
void i2c_SendNack();
unsigned char i2c_CheckACK();
void i2c_SendStop();
void i2c_SendStart();
void i2c_WaitMSSP();
unsigned char i2c_MSSP_Status();
void i2c_SendRStart();
unsigned char i2c_ReadByte();
void i2c_SendByte(unsigned char dato);
void i2c_fail();
void i2c_configure();
unsigned char i2c_write_byte(unsigned char control_byte, unsigned char address, unsigned char dato);
unsigned char i2c_read_byte(unsigned char control_byte, unsigned char address, unsigned char *dato);
void main() {
unsigned char ret;
unsigned char dato;
PORTB=0;
TRISB=0;
while(1){
  //-- Configurar el I2C como master
    delay_ms(100);
    i2c_configure();
    delay_ms(10);
    i2c_write_byte(0xA0, 0x7F, 0x0F);
    delay_ms(10);
        ret=i2c_read_byte(0xA0, 0x7F, &dato);
        if (ret==1) {
              PORTB = dato;
        delay_ms(500);}
    }
}
/****************************************
*    FUNCIONES DE BAJO NIVEL DEL I2C  *
****************************************/
// Envia Ack
// SDA = 0
void i2c_SendAck(){
  ACKDT = 0;  // Establece un ACK
  ACKEN = 1;  // Lo envia
}
// Envia Nack para finalizar la recepecion
// SDA = 1
void i2c_SendNack(){
  ACKDT = 1;  // Establece un NACK
  ACKEN = 1;  // Lo envia
}
// verifica ACK
// Mira si en el 9 pulso de reloj (SCL en estado a 1) la señal SDA está a 0
unsigned char i2c_CheckACK(){
  if ( ACKSTAT == 0 ) {
    return 0;  // correcto (lo he recibido )
  } else {
    return 1; // incorrecto (no lo he recibido)
  }
}
// Envia la condicion de STOP
// Libera el BUS I2C, SDA y SCL a nivel alto
// SDA=1 cuando SCL=1.
void i2c_SendStop(){
  PEN = 1;    // send stop bit
}
// Envia la condicion de START
// Inicializa el Bus I2C, SCL y SDA a nivel bajo
// Estando SCL=1 pone SDA=0, luego pone SCL=0
void i2c_SendStart(){
  SEN = 1;    // send start bit
}
// Espera a que el I2C reciba algun evento
void i2c_WaitMSSP(){
  while (SSPIF == 0);  // Espera evento
  SSPIF=0;            // Limpia FLAG
}
// Espera a que el I2C reciba algun evento
unsigned char i2c_MSSP_Status(){
  return SSPIF;
}
// Repeated start from master
// Queremos transmitir más datos pero sin dejar el BUS, es decir
// sin mandar previamente un STOP. O por ejemplo si queremos mandar un STOP y seguidamente un
// START para que ningún otro dispositivo ocupe la línea usaremos esto.
void i2c_SendRStart(){
  RSEN=1;
}
// Leer Byte por el I2C
// Devuelve byte leido
unsigned char i2c_ReadByte(){
  RCEN=1;        // Activar el RCEN
  i2c_WaitMSSP();
  return SSPBUF;
}
// Envia un Dato por el Bus I2C
// Entrada el dato a enviar
void i2c_SendByte(unsigned char dato){
  SSPBUF=dato;
}
// Fallo en el I2C
void i2c_fail(){
  i2c_SendStop();
  i2c_WaitMSSP();
}
/**************************************
*  FUNCIONES DE ALTO NIVEL del I2C  *
**************************************/
/* Configurar I2C
  Configuramos el I2C como Master
  y a una velocidad de 1Mhz */
void i2c_configure(){
  // configuramos SCL y SDA como pines de entrada
  TRISC=TRISC | 0x18;  // 1 entrada / 0 salida 
  SSPSTAT=0x0; 
  SSPSTAT=SSPSTAT | 0x80;  // SMP=1 Slew rate disable for 100Kh  @@@
                          // CKE=0 (modo maestro I2C) y UA=0 (7 bits
  SSPCON=0x08;      // I2C master mode (uso la formula del reloj con SSPAD) 
  SSPCON=SSPCON | 0x20;  // enable I2C  SSPEN=1
  SSPCON2=0x00;  // no se usa por ahora
  // velocidad = FOSC / ( 4 * (sspad + 1) )
  // Fosc=20Mhz
  SSPADD=49;  // 49->100Khz  @@@
  //SSPADD=24; // 24 -> 400khz  @@@
  // Limpia Flags de eventos
  SSPIF=0;  //Limpia flag de eventos SSP
}
// manda un byte al dispositivo i2c
unsigned char i2c_write_byte(unsigned char control_byte, unsigned char address, unsigned char dato){
  // 1º Envia Bit de Start
  i2c_SendStart();
  i2c_WaitMSSP(); 
  // 2º Envio la direccion del modulo
  i2c_SendByte(control_byte);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 3º mando el registro sobre el que voy a actuar
  i2c_SendByte(address);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 4º mando el dato
  i2c_SendByte(dato);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;    // Ha habido un error, salgo de la rutina
  }
  // 6º termino el envio
  i2c_SendStop();
  i2c_WaitMSSP();
  return 1;  // Byte mandado correctamente
}
// Lee 1 byte1  del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char control_byte, unsigned char address, unsigned char *dato){
  // 1º Envia Bit de Start
  i2c_SendStart();
  i2c_WaitMSSP(); 
  // 2º Envio la direccion del modulo
  i2c_SendByte(control_byte);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 3º mando el registro sobre el que voy a actuar
  i2c_SendByte(address);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 4º Repeated start
  i2c_SendRStart();
  i2c_WaitMSSP(); 
  // 4º mando direccion indicando lectura
  i2c_SendByte(control_byte | 1);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 5º leo el byte
  *dato=i2c_ReadByte();
  // 6º Mando NACK
  i2c_SendNack();
  i2c_WaitMSSP(); 
  // Mando el Stop
  i2c_SendStop();
  i2c_WaitMSSP(); 
  return 1;  // Lectura correcta
}
En cuanto tenga resultados con el 24LC1025 estare escribiendo, claro se que tengo que modificar el programa por los bytes en alto y bajo.
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Sáb 1 Oct 2011 - 20:01

Ya pude grabar y leer en el 24LC1025 pero tengo un ligero inconveniente. El 24LC1025 tiene dos bloques uno va de 0x0000-0xFFFF y el otro va de 0x10000-0x1FFFF, no hay problemas con el primer bloque, para el segundo bloque debo modificar mi direción de control por 0xA8 si fuera un solo chip y poner el pin 3 en 5Vcc, si programo esto por separado no hay problema, pero si quiero grabar y leer en cada bloque en la dirección 0x0000 a 0x1FFFF el problema es que no lee el segundo bloque, solo lee el primer bloque.
Código:
void main() {
unsigned char ret;
unsigned char dato;
PORTB=0;
TRISB=0;
while(1){
  //-- Configurar el I2C como master
    delay_ms(100);
    i2c_configure();
    delay_ms(10);
    i2c_write_byte(0xA0, 0xFFFF, 0x55);
    delay_ms(10);
        ret=i2c_read_byte(0xA0, 0xFFFF, &dato);
        if (ret==1) {
              PORTB = dato;
        delay_ms(200);}
    PORTB =0;
    delay_ms(10);
    i2c_write_byte(0xA8, 0xFFFF, 0x50);
    delay_ms(10);
        ret=i2c_read_byte(0xA8, 0xFFFF, &dato);
        if (ret==1) {
              PORTB = dato;
        delay_ms(100);}
    }
}


modifique en estos códigos para enviar la dirección de 16bits
Código:
unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;
// 1º Envia Bit de Start
  i2c_SendStart();
  i2c_WaitMSSP(); 
  // 2º Envio la direccion del modulo
  i2c_SendByte(control_byte);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
  // 3º mando el registro sobre el que voy a actuar
  i2c_SendByte(High_Byte);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  ///////////
  i2c_SendByte(Low_Byte);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 4º mando el dato
  i2c_SendByte(dato);
  i2c_WaitMSSP();
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;    // Ha habido un error, salgo de la rutina
  }
  // 6º termino el envio
  i2c_SendStop();
  i2c_WaitMSSP();
  return 1;  // Byte mandado correctamente
}
// Lee 1 byte1  del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;

 // 1º Envia Bit de Start
  i2c_SendStart();
  i2c_WaitMSSP(); 
  // 2º Envio la direccion del modulo
  i2c_SendByte(control_byte);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
  // 3º mando el registro sobre el que voy a actuar
  i2c_SendByte(High_Byte);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
////////////////
  i2c_SendByte(Low_Byte);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 4º Repeated start
  i2c_SendRStart();
  i2c_WaitMSSP(); 
  // 4º mando direccion indicando lectura
  i2c_SendByte(control_byte | 1);
  i2c_WaitMSSP(); 
  if (i2c_CheckACK()!=0) {
    i2c_fail();
    return 0;  // Ha habido un error, salgo de la rutina
  }
  // 5º leo el byte
  *dato=i2c_ReadByte();
  // 6º Mando NACK
  i2c_SendNack();
  i2c_WaitMSSP(); 
  // Mando el Stop
  i2c_SendStop();
  i2c_WaitMSSP(); 
  return 1;  // Lectura correcta
}


Favor de apoyarme a solucionar este problema, me es complicado simular esto porque proteus no tiene el 24LC1025 y basarme en el I2C que tiene es complicado, pero en la realidad si veo sus resultados.

Saludos cordiales!!
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Pikitin el Sáb 1 Oct 2011 - 21:19

Hola Tony8a87, gracias por ir compartiendo tus avances.

No entiendo bien a que problema te refieres, según lo veo ya lo tienes funcionando, para leer/escribir en el bloque bajo pones a 0 el bit 3 de control_byte (0xA0) y para seleccionar el bloque alto lo pones a 1 (0xA8).

Puedes poner un caso práctico o un ejemplo de donde tendrías el problema??


Saludos.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Dom 9 Oct 2011 - 3:41

Estimados compañeros he solucionado para el 24LC1025 este es mi código como realiza un barrido a todos los regristros tanto bloque 1 y 2, no puedo asegurar que funciono al 100% pues llege a ver hasta el dato 5000. Lo que proseguire es relizar un pequeño teclador y poder teclear el valor, el registro y si es bloque 1 o 2. Espero me puedan ofrecer algunos comentarios.
Código:
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f877a.h>
#include <delay.h>
#include <i2c.h>
//***************LCD Definiciones*****
#define RS RD0
#define RW RD1
#define EN RD2
#define lcdPortD
#include <pic/lcd4.h>
/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word at 0x2007 CONFIG = _XT_OSC & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF;
#define NUMBER_OF_DIGITS 16  /* space for NUMBER_OF_DIGITS + '\0' */
void uitoa(unsigned long value, char* string, int radix){
unsigned char index, i;
  index = NUMBER_OF_DIGITS;
  i = 0;
  do {
    string[--index] = '0' + (value % radix);
    if ( string[index] > '9') string[index] += 'A' - ':';  // continue with A, B,..
    value /= radix;
  } while (value != 0);
  do {
    string[i++] = string[index++];
  } while ( index < NUMBER_OF_DIGITS );
  string[i] = 0; // string terminator
}
void itoa(long value, char* string, int radix){
  if (value < 0 && radix == 10) {
    *string++ = '-';
    uitoa(-value, string, radix);
  }
  else {
    uitoa(value, string, radix);
  }
}
unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato);
unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato);
void main() {
unsigned char ret;
unsigned char dato;
unsigned long i=0;
unsigned char bloque_1=0xA0;
unsigned char bloque_2=0xA8;
char direccion[20]="";
PORTB=0;
TRISB=0;
PORTD=0;
TRISD=0;
lcd_iniciar();
lcd_posicion(1,1);
lcd_imprimir("INICIAR LCD");
delay_ms(100);
lcd_posicion(1,2);
lcd_imprimir("***COMPLETADA***");
delay_ms(100);
lcd_borrar();
i2c_configure();
lcd_posicion(1,1);
lcd_imprimir("CONFIGURAR I2C");
delay_ms(100);
lcd_posicion(1,2);
lcd_imprimir("***COMPLETADA***");
delay_ms(100);
lcd_borrar();
while(1){
for(i=0;i<=131071;i++){
    itoa(i,direccion,10); //conversión de int a string
    if(i<=65535){
        i2c_write_byte(bloque_1, i, 0x3);
        delay_ms(10);
        ret=i2c_read_byte(bloque_1, i, &dato);
        if (ret==1) {
            PORTB = dato;
            lcd_comando(linea1); //iniciar LCD en posición 1,1
            lcd_imprimir(direccion); //imprimir en el LCD
            lcd_posicion(1,2); //dirección en 1,2
            lcd_imprimir("BLOQUE 1");
            delay_ms(50);
            PORTB =0;}
        }
    else{
        RB7=1;
        i2c_write_byte(bloque_2, (i-65536), 0x2);
        delay_ms(10);
        ret=i2c_read_byte(bloque_2, (i-65536), &dato);
        if (ret==1) {
            PORTB = dato;
            lcd_comando(linea1); //iniciar LCD en posición 1,1
            lcd_imprimir(direccion); //imprimir en el LCD
            lcd_posicion(1,2); //dirección en 1,2
            lcd_imprimir("BLOQUE 2");           
            delay_ms(50);
            PORTB =0;}
        }
    }
    RB7=0;
    lcd_borrar();
}
}
// manda un byte al dispositivo i2c
    unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato){
    unsigned char High_Byte=0;
    unsigned char Low_Byte=0;
    // 1º Envia Bit de Start
      i2c_SendStart();
      i2c_WaitMSSP();
      // 2º Envio la direccion del modulo
      i2c_SendByte(control_byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
    High_Byte=(address&0xFF00)>>8;
    Low_Byte=address&0x00FF;
      // 3º mando el registro sobre el que voy a actuar
      i2c_SendByte(High_Byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
      ///////////
      i2c_SendByte(Low_Byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
      // 4º mando el dato
      i2c_SendByte(dato);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;    // Ha habido un error, salgo de la rutina
      }
      // 6º termino el envio
      i2c_SendStop();
      i2c_WaitMSSP();
      return 1;  // Byte mandado correctamente
    }
    // Lee 1 byte1  del dispositivo i2c
    // El dato leido lo devuelve por el parametro dato
    unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato){
    unsigned char High_Byte=0;
    unsigned char Low_Byte=0;

    // 1º Envia Bit de Start
      i2c_SendStart();
      i2c_WaitMSSP();
      // 2º Envio la direccion del modulo
      i2c_SendByte(control_byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
    High_Byte=(address&0xFF00)>>8;
    Low_Byte=address&0x00FF;
      // 3º mando el registro sobre el que voy a actuar
      i2c_SendByte(High_Byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
    ////////////////
      i2c_SendByte(Low_Byte);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
      // 4º Repeated start
      i2c_SendRStart();
      i2c_WaitMSSP();
      // 4º mando direccion indicando lectura
      i2c_SendByte(control_byte | 1);
      i2c_WaitMSSP();
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }
      // 5º leo el byte
      *dato=i2c_ReadByte();
      // 6º Mando NACK
      i2c_SendNack();
      i2c_WaitMSSP();
      // Mando el Stop
      i2c_SendStop();
      i2c_WaitMSSP();
      return 1;  // Lectura correcta
}
Por mi experiencia me ha orillado a que el mejor simulador es la vida real. Porque simular esto en proteus solo da cosas erroneas.
Saludos cordiales!!
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Pikitin el Dom 9 Oct 2011 - 4:47

Hola de nuevo.

Creo que ya entiendo a lo que te referías en el post anterior.
Una solución para el tema de direccionar los bloques podría ser usar un long para almacenar la dirección y pasar el bit 16 al bit 3 de control_byte:

Código:
// manda un byte al dispositivo i2c

unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
{
    unsigned char control_byte = 0xA0;
    control_byte |= address,16<<3;

    // Resto del codigo
}


Hace tiempo que no uso SDCC y no estoy seguro de que la sintaxis sea correcta, pero la idea es esa.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Dom 9 Oct 2011 - 14:54

Hola no entendi del todo la explicación pero lo que si me di cuenta es que el protocolo solicita realizar envios de 8bits y colocar Acknowledge entre cada uno. Adjunto una impresión de pantalla.

mediafire.com i/?vezm4db0x0b5x8z
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Pikitin el Dom 9 Oct 2011 - 17:54

Lo que te proponía es simplificar el direccionamiento:

Tu eeprom tiene 128 KBytes, para direccionar todas esas posiciones de memoria necesitas direcciones de 17 bits: 2^17 = 131072 bytes = 128 KBytes.

Pero el protocolo usa 2 bytes para la dirección, osea 16 bits, con lo que se pueden direccionar 64 KBytes.
Para solucionar el acceso al resto de la memoria y no tener que usar otro byte sólo para enviar el 17º bit, lo que hace es poner ese bit en la palabra de control. Digamos que la dirección está dividida en 2 partes: los 16 primeros bits (bits 0 : 15) que se ponen en un unsigned int y el bit 16 que se pone en control byte.

Cómo necesitas 17 bits para una dirección completa, lo que te proponía es usar un unsigned long (32 bits):

unsigned char i2c_write_byte( unsigned long address, unsigned char dato )


y luego poner el bit 16 de address en el bit 3 de config_word:

unsigned char control_byte = 0xA0;
control_byte |= address,16<<3;


De manera que cuando el bit 16 de address está a 0 (address<65535) entonces control_byte=0xA0, y cuando está a 1 entonces control_byte=0xA8.

Entonces ahora puedes hacer esto:
Código:

unsigned long i = 0;
for(i=0;i<=131071;i++){
        i2c_write_byte(i, 0x3);
}
Sin preocuparte de que la dirección esté en el 1º o 2º bloque.

Para leer tendrías que poner a 1 el bit 0 de control_byte:

Código:
// Lee un byte del dispositivo i2c

unsigned char i2c_read_byte( unsigned long address, unsigned char *dato )
{
    unsigned char control_byte = 0xA1;
    control_byte |= address,16<<3;

    // Resto del codigo
}

Si quieres dejarlo preparado para conectar 4 eeprom de esas y usarlo como si fuera un espacio continuo de 512 KB, tendrías que hacer lo mismo con los bits 17 y 18 de la dirección y pasarlos a los bits 1 y 2 de control_byte:

Código:
// manda un byte del dispositivo i2c

unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
{
    unsigned char control_byte = 0xA0;
    control_byte |= address,16<<3;
    control_byte |= address,18<<2;
    control_byte |= address,17<<1;

    // Resto del codigo
}



Respecto al ACK, este lo envía el dispositivo esclavo, en este caso la eeprom para confirmar que ha recibido el dato:

Código:
 
      if (i2c_CheckACK()!=0) {
        i2c_fail();
        return 0;  // Ha habido un error, salgo de la rutina
      }


Última edición por Pikitin el Dom 9 Oct 2011 - 20:23, editado 1 vez

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Pikitin el Dom 9 Oct 2011 - 18:59

Tenía un error en el código de los bits 17 y 18 de address, ya he editado el mensaje, pero sería así:
control_byte |= address,18<<2;
control_byte |= address,17<<1;


Otra cosa es que el pin A2 de la eeprom lo tienes que poner a Vcc (+5V) para activar el chip, en la imagen que pusiste hace un tiempo de la simulación en proteus, lo tienes a masa, con lo que creo que estaría desactivado.

Pikitin
veterano
veterano

Mensajes : 623
Fecha de inscripción : 26/11/2008

http://linuxmicros.blogspot.com/

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por tony8a87 el Dom 9 Oct 2011 - 19:12

Si pues, me di a la tarea de seguir investigando más sobre esta memoria, tienes razón me deje llevar por deducciones mias y como esta el diagrama de escritura y lectura del datasheet.

1.- El pin A2 se conecta a 5Vcc
2.- Es posible enviar una cadena donde incluya los 16bits.
3.- El maximo número de memorias es 4 (00,01,10,11).

Muchas gracias, realizare estos cambios y comentare mis resultados.
avatar
tony8a87
Participante Activo
Participante Activo

Mensajes : 34
Fecha de inscripción : 10/08/2010

Volver arriba Ir abajo

Re: empezando con el I2C sdcc

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Volver arriba


 
Permisos de este foro:
No puedes responder a temas en este foro.