Here is a working 18F2455 I2C slave. It will receive or send any amount of bytes you choose. The slave will not work if USB is enable on the chip.
In this example the Master is sending 0 to 127 on byte(0), and fixed data on Bytes 1 and 2.
The Slave sends three bytes back, tests the received byte(0) and lights a couple of leds. When the master sends (Byte(0) = 4), the slave ends three different bytes back. I also have eight leds connected to the slave, four on PortB 4-7 and four on PortA 0-3. These leds display the value of the received Byte(0).
Slave code
It seems the 18F chips are very sensitive to the correct timing. Also it is a good idea to read AN734B to understand the difference between I2C slave with 16F chips and 18F chips.Code:'* Date : 3/17/2009 * '* Version : 1.0 * '* Notes : * '* : 18F2550 Slave I2c * '**************************************************************** asm __CONFIG _CONFIG1L, _PLLDIV_5_1L & _FCMEN_OFF_1H __CONFIG _CONFIG1H, _FOSC_HS_1H __CONFIG _CONFIG2L, _VREGEN_OFF_2L __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H __CONFIG _CONFIG3H, _PBADEN_OFF_3H __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L endasm DEFINE OSC 20 Define I2C_SLOW 1 'At this clock speed this needed to be added to make it work. DEFINE I2C_HOLD 1 ADCON1 = $F 'All digital CMCON = 7 'PortA Digital '--------------- Define used register flags ------------------- SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 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 STAT_BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full STAT_RW VAR SSPSTAT.2 ' SSP (I2C) Read/Write STAT_DA VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKE VAR SSPSTAT.6 ' SSP (I2C) Data/Address WrData var byte j var byte '------------------- Rx Buffer defintion -------------------- RxBufferLEN con 16 RxBuffer var byte[Rxbufferlen] RxBufferIndex var byte RxCnt var byte rxcnt = 0 '------------------ Tx Buffer defintion ---------------------- TxBufferLEN con 3 TxBuffer var byte[txbufferlen] TxBufferIndex var byte TxCnt var byte txcnt = 0 '------------------ Define vars ------------------------ rxinptr var byte rxoutptr var byte txinptr var byte txoutptr var byte rxinptr = 0 rxoutptr = 0 txinptr = 0 txoutptr = 0 I2Caddress CON $02 ' Make address = 2 result VAR BYTE ' ADC result DummyRead var byte DataIn VAR BYTE[8] ' Data in DataOut VAR BYTE[8] ' Data out array readcnt VAR BYTE ' I2C read count address var byte StatMask var byte StatMask = %00101101 readcnt = 0 ' Zero counter ' PicBasic Pro I2C slave program ' Alias pins Led1 var PORTC.0 LED2 Var PORTC.1 scl VAR PORTB.1 ' I2C clock input sda VAR PORTB.0 ' I2C data input TRISB = %00000011 TRISC = %00000000 TRISA = %00000000 LATB = $F0 'PortA= $0F PORTA = $0F 'leds off on A port PORTB = $F0 ' Leds off on B port high LED1 high led2 ' -------------- Initialize I2C slave mode ------------------------ SSPADD = I2Caddress ' Set our address SSPCON1 = $36 ' Set to I2C slave with 7-bit address SSPCON2 = %00000000 ' clear sspcon2 SSPCON2 = %00000001 'enable clock stretching SSPSTAT = %00000000 ' clear sspstat SSPIE = 1 'Enable MSSP interrupt enable bit SSPIF = 0 'Clear MSSP interrupt flag RxBufferIndex = 0 TxBufferIndex = 0 Temp var byte RxIndex var byte TxIndex var byte Stat var byte dataout[0] = 41 ' just some data to start with dataout[1] = 122 dataout[2] = 103 dataout[3] = 4 ' ' Interrupt definition ' ' ==================== ' ' USB interrupt used to keep USB connection alive INCLUDE "DT_INTS-18.bas" ' Base Interrupt System INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes endm INT_CREATE ; Creates the interrupt processor endasm @ INT_ENABLE SSP_INT ; Master Synchronous Serial Port Interrupt Flag bit. The transmission/reception is complete '----------------------[ Skip over subs ]-------------------------------------- goto Programstart I2C_Int: If R_W = 0 then 'Write from master if D_A = 0 then ' It's address from master address = SSPBUF ' do nothing rxinptr = 0 ' Clear counters rxoutptr = 0 else WCOL = 0 sspov = 0 if bf = 1 then 'There is data in buffer if rxcnt < rxbufferlen then rxbuffer[rxinptr] = SSPBUF rxinptr = rxinptr + 1 if rxinptr = rxbufferlen then rxinptr = 0 endif rxcnt = rxcnt + 1 EndIF endif else ' Read by master if SSPSTAT = %00001101 then 'last byte was an address byte. txinptr = 0 'read BF txoutptr = 0 endif dummyread = SSPBUF 'dummy read empty buffer if bf = 0 then ' if buffer is empty if txcnt > 0 then ' Is there a byte to transfer SSPBUF = txbuffer[txoutptr] 'get the byte and send it txoutptr = txoutptr + 1 if txoutptr = txbufferlen then txoutptr = 0 txcnt = txcnt - 1 else 'no byte to send endif endif endif sspif = 0 CKP = 1 @ INT_RETURN '-------------------[ end of interrupt ]-------------------------------------- ' ************************************************************ ' * main program loop - * ' * * ' * .. * ' ************************************************************ ProgramStart: if txcnt < txbufferlen then TxBuffer[txinptr] = dataout[txinptr] txinptr = txinptr + 1 if txinptr = txbufferlen then txinptr = 0 txcnt = txcnt + 1 endif if rxcnt != 0 then datain[rxoutptr] = rxbuffer[rxoutptr] rxoutptr = rxoutptr + 1 if rxoutptr = rxbufferlen then rxoutptr = 0 endif rxcnt = rxcnt - 1 endif Select case datain[0] 'Test data from master byte 0 case 0 low led1 'turn on LED1 case 1 high led1 'turn off led1 low led2 'turn on led2 case 2 low led1: low led2 'turn on both case 3 high led1: high led2 'turn off both case 4 'Change the data out to master dataout[0] = 44 dataout[1] = 45 dataout[2] = 46 end select 'Eight leds for testing, 4 on Port b and four on Port a portb = ~datain(0) <<4 'Lower nibble to RB4 to RB7 porta = ~(datain(0) & $F0)>>4 'upper nibble RA0 to RA3 goto ProgramStart end
Hope this helps someone out
Dave




Bookmarks