

;===================================================================================
;       I2C MASTER TRASMETTITORE / RICEVITORE
;       versione per PIC16F876A
;
;	    di Walter Giocoso (http://digilander.iol.it/wgiocoso)
;       e Piero Speciale        
;
;
;	    compilato con MPASM 3.30
;
;
;       #   Nota: La simulazione della gestione I2C tramite registri, non è supportata
;           ne' da PIC SIMULATOR-IDE 5.21 della Oshonsoft, 
;           ne' da MPLAB SIM 30 1.0 (incluso in MPLAB IDE 6.20) della Microchip
;           In quest'ultimo è possibile settare manualmente i flag dei registri, emulando
;           la risposta del microcontrollore.
;
;       SORGENTE    è il dato da immettere nello stack; viene normalmente creato
;                   leggendo dai dispositivi I2C in ingresso
;                   (PIC Master ricevitore  <-- Slave trasmettitore)
;
;       DESTINAZIONE è il dato prelevato dallo stack; verrà inviato ad un dispositivo
;                   I2C in uscita (PIC Master trasmettitore --> Slave ricevitore)
;===================================================================================




;       Usando i blocchi di questo esempio è possibile gestire qualsiasi tipo di 
;       comunicazione da PIC 16F876 MASTER a dispositivi SLAVE sia in lettura
;       che in scrittura
;       Occorre: 
;           #   Aggiungere nel MAIN una chiamata per ogni dispositivo
;           #   Aggiungere nel BANCOVAR una EQU che associa il nome del dispositivo
;               al suo indirizzo
;           #   Personalizzare le procedure SCRIVI_DISP1 e LEGGI_DISP2
;       Gli altri blocchi non necessitano di modifiche (a meno di errori); vanno solo
;       richiamati laddove occore


;        -------------------------------------------------
;       |   SINTASSI DELLE OPERAZIONI LETTURA/SCRITTURA   |
;        -------------------------------------------------
;
;SCRITTURA SU SLAVE     -> = trasmesso          () = ricevuto
;------------------
;| Start 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | ACK 1 | Dato 8 | ACK 1 | Stop 1 |
;   ->          ->          w->     ()      ->       ()      ->       ()       ->   
;
;
;
;
;LETTURA DA SLAVE     -> = trasmesso          () = ricevuto
;----------------
;| Start 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | ACK 1 | Dato 8 | NACK 1 | Stop 1 |
;   ->          ->         r->      ()      ()       ->       ()       ->       ->
;
;
;
;
;SCRITTURA+LETTURA     -> = trasmesso          () = ricevuto
;-----------------
;| Start 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | ACK 1 |...
;   ->          ->         w->      ()      ->        ()
;
;              ...| RIStart 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | NACK 1 | Stop 1 |
;                       ->          ->         r->      ()      ()      ->      ->
;
;
;
;
;LETTURA+SCRITTURA     -> = trasmesso          () = ricevuto
;-----------------
;| Start 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | NACK 1 |...
;   ->          ->         r->      ()      ()       ->       
;
;               ...| RIStart 1 | SlaveADDR 7 | R/W 1 | ACK 1 | Dato 8 | ACK 1 | Stop 1 |
;                       ->          ->         w->      ()       ->       ()      ->











        PROCESSOR   16F876A
	    __CONFIG    3FF1H
	    RADIX 	    DEC
	    INCLUDE     "P16F876A.INC"
	    ERRORLEVEL  -302
	

        ORG     0xA0                    ;area variabili BANCO1 (BANCOVAR)


SORGENTE    RES 1                       ;contiene il dato da immettere nello stack

                    ; -------------------------SORGENTE----------------------------
                    ;|                                                              |
                    ;|  7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
                    ;|  -   |   -   |   -   |TIPO   |   S3  |   S2  |   S1  |   S0  |
                    ;|                                                              |
                    ;|                                                              |
TIPO        EQU 4   ;|  TIPO    =1      LIFO                =0      FIFO            |
                    ;|                                                              |
                    ; --------------------------------------------------------------


DESTINAZIONE    RES 1                   ;contiene il dato letto dallo stack
SLAVEADDR   RES 1                       ;Indirizzo Slave da "chiamare"
                                        ;NOTA!: il bit 0 non identifica il dispositivo
                                        ;   ma l'operazione da compiere R=0, W=1
RW          EQU 0                                        
;LEGGI       EQU 0
;SCRIVI      EQU 1                                        
SCL         EQU 3
SDA         EQU 4
DATA_BYTE1  RES 1
DATA_BYTE2  RES 2
DATA_BYTE   RES 1
COMMAND_BYTE    RES 1


addr_disp1  equ 00000010b   ;#SIMULAZIONE   Indirizzo disp.1
addr_disp2  equ 00000010b   ;#SIMULAZIONE   Indirizzo disp.2


        ORG     00H                     ;area programma



        CALL        I2CCONF             ;configura I2C

        
MAIN    ;#################################################################
        CALL        SCRIVI_DISP1;# PROCEDURA DA PERSONALIZZARE #
        CALL        LEGGI_DISP2 ;# PROCEDURA DA PERSONALIZZARE #
;        call        scrivi_display1
;        call        scrivi_voice1
;        call        leggi_expander_su
;        call        leggi_expander_giu
        GOTO        MAIN
        ;#################################################################






;scrivi_voice1
;scrivi_display1
SCRIVI_DISP1        ;--------------------------------------------------------                    
                                ;# PROCEDURA DA PERSONALIZZARE #
        CALL        BANCOVAR
        movlw       addr_disp1  ;#SIMULAZIONE: indirizzo simulato di un dispositivo
        movwf       SLAVEADDR   ;#SIMULAZIONE
        BSF         SLAVEADDR,  RW      ;modalità scrittura
        CALL        CHIAMA_SLAVE        ;invia Start bit + indirizzo
        ;---------------------------------------------------------------------
        CALL        BANCOVAR
        movlw       00000111B   ;#SIMULAZIONE command byte (se richiesto dal dispositivo)
        movwf       DATA_BYTE
        CALL        SCRIVI_SLAVE        ;byte di comando del dispositivo
        ;---------------------------------------------------------------------
        CALL        BANCOVAR
        movlw       00000111B   ;#SIMULAZIONE dato1 da scrivere
        movwf       DATA_BYTE
        CALL        SCRIVI_SLAVE        ;primi 8 bit dato
        ;---------------------------------------------------------------------
        CALL        BANCOVAR
        movlw       00001111B   ;#SIMULAZIONE dato2 da scrivere
        movwf       DATA_BYTE
        CALL        SCRIVI_SLAVE        ;eventuali successivi 8 bit dato
        ;---------------------------------------------------------------------
        CALL        STOP_BIT
        RETURN
      







;leggi_expander_su
;leggi_expander_giu
LEGGI_DISP2                     ;# PROCEDURA DA PERSONALIZZARE #
        CALL        BANCOVAR
        movlw       addr_disp2  ;#SIMULAZIONE: indirizzo simulato di un dispositivo
        movwf       SLAVEADDR   ;#SIMULAZIONE
        movlw       00011101b   ;#SIMULAZIONE: command byte del dispositivo (se richiesto)
        movwf       DATA_BYTE   ;#SIMULAZIONE
        
;        BSF         SLAVEADDR,  RW      ;modalità scrittura             |?????
;        CALL        CHIAMA_SLAVE        ;invia Start bit + indirizzo    |?????
;        CALL        STOP_BIT                                           ;|?????

        ;------------------------ command byte (se richiesto) -------------
        BSF         SLAVEADDR,  RW      ;modalità scrittura             
        CALL        CHIAMA_SLAVE        ;invia Start bit + indirizzo 
        MOVF        COMMAND_BYTE,   0                
        MOVWF       DATA_BYTE
        CALL        SCRIVI_SLAVE

        ;------------------------ lettura primo byte ---------------------
        CALL        BANCOVAR
        BCF         SLAVEADDR,  RW      ;modalità lettura
        CALL        CHIAMA_SLAVE        ;invia Start bit + indirizzo
        CALL        LEGGI_SLAVE
        CALL        PRELEVA_BUFFER
        CALL        BANCOVAR
        MOVF        DATA_BYTE,  0
        MOVWF       DATA_BYTE1  
        ;------------------------ lettura secondo byte --------------------
	    CALL        ACKNOWLEDGE_BIT     ;spedire un ack per tutte le letture 
	                                    ;   tranne l'ultima
        CALL        LEGGI_SLAVE         
        CALL        PRELEVA_BUFFER
        CALL        BANCOVAR
        MOVF        DATA_BYTE,  0
        MOVWF       DATA_BYTE2
        ;-------------------------------------------------------------------
        CALL        NOACKNOWLEDGE_BIT
        CALL        STOP_BIT
        RETURN










LEGGI_SLAVE         ;--------------------------------------------------------
        CALL        BANCO0
        BCF	        PIR1,       SSPIF	;pulisci interrupt flag
        CALL        BANCO1
	    BSF	        SSPCON2,    RCEN	;modalità ricezione
	    CALL        BANCO0
RDATA_TIME
	    BTFSS	    PIR1,       SSPIF	;MSSP ha ricevuto il byte di dati?
	    GOTO        RDATA_TIME          ;No! attendi...
        RETURN






PRELEVA_BUFFER      ;--------------------------------------------------------
        CALL        BANCO0	                                    
	    MOVF        SSPBUF,     0
	    CALL        BANCOVAR
        MOVWF       DATA_BYTE
        RETURN




ACKNOWLEDGE_BIT      ;--------------------------------------------------------
        CALL	    BANCO1
	    BCF 	    SSPCON2,    ACKDT   ;modalità ack
 	    BSF 	    SSPCON2,    ACKEN   ;invia ack o nack
ACKNOWLEDGE_TIME	    BTFSC       SSPCON2,    ACKEN
	    GOTO        ACKNOWLEDGE_TIME    ;attendi fine acknowledge bit 	    
        RETURN






NOACKNOWLEDGE_BIT	;--------------------------------------------------------
	    CALL	    BANCO1
	    BSF 	    SSPCON2,    ACKDT   ;modalità nack
 	    BSF 	    SSPCON2,    ACKEN   ;invia ack o nack
NOACKNOWLEDGE_TIME	    BTFSC       SSPCON2,    ACKEN
	    GOTO        NOACKNOWLEDGE_TIME  ;attendi fine noacknowledge bit 	    
	    RETURN	





  
        
        
STOP_BIT        ;--------------------------------------------------------
        CALL        BANCO1
        BSF	        SSPCON2,    PEN	    ;invia stop bit
STOP_TIME        
	    BTFSC	    SSPCON2,    PEN	    ;stop bit spedito?
	    GOTO        STOP_TIME           ;No! attendi...
        RETURN        
        



SCRIVI_SLAVE    ;--------------------------------------------------------
        CALL        BANCO0
        BCF         PIR1,       SSPIF	;pulisci interrupt flag
        CALL        BANCOVAR
        MOVF        DATA_BYTE,  0
        CALL        BANCO0
        MOVWF       SSPBUF	
WDATA_TIME        
        BTFSS       PIR1,       SSPIF   ;il dato seriale è stato spedito?
        GOTO        WDATA_TIME           ;no! attendi...
        CALL        BANCO1
ACKSLAVE_TIME        
        BTFSC	    SSPCON2,    ACKSTAT	;SLAVE pronto?
        GOTO        ACKSLAVE_TIME       ;no! attendi...
        RETURN






I2CCONF ;----------------------------------------------------------------
        CALL        BANCO1
        CLRF        TRISB		        ;PORTB in uscita (verrà controllato da MSSP
        BSF         SSPSTAT,    SMP	    ;I2C slew rate control disabilitato (100KHz)
        CALL        BANCO0
        MOVLW       00101000B
        MOVWF       SSPCON              ;abilita I2C modalità MASTER
        CALL        BANCO1
        MOVLW       0x09		        ;I2C clock 100kHz
       	MOVWF       SSPADD
       	BSF         TRISC,      SCL		;I2C SCL in ingresso (sarà controllato da MSSP)
       	BSF         TRISC,      SDA     ;I2C SDA in ingresso (sarà controllato da MSSP)
	    CALL        BANCO0
        BSF	        PORTC,      SCL		
        BSF         PORTC,      SDA
        RETURN





CHIAMA_SLAVE;--------------------------------------------------------------------------
                                        ;1)Invia Start Bit 
                                        ;2)Invia indirizzo Slave
                                        ;3)Se non ricevi ACK, rispedisci Start e riprova
