Slave I2C framework on 18F14K22

Coding and general discussion relating to user created compiler modules

Moderators: David Barker, Jerry Messina

Post Reply
Registered User
Registered User
Posts: 31
Joined: Tue May 31, 2011 2:59 pm
Location: Cambridge

Slave I2C framework on 18F14K22

Post by matherp » Sat Apr 21, 2012 2:19 pm

Thanks to the basis provided by octal I've produced a two way version of the slave i2c code working on a 14K22.

The basis of the framework is that the master sends a command byte with bit 7 (go bit) set, followed by any number of data bytes. The interrupt routine on the slave reads and stores the data and command and sets a flag for the main program when a new command has been received.

This allows the main program to act on the data and provide appropriate output in an output buffer. Once the processing is complete the main program clears the go bit in the command byte.

Thus the i2c master can send a command with data and then repeatedly read the command byte to check for the go bit being cleared. In this way it knows that the slave processing is completed and the data is ready for download

The example main slave program is:

Code: Select all

Device = 18F14K22
Clock = 64

Include "utils.bas"
Include "I2CSlave.bas"
Include "usart.bas"
Include "convert.bas"

dim i as byte




While true
     if i2cslave.dataavailable then
	 USART.Write("i2cStatus:", DecToStr(i2cstatus)," buff(0):",dectostr(DataBuffer(0)),13, 10)  // decimal number							  
          if i2cstatus=%10000001 then  ' process valid command
              for i=0 to databufferindex-1
          delayms(1000) 'make the master wait a bit to demonstrate polling
          i2cstatus=i2cstatus and %01111111 ' clear the go bit
   I2CSlave.DataAvailable = False
The slave i2c interrupt handling is:

Code: Select all

Module I2CSlave
#option ISR_SHADOW = false

' Registers And bits associated with i2c hardware SSP

' SSPSTAT bits
Dim BF As SSPSTAT.0     ' Buffer Full Status flag
Dim UA As SSPSTAT.1     ' Update Address bit
Dim R_W As SSPSTAT.2    ' Read/Write bit information bit
Dim S As SSPSTAT.3  ' Start bit
Dim P As SSPSTAT.4  ' STOPP bit
Dim D_A As SSPSTAT.5    ' Data/NOT_Address bit 
Dim CKE As SSPSTAT.6    ' SPI Clock Edge Select
Dim SMP As SSPSTAT.7    ' Sample bit

' SSPCON bits                                   Slave mode 7 bits
Dim SSPM0 As SSPCON1.0  ' SSP mode bits                 0
Dim SSPM1 As SSPCON1.1  ' "                             1
Dim SSPM2 As SSPCON1.2  ' "                             1
Dim SSPM3 As SSPCON1.3  ' "                             0
Dim CKP   As SSPCON1.4  ' Clock, 1 = Enable clock, 0 = clock stretch
Dim SSPEN As SSPCON1.5  ' SSP Enable Bit
Dim SSPOV As SSPCON1.6  ' Receive overflow indicator Bit. In receive mode, a
                          ' Byte is received While the SSPBUF is holding
                          ' previous Byte. Must be cleared in software.
Dim WCOL  As SSPCON1.7  ' Write collision detect Bit. In slave mode, 1 means
                          ' SSBUF written While transmitting previous Word.
                          ' Must be cleared in software.
Dim SSPIF As PIR1.3     ' SSP Interrupt flag Bit
Const SLAVE_ADDR = $22   ' Even number, must match address sent by Master PIC
                          ' To Read from Slave, make address from Master = (address + 1)
Const DataBufferLen = 100    ' RX Buffer size 
Public Dim DataBufferIndex,outbufferindex As Byte ' RX Buffer current Index
Public Dim DataBuffer(DataBufferLen) As Byte
Public Dim outBuffer(DataBufferLen) As Byte
Public dim i2cStatus,i2caddress as byte
Dim CASE_SWITCH,CKPbit,SSPCONBITS,scratch As Byte      ' States situation to be used by Select function
Public Dim DataAvailable As Boolean

' There can be 5 possible i2c states, SSPSTAT register relevant bits

Interrupt isr_I2C(2)
      save (0)
      SSPIF = 0                                      
      CASE_SWITCH = SSPSTAT And %00101101
      CKPbit=SSPCONBITS and %00010000
	  if (CASE_SWITCh XOR %00001001) <> 0 goto state2test
           DataAvailable = false
           DataBufferIndex = 255                   
           i2cAddress = SSPBUF  
           goto statedone
	  if (CASE_SWITCh XOR %00101001) <> 0 goto state3test
           if databufferindex=255 then
			   DataBuffer(DataBufferIndex) = SSPBUF
           goto statedone

	  if ((CASE_SWITCH AND %00101100) XOR %00001100) <> 0 goto state4test
      scratch=SSPBUF 'clear the BF flag
      SSPBUF = i2cstatus 'send status data byte
      goto exitonly

      if CKPbit<>0 goto state5test
	  If (CASE_SWITCh XOR %00101100) <> 0 goto exitonly
      SSPBUF = outbuffer(outbufferindex) 'send status data byte
      goto exitonly

	  CASE_SWITCH=CASE_SWITCH AND %00101000 'now mask out RW bit
	  If (CASE_SWITCh XOR %00101000) <> 0 goto exitonly
' put error handling here

      DataAvailable = SSPCONBITS.booleans(4)  
End Interrupt

Sub InitI2C()
   Input(PORTB.5)            ' Set SCL and SDA as inputs

   'SSPCON1 = $36            ' SSP settings: i2c slave mode, 7-bit address, enable SSP
   'SSPCON1 = %00110111            ' SSP settings: i2c slave mode, 7-bit address, enable SSP
   SSPCON1 = %00111110  ' i2c Slave, 7 bit Addr, I2C Start/Stop interrupts enabled
   SSPADD = SLAVE_ADDR      ' Initial slave address setting
   SSPCON2.7 = 0            ' disable  general call address  
   SSPSTAT = 0              ' Clear SSP Status reg
   PIE1.3 = 1               ' Enable SSP interrupts (SSPIE)
   SSPIF = 0                ' Clear SSP Interrupt flag                        
   INTCON.6 = 1             ' Enable perpheral Interrupts
   INTCON.7 = 1             ' Enable Global Interrupts
End Sub

Public Sub EnableI2C_isr()
End Sub

Public Sub DisableI2C_isr()
End Sub

DataAvailable = false
and my test program running on a picaxe is:

Code: Select all

setfreq m4

hi2csetup i2cmaster, $22, i2cfast_4, i2cbyte
hi2cout (%10000001,44,46,47,48) 'Command 1 with Go bit set
		inc w7
		hi2cin (b0)
	loop while b0>127 ' loop while go bit still set
	hi2cin (b0,b1,b2,b3,b4)
	sertxd (#w7," ",#b0," ",#b1," ",#b2," ",#b3," ",#b4,cr,lf)
I hope this is useful as a fully worked and working two way example, if anyone fancies tidying up the code further and putting "options" in for i2c ports and i2c address then please go ahead:-)

Best regards


Post Reply