; ;********************************************************************** ; i2ccmd.asm - Polled and Interrupt based I2C and EEPROM routines ;********************************************************************** ; ; John E. Andrews ; April 3rd, 1998 ; ; The following functions are included: ; InitI2C ; init the SSP peripheral and variables for I2C operation ; I2CRead ; read one byte from i2c address x ; I2CWrite ; write an x parameter to i2c addr x ; EERead ; read eeprom location x ; EEWrite ; write an x parameter into eeprom location x ; KickEERead ; read a string at eeprom location x via interrupts ; KickEEWrite ; write a string at eeprom location x via interrupts ; KickI2CRead ; read a string from an i2c slave via interrupts ; KickI2CWrt ; write reply addr, byte count and data to i2c addr ; I2CIsr ; I2C interrupt service routine ; ; The init function and the routines to start i2c master data tranfers ; are called by inline code. The init function is called at reset and ; the master data transfers are associated with PICos commands. ; I2CIsr provides continuous interrupt based slave or master data ; transfers and is called from the peripheral interrupt vector. It is ; terminated by a return to the peripheral interrupt service routine ; which restores context and performs the retfie. ; ; The default i2c slave address is defined here DfltSlvAddr equ 0x23 ; This address is shifted 1 bit left and used to match the address ; supplied at the beginning of an i2c transfer. This makes the lsb ; a don't care which is used by i2c to provide Read/write info. ; This address shouldn't be 0 since this is the general call address ; and it shouldn't be hex 50-5F since all 5x addresses are reserved ; by eeprom devices. Valid addresses are from 1-4F and 60-7F. ; This address can be changed at run time by the i2cAddr command. ; ; This data statement stores a constant ascii string in program ; memory. Its copied to a ram buffer using the CpyTbl2Buf macro in ; InitI2C and is output during slave transmit by I2CIsr. SlvRdD ; initial slave read data message data "Va Tech Rules!",0 ; ;********************************************************************** InitI2C ; initialize I2C operation after device reset ;********************************************************************** ; ; ***** Variables for I2C operation ***** ; i2cRxBufferSize equ 40 ; size of buffer for slave Rx data ; cblock ; declare bank 0 variables i2cState ; current I2C state i2cSlvAddr ; addr of i2c slave, 0-7F << 1, lsb=0 ; slave Rx buffer, allow extra char for 0 fill by command parser i2cRxBuffer: i2cRxBufferSize+1 i2cRxPtr ; pointer into Rx buffer used by inline code i2cIntRxPtr ; pointer into Rx buffer used by isr i2cDataPtr ; buffer pointer used for result output i2cAddr ; i2c addr for master transmit i2cRpyPend ; slave addr pending reply i2cRpyFncH ; function addr to involke on reply hi byte i2cRpyFncL ; function addr to involke on reply lo byte i2cByteCnt ; number of bytes in transfer packet i2cEEAddr ; addr in eeprom for current write cycle i2cFlags ; flag bits i2cSlvRdBuff: 20 ; buffer holding data for slave read i2cSlvPtr ; isr pointer into i2cSlvRdBuff endc ; ; bit flag definitions for i2cFlags i2cRxRdy equ 0 ; ; ***** executable code to init I2C operation ***** ; ; This function label is called once after device reset movlw DfltSlvAddr<<1 ; load default i2c slave address movwf i2cSlvAddr ; into gpr storage location bcf i2cSlvAddr, 0 ; clear lsb for Read/write bit setf i2cRpyPend ; init reply pending address to FF clrf i2cFlags ; init all flags to off ; ; Init buffer to be transmitted on slave read CpyTbl2Buf SlvRdD, i2cSlvRdBuff ; ; fall through to reset i2c to slave mode ; ;********************************************************************** RstI2C ; reset the SSP peripheral and variables for I2C slave operation ;********************************************************************** ; ; This function can be called by any routine wishing to reset the ssp ; to i2c slave operation. It sets up the SSP peripheral to provide ; buffered, line based, interrupt driven i2c slave receive and polled ; and interrupt driven i2c master transmit. EEPROM write and read are ; also provided including interrupt state machine driven, buffered, ; string input and output. ; movlb 6 ; select sfr bank for ssp movfp i2cSlvAddr, WREG ; fetch i2c slave address and movwf SSPADD ; load it into slave addr register movlw 0x36 ; enable ssp, set CKP, select I2C slave movwf SSPCON1 ; in SSPCON1 clrf i2cState ; init i2c state to idle movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts return ; ;********************************************************************* ; i2c slave mode command functions ;********************************************************************* SetI2C ; load hexidecimal parameter into i2c slave address ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2CADDR=x\r", CmdPC, "Set I2C slave address = 0-7F\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; ; copy hexidecimal parameter from buffer to SSPADD movlw cmdPrmBuff ; load parameter buffer addr movwf FSR1 ; into FSR1 movpf INDF1, WREG ; copy parameter to W ; shift address out of lsb which i2c uses for R/w bit rlncf WREG ; shift address left 1` bit bcf WREG, 0 ; clear lsb movwf i2cSlvAddr ; save in gpr call RstI2C ; set i2c slave address in ssp ; fall through to DspI2C ;********************************************************************* DspI2C ; create output string reporting i2c slave addr as a hex number ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2CADDR\r", CmdPC, "Display I2C slave address\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; copy first part of output string into output buffer using FSR0 CpyTbl2Out SlvD ; copy i2cSlvAddr value into output buffer as a hex number rrncf i2cSlvAddr, W ; unshift i2c slave addr into W bcf WREG, 7 ; clear msb of unshifted addr movlb 1 ; select SFR bank for PORTD movwf PORTD ; display on portd LEDs call Hex2Buf ; convert hex value into output buffer ; copy hex = into same output buffer using FSR0 CpyTbl2Out HxEqD ; display bits of address movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 7 ; skip if msb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 6 ; skip if nsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 5 ; skip if nsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 4 ; skip if nsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw ' ' ; load ascii ' ' into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 3 ; skip if nsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 2 ; skip if nsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '0' ; load ascii 0 char into W btfsc i2cSlvAddr, 1 ; skip if lsb is clear movlw '1' ; load ascii 1 char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw 'x' ; load ascii x char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '\n' ; load ascii LF char into W movwf INDF0 ; place char into output buffer incf FSR0 ; inc pointer to next char location movlw '\r' ; load ascii CR into last location in buff movwf INDF0 ; CR terminates cmd line when resubmited return ; return from Cmd ; This is the end of the functions executable code ; ; These data statements store constant ascii output strings in program ; memory. They're accessed using the CpyTbl2Out macro SlvD ; constant string for slave addr display data "\nI2C slave addr is ",0 HxEqD ; constant string for hex = display data " hex = ",0 ; ;********************************************************************* ; i2c master mode data transfer command functions ;********************************************************************* Wait4SSPIF macro ; this is equivalent to waiting for an ssp interrupt ;********************************************************************* ; ; switch banks and wait for SSPIF, clear and switch back to ssp bank movlb 1 ; select sfr bank for peripheral ints btfss PIR1, SSPIF ; poll for interrupt flag goto $-1 ; until then wait bcf PIR1, SSPIF ; s/w int flag clear movlb 6 ; select sfr bank for ssp endm ; ;********************************************************************* I2CRead ; read one byte from i2c address x ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2Cx\r", CmdPC, "Read byte at I2C addr x=0-7F\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value bsf SSPCON2, SEN ; initiate a start condition Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait movlw cmdPrmBuff ; load addr of parameter buffer movwf FSR1 ; into FSR1 rlncf INDF1, W ; read shifted i2c address into W bsf WREG, 0 ; set R/w bit for read movwf SSPBUF ; output i2c addr parameter Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait bsf SSPCON2, RCEN ; start receiving data byte Wait4SSPIF ; wait for SSPIF in PIR1 btfss SSPSTAT, BF ; skip once BF is set goto $-1 ; until then wait btfsc SSPCON2, RCEN ; skip once RCEN is cleared goto $-1 ; until then wait bsf SSPCON2, ACKDT ; generate nack to terminate read bsf SSPCON2, ACKEN ; start nack sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, ACKEN ; skip once ACKEN is cleared goto $-1 ; until then wait bsf SSPCON2, PEN ; initiate a stop sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait ; create output string reporting value of data byte ; copy first part of output string into output buffer using FSR0 CpyTbl2Out I2CD ; copy i2c addr into output buffer as a hex number movfp INDF1, WREG ; read ee memory addr into W call Hex2Buf ; convert hex value into output buffer ; copy = into same output buffer using FSR0 CpyTbl2Out EqD ; copy data byte into output buffer as a hexidecimal number movfp SSPBUF, WREG ; read data byte into W call Hex2Buf ; convert hex value into output buffer ; put a LF and CR after the data movlw '\n' ; load LF char movwf INDF0 ; put it into the output string incf FSR0 ; point to next output char location movlw '\r' ; load ascii CR into last location in buff movwf INDF0 ; CR terminates cmd line when resubmited call RstI2C ; reset to i2c slave operation return ; return from Cmd ; This is the end of the functions executable code ; ; These data statements store constant ascii output strings in program ; memory. They're accessed using the CpyTbl2Out macro. I2CD ; constant string for i2c display data "\nI2C addr ",0 EqD ; constant string for = display data " = ",0 ; ;********************************************************************* I2CWrite ; write an x parameter to i2c addr x ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2Cx=x\r", CmdPC, "Write x at I2C addr x=0-7F\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value bsf SSPCON2, SEN ; initiate a start condition Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait movlw cmdPrmBuff ; load addr of start of parameter buffer movwf FSR1 ; into FSR1 rlncf INDF1, W ; read shifted i2c address into W bcf WREG, 0 ; clear R/w bit for write movwf SSPBUF ; output i2c addr parameter Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf FSR1 ; point to data parameter movpf INDF1, SSPBUF ; write data parameter to i2c Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait bsf SSPCON2, PEN ; initiate a stop sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return null result string from Cmd ; ;********************************************************************* EERead ; read eeprom location x ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "EEx\r", CmdPC, "Read byte at EEPROM addr x\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; movlw cmdPrmBuff ; load addr of parameter buffer movwf FSR1 ; into FSR1 movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value bsf SSPCON2, SEN ; initiate a start condition Wait4SSPIF ; wait for SSPIF in PIR btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait movlw 0xA0 ; load I2C addr parameter for ee write movwf SSPBUF ; output I2C addr parameter for ee write Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait movpf INDF1, SSPBUF ; output ee memory addr parameter Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait bsf SSPCON2, RSEN ; initiate a restart condition Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, RSEN ; skip once RSEN is cleared goto $-1 ; until then wait movlw 0xA1 ; load I2C addr parameter for ee read movwf SSPBUF ; output I2C addr parameter for ee read Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait bsf SSPCON2, RCEN ; start receiving data byte Wait4SSPIF ; wait for SSPIF in PIR1 btfss SSPSTAT, BF ; skip once BF is set goto $-1 ; until then wait btfsc SSPCON2, RCEN ; skip once RCEN is cleared goto $-1 ; until then wait bsf SSPCON2, ACKDT ; generate nack to terminate ee read bsf SSPCON2, ACKEN ; start nack sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, ACKEN ; skip once ACKEN is cleared goto $-1 ; until then wait bsf SSPCON2, PEN ; initiate a stop sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait ; create output string reporting value of data byte ; copy first part of output string into output buffer using FSR0 CpyTbl2Out EED ; copy ee memory addr into output buffer as a hexidecimal number movfp INDF1, WREG ; read ee memory addr into W call Hex2Buf ; convert hex value into output buffer ; copy = into same output buffer using FSR0 CpyTbl2Out EqD ; copy data byte into output buffer as a hexidecimal number movfp SSPBUF, WREG ; read data byte into W call Hex2Buf ; convert hex value into output buffer ; put a LF and CR after the data movlw '\n' ; load LF char movwf INDF0 ; put it into the output string incf FSR0 ; point to next output char location movlw '\r' ; load ascii CR into last location in buff movwf INDF0 ; CR terminates cmd line when resubmited call RstI2C ; reset to i2c slave operation return ; return from Cmd ; This is the end of the functions executable code ; ; These data statements store constant ascii output strings in program ; memory. They're accessed using the CpyTbl2Buf and CpyTblCont macros ; with the addresses given by the labels. EED ; constant string for ee display data "\nEEPROM addr ",0 ; ;********************************************************************* EEWrite ; write an x parameter into eeprom location x ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "EEx=x\r", CmdPC, "Write x at EEPROM addr x\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; movlw cmdPrmBuff ; load addr of start of parameter buffer movwf FSR1 ; into FSR1 movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value bsf SSPCON2, SEN ; initiate a start condition Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait movlw 0xA0 ; load I2C addr parameter for ee write movwf SSPBUF ; output I2C addr parameter for ee write Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait movpf INDF1, SSPBUF ; output ee memory addr parameter Wait4SSPIF ; wait for SSPIF in PIR1 incf FSR1 ; point to data parameter btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait movpf INDF1, SSPBUF ; write data parameter to ee Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait bsf SSPCON2, PEN ; initiate a stop sequence Wait4SSPIF ; wait for SSPIF in PIR1 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return null result string from Cmd ; ;********************************************************************* KickEERead ; read a string starting at eeprom location x via interrupts ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "S@EEx\r", CmdPC, "Read string starting at EEPROM addr x\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; ; Initialize flags and pointers for interrupt based I2C master read. ; ; wait for any ongoing buffered I2C activity to complete tstfsz i2cState ; skip when I2C xfer complete goto $-1 ; until then wait movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value movlw .10 ; load value for EERdStart into W movwf i2cState ; set I2C state to read start complete movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts movlb 6 ; select sfr bank for ssp bsf SSPCON2, SEN ; initiate a start sequence ; the resulting interrupt kicks off the i2c int based state machine ; wait here until int based I2C read is complete tstfsz i2cState ; skip once state is idle goto $-1 ; until then wait return ; return result string built by I2CIsr ; ;********************************************************************** KickEEWrite ; write a string starting at eeprom location x via interrupts ;********************************************************************** ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "S@EEx=s\r", CmdPC, "Write s starting at EEPROM addr x\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; ; This function initiates an interrupt driven, buffered, i2c master ; write to eeprom memory. The i2c bus addr and R/w bit are constant ; 0xA1 and 0xA0 respectively. The starting eeprom memory addr is ; provided by Cmd in cmdPrmBuff[0] and an ascii, 0 terminated, string ; parameter follows. ; An 8 byte eeprom write buffer size is assumed. When the least ; significant three bits of the just completed ee write addr = 7 then ; stop, start, i2c addr and R/w, and ee momory addr sequences are ; performed by succesive SSPIF interrupts. Then the data write ; interrupt sequence continues until the 0 termination is reached. ; ; Initialize flags and pointers for interrupt based I2C master write. ; ; wait for any ongoing buffered I2C activity to complete tstfsz i2cState ; skip when I2C xfer complete goto $-1 ; until then wait movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts ; init ee memory addr and ptr to ee data parameters movlw cmdPrmBuff ; load cmd parameter buffer addr movwf FSR1 ; into FSR1 movpf INDF1, i2cEEAddr ; save ee memory write addr parameter incf FSR1 ; inc pointer to first data value movpf FSR1, i2cDataPtr ; save ptr into I2C master buffer ptr ; init ssp peripheral to 100KHz i2c master @ 16MHz movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value incf i2cState ; set I2C state for write start complete movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts movlb 6 ; select sfr bank for ssp bsf SSPCON2, SEN ; initiate a start sequence ; the resulting interrupt kicks off the i2c int based state machine ; wait here until int based I2C write is complete to prevent buffer crash tstfsz i2cState ; skip once state is idle goto $-1 ; until then wait return ; I2C start initiated, return from Cmd ; ;********************************************************************* KickI2CRead ; read a string from an i2c slave via interrupts ;********************************************************************* ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2Cx:\r", CmdPC, "Read string from i2c slave addr x\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; ; Initialize flags and pointers for interrupt based I2C master read. ; ; wait for any ongoing buffered I2C activity to complete tstfsz i2cState ; skip when I2C xfer complete goto $-1 ; until then wait movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value movlw .24 ; load value for MstrRdStart into W movwf i2cState ; set I2C state to read start complete movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts movlb 6 ; select sfr bank for ssp bsf SSPCON2, SEN ; initiate a start sequence ; the resulting interrupt kicks off the i2c int based state machine ; wait here until int based I2C read is complete tstfsz i2cState ; skip once state is idle goto $-1 ; until then wait return ; return result string built by I2CIsr ; ;********************************************************************** KickI2CWrt ; write reply addr, byte count and data to i2c addr via interrupts ;********************************************************************** ; install this command in the CmdMenu lookup table CmdPC = $ ; save current inline assembly PC value org CurCmdMenuAdr ; set assembly PC to addr for new entry ; CmdMenu table entry data "I2Cx:s\r", CmdPC, "Xfer s to I2C addr x for execution\r\n" CurCmdMenuAdr = $ ; set current CmdMenu addr for next entry org CmdPC ; begin cmd code gen at inline address ; ; This function initiates an interrupt driven, buffered, i2c master ; write to an i2c slave. The i2c slave addr is provided by Cmd in ; cmdPrmBuff[0] and an ascii, 0 terminated, string parameter follows. ; The characters in the string are counted and transmitted until the ; byte count is exhausted. ; ; Initialize flags and pointers for interrupt based I2C master write. ; ; wait for any ongoing buffered I2C activity to complete tstfsz i2cState ; skip when I2C xfer complete goto $-1 ; until then wait movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts ; init i2c addr movlw cmdPrmBuff ; load cmd parameter buffer addr movwf FSR1 ; into FSR1 movpf INDF1, i2cAddr ; save i2c addr parameter into addr gpr rlncf i2cAddr ; shift i2c addr out of lsb bcf i2cAddr, 0 ; clear lsb for write movpf FSR1, i2cDataPtr ; save ptr prestart into master buffer ptr clrf i2cByteCnt ; init byte count ; loop here to count chars until 0 termination incf FSR1 ; inc to next char incf i2cByteCnt ; inc byte count tstfsz INDF1 ; skip if current char is 0 goto $-3 ; otherwise test next char movlw 0x0D ; load ascii CR char movwf INDF1 ; replace 0 with CR for input termination ; init ssp peripheral to 100KHz i2c master @ 16MHz movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value movlw .19 ; load state number for master transmit movwf i2cState ; set I2C state for write start complete movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts movlb 6 ; select sfr bank for ssp bsf SSPCON2, SEN ; initiate a start sequence ; the resulting interrupt kicks off the i2c int based state machine clrf cmdOutBuff ; prevent new cmd line prompt return ; I2C start initiated, return from Cmd ; ;********************************************************************** KickI2CRpy ; send reply to device which submitted command via i2c ;********************************************************************** ; ; This function initiates an interrupt driven, buffered, i2c master ; write to an i2c slave. The i2c slave addr is provided by Cmd in ; cmdPrmBuff[0] and an ascii, 0 terminated, string parameter follows. ; The characters in the string are counted and transmitted until the ; byte count is exhausted. ; ; Initialize flags and pointers for interrupt based I2C master write. ; ; wait for any ongoing buffered I2C activity to complete tstfsz i2cState ; skip when I2C xfer complete goto $-1 ; until then wait movlb 4 ; select sfr bank for PIE2 bcf PIE2, SSPIE ; disable SSP interrupts ; init i2c out pointer movlw cmdOutBuff - 1 ; load prestart of output buffer movwf FSR1 ; into FSR1 movwf i2cDataPtr ; and into master buffer ptr movlw 0x0D ; load ascii CR char into W clrf i2cByteCnt ; init byte count ; loop here to count chars until CR incf FSR1 ; inc to next char incf i2cByteCnt ; inc byte count cpfseq INDF1 ; skip if current char is CR goto $-3 ; otherwise test next char ; init ssp peripheral to 100KHz i2c master @ 16MHz movlb 6 ; select sfr bank for ssp movlw 0x28 ; enable ssp periph and select I2C Master movwf SSPCON1 ; in SSPCON1 movlw .19 ; SSPBRG value for 16MHz and 100KHz movwf SSPADD ; init baud rate generator reload value movlw .19 ; load state number for master transmit movwf i2cState ; set I2C state for write start complete movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; init interrupt flag bsf PIE2, SSPIE ; enable SSP interrupts movlb 6 ; select sfr bank for ssp bsf SSPCON2, SEN ; initiate a start sequence ; the resulting interrupt kicks off the i2c int based state machine return ; I2C start initiated, return from Cmd ; ;********************************************************************** I2CIsr ; I2C interrupt service routine ;********************************************************************** ; ; The following macro causes this function to be called from the ; peripheral interrupt vector when the SSPIF flag and SSPIE interrupt ; enable are set. This macro must be placed immediately following the ; label at the beginning of the isr function and prior to any ; executable code. ; ; include bit testing at the peripheral int vector at assembly time InstallISR 4, PIR2, SSPIF ; install isr for ssp ; ; This function must be terminated by a return to the peripheral isr ; which restores context and performs the retfie. ; ; Each time this function is called it clears the interrupt flag, ; initiates an action that will cause another interrupt to occur, ; and then returns. A state machine causes the correct action to be ; initiated during processing of each sequential interrupt. ; ; clear interrupt flag movlb 4 ; select sfr bank for PIE2 bcf PIR2, SSPIF ; s/w clear of interrupt flag movlb 6 ; select sfr bank for ssp ; ; The sequence of control for the ssp peripheral, i2c protocol, and ; i2c eeprom device is provided by a software state machine. This ; state machine is implimented as a jump table in which a variable, ; i2cState, is added to the current PC. This redirects processor ; execution into a block of sequential goto instructions. These goto ; instructions jump to the code to be executed for this state of the ; sequence This code can initiate an action that will cause another ; ssp interrupt. It also controls the value of i2cState vsriable ; which controls which state code will be executed on the next ssp ; interrupt. ; ; define mask that limits the range of value of the state variable i2cSizeMask equ 0x3F ; allow 64 states, must be a power of 2 ; Note: Macro fills jump table to this many instructions preventing ; branching beyond the end. ; ; ***** Executable code for I2C isr ***** ; movlw high (I2CJump) ; fetch upper byte of jump table address movwf PCLATH ; load into upper PC latch movlw i2cSizeMask ; load number of states andwf i2cState, W ; load the masked state variable into W addlw low (I2CJump) + 1 ; calc state machine jump addr into W btfsc ALUSTA, C ; skip if carry occured incf PCLATH ; otherwise add carry I2CJump ; address were jump table branch occurs, this addr also used in fill movwf PCL ; index into state machine jump table ; jump to processing for each state = i2cState value for each state goto I2CIdle ; i2c idle = 0 ; I2C master eeprom write state sequence w/ ack polling goto EEWrtStart ; write start sequence completed = 1 goto EEWrtCmd ; ee write command completed = 2 goto EEWrtAddr ; ee memory address out completed = 3 goto EEWrtData ; data out completed = 4 goto EEWrtStop ; stop sequence completed = 5 goto EEWrtBufFull ; eeprom write buffer full = 6 goto EEWrtFullStop ; restart new write = 7 goto EEWrtFullStart ; buff full start sequence complete = 8 goto EEWrtRdCmd ; ack test write command completed = 9 ; I2C master eeprom read state sequence goto EERdStart ; read start sequence completed = 10 goto EERdWrtCmd ; ee write command completed = 11 goto EERdAddr ; ee memory addr out completed = 12 goto EERdRestart ; restart sequence completed = 13 goto EERdCmd ; ee read command completed = 14 goto EERdData ; data read completed = 15 goto EERdAck ; ack sequence completed = 16 goto EERdNack ; nack sequence completed = 17 goto EERdStop ; stop sequence completed = 18 ; I2C master write state sequence goto MstrWrtStart ; write start sequence completed = 19 goto MstrWrtAddr ; i2c address out completed = 20 goto MstrRpyAddr ; reply address out completed = 21 goto MstrByteCnt ; byte count out completed = 22 goto MstrDataTx ; data buffer out completed = 23 ; I2C master read state sequence goto MstrRdStart ; read start sequence completed = 24 goto MstrRdAddr ; read address completed = 25 goto MstrRdData ; data read completed = 26 goto MstrRdAck ; ack sequence completed = 27 goto MstrRdStop ; stop sequence completed = 28 ; I2C slave write state sequence goto SlavRpyAddr ; reply address received = 29 goto SlavByteCnt ; byte count received = 30 goto SlavDataRx ; data byte received = 31 ; I2C slave read state sequence goto SlavDataTx ; read data sequence completed = 32 ; total range of jump table is set by i2cSizeMask ; fill with return from here to end of maximum I2CJump table Fill (return), I2CJump + i2cSizeMask - $ ; I2CIdle ; i2c idle = 0 btfsc SSPCON1, 3 ; skip if not in master mode goto $ ; otherwise muti-master error trap btfsc SSPSTAT, D_A ; skip if address was received goto $ ; otherwise data error trap ; i2c slave address match has occurred movfp SSPBUF, WREG ; clear address from SSPBUF btfsc SSPSTAT, R_W ; skip if operation is a write goto SlvRd ; otherwise operation is a read movlw i2cRxBuffer - 1 ; load prestart of Rx buffer movwf i2cIntRxPtr ; into pointer for slave receive movlw .29 ; load value for SlavRpyAddr movwf i2cState ; into i2cState return ; return to restore context and exit isr SlvRd ; slave transmission has been requested movlw i2cSlvRdBuff ; load start of slave read string movwf FSR1 ; into FSR1 movpf INDF1, SSPBUF ; load first char for transmission bsf SSPCON1, CKP ; release SCL to allow transfer movpf FSR1, i2cSlvPtr ; save pointer movlw .32 ; load value for SlavDataTx movwf i2cState ; into i2cState return ; return to restore context and exit isr ; ; ***** I2C master write state sequence ***** ; EEWrtStart ; write start sequence completed = 1 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait incf i2cState ; start complete increment I2C state movlw 0xA0 ; load I2C addr command for ee write movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; EEWrtCmd ; ee write command completed = 2 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; cmd out complete increment I2C state movfp i2cEEAddr, WREG ; fetch ee memory write addr movwf SSPBUF ; output ee memory write addr return ; return to restore context and exit isr ; EEWrtAddr ; ee memory address output completed = 3 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait ; start write of data pointed to by i2cDataPtr movfp i2cDataPtr, FSR1 ; load buffer pointer into FSR1 movpf INDF1, SSPBUF ; output ee memory data parameter tstfsz INDF1 ; skip if last output value was zero goto $+3 ; otherwise point to next data parameter ; last data output was 0, terminate write incf i2cState ; output 0 terminated, increment I2C state return ; return to restore context and exit isr ; last data output was not 0, test for ee buffer overflow incf i2cDataPtr ; inc pointer to next data value incf i2cEEAddr ; inc current ee write addr movlw 0x07 ; load mask for 8 byte ee write buffer andwf i2cEEAddr, W ; mask ee write addr into W tstfsz WREG ; is next addr at start of ee write buffer? ; if not return w/o changeing i2cState, this code again next int return ; return to restore context and exit int ; otherwise stop and resend ee memory addr before ack polling movlw 6 ; load numeric value for MstWrtBufFull movwf i2cState ; into MstWrtData, making it the next state return ; return to restore context and exit isr ; EEWrtData ; data out completed = 4 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; data out complete increment I2C state bsf SSPCON2, PEN ; initiate a stop sequence return ; return to restore context and exit isr ; EEWrtStop ; stop sequence completed = 5 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return to restore context and exit isr ; EEWrtBufFull ; eeprom write buffer full = 6 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; ee write buffer full inc I2C state bsf SSPCON2, PEN ; initiate a stop sequence return ; return to restore context and exit isr ; EEWrtFullStop ; buffer full stop sequence complete= 7 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait incf i2cState ; buffer full stop complete inc I2C state bsf SSPCON2, RSEN ; initiate a restart sequence return ; return to restore context and exit isr ; EEWrtFullStart ; buff full start sequence complete = 8 btfsc SSPCON2, RSEN ; skip once RSEN is cleared goto $-1 ; until then wait incf i2cState ; start complete, increment I2C state movlw 0xA0 ; load command for ee write to test ack movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; EEWrtRdCmd ; ack test write command completed = 9 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait btfss SSPCON2, ACKSTAT ; skip if no write ack goto $+4 ; otherwise ack received, cont write decf i2cState ; no ack, decrement I2C state bsf SSPCON2, RSEN ; initiate a restart sequence return ; return to restore context and exit isr ; ack received, eeprom ready, write eeprom memory address movlw 3 ; eeprom ready, load I2C state movwf i2cState ; so next state is memory write complete movfp i2cEEAddr, WREG ; fetch ee memory write addr movwf SSPBUF ; output ee memory write addr return ; return to restore context and exit isr ; ; ***** I2C master read state sequence ***** ; EERdStart ; read start sequence completed = 10 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait incf i2cState ; start complete increment I2C state movlw 0xA0 ; load I2C addr command for ee write movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; EERdWrtCmd ; ee write command out completed = 11 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; write cmd complete, increment I2C state movlw cmdPrmBuff ; load addr of cmd parameter buffer start movwf FSR1 ; into FSR1 movpf INDF1, SSPBUF ; output ee memory address parameter return ; return to restore context and exit isr ; EERdAddr ; ee memory address out completed = 12 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; ee addr out complete, increment I2C state bsf SSPCON2, RSEN ; initiate a restart condition return ; return to restore context and exit isr ; EERdRestart ; restart sequence completed = 13 btfsc SSPCON2, RSEN ; skip once RSEN is cleared goto $-1 ; until then wait incf i2cState ; restart complete, increment I2C state movlw 0xA1 ; load I2C addr command for ee read movwf SSPBUF ; output I2C addr command for ee read return ; return to restore context and exit isr ; EERdCmd ; read command completed = 14 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; read cmd complete increment I2C state movfp cmdOutPtr, WREG ; load cmd output pointer into W incf WREG ; point to next output buffer location movwf i2cDataPtr ; save it into I2C master pointer bsf SSPCON2, RCEN ; start receiving data byte return ; return to restore context and exit isr ; EERdData ; data read completed = 15 btfsc SSPCON2, RCEN ; skip once RCEN is cleared goto $-1 ; until then wait btfss SSPSTAT, BF ; skip once BF is set goto $-1 ; until then wait incf i2cState ; data read complete increment I2C state movfp i2cDataPtr, FSR1 ; load buffer pointer into FSR1 movfp SSPBUF, INDF1 ; copy ee data value into output buffer tstfsz INDF1 ; skip if last read value was zero goto EERdNZ ; otherwise jump to test output addr EERdZ ; last data read was zero, or buffer is full, send nack to end read movlw '\n' ; load LF to replace last char so that movwf INDF1 ; u1: will redraw cmd line prompt incf FSR1 ; point to next location movlw '\r' ; load ascii CR into last location in buff movwf INDF1 ; CR terminates cmd line when resubmited incf i2cState ; all data read so inc I2C state again bsf SSPCON2, ACKDT ; set nack to terminate ee read bsf SSPCON2, ACKEN ; start nack sequence return ; return to restore context and exit isr EERdNZ ; last data was not 0, if buffer full jump back to nack movlw cmdOutBuff + cmdOutBuffSize - 2 ; load end addr in cmdOutBuff cpfslt i2cDataPtr ; skip if output buffer is not full goto EERdZ ; otherwise buffer is full, send nack incf i2cDataPtr ; inc pointer to next output location bcf SSPCON2, ACKDT ; generate ack to continue ee read bsf SSPCON2, ACKEN ; start ack sequence return ; return to restore context and exit isr ; EERdAck ; ack sequence completed = 16 btfsc SSPCON2, ACKEN ; skip once ACKEN is cleared goto $-1 ; until then wait decf i2cState ; ack complete decrement I2C state bsf SSPCON2, RCEN ; start receiving data byte return ; return to restore context and exit isr ; EERdNack ; nack sequence completed = 17 btfsc SSPCON2, ACKEN ; skip once ACKEN is cleared goto $-1 ; until then wait incf i2cState ; nack complete increment I2C state bsf SSPCON2, PEN ; initiate a stop sequence return ; return to restore context and exit isr ; EERdStop ; stop sequence completed = 18 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return to restore context and exit isr ; ; ***** I2C master write state sequence ***** ; MstrWrtStart ; write start sequence completed = 19 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait incf i2cState ; start complete increment I2C state movfp i2cAddr, WREG ; load I2C addr movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; MstrWrtAddr ; i2c address out completed = 20 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait movfp i2cAddr, WREG ; move the acknowledged i2c addr movwf i2cRpyPend ; into the pending reply gpr incf i2cState ; data out complete, increment I2C state movfp i2cSlvAddr, WREG ; load local slave address for reply movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; MstrRpyAddr ; reply address out completed = 21 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; reply out complete, increment I2C state movfp i2cByteCnt, WREG ; load byte count movwf SSPBUF ; output I2C addr command for ee write return ; return to restore context and exit isr ; MstrByteCnt ; byte count out completed = 22 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cDataPtr ; point to new data location movfp i2cDataPtr, FSR1 ; load output buffer pointer into FSR1 movpf INDF1, SSPBUF ; put data value into buffer decfsz i2cByteCnt ; decrement byte count and skip if 0 return ; otherwise return to restore and exit isr incf i2cState ; data out complete, increment I2C state bsf SSPCON2, PEN ; initiate a stop sequence return ; return to restore context and exit isr ; MstrDataTx ; data buffer out completed = 23 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return to restore context and exit isr ; ; ***** I2C master read state sequence ***** ; MstrRdStart ; read start sequence completed = 24 btfsc SSPCON2, SEN ; skip once SEN is cleared goto $-1 ; until then wait incf i2cState ; start complete, increment I2C state movlw cmdPrmBuff ; load addr of cmd parameter buffer start movwf FSR1 ; into FSR movpf INDF1, WREG ; fetch i2c address parameter into W rlncf WREG ; shift i2c addr out of lsb bsf WREG, 0 ; set lsb for read movwf SSPBUF ; output addr / command for i2c read return ; return to restore context and exit isr ; MstrRdAddr ; i2c address out completed = 25 btfsc SSPSTAT, R_W ; skip once R/W is cleared goto $-1 ; until then wait incf i2cState ; i2c addr out complete, increment state movfp cmdOutPtr, WREG ; load cmd output pointer into W incf WREG ; point to next location, keeping \n movwf i2cDataPtr ; save it into I2C master pointer bsf SSPCON2, RCEN ; start receiving data byte return ; return to restore context and exit isr ; MstrRdData ; data read completed = 26 btfsc SSPCON2, RCEN ; skip once RCEN is cleared goto $-1 ; until then wait btfss SSPSTAT, BF ; skip once BF is set goto $-1 ; until then wait incf i2cState ; data read complete increment I2C state movfp i2cDataPtr, FSR1 ; load buffer pointer into FSR1 movfp SSPBUF, INDF1 ; copy ee data value into output buffer tstfsz INDF1 ; skip if last read value was zero goto MstrRdNZ ; otherwise jump to test output addr MstrRdZ ; last data read was zero, or buffer is full, send nack to end read movlw '\n' ; load LF to replace last char so that movwf INDF1 ; u1: will redraw cmd line prompt incf FSR1 ; point to next location movlw '\r' ; load ascii CR into last location in buff movwf INDF1 ; CR terminates cmd line when resubmited incf i2cState ; all data read so inc I2C state again bsf SSPCON2, ACKDT ; set nack to terminate ee read bsf SSPCON2, ACKEN ; start nack sequence return ; return to restore context and exit isr MstrRdNZ ; last data was not 0, if buffer full jump back to nack movlw cmdOutBuff + cmdOutBuffSize - 2 ; load end addr in cmdOutBuff cpfslt i2cDataPtr ; skip if output buffer is not full goto MstrRdZ ; otherwise buffer is full, send nack incf i2cDataPtr ; inc pointer to next output location bcf SSPCON2, ACKDT ; generate ack to continue ee read bsf SSPCON2, ACKEN ; start ack sequence return ; return to restore context and exit isr ; MstrRdAck ; ack sequence completed = 27 btfsc SSPCON2, ACKEN ; skip once ACKEN is cleared goto $-1 ; until then wait decf i2cState ; ack complete decrement I2C state bsf SSPCON2, RCEN ; start receiving data byte return ; return to restore context and exit isr ; MstrRdStop ; stop sequence completed = 28 btfsc SSPCON2, PEN ; skip once PEN is cleared goto $-1 ; until then wait call RstI2C ; reset to i2c slave operation return ; return to restore context and exit isr ; ; ***** I2C slave write state sequence ***** ; SlavRpyAddr ; reply address received = 29 movfp SSPBUF, WREG ; receive reply addr into W movwf i2cAddr ; store it in gpr incf i2cState ; inc i2c state to receive byte count return ; return to restore context and exit isr ; SlavByteCnt ; byte count received = 30 movfp SSPBUF, WREG ; receive byte count into W movwf i2cByteCnt ; store it in gpr incf i2cState ; inc i2c state to receive data return ; return to restore context and exit isr ; SlavDataRx ; data byte received = 31 incf i2cIntRxPtr ; point to new data location movfp i2cIntRxPtr, FSR1 ; load slave write buffer pointer into FSR1 movfp SSPBUF, INDF1 ; receive data value into buffer decfsz i2cByteCnt ; decrement byte count and skip if 0 return ; otherwise return to restore and exit isr bsf i2cFlags, i2cRxRdy ; set flag indicating buffer is ready clrf i2cState ; reset i2c state to idle return ; return to restore context and exit isr ; ; ***** I2C slave read state sequence ***** ; SlavDataTx ; read data sequence completed = 32 btfss SSPSTAT, R_W ; skip when ACK is sent goto SlvNACK ; otherwise nack was received incf i2cSlvPtr ; point to next char in read buffer movfp i2cSlvPtr, FSR1 ; load data read pointer into FSR1 movpf INDF1, SSPBUF ; load char for transmission bsf SSPCON1, CKP ; release SCL to allow transfer return ; otherwise return to restore and exit isr SlvNACK ; negative acknowledge has been sent, read is complete clrf i2cState ; reset i2c state to idle return ; return to restore context and exit isr ; movlb 1 ; select portd bank ; btg PORTD, 7 ; toggle debug bit ; movlb 6 ; select ssp bank ; movfp SSPSTAT, WREG ; fetch SSPSTAT into W ; movlb 1 ; select portd bank ; movwf PORTD ; display SSPSTAT on debug LEDs ; movlb 6 ; select ssp bank ; end of file i2ccmd.asm ******************************************************
Interested: