Although my slave example may not be as robust as AN734, I have systems running that have 14 slaves running. All 14 slaves are polled on 2 second intervals. The master uses bit-banging (I2CWrite). I have never had trouble with the code below. I have tested it with -
18F8723, 18F2221, 18F2321, 18F2523 and had excellent results.
Code:'**************************************************************** '* Name : I2C slave * '* Author : Charles Linquist * '* Notice : Copyright (c) 2010 [select VIEW...EDITOR OPTIONS] * '* : All Rights Reserved * '* Date : 10/20/2010 * '* Version : 1.0 * '* Notes : Transmits 100 bytes in ~14 ms (Master SEND) * '* : Recives 100 bytes in ~12 ms (Master RECEIVE) * '* : Could possibly go faster. Master used for the * '* : test used bit-banging (I2CREAD/I2CWRITE * '* : settings on that end were * '* : DEFINE I2C_SLOW 1 ,DEFINE I2C_HOLD 1 * '**************************************************************** ASM ifndef __18F2221 error "18F2221 not selected" endif ENDASM ASM movlw 0x62 ; %0110 0010 = 4 Mhz, internal osc block movwf OSCCON movlw 0x80 ; %1000 0000 = PLL disabled movwf OSCTUNE ENDASM DATA @0,0 ; programming flag DEFINE OSC 4 DEFINE NO_CLRWDT 1 ' Don't waste cycles clearing WDT Define USE_LFSR 1 define USE_LOWPRIORITY 1 ;---------------- Alias the bits ------------------------------------ SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 ' Int Enable SSPUA VAR SSPSTAT.1 SSPS VAR SSPSTAT.3 SSPP VAR SSPSTAT.4 SSPSMP VAR SSPSTAT.7 BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKP VAR SSPCON1.4 ' SSP (I2C) SCK Release Control SSPEN VAR SSPCON1.5 ' SSP (I2C) Enable SSPOV VAR SSPCON1.6 ' SSP (I2C) Receive Overflow Indicator WCOL VAR SSPCON1.7 ' SSP (I2C) Write Collision Detect GENCALL VAR SSPCON2.7 ' General Call enabled MainTimer var word bankA System I2CTimer var word bankA System I2CTimerGate var byte bankA System I2CErr var byte bankA System ;------------------------------------------------------------------------- ;Alias pins SCL VAR PORTC.3 ' I2C clock input SDA VAR PORTC.4 ' I2C data input LED VAR PORTB.5 '------------------- Rx Buffer defintion -------------------- RxBufferLEN con 10 RxBuffer var BYTE[Rxbufferlen + 1] TxBufferLEN CON 10 TXBuffer VAR BYTE[TxBufferLEN + 2] InBuff VAR BYTE GeneralCall VAR BIT RXBufferOverFlow VAR BIT TxBufferUnderFlow VAR BIT RXBufferPointer VAR Byte TXBufferPointer VAR Byte address VAR BYTE x VAR BYTE dummy var byte I2CAddress VAR BYTE WCOLCounter VAR BYTE ;------------------------------------------------------------- TXBuffer[TxBufferLen + 1] = $FF ; Char to send if requestor asks for too much. I2CDeviceAddress VAR BYTE I2CMajorAddress CON $3 I2CDeviceAddress = $8 I2CAddress = (I2CMajorAddress <<4) | I2CDeviceAddress ;--------------------------------------------------------------- SSPADD = I2Caddress ' Set our address SSPCON2.0 = 1 ; Stretch the clock SSPSTAT = 0 SSPEN = 1 SSPIE = 1 SSPIF = 0 GenCall = 1 ; Turn general call on SSPCON2.7 = 1 ' General call address ENABLED SSPCON1 = $36 ' Set to I2C slave with 7-bit address ;--------------------------------------------------------------- TRISA = %11111111 TRISB = %11011111 TRISC = %11111111 ' -------------- Turn on Ints ------------------------ INTCON.7 = 1 ; global ints INTCON.6 = 1 ; peripheral ints ;------------------ Clear parameters -------------- RXBufferPointer = 0 TxBufferPointer = 0 GeneralCall = 0 RxBufferOverFlow = 0 TXBufferUnderFlow = 0 WCOLCounter = 0 ;--------------------------------------------------------------------- INCLUDE "DT_INTS-18.bas" ' Base Interrupt System INCLUDE "ReEnterPBP-18.bas" ' Use PBP interrupts include "ReEnterPBP-18LP.bas" ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler TMR0_INT, TimerInt, ASM, yes endm INT_CREATE ; Creates the interrupt processor INT_LIST_L macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes endm INT_CREATE_L ; Creates the LP interrupt processor endasm ''----------------- Initialization Done! ----------------------------- Goto OverInt ; jump over ISR asm TimerInt infsnz MainTimer incf MainTimer + 1 btfsc I2CTimerGate,0 ; Don't count if low bit is clr incf I2CTimer btfss I2CTimer,2 ; Bit 2 is set , we have at least 4 counts, we must be hung bra NoProb bcf PIR1,3 ; Clear Int flag bcf SSPCON1,5 ; Stop the bsf SSPCON1,5 bsf I2CErr,0 clrf I2CTimer NoProb bcf INTCON,2 INT_RETURN endasm '------------------------- I2C subroutine -------------------------------- I2C_Int: ; We don't get here uless someone has matched our address register. @ bsf I2CTimerGate,0 ; start the counter If R_W = 0 then 'This is a WRITE by the master to us IF BF = 0 Then goto i2CEXIT ; Nothing for us! if D_A = 0 then 'We have an address address = SSPBUF 'Need to READ to satisfy Microchip IF Address = 0 THEN GeneralCall = 1 ELSE GeneralCall = 0 ENDIF else IF WCOL OR SSPOV THEN I2CExit RXBuffer [RxBufferPointer] = SSPBuf ; RxBufferPointer = RXBufferPointer + 1 IF RXBufferPointer > RxBufferLen THEN RXBufferOverFlow = 1 RXBufferPointer = 0 ENDIF ENDIF else ' R_W = 1 Master wants to read FROM us IF !D_A Then TxBufferPointer = 0 ' Mark as first read RXBufferPointer = 0 EndIF IF CKP THEN I2CExit dummy = SSPBUF ;NECESSARY! If TXBufferPointer < TxbufferLen THEN SENDI2C: WCOL = 0 SSPBUF = TXBuffer[TXBufferPointer] ' Get data from array IF WCOL THEN WCOLCounter = WCOLCounter + 1 ; Don't hang the bus with infinite WRITES! IF WColCounter = 0 Then goto I2CExit ; Rolled over Goto SendI2C ; Rety ELSE WColCounter = 0 ENDIF TXBufferPointer = TXBufferPointer +1 TXBufferPointer = TXBufferPointer MIN TXBufferLen + 1 ; Don't let it get larger than this ; Send FFs if requestor asks for too much data ELSE TXBufferPointer = 0 TXBufferUnderflow = 1 ENDIF ENDIF I2CEXIT: Asm bcf SSPCON1,6 bcf SSPSTAT,0 bcf PIR1,3 bsf SSPCON1,4 bcf I2CTimerGate,0 ; stop the counter INT_ENABLE SSP_INT ; probably don't need this, but want to make certain it gets reenabled INT_RETURN endasm ' -------------------------end I2C subroutine -------------------------------- '--------------------[ main program loop]--------------------------------------- OverInt: Asm clrf MainTimer clrf I2CTimer bcf INTCON,2 bcf PIR1,3 ; Clear the I2C flag before we turn on the INT. movlw 0x83 movf T0CON INT_ENABLE SSP_INT INT_ENABLE TMR0_INT endasm MAIN PROGRAM LOOP GOES HERE!




Bookmarks