Problemas de escritura en memoria serial I2C (solucionado)

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 :)
 
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
 
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.

coloque el codigo para poder verificarlo

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 :LOL: 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 :)
 
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

Código:
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
;*********************************************************************************
 
Última edición por un moderador:
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'
call enviar ; direccion esclavo
banksel SSPCON2
btfsc SSPCON2,ACKSTAT ; chequea el ack
call led

call completo
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!
 
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
 
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.. :eek:
 
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
 
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...
 
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
 
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.. :eek:

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.
 
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.

coloque el codigo para poder verificarlo

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 :LOL: 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 :eek:

chaos :)
 
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
 
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
 

Adjuntos

  • i2c_pureba_775.zip
    3.5 KB · Visitas: 113
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
 
Atrás
Arriba