# Problemas de escritura en memoria serial I2C (solucionado)



## PHLAKO (Ago 9, 2006)

Hola amigos, es mi primer post y es para consultarles...... estoy trabando con el PIC16F877A y la 24LC512 de microchip, la cosa esk puedo leer y escribirla con un retado excesivo entre la escritura de byte a byte, es decir, escribo 1Byte y necesito unos cuantos milisegundos para volver a escribir otro byte, si le acorto el delay k le tengo puesto, la EEPROM es escrita a saltos, le he dado muchas vueltas pero no encuentro el error, lal programacion es en ASM ya k no he aprendido C ops: 

alguien ha tenido mejor resultado?

chaos


----------



## Gacsms (Ago 24, 2006)

Hola, Probaste con un pic nuevo?


----------



## danielgarcia39 (Ago 25, 2006)

tocaria ver el codigo para saber como estas manejando el retardo  estas memoria tienen una
funcion que se implementa para saber cuando termino el ciclo de escritura llamado ACKNOWLEDGE POLLING.

en el datasheet se encuentra que en el peor de los casos para escribir 1 byte se demora 5,37 ms  y  128 bytes  687 ms  esto a 100khz, lo mas probable es que hay algun eror en como se esta manejando el retardo.

coloque el codigo  para poder verificarlo


----------



## PHLAKO (Ago 27, 2006)

danielgarcia39 dijo:
			
		

> tocaria ver el codigo para saber como estas manejando el retardo  estas memoria tienen una
> funcion que se implementa para saber cuando termino el ciclo de escritura llamado ACKNOWLEDGE POLLING.
> 
> en el datasheet se encuentra que en el peor de los casos para escribir 1 byte se demora 5,37 ms  y  128 bytes  687 ms  esto a 100khz, lo mas probable es que hay algun eror en como se esta manejando el retardo.
> ...



amigos, ya encontre el problema, pensaba yo k era cosa de esperar el "ACKNOWLEDGE POLLING" pero, no, hay k considerar los 5ms de retardo k demora en escribir despues del "ACKNOWLEDGE POLLING", (eso en la 24LCxx)...asi k cuando llega el "ACKNOWLEDGE POLLING" le pones el delay de 5ms(en mi caso) y listoco  ese era el problema, ya k el "ACKNOWLEDGE POLLING" solo indica k se solto el bus, pero no k se acepta otro comando  

PD: probe la escritura por pagina y esta cosa ahora vuela 16KByte en 2.2 segundos + -  

salu2 y gracias por responder, espero les sirvan los datos k puse para k no les pase lo mismo 

chaos


----------



## danielgarcia39 (Ago 29, 2006)

que mas estoy manejando la eeprom 24lc512 aparentemente escribe bien pero cuando voy a leer solo me lee unos.

aqui adjunto el codigo para que me den sugerencias


