Menu

MasterI2C.h Library

2007-06-23
2013-05-30
  • Nobody/Anonymous

    Here is the header file to accompany the posted example on how to use the Master Synchronous Serial Port (MSSP).  Have not tested on other devices or generalized the InitI2C sub to handle other devices if so required?  Comments welcome.

    '--------------------------------------------------------
    'Header file name MasterI2c.h
    'Master I2C Mode (Hardware-Synchronous)
    'By Kent Schafer June 21, 2007
    'This is a port of Microchip Tutorial "I2C Master Mode"
    'and AN976
    '
    'This header is currently set up for word size addressing
    'like in the larger size eeproms.
    'No polling is taking place after writes or reads
    'A suitable delay is required (5 ms or ??)
    '--------------------------------------------------------

    sub InitI2C  'Disable slew rate control (SMP)
    SSPSTAT = b'1000000'  'ClockValue or SSPADD = (FOSC / (4 * Baud)) - 1 
    SSPADD = ClockValue  'Clear the register, only cleared on POR
    SSPCON2 = 0  'Set SSPEN and SSPMx bits for SSP Enable and Master I2C mode
    SSPCON = b'00101000'
    SET PIR1.SSPIF OFF
    SET PIR2.BCLIF OFF
    end sub

    sub Start
      Set PIR1.SSPIF Off  'Clear SSP interrupt flag
      Set SSPCON2.SEN On  'set start condition
    waitstart:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitstart
      end if
    end sub

    sub Restart
      Set PIR1.SSPIF Off  'Clear SSP interrupt flag
      Set SSPCON2.RSEN On  'set stop condition
    waitRestart:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitRestart
      end if
    end sub

    sub TxI2C(SendByte)
      Set PIR1.SSPIF Off 
      SSPBUF = SendByte
    'Wait for acknowledge
    waitTx:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitTx
      end if
    waitAck:
      If SSPCON2.ACKSTAT On Then
      goto waitAck
      end if
    end sub

    sub RxI2C
      Set PIR1.SSPIF Off
      Set SSPCON2.RCEN On  'Initiate reception
    waitRx1:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitRx1
      end if
      ReadByte = SSPBUF  'Read byte in buffer
    'Wait for Not acknowledge
      Set PIR1.SSPIF Off
      Set SSPCON2.ACKEN On  'Select to send NO ACK
    waitNoAck:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitNoAck
      end if
    end sub

    sub Stop
      Set PIR1.SSPIF Off
      Set SSPCON2.PEN On  'Set Stop condition
    waitStop:
      If PIR1.SSPIF Off Then  'Check if operation complete
      goto waitStop
      end if
    end sub

    'sub Poll
    ' For pollcount = 1 to 40
    '  Restart
    '  TxI2C(eeprom_write)
    'end sub

    sub I2CWrite(WriteID,HighAddr,LowAddr,I2Cdata) '#NR
      Start
      TxI2C(WriteID)  'Device ID write byte
      TxI2C(HighAddr)  'Send word address high byte
      TxI2C(LowAddr)  'Send word address low byte
      TxI2C(I2Cdata)  'Send out data byte to slave
      Stop
      'Poll
    end sub

    Function I2CRead(WriteID,HighAddr,LowAddr,ReadID)
      Start
      TxI2C(WriteID)  'Device ID read byte
      TxI2C(HighAddr)  'Send word address high byte
      TxI2C(LowAddr)  'Send word address low byte
      Restart
      TxI2C(ReadID)  'Device ID read byte
      Set SSPCON2.ACKDT On  'Send no acknowledge
      RxI2C  'Receive data byte from slave
      I2CRead = ReadByte 
      Stop
    end function

     
    • Hugh Considine

      Hugh Considine - 2007-06-25

      A couple of suggestions:

      First, the address could be passed as a word variable. For example:

      sub I2CWrite(WriteID,Addr As Word,I2Cdata) '#NR
      Start
      TxI2C(WriteID) 'Device ID write byte
      TxI2C(Addr_H) 'Send word address high byte
      TxI2C(Addr) 'Send word address low byte
      TxI2C(I2Cdata) 'Send out data byte to slave
      Stop
      'Poll
      end sub

      Also, it may be possible to take away the names of the registers, and just use the name of the bit. "Set SSPCON2.RCEN On" may be able to be changed to "Set RCEN On". This depends on whether there are multiple bits in different registers with the same name. If this is possible, it improves the portability of the code between devices.

      The code looks good, I'll try it out on a few chips sometime in the next couple of days and let you know how it goes.

       
    • Nobody/Anonymous

      Hugh,
      The Addr as word suggestion works as expected, so less variables to keep track of, thanks!

      Using just the bit values, rather than register and bit values, also works.  Little unsure on how to procede on device migration,  seems like a big task, but maybe you could point to an appnote, or use your method for testing code on different device family's.

      One method of device migration might be to do a parametric search for MSSP on the Microchip site. Then you could group those results into device family's, for which I believe there is an AppNote?  Currently don't have any other 16fxxx or 18Fxxxx devices with MSSP to test with.

      Lots more work can be done on the header file.  Like adding 100KHz, and 400KHz modes, like in your SPI library.  Also, need 8bit address handling routines.  Have tried to make my Real Time Clock code work in the 8bit mode, to no avail.  The RTC code worked fine in the software I2C library, so its a mystery.  Need a couple of aspirin and a fresh view on things I guess.

      Kent

       
    • Hugh Considine

      Hugh Considine - 2007-07-03

      Normally when I'm writing code for several devices, I first concentrate on getting it to work on one. Then, I look through the datasheets to find other PICs that I have with the same feature, and try and make it work on them. Even without a given PIC, it's usually possible to assume that the program will work fine if it'll assemble in MPASM.

      Another thing - there is a small script in the ssp.h file that will automatically calculate the SSPADD value for a given baud rate:

      #define I2CBaud 100 'Change to desired frequency

      #script
      I2CBaudTemp = int((ChipMhz * 1000000) / (4000 * I2CBaud)) - 1
      #endscript

      That sets the constant I2CBaudTemp to the correct value, based on I2CBaud and the chip speed. I2CBaud is in KHz, hence the multiplication by 4000 rather than 4.

      Perhaps it would be worth combining your routines with the code already in ssp.h?

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.