On Tue, 6 Jan 2004 09:00:19 -0000, Alan B. Pearce wrote on Re: [PIC:] Pic as an i2c slave: >> At the moment I am looking for something really elusive, and >> I am specifically searching for a source of inspiration that >> would help me discover whether it is me, the compiler and >> relevant interrupt routines, the litterature, or the stupid >> silicium that is the problem. >> >> So far and with help of an oscilloscope I have been unable >> to eliminate any of these four potential culprits (PIC >> silicium has had bugs in the MSSP for some revisions and >> chips, Microchip documentation has had flaws, Application >> notes code my Microchip have bugs etc), > >hang on a minute. Are you really telling us that the code in Microchip >Application Note AN734 doesn't work?=20 I am saying that it does not work reliably (i.e. on every occurence) in my context, that is as an assembler routine inserted in my Basic application, with use of preamble and postamble routines to the effect of saving and restoring the PIC's registers and the compiler internal variables. >I used this code to make my interrupt driven I2C slave module quite = satisfactorily.=20 This information is valuable indeed, because it seems to show that the logics are OK (they seem to be when analysed with the PIC's reference book as a bible) and work for some people in some contexts.=20 Would you care indicate whether yours was a large application (how busy the PIC was when not managing i2c), and whether the i2c was managed in the program's main loop or as a real interrupt service routine? >If you have a look in the PICList archive for messages with the subject = line "I2C Troubles" you will >find all the info you need on this. I have found this message a long time ago and taken note that some people had had problems running that AN734 code until it apparently was corrected. The message (by Bob Blick) says this: *** On Sun, 24 Mar 2002, Claudio Tagliola wrote: > Now I'm confused too, I am working with that appnote and the sample = code > works correctly, even after the first transfer. Does this behaviour = only > pop up on specific I2C master devices? Hi Claudio, The sample works except when you read from the slave. In the example they forgot to set CKP after the slave is done transmitting. Cheers, Bob *** Apparently , a "CKP =3D 1" instruction, or rather, in assembler, bsf SSPCON,CKP ; Release the clock. was missing. Problem is this instruction is present in the "Doi2cWrite" sub, which is called every time the slave is read by the master (states 3 and 4). So my question is "where is (or was) that instruction missing?".=20 Also, if it is not missing in the version I have, why does it basically work, but unreliably? More mysteries... =46or reference, here is the AN734 routine I used: ************************************************ ;----------------------------------------------- ; Software License Agreement ; ; The software supplied herewith by Microchip Technology Incorporated=20 ;(the =93Company=94) for its PICmicro=AE Microcontroller is intended and=20 ; supplied to you, the Company=92s customer, for use solely and=20 ; exclusively on Microchip PICmicro Microcontroller products. The=20 ; software is owned by the Company and/or its supplier, and is=20 ; protected under applicable copyright laws. All rights are reserved.=20 ; Any use in violation of the foregoing restrictions may subject the=20 ; user to criminal sanctions under applicable laws, as well as to=20 ; civil liability for the breach of the terms and conditions of this=20 ; license. ; ; THIS SOFTWARE IS PROVIDED IN AN =93AS IS=94 CONDITION. NO WARRANTIES,=20 ; WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED=20 ; TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A=20 ; PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,=20 ; IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR ; CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. ; ;--------------------------------------------------------------------- ; File: an734.asm ; ; Written By: Stephen Bowling, Microchip Technology ; ; Version: 1.00 ; ; Assembled using Microchip Assembler=20 ; ; Functionality: ; ; This code implements the basic functions for an I2C slave device ; using the SSP module. All I2C functions are handled in an ISR. ; Bytes written to the slave are stored in a buffer. After a number ; of bytes have been written, the master device can then read the ; bytes back from the buffer. ; ; Variables and Constants used in the program: ; ; The start address for the receive buffer is stored in the variable ; 'RXBuffer'. The length of the buffer is denoted by the constant ; value 'RX_BUF_LEN'. The current buffer index is stored in the=20 ; variable 'Index'. ; ;-------------------------------------------------------------------- ;=20 ; The following files should be included in the MPLAB project: ; ; an734.asm-- Main source code file ; ; 16f872.lkr-- Linker script file ; (change this file for the device ; you are using) ; ;--------------------------------------------------------------------- ;--------------------------------------------------------------------- ; Include Files ;--------------------------------------------------------------------- #include ; Change to device that you are using. ;--------------------------------------------------------------------- ;Constant Definitions ;--------------------------------------------------------------------- #define NODE_ADDR 0x02 ; I2C address of this node ; Change this value to address that ; you wish to use. ;--------------------------------------------------------------------- ; Buffer Length Definition ;--------------------------------------------------------------------- #define RX_BUF_LEN 32 ; Length of receive buffer ;--------------------------------------------------------------------- ; Variable declarations ;--------------------------------------------------------------------- udata WREGsave res 1 STATUSsave res 1 =46SRsave res 1 PCLATHsave res 1 Index res 1 ; Index to receive buffer Temp res 1 ; RXBuffer res RX_BUF_LEN ; Holds rec'd bytes from master ; device. =09 ;--------------------------------------------------------------------- ; Vectors ;--------------------------------------------------------------------- STARTUP code nop =09 goto Startup ;=20 nop ; 0x0002 nop ; 0x0003 goto ISR ; 0x0004 PROG code ;--------------------------------------------------------------------- ; Macros ;--------------------------------------------------------------------- memset macro Buf_addr,Value,Length movlw Length ; This macro loads a range of data memory movwf Temp ; with a specified value. The starting movlw Buf_addr ; address and number of bytes are also=20 movwf FSR ; specified. SetNext movlw Value movwf INDF incf FSR,F decfsz Temp,F goto SetNext endm LFSR macro Address,Offset ; This macro loads the correct value movlw Address ; into the FSR given an initial data=20 movwf FSR ; memory address and offset value. movf Offset,W addwf FSR,F endm ;--------------------------------------------------------------------- ; Main Code ;--------------------------------------------------------------------- Startup bcf STATUS,RP1 bsf STATUS,RP0 call Setup Main clrwdt ; Clear the WDT =09 goto Main ; Loop forever. =09 ;--------------------------------------------------------------------- ; Interrupt Code ;--------------------------------------------------------------------- ISR movwf WREGsave ; Save WREG movf STATUS,W ; Get STATUS register banksel STATUSsave ; Switch banks, if needed. movwf STATUSsave ; Save the STATUS register movf PCLATH,W ; movwf PCLATHsave ; Save PCLATH movf FSR,W ; movwf FSRsave ; Save FSR banksel PIR1 btfss PIR1,SSPIF ; Is this a SSP interrupt?=09 goto $ ; No, just trap here. bcf PIR1,SSPIF call SSP_Handler ; Yes, service SSP interrupt. =09 banksel FSRsave movf FSRsave,W ; movwf FSR ; Restore FSR movf PCLATHsave,W ;=20 movwf PCLATH ; Restore PCLATH movf STATUSsave,W ; movwf STATUS ; Restore STATUS swapf WREGsave,F ; swapf WREGsave,W ; Restore WREG =09 retfie ; Return from interrupt. =09 ;--------------------------------------------------------------------- Setup ; ; Initializes program variables and peripheral registers. ;--------------------------------------------------------------------- banksel PCON bsf PCON,NOT_POR bsf PCON,NOT_BOR banksel Index ; Clear various program variables clrf Index clrf PORTB clrf PIR1 banksel TRISB clrf TRISB movlw 0x36 ; Setup SSP module for 7-bit=20 banksel SSPCON movwf SSPCON ; address, slave mode movlw NODE_ADDR banksel SSPADD movwf SSPADD clrf SSPSTAT =09 =09 banksel PIE1 ; Enable interrupts bsf PIE1,SSPIE bsf INTCON,PEIE ; Enable all peripheral interrupts bsf INTCON,GIE ; Enable global interrupts bcf STATUS,RP0 return ;--------------------------------------------------------------------- SSP_Handler ;--------------------------------------------------------------------- ; The I2C code below checks for 5 states: ;--------------------------------------------------------------------- ; State 1: I2C write operation, last byte was an address byte. ; ; SSPSTAT bits: S =3D 1, D_A =3D 0, R_W =3D 0, BF =3D 1 ; ; State 2: I2C write operation, last byte was a data byte. ; ; SSPSTAT bits: S =3D 1, D_A =3D 1, R_W =3D 0, BF =3D 1 ; ; State 3: I2C read operation, last byte was an address byte. ; ; SSPSTAT bits: S =3D 1, D_A =3D 0, R_W =3D 1, BF =3D 0 ; ; State 4: I2C read operation, last byte was a data byte. ; ; SSPSTAT bits: S =3D 1, D_A =3D 1, R_W =3D 1, BF =3D 0 ; ; State 5: Slave I2C logic reset by NACK from master. ;=09 ; SSPSTAT bits: S =3D 1, D_A =3D 1, R_W =3D 0, BF =3D 0 ; ; For convenience, WriteI2C and ReadI2C functions have been used. ;---------------------------------------------------------------------- banksel SSPSTAT movf SSPSTAT,W ; Get the value of SSPSTAT andlw b'00101101' ; Mask out unimportant bits in SSPSTAT. banksel Temp ; Put masked value in Temp movwf Temp ; for comparision checking. State1: ; Write operation, last byte was an movlw b'00001001' ; address, buffer is full. xorwf Temp,W ;=20 btfss STATUS,Z ; Are we in State1? goto State2 ; No, check for next state..... =09 memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer. clrf Index ; Clear the buffer index. call ReadI2C ; Do a dummy read of the SSPBUF. return =09 State2: ; Write operation, last byte was data, movlw b'00101001' ; buffer is full. xorwf Temp,W btfss STATUS,Z ; Are we in State2? goto State3 ; No, check for next state..... =09 LFSR RXBuffer,Index ; Point to the buffer. call ReadI2C ; Get the byte from the SSP. movwf INDF ; Put it in the buffer. incf Index,F ; Increment the buffer pointer. movf Index,W ; Get the current buffer index. sublw RX_BUF_LEN ; Subtract the buffer length. btfsc STATUS,Z ; Has the index exceeded the buffer length? clrf Index ; Yes, clear the buffer index. return =09 State3: ; Read operation, last byte was an movlw b'00001100' ; address, buffer is empty. xorwf Temp,W btfss STATUS,Z ; Are we in State3? goto State4 ; No, check for next state..... =09 clrf Index ; Clear the buffer index. LFSR RXBuffer,Index ; Point to the buffer movf INDF,W ; Get the byte from buffer. call WriteI2C ; Write the byte to SSPBUF incf Index,F ; Increment the buffer index. return =09 State4: ; Read operation, last byte was data, movlw b'00101100' ; buffer is empty. xorwf Temp,W btfss STATUS,Z ; Are we in State4? goto State5 ; No, check for next state.... =09 movf Index,W ; Get the current buffer index. sublw RX_BUF_LEN ; Subtract the buffer length. btfsc STATUS,Z ; Has the index exceeded the buffer length? clrf Index ; Yes, clear the buffer index. LFSR RXBuffer,Index ; Point to the buffer movf INDF,W ; Get the byte call WriteI2C ; Write to SSPBUF incf Index,F ; Increment the buffer index. return State5: movlw b'00101000' ; A NACK was received when transmitting xorwf Temp,W ; data back from the master. Slave logic btfss STATUS,Z ; is reset in this case. R_W =3D 0, D_A =3D 1 goto I2CErr ; and BF =3D 0 return ; If we aren=92t in State5, then something is=20 ; wrong. I2CErr nop banksel PORTB ; Something went wrong! Set LED bsf PORTB,7 ; and loop forever. WDT will reset goto $ ; device, if enabled. return ;--------------------------------------------------------------------- ; WriteI2C ;--------------------------------------------------------------------- WriteI2C banksel SSPSTAT btfsc SSPSTAT,BF ; Is the buffer full? goto WriteI2C ; Yes, keep waiting. banksel SSPCON ; No, continue. DoI2CWrite bcf SSPCON,WCOL ; Clear the WCOL flag. movwf SSPBUF ; Write the byte in WREG btfsc SSPCON,WCOL ; Was there a write collision? goto DoI2CWrite bsf SSPCON,CKP ; Release the clock. return ;--------------------------------------------------------------------- ReadI2C ;--------------------------------------------------------------------- =09 banksel SSPBUF movf SSPBUF,W ; Get the byte and put in WREG return =09 end ; End of file * Xrobert.soubie@free.frX (veuillez supprimer les "X") * http://www.astrosurf.com/soubie * Au royaume des aveugles, les borgnes sont mal vus... - P.Dac -- http://www.piclist.com hint: To leave the PICList mailto:piclist-unsubscribe-request@mitvma.mit.edu