```
call configuracion ;configura modo I2c
banksel PIR1
clrf PIR1
 
escritura_eeprom: 
 
call start 
call completo
 
MOVLW b'10100000' 
call enviar ; direccion esclavo
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
 
call completo
movlw 0x5A ; direccion alta
call enviar
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led ; si el led se prende el escalvo no envio el ack
 
call completo
movlw 0xA5 ; direccion baja
call enviar
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
 
call completo
movlw b'00000011' ; dato
call enviar
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
 
call completo
call stop ;condicion de parada
call completo
 
call retardo2; retardo de 1 segundo
 
lectura_eeprom
call retardo1
call configuracion ;configura modo I2c
banksel PIR1
clrf PIR1
 
call start ;condicion start 
call completo
movlw b'10100000' ; byte de control para escribir el ds1307
call enviar ; carga el byte a transmitir en sspbuff 
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
 
call completo
movlw 0x5A ; direccion registro apuntador del ds1307
call enviar ; carga el byte a transmitir en sspbuff 
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
 
call completo
movlw 0xA5 ; direccion registro apuntador del ds1307
call enviar ; carga el byte a transmitir en sspbuff 
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led 
 
call completo
call stop
call completo
 
 
lectura
call start
call completo
movlw b'11010001' ; byte de control para escribir el ds1307
call enviar ; carga el byte a transmitir en sspbuff 
BANKSEL SSPCON2 
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led
call completo
 
call leer
movwf segundos
call I2CNak 
call completo
 
call stop
call completo
 
;************************************************************
; RETARDO
;************************************************************
retardo1
pau 
MOVLW .0 ;(1) Carga dato N
MOVWF cont1 ;(1) inicializa contador1 ciclo externo
rep1 
MOVLW .0 ;(1) Carga dato M
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 
DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina
;************************************************************
; RETARDO
;************************************************************
retardo2
 
d1seg 
MOVLW 0x8 ;(1)carga duración del ciclo
MOVWF cont3 ;(1)inicializa contador3
ciclo1
CALL pau ;(196868)pausa de 0.197639 seg
DECFSZ cont3,1 ;(1,2)Decrementa y escapa si cero
GOTO ciclo1 ;(2)si no es cero repite
RETURN ;(2)si es cero retorna
 
;-------------------------------------------------------------------;
;************************* Subrutinas para modo I2C *****************
;-------------------------------------------------------------------;
start: ; esta rutina da la condicion de start 
BANKSEL SSPCON2 
bsf SSPCON2,SEN
return
;-------------------------------------------------------------------;
completo: ; se completo la operacion I2C
BANKSEL PIR1 
btfss PIR1,SSPIF 
goto $-1 
bcf PIR1,SSPIF 
return
;-------------------------------------------------------------------;
enviar: 
BANKSEL SSPBUF 
movwf SSPBUF 
return
;-------------------------------------------------------------------;
stop:
BANKSEL SSPCON2
bsf SSPCON2,PEN
return 
;-------------------------------------------------------------------;
leer:
banksel SSPCON2
bsf SSPCON2,RCEN 
call completo 
banksel SSPBUF
movf SSPBUF,W 
return
 
;-------------------------------------------------------------------;
I2CAck:
banksel SSPCON2
bcf SSPCON2,ACKDT 
bsf SSPCON2,ACKEN
return 
 
;-------------------------------------------------------------------;
I2CNak:
banksel SSPCON2
bsf SSPCON2,ACKDT 
bsf SSPCON2,ACKEN 
return 
;-------------------------------------------------------------------;
configuracion:
 
BANKSEL TRISC
MOVLW 0x00
MOVWF TRISC
 
BANKSEL SSPCON ;Habilita el MSSP, selecciona Fosc por SSPADD
MOVLW b'00101000' ;0x28 ; WCOL-SSPOV-SSPEN- CKP -SSPM3-SSPM2-SSPM1-SSPM0
MOVWF SSPCON ; 0 - 0 - 1 - 0 - 1 - 0 - 0 - 0
 
BANKSEL SSPSTAT 
MOVLW b'10000000' ; 0x80 ; SMP - CKE - D/A - P - S - R/W - UA - BF
MOVWF SSPSTAT ; 1 - 0 - 0 - 0 - 0 - 0 - 0 - 0
 
BANKSEL SSPADD ; (Fosc / (4 * 100KHz)) - 1
MOVLW .9 ;.10 ;0x09 ;Valor hallado para trabajar a 100KHz cristal 4mhz
MOVWF SSPADD ;que se coloca en SSPADD
return
;*********************************************************************************
```


----------



## PHLAKO (Ago 30, 2006)

como puedes saber si escribe bien? ya k no puedes leerla......

dejame ver el codigo aver si puedo ayudarte 

chaos


----------



## shougo (Sep 1, 2006)

Hola a todos:



			
				danielgarcia39 dijo:
			
		

> configuracion:
> 
> BANKSEL	TRISC
> MOVLW		0x00
> MOVWF		TRISC



estás configurando el puerto C como salidas, Leí en un libro que SCL y SDA del puerto C (RC3 y RC4) deben de estar configuradas como entradas para poder soportar el protocolo I2C



			
				danielgarcia39 dijo:
			
		

> call start
> call completo
> 
> MOVLW b'10100000'
> ...


y aquí no entiendo mucho por qué pones la función "call led" antes de "call completo" ya que pienso que no le estás dando tiempo al dispositivo que genere la condición de ACK.

Sin embargo, no soy la mejor fuente de información ya que estoy tratando de implementar el bus I2C con un 16F876 para leer la fecha y la hora de un RTC DS1307 y no está funcionando bien. Pareciera como si el programa se quedara pegado cuando el dispositivo está en el bus I2C. Si quito el dispositivo del bus, el programa sigue corriendo, por supuesto que muestra errores ya que no está agarrando los verdaderos datos.

Por cierto, estoy mostrando los datos del RTC en un LCD, por eso se que los datos son errados. Si alguien tiene alguna idea al respecto serìa de gran utilidad.

Y a danielgarcia39, ojalá lo que te escribí arriba te ayude en algo, el resto de tu código me pareció que estaba bien

Saludos!


----------



## PHLAKO (Sep 1, 2006)

justamente, como dice "shougo", los pines de el puerto (b3 y b4) deben ser entradas 

chaos


----------



## danielgarcia39 (Sep 11, 2006)

hola a todos

muchas gracias por las respuestas no habia  caido en cuenta de que  el pueto c habia que configurarlo como salida, voy a probar a ver como me va y les comento.

gracias


----------



## tweetydj (Sep 12, 2006)

Daniel, te esta funcionando ese codigo que tenes arriba? tengo que implementar algo similar pero con una ee mas chica, sacaste ese codigo de alguna nota de aplicacion?
Si alguien sabe donde sacar ese codigo me chifla asi me ahorro el trabajito.

