;---=== PIC Defines ===--- ;------------------------- ; PIC16F877A DEFINE OSC 20 'Oscillator speed in MHz: 3(3.58) 4 8 10 12 16 20 24 25 32 33 40 'Setup for 9600 baud DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 17 ' 9600 Baud @ -0.03% '************************************************************ '* I2C_Subs ;************************************************************ I2CBufferSize con 64 Reg_Pointer Var Byte ; Address register I2CDATA Var Byte ; data to read/write I2CAddr Var Byte ; Device address I2C_Wait var byte countI2C var byte I2CWRBuff var byte (I2CBufferSize) I2CWRsize Var Byte I2CRDBuff var byte (I2CBufferSize) I2CRDsize Var Byte I2CErrCode Var Byte I2CErrCode = 0 SSPSTAT.7 = 0 ; SMP<7> - Slew rate control Enabled (400kHz) SSPCON = %00101000 ; | ''''-- SSPM<3:0> - I2C Master mode, clock = FOSC / (4 * (SSPADD+1)) ; '-------- SSPEN<5> - Synchronous Serial Port Enable bit SSPADD = $0E ; set I2C clock rate to 400kHz 'SSPADD = $59 ; set I2C clock rate to 100kHz goto Over_I2C_Subs ;----------------------------------------------------------- ; Main Routines ;----------------------------------------------------------- Write1Byte: I2CErrCode.1 = 0 I2CAddr.0 = 0 ;Set Write Bit Gosub StartI2C ;Send Start, Addr, Wait for Ack if I2CErrCode.1 = 1 then RETURN I2CDATA = I2CWRBuff(0) gosub I2CWRByte ;Send I2CDATA Byte Gosub SendStopBit ;Send Stop Bit Return ;----------------------------------------------------------- WriteXBytes: I2CErrCode.1 = 0 I2CAddr.0 = 0 ;Set Write Bit Gosub StartI2C ;Send Start, Addr, Wait for Ack if I2CErrCode.1 = 1 then RETURN For countI2C = 0 to I2CWRsize-1 I2CDATA = I2CWRBuff(countI2C) ; hserout [dec countI2C,"-",ihex2 I2CDATA," ",13,10] gosub I2CWRByte ;Send I2CDATA Byte next countI2C Gosub SendStopBit ;Send Stop Bit Return ;----------------------------------------------------------- Read1Byte: I2CErrCode.1 = 0 I2CAddr.0 = 1 ;Set Read Bit Gosub StartI2C ;Send Start, Addr, Wait for Ack if I2CErrCode.1 = 1 then RETURN gosub I2CRDByte I2CRDBuff(0) = I2CDATA gosub Send_NO_Ack Gosub SendStopBit Return ;----------------------------------------------------------- ReadXBytes: I2CErrCode.1 = 0 I2CAddr.0 = 1 ;Set Read Bit Gosub StartI2C ;Send Start, Addr, Wait for Ack if I2CErrCode.1 = 1 then RETURN for countI2C = 0 to I2CRDsize-2 gosub I2CRDByte gosub Send_Ack I2CRDBuff(countI2C) = I2CDATA next countI2C countI2C = I2CRDsize - 1 gosub I2CRDByte gosub Send_NO_ACK Gosub SendStopBit I2CRDBuff(countI2C) = I2CDATA Return ;----------------------------------------------------------- ; Process Routines ;----------------------------------------------------------- StartI2C: ;Send Start Bit SSPCON2.0 = 1 ; SEN<0> - Send start bit while SSPCON2.0 = 1 : wend ; Wait for completion ;Send Slave Address PIR1.3 = 0 ; SSPIF - Clear interrupt Flag SSPBUF = I2CAddr ; move slave address to SSPBUF While PIR1.3 = 0 : Wend ; SSPIF - Wait for SSP to complete sending slave address ;Wait for Acknowledge or Restart i2c_wait = 0 ; Reset wait counter While SSPCON2.6 = 1 ; Wait for Acknowledge from slave 1=NotAck I2C_Wait = I2C_Wait + 1 ; Increment wait counter if I2C_Wait = 0 then ; Wait for 256 counts goto I2CResError ; Acknowledge "Time Out" - Report error and RETURN else ; Send Repeated Start SSPCON2.1 = 1 ; RSEN - Send Repeated Start while SSPCON2.1 = 1 : wend ; Wait for completion ; Resend the Slave Address PIR1.3 = 0 ; SSPIF - Clear interrupt Flag SSPBUF = I2CAddr ; move slave address to SSPBUF While PIR1.3 = 0 : Wend ; SSPIF - Wait to complete sending Slave Address endif wend RETURN ; Acknowledge recieved Return ;----------------------------------------------------------- I2CWRByte: PIR1.3 = 0 ; SSPIF - Clear interrupt Flag SSPBUF = I2CDATA ; Move data to SSPBUF While PIR1.3 = 0 : Wend ; SSPIF - Wait for SSP to complete sending ;Wait for Acknowledge or Abort i2c_wait = 0 ; Reset wait counter While SSPCON2.6 = 1 ; Wait for Acknowledge from slave 1=NotAck I2C_Wait = I2C_Wait + 1 ; Increment wait counter if I2C_Wait = 0 then ; Wait for 256 counts goto I2CResError ; Acknowledge "Time Out" - Report error and RETURN endif wend RETURN ; Acknowledge recieved Return ;----------------------------------------------------------- I2CRDByte: PIR1.3 = 0 ; SSPIF - Clear interrupt Flag SSPCON2.4 = 1 ; RCEN - Enable receive mode While PIR1.3 = 0 : Wend ; SSPIF - Wait for SSP to complete receiving I2CDATA = SSPBUF Return ;----------------------------------------------------------- SendStopBit SSPCON2.2 = 1 ; PEN - send stop bit While SSPCON2.2 = 1 : Wend ; Wait for SSP to complete Return ;----------------------------------------------------------- Send_NO_Ack: SSPCON2.5 = 1 ; ACKDT - Set Ack bit to NotAck SSPCON2.4 = 1 ; ACKEN - send ACKDT bit While SSPCON2.4 = 1 : Wend ; Wait for SSP to complete Return ;----------------------------------------------------------- Send_Ack: SSPCON2.5 = 0 ; ACKDT - Set Ack bit to Ack SSPCON2.4 = 1 ; ACKEN - send ACKDT bit While SSPCON2.4 = 1 : Wend ; Wait for SSP to complete Return ;----------------------------------------------------------- I2CResError: I2CErrCode.1 = 1 hserout [13,10,"I2C Error!!!",13,10] Return ;----------------------------------------------------------- Over_I2C_Subs: ;******************************************************************************* ;* EEPROM_256k_subs: Routines for a 256k EEPROM. ;******************************************************************************* EEaddr CON %10100000 Col_Reg CON $08 Col_Sel VAR Byte Page_Val var word Row_Sel VAR Page_Val.highbyte Cell_Reg var Page_Val.lowbyte Page_Addr VAR WORD ;(0-8191 or $0000-$1FFF) EEX var word EEY var Word DumpStart var word DumpEnd var word Page_Val = 0 goto OverEEPROM ;------------------------------------------------------------------------------- ;---=== Wipe Entire EEPROM with FF ===--- ; This routine takes approx. 1 Second ; to complete entire wipe of 256K EEPROM EEPROM_Wipe: hserout ["Wiping EEPROM!",13,10] for EEX = 0 to 70 I2CWRBuff(EEX) = $FF next EEX for EEX = 0 to 511 EEY = EEX * 64 I2CAddr = EEAddr : I2CWRSize = 67 I2CWRBuff(0) = EEY.HIGHBYTE I2CWRBuff(1) = EEY.LOWBYTE ;Page Write FF GOSUB WriteXBytes next EEX hserout ["EEPROM Wipe Complete",13,10] return ;---=== Dump Entire EEPROM to HSEROUT ===--- EEPROM_DUMP: hserout ["Dumping EEPROM! "] eex = dumpstart * 64 hserout [" Starting:",ihex4 eex] hserout [" Ending :",ihex4 (DumpEnd*64)+63,13,10] hserout [rep "*"\102] hserout [13,10,rep " "\7] for eey = 0 to 31 hserout [hex2 eey," "] next eey I2CAddr = EEAddr I2CWRSize = 2 I2CWRBuff(0) = eex.highbyte ; High Byte of Page Register (Col 0-7) I2CWRBuff(1) = eex.Lowbyte ; Low Byte of Page Register (Row 0-255) GOSUB WriteXBytes ; Set EEPROM Read Address to Page Register I2CRDSize = 64 for eex = dumpstart to dumpend Gosub ReadXBytes ; Read Col_Reg and Row_Sel Bytes for eey = 0 to 63 if eey//32 = 0 then hserout [13,10] hserout [ihex4 ((eex * 64) + eey),": "] endif if I2CRDBuff(eey) = $FF then hserout ["-- "] else hserout [hex2 I2CRDBuff(eey), " "] endif next eey next eex hserout [13,10,rep "*"\102,13,10] hserout ["Dump Complete",13,10] return ;------------------------------------------------------------------------------- OverEEPROM: ;******************************************************************************* ;* Other I2C Implementation Samples (Using a DS1678 RTC) ;******************************************************************************* ClockAddr con %10010100 ; Device address Init_RTC: I2CAddr = ClockAddr : I2CWRSize = 2 ;Resest RTC Alarms I2CWRBuff(0) = $8: I2CWRBuff(1) = 0: Gosub WriteXBytes I2CWRBuff(0) = $9: I2CWRBuff(1) = 0: Gosub WriteXBytes I2CWRBuff(0) = $A: I2CWRBuff(1) = 0: Gosub WriteXBytes I2CWRBuff(0) = $B: I2CWRBuff(1) = 0: Gosub WriteXBytes ;Reset RTC Flags I2CWRBuff(0) = $E: I2CWRBuff(1) = %01010011: Gosub WriteXBytes I2CWRBuff(0) = $F: I2CWRBuff(1) = %00010000: Gosub WriteXBytes Return ;Get Time from DS1678 Get_Time: I2CWRBuff(0) = 0:I2CAddr = ClockAddr: Gosub Write1Byte I2CRDSize = 8: Gosub ReadXBytes Return Get_RTC_Time_and_Data: ;Get Time and Data from DS1678 I2CWRBuff(0) = 0:I2CAddr = ClockAddr: Gosub Write1Byte ;Set Pointer I2CRDSize = $43: Gosub ReadXBytes Return