Slave I2C framework on 18F14K22

Coding and general discussion relating to user created compiler modules

Moderators: David Barker, Jerry Messina

Post Reply
matherp
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

SetAllDigital()

SetBaudrate(br19200)

EnableI2C_isr()

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
              	  outbuffer(i)=databuffer(i)*2
              next
          endif
          delayms(1000) 'make the master wait a bit to demonstrate polling
          i2cstatus=i2cstatus and %01111111 ' clear the go bit
	 endif
   I2CSlave.DataAvailable = False
Wend
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
      SSPCONBITS=SSPCON1
      CKPbit=SSPCONBITS and %00010000
	   
state1:
	  if (CASE_SWITCh XOR %00001001) <> 0 goto state2test
           DataAvailable = false
           DataBufferIndex = 255                   
           i2cAddress = SSPBUF  
           goto statedone
state2test:
	  if (CASE_SWITCh XOR %00101001) <> 0 goto state3test
           if databufferindex=255 then
               databufferindex=0
               i2cstatus=SSPBUF
		   else
			   DataBuffer(DataBufferIndex) = SSPBUF
               Inc(DataBufferIndex)
		   endif                  
           goto statedone

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

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

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

statedone:
      DataAvailable = SSPCONBITS.booleans(4)  
exitonly:
restore
CKP=1  
End Interrupt
         
            


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

   '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()
    Enable(isr_I2C)
End Sub

Public Sub DisableI2C_isr()
    Disable(isr_I2C)
End Sub

InitI2C()
DataAvailable = false
outbufferindex=0
databufferindex=0
and my test program running on a picaxe is:

Code: Select all

#picaxe28X1
setfreq m4

hi2csetup i2cmaster, $22, i2cfast_4, i2cbyte
do
hi2cout (%10000001,44,46,47,48) 'Command 1 with Go bit set
w7=0
	do
		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)
loop
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

Peter

Post Reply