Gracias..


----------



## maunix (Sep 13, 2006)

tweetydj dijo:
			
		

> Daniel, te esta funcionando ese codigo que tenes arriba? tengo que implementar algo similar pero con una ee mas chica, sacaste ese codigo de alguna nota de aplicacion?
> Si alguien sabe donde sacar ese codigo me chifla asi me ahorro el trabajito.
> 
> Gracias..



Te dejo este link

Microchip AN979 - Interfacing to i2c memory with PIC18

Saludos


----------



## maunix (Sep 13, 2006)

PHLAKO dijo:
			
		

> Hola amigos, es mi primer post y es para consultarles...... estoy trabando con el PIC16F877A y la 24LC512 de microchip, la cosa esk puedo leer y escribirla con un retado excesivo entre la escritura de byte a byte, es decir, escribo 1Byte y necesito unos cuantos milisegundos para volver a escribir otro byte, si le acorto el delay k le tengo puesto, la EEPROM es escrita a saltos, le he dado muchas vueltas pero no encuentro el error, lal programacion es en ASM ya k no he aprendido C ops:
> 
> alguien ha tenido mejor resultado?
> 
> chaos



Las memorias EEPROM tienen un retardo que puede ser entre 5 a 10mseg por byte (para la escritura, claro está).

Para optimizar esto y no estar 'todo el tiempo' accesando la memoria, lo que suelen traer es un buffer de 16, 32, 64, 128 bytes, dependiendo del tamaño de la memoria.

Entonces se puede hacer loq eu se llama el "page write".  Uno indica la dirección y luego envía tantos bytes seguidos como bytes tenga el buffer.

Para hacer la grabación lo más rápida posible, se usa el método de "acceso" a la memoria.

El Protocolo i2c, prevee que un dispositivo no responda si es que está ocupado.

Mediante esta técnica uno puede un byte, luego verificar el ACK, si no se recibe, reintentar hasta que se de por positivo el acceso.

Con esto hay que tener cuidado ya que el no verificar el ACK puede ser causa de que la memoria simplemente no esté en el bus i2c!  En mi caso suelo usar un "timeout" , que es proporcional al máximo tiempo que puede durar una memoria ocupada, el cual depende de cada memoria.  En gral ese tiempo sería Twrite x Tamaño Buffer -->

Un caso típico sería

Twrite = 5mseg
Tamaño Buffer = 16 bytes
TiempoTimeout > 80mseg.

Esa es la forma más optima de acceder a una memoria i2c, no la de usar timers para esperar que luego de enviar un dato se 'grabe solo', porque el tiempo puede variar de una memoria a otra.

Para la lectura no hay retrasos de ningun tipo, es inmediata.

Saludos


----------



## tweetydj (Sep 13, 2006)

Muy buenos tus aportes Mauiricio...un espectaculo. 
TE hago una consulta ya que pareces todo un erudito en el tema de eeprom.
Sabes si hay algun problema con las memorias de la marca atmel y los pic? me dijieron que habia alguna diferencia con el tiempo pero no sé si es verdad y ni siquiera se como es el problema.
Y otra cosa la memoria 24c02 tiene tambien buffer?
Gracias...


----------



## maunix (Sep 13, 2006)

tweetydj dijo:
			
		

> Muy buenos tus aportes Mauiricio...un espectaculo.
> TE hago una consulta ya que pareces todo un erudito en el tema de eeprom.


Gracias, pero no es para tanto.  Simplemente me leí a fondo las datasheet y la especificación i2c y si algo le debo a mi abuela y a mi madre, es tener buena memoria.



			
				tweetydj dijo:
			
		

> Sabes si hay algun problema con las memorias de la marca atmel y los pic? me dijieron que habia alguna diferencia con el tiempo pero no sé si es verdad y ni siquiera se como es el problema.


No las he probado, pero no debiera haber problemas!! Hasta donde sé son de las mejorcitas.  Ojo que hay varios modelos y tal vez te han dicho alguna que tenga tiempo de escritura de 10mseg y si tu código está hecho para 5mseg (por tiempo y no por verificacion del ack) entonces no te funcionará.



			
				tweetydj dijo:
			
		

> Y otra cosa la memoria 24c02 tiene tambien buffer?



Suelen tener, las que yo tengo (ST) tienen 16 bytes.  Es un dato que suele estar en la primera hoja del datasheet.  

¿Tienes el datasheet o el link de donde bajarlo?   Te ofrezco leer el datasheet y te comento lo que interpreto del mismo.

Saludos


----------



## danielgarcia39 (Sep 14, 2006)

tweetydj dijo:
			
		

> Daniel, te esta funcionando ese codigo que tenes arriba? tengo que implementar algo similar pero con una ee mas chica, sacaste ese codigo de alguna nota de aplicacion?
> Si alguien sabe donde sacar ese codigo me chifla asi me ahorro el trabajito.
> 
> Gracias..



