;12i2c-V1.asm ;WWW.MWFTR.COM/book.html ;Charles Kim ;i2C Master Mode Program ;for use in 24LC16B Serial EEPROM access by 16F877 ;in I2C Master Mode Operation of SSP Module of 16F877 (with Fosc = 20 MHz ) ; ; by Charles J. Kim ; April 2003 ; ; All right reserved. 2003 ; ; I2C Master Mode Operation for EEPROM (slave) Access ; EEPROM SPEC: 1.Microchip 24LC16B (16K Bits or 2KBytes) ; 2.8 Internal blocks (256 Bytes for each block) ; I2C ADDRESS SPEC: ; 1. I2C Spec code for EEPROM SELECTION: 1010 must be the highest 4 Bits in ; the Higher Address ; 2. 3-bit Block Code (from 000 to 111) follows the EEPROM SELECTION bits ; 3. R/W bit follows to Complete the 8-bit Higher Address ; 4. Actual EEPROM address is selected by the 8-bit Lower Address ; ; ; =================================================================== list p=16f877 INTCON EQU 0x0B STATUS EQU 0x03 ZERO EQU 0x00 ;for STATUS PIR2 EQU 0x0D ;I2C Modules BCLIF EQU 0x03 ;Bus Interrupt Flag PIR1 EQU 0x0C SSPIF EQU 0x03 ;SSP Interrupt Flag (must be cleared for next I2C) PIE1 EQU 0x8C PIE2 EQU 0x8D BCLIE EQU 0x03 ;bUS iNTERRUPT Enable SSPCON EQU 0x14 WCOL EQU 0x07 ;Write Collision detect SSPSOV EQU 0x06 ;Receive Overflow Indicator SSPEN EQU 0x05 ;SSP Enable bit SSPCON2 EQU 0x91 ACKSTAT EQU 0x06 RCEN EQU 0x03 PEN EQU 0x02 RSEN EQU 0x01 SEN EQU 0x00 ACKEN EQU 0x04 ACKDT EQU 0x05 SSPSTAT EQU 0x94 SMP EQU 0x07 ;SMP=1 for 100KHz, SMP=0 for 400KHz (Choose 100KHZ) SSPADD EQU 0x93 baud100 EQU 0x31 ;100KHZ standard speed baud400 EQU 0x0B ;400KHz fast speed ($0B) TRISC EQU 0x87 SSPBUF EQU 0x13 ; TXSTA EQU 0x98 ;TX status and control RCSTA EQU 0x18 ;RX status and control SPBRG EQU 0x99 ;Baud Rate assignment TXREG EQU 0x19 ;USART TX Register RXREG EQU 0x1A ;USART RX Register PIR1 EQU 0x0C ;USART RX/TX buffer status (empty or full) RCIF EQU 0x05 ;PIR1<5>: RX Buffer 1-Full 0-Empty TXIF EQU 0x04 ;PIR1<4>: TX Buffer 1-empty 0-full TXMODE EQU 0x20 ;TXSTA=00100000 : 8-bit, Async RXMODE EQU 0x90 ;RCSTA=10010000 : 8-bit, enable port, enable RX BAUD EQU 0x0F ;0x0F (19200), 0x1F (9600) ; ; ; CBLOCK 0x20 temp Kount20us Kount120us ;Delay count (number of instr cycles for delay) Kount100us Kount1ms Kount10ms Kount1s Kount10s Kount1m ENDC ;========================================================= ;The Next 5 lines must be here ;because of bootloader arrangement ;Bootloader first execute the first 4 addresses ;then jump to the address what the execution directs ;========================================================= org 0x0000 ;line 1 GOTO START ;line 2 ($0000) NOP ;line 3 ($0001) NOP ;line 4 ($0002) NOP ;line 5 ($0003) ;====================================================== ;start of the program from $0004 START call ASYNC_MODE ;for RS232 ;i2c operation ;PORTC setup - SDA and SCL both as inputs movlw 0x18 ;0001 1000 banksel TRISC movwf TRISC ;RC4 (SDA) and RC3(SCL) as inputs ;MSSP Module Setup movlw baud100 ;100KHz speed banksel SSPADD movwf SSPADD ;write baud rate movlw 0x80 ;1000 0000 banksel SSPSTAT movwf SSPSTAT ;100KHZ (no slew rate control) ;selection with I2C mode movlw 0x28 ;0010 1000 (SSPEN=1, SSPM3:0= 1000 ) master mode banksel SSPCON movwf SSPCON ;=========================================================================== ;WRITING for a byte data ;Sequence ;1. Start event ;2. Send Control Byte for EPEROM with Write Op ; CONTROL BYTE STRUCTURE OF 24LC16B ; 1 0 1 0 A2 A1 A0 R/W ; The first 4-bit code is establisihed for serial EEPROM by the I2C Bus Specification ; Next 3 bits are for Block Select (26LC16B has 8 blocks, with each block having 256 Bytes) ; R/W = 1 for reading ; R/W = 0 for writing ;3. Wait for ACK from EEPROM (Use SSPIF of PIR1) ;4. Send the address in a block of EEPROM ;5. Wait for ACK from EEPROM ;6 Send a byte of data ;7. Wait for ACK from EEPROM ;8. STop EVENT

