' Program HBUS.INC
' HBUSIN amd HBUSOUT macros
' Using the Master Synchronous Serial Port (MSSP). Configured as an I2C master.
' The Eread and Ewrite subroutines, as well as the individual I2C conditions, are written in assembler for more efficiency.

' ** Declare some SYSTEM Variables **
		GEN			Var Word	SYSTEM		' 16-bit address of eeprom
        PP0			Var Byte	SYSTEM		' 8-bit Slave address
        PP0H		Var Byte	SYSTEM		' Byte to access eeprom				
		
' Configure the SSP for master I2C mode
'		TRISC.3 = 1											' Make Portc.3 an input (SCL)
'    	TRISC.4 = 1											' Make Portc.4 an input (SDA)
    	SSPSTAT = %01000000									' Disable the slew rate for normal 100khz operation
        													' Set the input levels to conform to I2C specs
    	SSPADD = ((XTAL * 1000) / (100 * 4)) - 1 			' Calculate the Baud rate value for SSPADD
    	SSPCON = %00101000									' I2C master mode selected and Enable the SSP
                
		Goto Over_SSP_Subs						' Jump over rhe subroutines
'-----------------------------------------------------------------------------------------------
' Create the HBUSIN and HBUSOUT macros
HBUSOUT MACRO SLAVE_ADDRESS , ADDRESS , Byteout1

		#if (PRM_1 == BYTE)
        	Byte_Byte SLAVE_ADDRESS , PP0
        #endif
		#if (PRM_1 == WORD)
        	Byte_Byte SLAVE_ADDRESS , PP0
        #endif
        #if ((PRM_1 == NUM8) || (PRM_1 == NUM16))
        	Num_Byte SLAVE_ADDRESS , PP0
        #endif

		#if (PRM_2 == BYTE)
        	Byte_Word ADDRESS , GEN
        #endif
		#if (PRM_2 == WORD)
        	Word_Word ADDRESS , GEN
        #endif
        #if ((PRM_2 == NUM8) || (PRM_1 == NUM16))
        	Num_Word ADDRESS , GEN
        #endif        		

        #if(PRM_C >= 3)
        	Call EEREAD
			#if (PRM_3 == BIT)
        		Byte_Bit Byteout1,PP0H
        	#endif
            #if (PRM_3 == BYTE)
        		Byte_Byte Byteout1,PP0H
        	#endif
			#if (PRM_3 == WORD)
        		Byte_Word Byteout1,PP0H
        	#endif
            Call EEWRITE
        #endif       			
		ENDM
        
HBUSIN	MACRO SLAVE_ADDRESS , ADDRESS , Bytein1
		#if (PRM_1 == BYTE)
        	Byte_Byte SLAVE_ADDRESS , PP0
        #endif
		#if (PRM_1 == WORD)
        	Byte_Byte SLAVE_ADDRESS , PP0
        #endif
        #if ((PRM_1 == NUM8) || (PRM_1 == NUM16))
        	Num_Byte SLAVE_ADDRESS , PP0
        #endif

		#if (PRM_2 == BYTE)
        	Byte_Word ADDRESS , GEN
        #endif
		#if (PRM_2 == WORD)
        	Word_Word ADDRESS , GEN
        #endif
        #if ((PRM_2 == NUM8) || (PRM_1 == NUM16))
        	Num_Word ADDRESS , GEN
        #endif
                       
        #if(PRM_C >= 3)
        	Call EEREAD
			#if (PRM_3 == BIT)
        		Byte_Bit PP0H , Bytein1
        	#endif
            #if (PRM_3 == BYTE)
        		Byte_Byte PP0H , Bytein1
        	#endif
			#if (PRM_3 == WORD)
        		Byte_Word PP0H , Bytein1
        	#endif
        #endif               
    	ENDM
'-----------------------------------------------------------------------------------------------        
' ** ASSEMBLER SUBROUTINES **
'-----------------------------------------------------------------------------------------------
Asm
;************************** 
;* Generate an I2C START  * 
;************************** 
Send_Start 
		Bsf STATUS,RP0							; Point to register Bank1        	
		Bsf SSPCON2,SEN					; Send a start condition
		#if (WATCHDOG_REQ == 1)
			Clrwdt
            Btfsc SSPCON2,SEN			; Wait for the Start condition to end
			Goto $ - 2
		#else
			Btfsc SSPCON2,SEN			; Wait for the Start condition to end
			Goto $ - 1
        #endif
        Bcf STATUS,RP0					; Point back to register Bank0
		Return
;-----------------------------------------------------------------------------------------------
;************************** 
;* Generate an I2C STOP   * 
;**************************
Send_Stop
		Bsf STATUS,RP0							; Point to register Bank1
		Bsf SSPCON2,PEN					; Send a start condition
		#if (WATCHDOG_REQ == 1)
			Clrwdt
            Btfsc SSPCON2,PEN			; Wait for the Stop condition to end
			Goto $ - 2
        #else
			Btfsc SSPCON2,PEN			; Wait for the Stop condition to end
			Goto $ - 1
		#endif
        Bcf STATUS,RP0					; Point back to register Bank0
		Return
