Si el esclavo no responde al primer byte con el ACK es que no reconoce su dirección. Comprueba con un polímetro, que las entradas A0 A1 A2 y WP están a masa.
Codigo:
Otra cosa que he observado es que despues de enviar el bit de STOP, ambas lineas se mantienen a "1", y esto digamos que es infinito.
Este es el estado por defecto en el bus I2c, es decir, las dos líneas a 1 lógico. Comprueba con el osciloscopio que antes de comenzar la comunicación ambas líneas estén a 1.
El primer paso entonces es comprobar que ambas líneas están a 1, después se envía un START, seguidamente la dirección "10100000" y después se recibe un ACK.
Después de revisar detalladamente tus subrrutinas y de mirarme bien el datasheet del PIC, he detectado varios errores:
El primero en la función TX:
Codigo:
; FUNCION PARA TRANSMITIR A LAS MEMORIAS I2C
TX bcf STATUS, RP1
bcf STATUS, RP0 ; Banco 0
movf TXBUF, W
movwf SSPBUF ; Coloco el dato a transmitir en el buffer de salida del
; bus I2C
bcf STATUS, RP1
bsf STATUS, RP0 ; Banco 1
ENVIANDO btfsc SSPSTAT, R_W
goto ENVIANDO ; Espero a que se haya transmitido todo el dato
REC_ACK btfsc SSPCON2, ACKDT
REC_ACK btfsc SSPCON2, ACKSTAT
goto REC_ACK ; Compruebo que se haya recibido ACK
bcf STATUS, RP1
bcf STATUS, RP0 ; Banco 0
return
Debes comprobar el bit ACKSTAT para comprobar que efectivamente el ACK se ha recibido. El ACKDT es cuando, en una operación de lectura, el PIC debe mandar un ACK a la memoria.
Si con el osciloscopio te sale que en el noveno pulso de reloj el SDA está a 1, el bit ACKSTAT que compruebes estará a 1 también por lo que el PIC se te quedará colgado. El problema está entonces en que la memoria no reconoce su dirección (el dato que cargas en SCLAVO). Para ver que todo anda bien, debes comprobar con un polímetro que los pines de la memoria A0, A1, A2, WP esten a masa. Si estos pines están a masa y en el noveno pulso sigues teniendo un 1 es que la memoria no es la que dices, o bien la memoria no soporta los 400KHz prueba a hacerlo más lento con 100KHz por ejemplo, o bien está quemada, prueba con otra.
De que soluciones ese problema, y no antes
, podrías excplicarme para que haces lo siguiente que te señalo en rojo:
Codigo:
; FUNCION QUE REALMENTE SE ENCARGA DE LA ESCRITURA EN LAS MEMORIAS I2C
ESC_MEMO movf DIR_ALT_AUX, W
movwf DIR_ALT ; Paso la parte alta de la direccion, en la funcion
movf DIR_BAJ_AUX, W
movwf DIR_BAJ ; Paso la parte baja de la direccion, en la funcion
call B_START ; Genero el bit de START
movf SCLAVO, W
movwf TXBUF ; Coloco el dato, para poder pasarlo a la funcion TRANSMITIR
call TX ; Transmito el dato
movf DIR_ALT, W
movwf TXBUF ; Coloco la parte alta de la direccion,
; para poder pasarlo a la funcion TRANSMITIR
call TX ; Transmito el dato
movf DIR_BAJ, W
movwf TXBUF ; Coloco la parte baja de la direccion,
; para poder pasarlo a la funcion TRANSMITIR
call TX ; Transmito el dato
movf DATO, W
movwf TXBUF ; Coloco el dato a escribir,
; para poder pasarlo a la funcion TRANSMITIR
call TX ; Transmito el dato
call B_STOP ; Genero el bit de STOP
ESCRITO call B_START ; Genero el bit de START
movf SCLAVO, W
movwf TXBUF
movf TXBUF, W
movwf SSPBUF ; Coloco el dato a transmitir en el buffer de salida del
; bus I2C
bcf STATUS, RP1
bsf STATUS, RP0 ; Banco 1
ENVIANDO2 btfsc SSPSTAT, R_W
goto ENVIANDO2 ; Espero a que se haya escrito todo el dato
btfsc SSPCON2, ACKDT
goto ESCRITO ; Compruebo que se haya recibido ACK
bcf STATUS, RP1
bcf STATUS, RP0 ; Banco 0
return
porque realmente no hace nada.
La única forma de comprobar que se ha escrito algo en la memoria es leyendola, por lo que debes realizar otro bucle con las lecturas en el programa principal. Primero escribes y luego lees.
No te he revisado antes las subrrtinas por falta de tiempo y porque yo siempre utilizo el bus I2C por software. Si lo quieres, te paso un archivo con mis rutinas por soft que te aseguro que funcionan y compruebas si la memoria anda bien o no.
Bueno no te desesperes. Te comento lo que tienes mal:
Codigo:
PROGRA clrf PORTA
clrf PORTB
clrf PORTC
Esto esta muy bien pero mejor configuras el puerto C como salida y debes desactivar el conversor analógico-digital del puerto A asi:
;Inicio de los puertos/registros del PIC
inicio bsf status,5 ;Banco 1
clrf PORTA ;PA como salida
clrf PORTB ;PB como salida
clrf PORTC ;PC como salida
movlw b"00000111"
movwf ADCON ;CAD desactivado
bcf status,5 ;Banco 0
movlw 0x03
movwf PORTC ;SDA y SCL a 1 que es como tienen que estar por defecto
call start
call rx_ack ;No hace falta esperar por el ACK después de un START
movlw 0x00 ;La dirección de memoria es la 10100000
movlw 0xA0
call tx_byte ; Dirección del esclavo
call rx_ack ; Puntero ALTO ; Si te fijas en mi rutina, se espera por el ACK siempre después de enviar un byte
movlw 0x00 ; Dirección alta
call tx_byte
movlw 0x00 ; Dirección baja
call tx_byte
movlw 0xAA ; Dato a escribir
call tx_byte
call stop
BUCLE bsf PORTC, 0 ; Enciendo el LED
No puedes poner un led en el bit SDA, altamente desaconsejado. Mejor en el bit 2 que está libre.
BUCLE bsf PORTC,2 ;Enciendo el LED
goto BUCLE
end
Si con este programa no te funciona, me compro una memoria igual y hago el código aqui en casa y lo pruebo yo mismo