;9. Give 24LC16 a few ms to write the data ;==================================================================== ; SEQUENCE IN WRITING ; PIC (master Side) >S>> >C>> >A>> >D>> >P>> ; 24LC16 (slave side) <S>> call i2cStart ;>C>> movlw 0xA0 call i2cSend ;block code write to 24LC16 ;>A>> movlw 0x00 ;address info call i2cSend ;>D>> movlw 'm' ;1 byte data call i2cSend ;>P>> call i2cSTOP call delay10ms ; call delay10ms ; ;================================================================ ;Sequence of Data (random) Read operation ; >S>> >C>> >A>> >RS>> >C>> <P>> ; <S>> ;2. Send Control Byte to Slave (with RW=0 i.e., write) >C>> ;3. Check for ACK from slave <A>> ;5. Wait for ACK <RS>> ;7.Send Control Byte to EEPROM again (with RW=1 i.e. now we read) >C>> ;8. wait for ACK <P>> ;================================================================= ;disable i2c ; banksel SSPCON ; movlw 0x08 ; banksel SSPCON ; movwf SSPCON ;Flag Clear ; banksel PIR1 ; bcf PIR1, SSPIF ;clear the SSP flag ;enable i2C ; banksel SSPCON ; movlw 0x28 ; movwf SSPCON ; movlw 0x18 ; banksel TRISC ; movwf TRISC ;>S>> call I2CStart ;>C>> movlw 0xA0 call i2cSend ;>A>> movlw 0x00 call i2cSend ;>RS>> REPEATED START call i2cRstart call delay100us ;>C>> ; COntrol Byte = 10100001=0xA1 for READ movlw 0xA1 banksel SSPBUF movwf SSPBUF call delay100us ;< W ; banksel temp ; movwf temp ;W --> TEMP ; Send NACK to 24LC16 call i2cNack ;>P>> call i2cSTOP banksel SSPBUF movf SSPBUF,0 ;EEPROM data --> W call DATATX movlw '.' call DATATX movlw H'0d' ;CR call DATATX movlw H'0a' ;LF call DATATX FINI nop goto FINI ;idling ;sybroutine I2CSTART ===== I2Cstart banksel SSPCON2 bsf SSPCON2, SEN ;START banksel PIR1 Swait btfss PIR1, SSPIF goto Swait bcf PIR1, SSPIF return ;-------------------------------------------------- ;subroutine i2cblock for write i2cSend banksel SSPBUF movwf SSPBUF banksel PIR1 cwait btfss PIR1, SSPIF goto cwait bcf PIR1, SSPIF return ;------------------------------------------------ ;---------------- ;sybroutine I2CRSTART (Repeated Start. Use in READING ===== i2cRstart banksel SSPCON2 bsf SSPCON2, RSEN ;REPEATED START return ;-------------------------------------------------- ;SUBROUTINE i2cREAD READ event ============= i2cREAD banksel SSPCON2 bsf SSPCON2, RCEN banksel PIR1 ;read event completion check Rwait btfss PIR1, SSPIF goto Rwait bcf PIR1, SSPIF return ;--------------------------------------------- ;SUBROUTINE I2CSTOP ============================================= I2CSTOP banksel SSPCON2 bsf SSPCON2, PEN banksel PIR1 Pwait btfss PIR1, SSPIF goto Pwait bcf PIR1, SSPIF return ;--------------------------------------- ;subroutine i2cNack banksel SSPCON2 bsf SSPCON2, ACKDT bsf SSPCON2, ACKEN banksel PIR1 nwait btfss PIR1, SSPIF goto Nwait bcf PIR1, SSPIF return ;-------------------------------- ;SUBROUTINE ACK from SLAVE ============================ ACK banksel SSPCON2 ackwait btfsc SSPCON2, ACKSTAT ;test for ACK ;from slave (ACKSTAT=0 if rec.) goto ackwait return ;-------------------------------------------------- ;subroutine ACKTX ======================== ;SENDING ACK from EEPROM PC MONITOR ACKTX banksel PIR1 btfss PIR1, TXIF goto ACKTX ;if full, wait movlw 'A' banksel TXREG movwf TXREG return ;==subroutine DATATX ;W contains the data to be transferred to PC DATATX banksel PIR1 btfss PIR1, TXIF goto DATATX ;if full, wait banksel TXREG movwf TXREG return ;======================================== ;======================================== Async_mode banksel SPBRG movlw baud movwf SPBRG ;Baud Rate Setup movlw TXMODE movwf TXSTA banksel RCSTA movlw RXMODE movwf RCSTA return ;========================================= ;========================================================== ;DELAY SUBROUTINES ; 1 instruction cycle for 20MHz clock is 0.2 us ; Therefore 120 uS delay needs 600 instuction cycles ; 600 =199*3 +3 ---->Kount=199=0xC7 ; or =198*3 +6 ---->Kount=198=0xC6 ; or =197*3 +9 ---->Kount=197=0xC5 Delay20us banksel Kount20us movlw H'1F' ;D'31' movwf Kount20us R20us decfsz Kount20us goto R20us return ; ; Delay120us banksel Kount120us movlw H'C5' ;D'197' movwf Kount120us R120us decfsz Kount120us goto R120us return ; ;100us delay needs 500 instruction cycles ; 500 =166*3 +2 ---->Kount=166=0xA6 ; or =165*3 +5 ---->Kount=165=0xA5 ; or =164*3 +8 ---->Kount=164=0xA4 Delay100us banksel Kount100us movlw H'A4' movwf Kount100us R100us decfsz Kount100us goto R100us return ; ;10ms delay ; call 100 times of 100 us delay (with some time discrepancy) Delay10ms banksel Kount10ms movlw H'64' ;100 movwf Kount10ms R10ms call delay100us decfsz Kount10ms goto R10ms return ; ; ;1 sec delay ;call 100 times of 10ms delay Delay1s banksel Kount1s movlw H'64' movwf Kount1s R1s call Delay10ms decfsz Kount1s goto R1s return ; ; ;10 s delay ;call 10 tiems of 1 s delay Delay10s banksel Kount10s movlw H'0A' ;10 movwf Kount10s R10s call Delay1s decfsz Kount10s goto R10s return ; ;1 min delay ;call 60 times of 1 sec delay Delay1m banksel Kount1m movlw H'3C' ;60 movwf Kount1m R1m call Delay1s decfsz Kount1m goto R1m return ;====================================================== END