.include "p33fj32mc202.inc"
;..............................................................................
; Configuracion, Palabras sacadas del include.
; Primero va el registro con 2 guion bajo (__FOSC) por ejemplo y luego la
; configuracion del mismo
;..............................................................................
config __FOSCSEL, FNOSC_PRI & IESO_OFF
config __FOSC, POSCMD_XT & OSCIOFNC_OFF & FCKSM_CSDCMD
config __FWDT, FWDTEN_OFF
config __FPOR, FPWRT_PWR16 & ALTI2C_OFF & LPOL_ON & HPOL_ON & PWMPIN_ON
config __FGS, GCP_OFF
;..............................................................................
;Declaraciones Globales:
;Aca declaramos las etiquetas que pueden ser usadas por otros archivos y
;tambien los vectores de interrupcion, los nombres de estos se peuden ver en
;el archivo de linker p33fj32mc202.gld para este caso
;..............................................................................
.global _wreg_init ;No es necesario pero esta por si algun otro
;archivo desea usarlo
.global __reset ;Indicador del vector de interrupcion.
.global __MI2C1Interrupt ;Vector de interrupcion del I2C
;..............................................................................
; Variable no inicializadas
;..............................................................................
.section .data
Direccion: .word 0x01
Dato: .word 0x02
Estado: .word 0x03
;..............................................................................
;Iniciacion de Puntero de pila y registros W
;..............................................................................
.text ;Indicador para el compilador de inicio
__reset: ;de codigo de programa, para ubicarlo en la memoria
MOV #__SP_init, W15 ;Inicializacion del puntero de pila, valor dado por
MOV #__SPLIM_init, W0 ;el linker p33fj32mc202.gld
MOV W0, SPLIM
NOP ;Necesario un NOP luego de inicializar
_wreg_init: ;Limpieza de registros de W0 a W14
CLR W0 ;Siendo W0 la direccion 0x0000 del SFR
MOV W0, W14
REPEAT #12 ;Se repite la instruccion que le sigue
MOV W0, [++W14] ;Con un pre incremento para ir borrando uno
CLR W14 ;por uno hasta W13 y luego se borra W14
;que sirvio de puntero
;..............................................................................
;Configuracion de pines
;..............................................................................
mov #0xffff, W0 ; Pongo las I/O a digitales
mov W0, ADPCFG ;
mov W0, TRISA ; Pongo el puerto A como entrada
nop
clr LATB
nop
bclr ADPCFG,#PCFG0 ; Configuro AN0 como entrada analogica
clr ODCB ; Se configuran los pines para no trabajar como
; como colector abierto.
bset ODCB,#ODCB8 ; Ponemos como colector abierto los pines de I2C
bset ODCB,#ODCB9 ; Pines: SDA1, SCL1
;..............................................................................
;Configuracion del I2C
;..............................................................................
; Registro I2C1MSK & I2C1ADD
clr I2C1MSK ; Desenmascro los bits de direccion
clr I2C1ADD ; Direccion de esclavo
; Registro I2C1BRG ( Baud Rate Generator)
mov #0x015,W0 ; Valor tomado del Seccion I2C de dspic
mov W0,I2C1BRG ; Para FCY = 10Mhz y Fscl = 400Khz
; Registro IEC1 y IFS1
bclr IFS1,#MI2C1IF ; Limpio bandera de interrupcion
bset IEC1,#MI2C1IE ; Habilito interrupcion
; Registro I2C1CON
clr I2C1CON ; Configuro a 7 bit
bset I2C1CON,#SCLREL ; Libero el reloj
bset I2C1CON,#I2CEN ; Inicio modulo I2C
mov #0x10,W0 ; A modo de ejemplo doy
mov W0, Dato ; los valores a Dato y Direccion
mov #0x20,W0 ; Dato: 0x10
mov W0, Direccion ; Direccion: 0x20
clr Estado ; Limpio variable Estado
;..............................................................................
;Programa Principal
;..............................................................................
MainLoop:
cp0 Estado ; Comparo Estado con literal = 0
btsc SR,#Z ; Salta si no es cero
call LeerI2C ; Llamada a rutina de lectura
bra MainLoop ; Inicio nuevamente
;..............................................................................
;Rutina de interrupcion I2C
;..............................................................................
__MI2C1Interrupt: ; Vector de interrupcion del I2C
bclr IFS1,#MI2C1IF ; Limpieza de bandera de I2C
cp0 Estado ; Compar Estado con 0x0000
btsc SR,#Z ; Si lo es, es por que fue recibido la interrupcion de stop
retfie ; Vuelvo al programa
rlnc Estado,WREG ; En caso que sea distinto a 0. W0 = Estado * 2
add PCL,WREG ; Y sumo W0 = W0 + PCL
goto WREG0 ; Voy a la direccion que me indica W0
bra SendAddress ; Dependiendo de la variable estado SALTO
bra Ackaddr ; n cantidad de posiciones, como el PC aumenta de a 2
bra Ackdata ; hizo falta el rotate left sin carry.
bra Sendack ; En caso que hubiera un error habria q limpiar el valor
bra Stop ; de Estado para poder usarlo de nuevo
retfie ; Vuelta de la interrupcion, al programa inicial, por las dudas.
LeerI2C:
rlnc Direccion ; Acomodo la direccion
bset Direccion,#0 ; Y seteo el bit 0 para indicar lectura
bra Start ; Salto a la rutina de comienzo
EscribirI2C:
rlnc Direccion ; Acomodo la direccion
bclr Direccion,#0 ; limpio bit 0 para indicar escritura
Start: ; Estado 0
bset I2C1CON,#SEN ; Pongo a 1 el bit de start
inc Estado ; Incremento estado
return ; Vuelvo a programa principal mientras espero
; La interrupcion
SendAddress: ; Estado 1
mov Direccion, W0 ; Cargo la direccion y la escribo
mov W0, I2C1TRN ; en el registro de transmision
inc Estado ; Automaticamente envia el mismo
retfie ; Vuelvo a programa principal mientras espero
; que me indica el ACK de la direccion
Ackaddr: ; Estado 2
btsc I2C1STAT,#ACKSTAT ; Recibi el ack de la direccion?
bra StopE ; Si no lo recibi, detengo con error.
btsc Direccion,#0 ; Si es escritura (mandar dato) salta
bra Recdata ; Si es lectura preparo para recibir el dato
Senddata:
mov Dato,W0 ; Escribo dato en el registro de transmision
mov W0, I2C1TRN ; Esto habilita de por si la TX en modo maestro
inc Estado ; Incremento Estado
retfie ; Vuelvo a programa principal mientras espero
; que me indica el ACK del dato enviado
Recdata: ; Seccion. habilitacion de entrada de datos
bset I2C1CON,#RCEN ; Pongo a uno el bit, lo cual empieza a funcionar el clk
inc2 Estado ; incremento el Estado en 2
retfie ; Vuelvo a programa principal mientras espero
; la interrupcion para dar el NACK
Ackdata: ; Estado 3
btsc I2C1STAT,#ACKSTAT ; Recibi el ack del dato en la escritura?
bra StopE ; Si no lo recibi, detengo con error.
bra Stop ; Si lo recibi detengo bien.
Sendack: ; Estado 4
inc Estado ; Incremento Estado
bset I2C1CON,#ACKEN ; Pongo al bit para mandar un NACK al esclavo
retfie ; Vuelvo a programa principal mientras espero
; la interrupcion que indica que fue enviado el NACK
StopE:
clr Estado ; Cargo con el valor 0xFFFF
dec Estado ; En caso que haya un error en el envio
goto $+4 ; Salto hasta la inrtuccion bset i2c1con,#pen
Stop: ; **** Estado 5 ****
clr Estado ; Pongo a 0 la variable estado, indicando bus libre
bset I2C1CON,#PEN ; Activo la parada del I2C
retfie ; Vuelvo a programa principal mientras espero
; la interrupcion que indica que fue recibido la parada.
;----------------- Fin del codigo ---------------------------------------------
.end