;START_BIT   
        CALL        BANCO1
        BSF         SSPCON2,    SEN
START_TIME
        BTFSC       SSPCON2,    SEN
		GOTO        START_TIME          ;attendi fine start bit
INDIRIZZA_SLAVE
        CALL        BANCO0
        BCF         PIR1,       SSPIF	;cancella flag interrupt ricevuto
        NOP
        CALL        BANCOVAR
	    MOVF	    SLAVEADDR,  0
	    CALL        BANCO0
	    MOVWF       SSPBUF		        ;scrivi indirizzo dispositivo su MSSP buffer
ADDR_TIME	    
	    BTFSS	    PIR1,       SSPIF	;SLAVEADDR è stato inviato?
	    GOTO        ADDR_TIME           ;NO: ripeti controllo.
	    CALL        BANCO1
	    BTFSS	    SSPCON2,    ACKSTAT	; ricevuto ACK da parte dello SLAVE?
	    RETURN		                    ;Si!: Slave pronto
	    BSF	        SSPCON2,    RSEN    ;No!: invia nuovamente Start-Bit
RSTART_TIME
	    BTFSC       SSPCON2,    RSEN
	    GOTO        RSTART_TIME         ;Attendi fine Start-Bit
        GOTO        INDIRIZZA_SLAVE     ;indirizza di nuovo
        RETURN




;DEFINIZIONE BANCHI ;----------------------------------------------------
BANCO0
bancosim                ;#SIMULAZIONE   
        BCF         STATUS, RP1
        BCF         STATUS, RP0
        RETURN
BANCO1
BANCOVAR                                ;banco delle variabili e STACK
        BCF         STATUS, RP1
        BSF         STATUS, RP0
        RETURN
BANCO2
        BSF         STATUS, RP1
        BCF         STATUS, RP0
        RETURN
BANCO3
        BSF         STATUS, RP1
        BSF         STATUS, RP0
        RETURN
	

        END