;-----------------------------------------------------------------------------------------------
;*************************** 
;* Generate an I2C RESTART * 
;***************************
Send_Restart
		Bsf STATUS,RP0							; Point to register Bank1
		Bsf SSPCON2,RSEN				; Send a repeat start condition
		#if (WATCHDOG_REQ == 1)
			Clrwdt
        	Btfsc SSPCON2,RSEN			; Wait for the Restart condition to end
			Goto $ - 2
        #else
        	Btfsc SSPCON2,RSEN			; Wait for the Restart condition to end
			Goto $ - 1
		#endif
		Bcf STATUS,RP0					; Point back to register Bank0
		Return
;-----------------------------------------------------------------------------------------------
;*************************** 
;* Generate an I2C NACK    * 
;***************************
Send_NACK
		Bsf STATUS,RP0					; Point to register Bank1
		Bsf SSPCON2,ACKDT				; Sent the NACK condition
		Bsf SSPCON2,ACKEN
		#if (WATCHDOG_REQ == 1)
			Clrwdt
        	Btfsc SSPCON2,ACKEN			; Check if we are in idle mode
			Goto $ - 2
        #else
        	Btfsc SSPCON2,ACKEN			; Check if we are in idle mode
			Goto $ - 1
		#endif
		Bcf STATUS,RP0					; Point back to register Bank0
		Return
;-----------------------------------------------------------------------------------------------
;*********************** 
;* Send a byte via I2C * 
;*  Send the contents  *
;*     of the W reg    *
;*********************** 
Out_Byte
		Movwf SSPBUF					; Place the byte to output into the buffer
		Bsf STATUS,RP0					; Point to register Bank1
        #if (WATCHDOG_REQ == 1)
        	Clrwdt
        	Btfsc SSPSTAT,R_W			; Check if data transmit is complete
			Goto $ - 2
			;Clrwdt
            ;Btfsc SSPCON2,ACKSTAT		; Check if acknowledge was received
			;Goto $ - 2
        #else
        	Btfsc SSPSTAT,R_W			; Check if data transmit is complete
			Goto $ - 1
			;Btfsc SSPCON2,ACKSTAT		; Check if acknowledge was received
			;Goto $ - 1
		#endif
        Bcf STATUS,RP0					; Point back to register Bank0
		Return
;-----------------------------------------------------------------------------------------------
;************************** 
;* Receive a byte via I2C * 
;*  The byte received is  *
;*   held in the W reg    *
;**************************
In_Byte
		Bsf STATUS,RP0					; Point to register Bank1
        Bsf SSPCON2,RCEN				; Send Receive condition		
        #if (WATCHDOG_REQ == 1)
			Clrwdt
        	Btfsc SSPCON2,RCEN
			Goto $ - 2
            Clrwdt
			Btfss SSPSTAT,BF			; Wait for buffer to fill up
			Goto $ - 2
        #else
        	Btfsc SSPCON2,RCEN
			Goto $ - 1
			Btfss SSPSTAT,BF			; Wait for buffer to fill up
			Goto $ - 1
		#endif
        Bcf STATUS,RP0					; Point back to register Bank0
		Movfw SSPBUF					; Place the buffer into W	
		Return
;-----------------------------------------------------------------------------------------------
;*********************** 
;* Send the 16-bit     *
;* address via I2C     * 
;*********************** 	
Send_Address
		Call Send_Start					; Send a START condition
		Bcf PP0,0						; Set the R/W bit to WRITE
		Movfw PP0						; Send the device+slave address+ WRITE bit
		Call Out_Byte
		Movfw GENH						; Send the highbyte of the 16-bit address
		Call Out_Byte
		Movfw GEN						; Send the lowbyte of the 16-bit address
		Call Out_Byte
		Return
Endasm	
'-----------------------------------------------------------------------------------------------
' Write a single byte to the Eeprom
' The address is held in the variable "GEN"
' The byte to be written is held in the variable "PP0H"
EEWrite:
		TRISC.3 = 1						; Make Portc.3 an input (SCL)				
    	TRISC.4 = 1						; Make Portc.4 an input (SDA)
Asm        
        Call Send_Address				; Send the Start, slave address, and memory address
		Movfw PP0H						; Send the byte to be placed within the eeprom
		Call Out_Byte
		Call Send_Stop					; Send a STOP condition
Endasm
		Return							' Basic RETURN command
'-----------------------------------------------------------------------------------------------
' Read a single byte from the Eeprom
' The address is held in the variable "GEN"
' The byte read is returned in the variable "PP0H"
EERead:
		TRISC.3 = 1					; Make Portc.3 an input (SCL)				
    	TRISC.4 = 1					; Make Portc.4 an input (SDA)
Asm
		Call Send_Address			; Send the Start, slave address, and memory address
		Call Send_Restart			; Send a Restart condition
		Bsf PP0,0					; Set the R/W bit to READ	
		Movfw PP0
		Call Out_Byte				; Send the device+slave address+ READ bit
		Call In_Byte				; Read the byte from the eeprom (returned in E_BYTEIN)
		Movwf PP0H					; Place the buffer into E_Bytein
		Call Send_NACK				; Send a NACK condition (to release the SDA line)
		Call Send_Stop				; Send a STOP condition
Endasm
		Return
'-----------------------------------------------------------------------------------------------
' Make sure the HBUS library fits in the first page
Asm
    if ($ >= H'0800')
    ERROR "HBUS has exceeded page 0."
    endif
Endasm
Over_SSP_Subs:
	