todavia no logro que me funcione, pero he revisado las señales en el osciloscopio y las señales estan bien, lo que pasa es que cuando voy a leer me lee solo unos.


----------



## PHLAKO (Sep 14, 2006)

Las memorias EEPROM tienen un retardo que puede ser entre 5 a 10mseg por byte (para la escritura, claro está).

Para optimizar esto y no estar 'todo el tiempo' accesando la memoria, lo que suelen traer es un buffer de 16, 32, 64, 128 bytes, dependiendo del tamaño de la memoria.

Entonces se puede hacer loq eu se llama el "page write".  Uno indica la dirección y luego envía tantos bytes seguidos como bytes tenga el buffer.

Para hacer la grabación lo más rápida posible, se usa el método de "acceso" a la memoria.

El Protocolo i2c, prevee que un dispositivo no responda si es que está ocupado.

Mediante esta técnica uno puede un byte, luego verificar el ACK, si no se recibe, reintentar hasta que se de por positivo el acceso.

Con esto hay que tener cuidado ya que el no verificar el ACK puede ser causa de que la memoria simplemente no esté en el bus i2c!  En mi caso suelo usar un "timeout" , que es proporcional al máximo tiempo que puede durar una memoria ocupada, el cual depende de cada memoria.  En gral ese tiempo sería Twrite x Tamaño Buffer -->

Un caso típico sería

Twrite = 5mseg
Tamaño Buffer = 16 bytes
TiempoTimeout > 80mseg.

Esa es la forma más optima de acceder a una memoria i2c, no la de usar timers para esperar que luego de enviar un dato se 'grabe solo', porque el tiempo puede variar de una memoria a otra.

Para la lectura no hay retrasos de ningun tipo, es inmediata.

Saludos[/quote]



			
				danielgarcia39 dijo:
			
		

> tocaria ver el codigo para saber como estas manejando el retardo  estas memoria tienen una
> funcion que se implementa para saber cuando termino el ciclo de escritura llamado ACKNOWLEDGE POLLING.
> 
> en el datasheet se encuentra que en el peor de los casos para escribir 1 byte se demora 5,37 ms  y  128 bytes  687 ms  esto a 100khz, lo mas probable es que hay algun eror en como se esta manejando el retardo.
> ...



amigos, ya encontre el problema, pensaba yo k era cosa de esperar el "ACKNOWLEDGE POLLING" pero, no, hay k considerar los 5ms de retardo k demora en escribir despues del "ACKNOWLEDGE POLLING", (eso en la 24LCxx)...asi k cuando llega el "ACKNOWLEDGE POLLING" le pones el delay de 5ms(en mi caso) y listoco  ese era el problema, ya k el "ACKNOWLEDGE POLLING" solo indica k se solto el bus, pero no k se acepta otro comando  

PD: probe la escritura por pagina y esta cosa ahora vuela 16KByte en 2.2 segundos + -  

salu2 y gracias por responder, espero les sirvan los datos k puse para k no les pase lo mismo 

chaos 

ya habia posteado esto  

el problema esta resuelto desde esa fecha, ahora toy en la emulacion...recuerdas?



PD2: estoy en desacuerdo contigo respecto a esto :

Twrite = 5mseg
Tamaño Buffer = 16 bytes
TiempoTimeout > 80mseg.

ya que los 5mseg(en algunas eeprom) es el tiempo que demora en escribir un byte, solo cuando escribes byte a byte, si estas en modo pagina se demora 5mseg. en escribir toda la pagina, no seria gracia esperar 80 segundos para escribir 16KB  

chaos


----------



## danielgarcia39 (Sep 14, 2006)

tweetydj ese codigo lo hice cuando trabaje con un ds1307 el cual tambien funciona con i2c, es casi lo mismo lo unico que cambia es que hay que manejar dos bytes para la direccion de la memoria, el codigo me funciono para el  ds1307 , por lo cual deberia funcionar para la       eeprom, 

he mirado las señales en el osciloscopio y las envia perfecto y la eeprom esta enviando  el acknowlegde, un error que habia y que aqui en en foro me hicieron  caer en cuenta es que el puerto c hay que configurarlo como entrada, observe la señal en el osciloscopio y se ve  el tren de pulsos perfecto y cuando configuraba el puerto c como salida el tren de pulsos no se ve tambien.

otra cosa que hay que tener en cuenta es colocar un condensador entre vcc y GND para disminuir el ripple que se ve en las señales I2c


la Funcion CALL LED es para saber cuando la eeprom no envio el ack  y si no lo envio prende unos leds.  en esta funcion debe ir es una rutina que libere el  bus i2c es decir un stop y deje las dos lineas  a 5 v y que vuelva a repetir la cominicacion


----------



## oretgita (Nov 15, 2006)

hola, veo que saben mucho de I2C, y tengo una pregunta sobre el tema.
Estoy manejando un pic18f2550 (los registros son parecidos al pic16f877a), con una memoria 24lc256, he probado que tanto la escritura y lectura por separado funcionan, pero al realizar las dos operaciones una seguida de otra sin cambiar de programa( ecribir un dato en la memoria y luego leer, todo en la misma posicion) , no funciona.

entonces lo que hice para probar el programa generar algun mensaje de error atraves de HyperTerminal, por ejemplo el cuando no se recibe el bit de reconocimento del esclavo, con esta rutina encontre que la tx la estaba realizando bien ( creo) pero cuando se inicia la secuancia de rx al enviar la direccion de dispositivo no se recibe el bit de reconocimiento.

agradeceria su ayuda.
por si acaso adjunto el .asm


----------



## danielgarcia39 (Nov 16, 2006)

que mas oretgita despues de la rutina de  escribir  inmediatamente mandas el stop hay que esperar 5ms  para que el dato sea escrito en la memoria durante ese tiempo la memoria no enviara ningun ack, puede ser que este pasando eso, prueba colocando un retardo antes de ejecutar la rutina de  lectura, son 5 ms para un byte  y para todo el buffe 265ms, tranqilamente coloca un retardo de 1 segundo para ensayar, y si necesitas mas velocidad le colocas los 5ms para un byte y 265ms para el buffer completo(creo 64bytes para 24lc512


----------



## oretgita (Nov 16, 2006)

Oye daniel muchas gracias por tu consejo me funciono al pelo


----------



## antiquisimus (Jul 4, 2007)

Hola!

Oigan, un favorsote, yo tengo un problema al escribir entre una y otra página.

Trabajo con la 24C64 y no tengo problemas cuando escribo una página de 32 Bytes, pero si quiero seguir a la página siguiente cuando le doy después del stop, un retardo de hasta un segundo no hace nada; vuelve a sobreescribir sobre la dirección 0x00 hasta la 0x1f y allí se queda siempre, nomás sobreescribiendo y sobreescribiendo.

Así como si le pido que escriba por primera vez en una dirección que no sea la 0x00, no hace caso; solo obedece cuando es la dirección cero.

¿qué hago?

Ya me tardé mucho y no le hallo.


Muchísimas gracias,

Fabián


----------



## antiquisimus (Jul 4, 2007)

P.D. 

Y el retardo se lo he dado antes y después del AcnowledgePollling, para dis que no fallarle, pero ni así   

Saludos,


----------



## danielgarcia39 (Jul 5, 2007)

coloca el codigo para saber en donde esta fallando la escritura


----------



## antiquisimus (Jul 5, 2007)

```
#include<p18f452.h>
#include <my_i2c.h>

#pragma config LVP = OFF
#pragma config STVR = OFF
#pragma config WDT = OFF
#pragma config OSC = HS 

void main(void)
{
char c;
PORTA = PORTB = PORTC = PORTD = PORTE = 0x00;
TRISA = 0;
TRISB = 0;
TRISD = 0;
TRISC = 0x18;

OpenI2C(MASTER, SLEW_OFF);
SSPADD = 19;

comienzaI2C();
PrepareWWord_I2C(0xa0,0x00,0x00);
for (c=0x01;c<=0x20;c++)
{
WWord_I2C(c);
}
FinishWWord_I2C();
AckPolling(0xa0);


comienzaI2C();
PrepareWWord_I2C(0xa0,0x00,0x20);
for (c=0x01;c<=0x20;c++)
{
WWord_I2C(c);
}
FinishWWord_I2C();

retardo_1ms(0xfe);
AckPolling(0xa0);

PrepareWWord_I2C(0xa0,0x00,0x20);
for (c=0x02;c<=0x40;c=c+0x02)
{
WWord_I2C(c);
}
FinishWWord_I2C();

retardo_1ms(0xfe);
AckPolling(0xa0);


c = 0x01;
comienzaI2C();
PrepareRWord_I2C(0xa0,0x00,0x00);
for (c=0x00;c<=0x3f;c++)
{
PORTB = RWord_I2C();
retardo_1ms(0x80);
}
FinishRWord_I2C();
IdleI2C();


PORTAbits.RA0 = 1;


while(1)
{
}
}


Este es el main, y estas las funciones como header file:





#include <funciones_i2c.h>
#include <my_Delays.h>
/**************************************
*									  *
*        Escribe I2C  Byte            *
*									  *
**************************************/
unsigned char dato[7];


unsigned char escribeI2C(unsigned char dir_slv, 
						 unsigned char dir_low, 
						 unsigned char dir_high, 
						 unsigned char dato )
{
 WriteI2C(dir_slv);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_high);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_low);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dato);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )
 IdleI2C();
 StopI2C();
 while ( SSPCON2bits.PEN );      // wait until stop condition is over 
return (0);
}




/**************************************
*									  *
*            Lee I2C  Random          *
*									  *
**************************************/

unsigned char leeI2C( unsigned char dir_slv, 
					  unsigned char dir_high, 
					  unsigned char dir_low) 
{
 unsigned char read;
 WriteI2C(dir_slv);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_high);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_low);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 RestartI2C();
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_slv+0x01);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 IdleI2C();
 read = ReadI2C();
 NotAckI2C();
 while ( SSPCON2bits.ACKEN ); // wait until ACK sequence is over 
 StopI2C();
 while ( SSPCON2bits.PEN ); // wait until stop condition is over 
 return (read);
}


/**************************************
*									  *
*        Comienza I2C                 *
*									  *
**************************************/

void comienzaI2C(void)
{
 IdleI2C();
 StartI2C();
 while ( SSPCON2bits.SEN );      // wait until start condition is over

}



/**************************************
*									  *
*        Detiene I2C                  *
*									  *
**************************************/
void detenI2C(void)
{
IdleI2C();
StopI2C();
while ( SSPCON2bits.PEN ); // wait until stop condition is over 
}


/***********************************************************************
************************************************************************
*									                        
*        				Escribe I2C  Word                              
*									  			*********************************************************************
/***********************************************************************/


 void PrepareWWord_I2C ( unsigned char dir_slv, 
					     unsigned char dir_low, 
					     unsigned char dir_high )
{
 WriteI2C(dir_slv);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_high);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_low);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )
 IdleI2C();
}

void WWord_I2C(unsigned char Word)
{
 WriteI2C(Word);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )
 IdleI2C();
}

 void FinishWWord_I2C(void)
{
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )
 IdleI2C();
 StopI2C();
 while ( SSPCON2bits.PEN );      // wait until stop condition is over 
}




/***********************************************************************
************************************************************************
*									                      *
*        			    	Lee I2C  Word                                                            *
*									  	          *
************************************************************************
/***********************************************************************/
unsigned char PrepareRWord_I2C( unsigned char dir_slv, 
					  			unsigned char dir_high, 
					  			unsigned char dir_low) 
{
 WriteI2C(dir_slv);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_high);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_low);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 RestartI2C();
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )

 WriteI2C(dir_slv+0x01);
 IdleI2C();
 if ( !SSPCON2bits.ACKSTAT )
 IdleI2C();
 return (0);
}

 unsigned char RWord_I2C(void)
{
  ReadI2C();	
  AckI2C();
  return (SSPBUF);
}

void FinishRWord_I2C()
{
 NotAckI2C();
 while ( SSPCON2bits.ACKEN ); // wait until ACK sequence is over 
 StopI2C();
 while ( SSPCON2bits.PEN ); // wait until stop condition is over 
}



/********************************************************************
********************************************************************/
unsigned char AckPolling( unsigned char control )
{
  IdleI2C();                      // ensure module is idle 
  StartI2C();                     // initiate START condition
  while ( SSPCON2bits.SEN );      // wait until start condition is over 
  WriteI2C( control );    // write byte - R/W bit should be 0
  IdleI2C();                    // ensure module is idle   
   while ( SSPCON2bits.ACKSTAT ) // test for ACK condition received
   {
    RestartI2C();               // initiate Restart condition
    while ( SSPCON2bits.RSEN ); // wait until re-start condition is over 
    WriteI2C( control );  // write byte - R/W bit should be 0
    IdleI2C();                  // ensure module is idle
   }
  StopI2C();                      // send STOP condition
  while ( SSPCON2bits.PEN );      // wait until stop condition is over         
  return ( 0 );                   // return with no error     
}
```


----------



## antiquisimus (Jul 5, 2007)

```
#define SSPENB 0x20 /* Enable serial port and configures
SCK, SDO, SDI */
#define SLAVE_7 6 /* I2C Slave mode, 7-bit address */
#define SLAVE_10 7 /* I2C Slave mode, 10-bit address */
#define MASTER 8 /* I2C Master mode */
 
/* SSPSTAT REGISTER */
#define SLEW_OFF 0xC0 /* Slew rate disabled for 100kHz mode */
#define SLEW_ON 0x00 /* Slew rate enabled for 400kHz mode */
 
 
 
 
/********************************************************************
* Function Name: IdleI2C *
* Return Value: void *
* Parameters: void *
* Description: Test and wait until I2C module is idle. *
********************************************************************/
void IdleI2C( void )
{
while ( ( SSPCON2 & 0x1F ) | ( SSPSTATbits.R_W ) );
}
 
 
 
 
 
/********************************************************************
* Function Name: ReadI2C *
* Return Value: contents of SSPBUF register *
* Parameters: void *
* Description: Read single byte from I2C bus. *
********************************************************************/
unsigned char ReadI2C( void )
{
SSPCON2bits.RCEN = 1; // enable master for 1 byte reception
while ( SSPCON2bits.RCEN ); // wait until byte received 
return ( SSPBUF ); //return with read byte 
}
 
 
 
 
 
 
 
 
/********************************************************************
* Function Name: RestartI2C *
* Return Value: void *
* Parameters: void *
* Description: Send I2C bus restart condition. *
********************************************************************/
void RestartI2C( void )
{
SSPCON2bits.RSEN = 1; // initiate bus restart condition
}
 
 
 
 
 
/********************************************************************
* Function Name: StopI2C *
* Return Value: void *
* Parameters: void *
* Description: Send I2C bus stop condition. *
********************************************************************/
 
void StopI2C( void )
{
SSPCON2bits.PEN = 1; // initiate bus stop condition
}
 
 
 
 
 
 
/********************************************************************
* Function Name: StartI2C *
* Return Value: void *
* Parameters: void *
* Description: Send I2C bus start condition. *
********************************************************************/
 
void StartI2C( void )
{
SSPCON2bits.SEN = 1; // initiate bus start condition
}
 
 
/********************************************************************
* Function Name: WriteI2C *
* Return Value: Status byte for WCOL detection. *
* Parameters: Single data byte for I2C bus. *
* Description: This routine writes a single byte to the * 
* I2C bus. *
********************************************************************/
unsigned char WriteI2C( unsigned char data_out )
{
IdleI2C();
SSPBUF = data_out; // write single byte to SSPBUF
if ( SSPCON1bits.WCOL ) // test if write collision occurred
return ( -1 ); // if WCOL bit is set return negative #
else
{
while( SSPSTATbits.BF ); // wait until write cycle is complete 
IdleI2C(); // ensure module is idle
}
if ( !SSPCON2bits.ACKSTAT ) // test for ACK condition, if received 
return ( 0 ); // if WCOL bit is not set return non-negative #
else
{
return ( -3 );
}
}
 
 
/********************************************************************
* Function Name: NotAckI2C *
* Return Value: void *
* Parameters: void *
* Description: Initiate NOT ACK bus condition. *
********************************************************************/
 
void NotAckI2C( void )
{
SSPCON2bits.ACKDT = 1; // set acknowledge bit for not ACK
SSPCON2bits.ACKEN = 1; // initiate bus acknowledge sequence
}
 
 
 
/********************************************************************
* Function Name: AckI2C *
* Return Value: void *
* Parameters: void *
* Description: Initiate ACK bus condition. *
********************************************************************/
 
void AckI2C( void )
{
SSPCON2bits.ACKDT = 0; // set acknowledge bit state for ACK
SSPCON2bits.ACKEN = 1; // initiate bus acknowledge sequence
while ( SSPCON2bits.ACKEN ); // wait until ACK sequence is over
}
 
 
 
/********************************************************************
* Function Name: OpenI2C *
* Return Value: void *
* Parameters: SSP peripheral setup bytes *
* Description: This function sets up the SSP module on a * 
* PIC18CXXX device for use with a Microchip I2C *
* EEPROM device or I2C bus device. *
********************************************************************/
void OpenI2C( unsigned char sync_mode, unsigned char slew )
{
SSPSTAT &= 0x3F; // power on state 
SSPCON1 = 0x00; // power on state
SSPCON2 = 0x00; // power on state
SSPCON1 |= sync_mode; // select serial mode 
SSPSTAT |= slew; // slew rate on/off 
DDRCbits.RC3 = 1; // Set SCL (PORTC,3) pin to input
DDRCbits.RC4 = 1; // Set SDA (PORTC,4) pin to input
SSPCON1 |= SSPENB; // enable synchronous serial port 
SSPADD = 19; // CLK = [8MHz/4*(19+1)] = 100 KHz
}
```


----------



## antiquisimus (Jul 11, 2007)

que gachos 

nadie ayuda


----------



## VIKKOSKY (Ago 14, 2008)

Epa! mas pic..
Sois unos genios..!

Sigan con el Foro eh!

son unos geniales...


----------



## luis872727 (May 31, 2009)

hola yo tengo problemas porque no me lee nada, solo me aparece parpadeando el cursos en el lcd, este es mi codigo cualquier cosa por favor me sirve, trabajo con C18


```
#include <p18f1320.h>
#include <delays.h>
#include <adc.h>
#include <xlcd.h>
#include <sw_i2c.h>
#include <stdlib.h>
#include <stdio.h>
#pragma config OSC=INTIO2, WDT=OFF, MCLRE=ON, LVP=OFF
 
void DelayFor18TCY( void )
{
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
}
 
void DelayPORXLCD (void)
{
Delay1KTCYx(60); // Delay of 15ms
// Cycles = (TimeDelay * Fosc) / 4
// Cycles = (15ms * 16MHz) / 4
// Cycles = 60,000
return;
}
 
void DelayXLCD (void)
{
Delay1KTCYx(20); // Delay of 5ms
// Cycles = (TimeDelay * Fosc) / 4
// Cycles = (5ms * 16MHz) / 4
// Cycles = 20,000
return;
}
 
 
void main(void)
{
 
 
int dato,x,otra,cont,contador2;
unsigned char buf[9],cosa,contchar,i2c,nuevo;
 
 
ADCON1=0x7F;
TRISA=0xFF;
TRISB=0x00;
PORTBbits.RB7=0;
 
OpenXLCD( FOUR_BIT & LINES_5X7 );
 
WriteCmdXLCD( BLINK_ON );
putrsXLCD("ESIME CULHUACAN"); 
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 ); 
putrsXLCD("1ER AVANCE");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 ); 
 
cont=35;
 
while(1)
{
/*Inicializa el convertidor ADC con canal 0 como entrada analógica */
OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_12_TAD,
ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS &
ADC_CH0 & ADC_INT_OFF, 0x7E );
 
 
SetDDRamAddr(0x00);
//while(BusyXLCD());
putrsXLCD("PRESIONA UNA TECLA");
do{
x=0;
ConvertADC(); 
while(BusyADC()); 
dato= ReadADC();
}while(dato<20); 
 
 
while(BusyXLCD()); 
 
if(dato>855&&dato<875)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 1");
Delay1KTCYx(10);
itoa(cont, contchar);
WriteCmdXLCD( 0x01 );
SWStartI2C();
SWPutcI2C(0xA0); // control byte
SWAckI2C();
SWPutcI2C(0x00); // address high byte
SWAckI2C();
SWPutcI2C(0x00); //address low byte
SWAckI2C();
SWPutcI2C(contchar); // data
SWAckI2C();
SWStopI2C();
Delay100TCYx(100);
}
 
if(dato>645&&dato<655)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 2");
Delay1KTCYx(10); 
WriteCmdXLCD( 0x01 );
SWStartI2C();
SWPutcI2C(0xA0); // control byte
SWAckI2C();
SWPutcI2C(0x00); // address high byte
SWAckI2C();
SWPutcI2C(0x00); //address low byte
SWAckI2C();
SWStartI2C();
SWPutcI2C(0xA1);
SWAckI2C();
i2c=SWGetcI2C(); // data
SWNotAckI2C();
SWStopI2C(); 
Delay100TCYx(100);
WriteCmdXLCD( 0x01 );
}
 
if(dato>495&&dato<515)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 3");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 ); 
itoa(cont, nuevo);
putsXLCD( nuevo ); 
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
putsXLCD( i2c );
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>335&&dato<345)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 4");
cont++; 
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>797&&dato<809)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 5");
Delay1KTCYx(10);
}
 
if(dato>610&&dato<621)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 6");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>480&&dato<491)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 7");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>322&&dato<333)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 8");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>728&&dato<740)
{
WriteCmdXLCD( 0x01 );
putrsXLCD("tecla 9");
Delay1KTCYx(10);
WriteCmdXLCD( 0x01 );
}
 
if(dato>568&&dato<580)
{
WriteCmdXLCD( 0x01 ); 
putrsXLCD("corrertecla");
do{ //WriteCmdXLCD( 0x01 );
Delay1KTCYx(10);
WriteCmdXLCD( SHIFT_CUR_LEFT );
x++; 
}while(x<4);
Delay1KTCYx(10);
while ( BusyXLCD() );
cosa = ReadDataXLCD();
btoa(cosa, buf);
WriteCmdXLCD( 0x01 ); 
putsXLCD(buf);
Delay1KTCYx(10);
atoi(cosa);
WriteCmdXLCD( 0x01 ); 
putsXLCD(cosa);
Delay1KTCYx(10); 
WriteCmdXLCD( 0x01 );
}
 
CloseADC(); 
while(BusyADC());
}
 
 
}
```


----------



## stiago22 (Jun 15, 2009)

hola, estoy envalado por q  no he podido poner a funcionar el adc interno y la memoria i2c simultaneamente, cada uno funciona muy bien independientemente pero al usarlos a la vez el programa se bloquea, estoy usando un pic 18f4455, hay q tener en cuenta algun retardo entre lectura adc y escritura eeprom, o q hay q hacer?


----------



## alnavasqui (Mar 4, 2010)

Aparte de problemas con el código, puede que la memoria se joda al soldarla a la PCB? Me refiero a un excesivo calor a la hora de soldar


----------



## rei3 (Ago 23, 2010)

fijense que andando con el mismo problema acerca de como conectar memorias I2C a un pic y leerlas asi como escribirlas correctamente me encontre un tutorial en español para utilizar todas las memorias seriales 24c02,24c04,24c08,24c16,24c32,24c64,24c128,24c256,24c512 y la 24c1025 asi como los ejemplos para conectarlas a cualquier tipo de pic, todos los ejemplos estan en ASM lenguaje ensamblador aqui:


----------

