Hardware I2C



THE BOOK of DT's INTERRUPTS is an organization of interrupt service routines and other works written by Darrel Taylor, RIP.

Interrupt routines are arranged per Darrel's original list. Darrel Taylor's Instant Interrupts are an extension of the work of Tim Box whom in October of 2002 wrote INT_CTRL.pbp

Many of the forum members felt this is a long overdue project.

THE BOOK of DT's INTERRUPTS
will be a valuable resource and a tribute to Darrel Taylor the "Fanatical Contributor".

THE BOOK of DT's INTERRUPTS is located at http://dt.picbasic.co.uk/

+ Reply to Thread
Results 1 to 12 of 12

Thread: Hardware I2C

  1. #1
    Join Date
    Jun 2005
    Posts
    29

    Default Hardware I2C

    Is it possible to use the Hardware I2C in PicBasic Pro?

    I need to read faster than I2CREAD PicBasic Pro command. Even with a 20MHz crystal I'm unable to obtain full speed I2C.

    Surely someone have ever work on that issue. Maybe an assembly include?

    Thank you

  2. #2
    Join Date
    Sep 2004
    Location
    Mentor, Ohio
    Posts
    351


    Did you find this post helpful? Yes | No

    Smile

    Hi Toley00,

    It may be worth your time to download the I2C Bus Specification manual from Phillips. There are 3 data modes for I2C, Standard Mode = upto 100kbits/sec, Fast Mode = upto 400kbits/sec, and High Speed Mode = 3.4Mbits/sec. I've only used I2C for RTC's using both software I2C and Hardware I2C. I didn't have to set anything up special on my PICs for speed. But you do have to put a 10ms pause after any write command to give it time to catch up or settle down. I have seen some posts on this forum where I2C worked better when it was slowed down.

    Don't know if this helps, but I think maybe their manual might give you a better insight into the whole process.

    BobK

  3. #3
    Join Date
    Jun 2005
    Posts
    29


    Did you find this post helpful? Yes | No

    Default

    Thank you BobK for your reply.
    I already know about I2C timing protocol, and I use it in many project already. I just need it to read an EEPROM faster than I2CREAD can do.
    Thanks for your help but a 10ms pause will not give me speed...

  4. #4
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    I don't know what PIC you are using, so I can't promise anything, but I've attached a file containing some portions of code I have used with the hardware I2C on a PIC 18F4620.

    The file is a compilation of cut and past from a few include files, and has only been minimally "cleaned up" for public viewing. It has 4 sections:
    1) Basic PIC and HSEROUT setup (mostly to reinforce what pic and how it's configured)
    2) The meat of the I2C commands
    3) Samples of Large Block Reading/Writing to an EEPROM
    4) Samples of Reading/Writing to an RTC

    Hopefully this will get you started.
    Best of luck,
    Steve B

    Disclaimer: Looking a little closer I recall this being one of my first PBP-ASM items I tackled. It worked, and with other things pressing, I haven't gone back and cleaned things up, like unused variables (DelayCtr1 and DelayCtr2) and rements of HSEROUT commands used to debug.
    Attached Files Attached Files
    Last edited by SteveB; - 20th January 2007 at 05:50. Reason: Added disclaime

  5. #5
    Join Date
    Jun 2005
    Posts
    29


    Did you find this post helpful? Yes | No

    Default

    Thank you SteveB, looks like what I need. I will take a closer look and adapt it to my needs. I'm using a PIC16F886, but I think all MSSP modules work the same way, and I only need to read from the EEPROM.

  6. #6
    Join Date
    Oct 2005
    Location
    Pinckney, Michigan
    Posts
    91


    Did you find this post helpful? Yes | No

    Default

    Also consider the RAMTRON FM24C256 32K X 8 eeprom.

    It reads and writes at FULL I2C buss speed. No artificial delays required.

    It is also pin-for-pin compatible with many common serial eeproms, and might just plug directly into your eeprom socket.

  7. #7
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Toley00 View Post
    Thank you SteveB, looks like what I need. I will take a closer look and adapt it to my needs. I'm using a PIC16F886, but I think all MSSP modules work the same way, and I only need to read from the EEPROM.
    A couple of things right off the top of my head. The buffer size will need to be reduced for a 16F. Also, the way I allocated variables to "BANKA" or "BANKX" in the declaration statements will also need changing. If I get a chance later I'll try to give it a look-over for anything else. As I recall, I think I got the basics of the ASM routines from a Microchip document/source, and adapted them for the 18F. So that might also be an avenue to persue.

    Steve B

  8. #8
    Join Date
    Feb 2005
    Location
    Kolkata-India
    Posts
    563


    Did you find this post helpful? Yes | No

    Thumbs up Thanks SteveB

    Hi,

    SteveB your routines are neat (at least than mine) and I learnt from it as well. Thanks to you and Toley for raising the topic.
    Regards

    Sougata

  9. #9
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    I made a quick run through the code (while my kids took a nap). Changed all the ASM to PBP. Also modified the buffer size, and some SFR lables to correspond the 16F. It compiles OK, but no 16F's to test it (nor anything to setup the circut without canibalizing something else). Keep in mind, on many of the 18Fs, you've got RAM to burn, so the buffers reflect that. On the 16Fs, you don't have that luxary.

    Hopefully, if you are working it on your end, you can compare/use what I've done to move further down the road.

    I did notice a number of areas where things could be improved or I would do thing differently. The error handling is especially weak. However, I never got any errors with the code and my setup, so never needed it to be very robust. So, I will put this on my *LONG* list of things to do when I get around to it.

    SteveB
    Attached Files Attached Files
    Last edited by SteveB; - 21st January 2007 at 04:58.

  10. #10
    Join Date
    Jun 2005
    Posts
    29


    Did you find this post helpful? Yes | No

    Thumbs up Project finished!

    Thank you SteveB, with your help (and a lot of time) I finally make it work. I've changed some things in your Routines. First I changed the Labels for shorter names. I've also changed the lines refer to PIR1.3 for SSPSTAT.2 to indicate when a transmit is over. And I fixed a little error in your code RCEN is SSPCON2.3 instead of SSPCON2.4.

    In Fact all that is need is to correctly set the MSSP module :

    SSPSTAT.7 = 0 'High Speed Filter
    SSPADD = $0C '400 kHz @ 20 MHz
    SSPCON = %00101000 'I2C Master Mode Enable

    And in your main program use the 6 next sub routines as needed :

    ;-----------------------------------------------------------
    ; Process Routines
    ;-----------------------------------------------------------
    I2CSTART:
    SSPCON2.0 = 1 ; SEN - Start Condition Enable Bit
    WHILE SSPCON2.0 = 1 : WEND ; Wait for Start to complete
    RETURN
    ;-----------------------------------------------------------
    I2CRD:
    SSPCON2.3 = 1 ; RCEN - Enable receive mode
    WHILE SSPCON2.3 = 1 : WEND ; Wait for Read to complete
    I2CDATA = SSPBUF
    Return
    ;-----------------------------------------------------------
    I2CWR:
    SSPBUF = I2CDATA ; Move data to SSPBUF
    WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
    While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave 1=NotAck
    RETURN ; Acknowledge recieved
    Return
    ;-----------------------------------------------------------
    I2CSTOP:
    SSPCON2.2 = 1 ; PEN - send stop bit
    While SSPCON2.2 = 1 : Wend ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------
    I2CNOACK:
    SSPCON2.5 = 1 ; ACKDT - Set Ack bit to NotAck
    SSPCON2.4 = 1 ; ACKEN - send ACKDT bit
    While SSPCON2.4 = 1 : Wend ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------
    I2CACK:
    SSPCON2.5 = 0 ; ACKDT - Set Ack bit to Ack
    SSPCON2.4 = 1 ; ACKEN - send ACKDT bit
    While SSPCON2.4 = 1 : Wend ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------

    Now By using thoses sub routines, I'm able to access an EEPROM fast enough to read a 8 sec. wav files at 8 kHz. Everything is written in PicBasic Pro (no assembly) and is at least 3 times faster than standard I2CREAD statement.

    Ok I know it's not really "User friendly" but my programming skills are limited and it work fine for me like this. Maybe someone can write something easier to use, it could be very handy.

  11. #11
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default

    It's great to here when someone has success. Especially when they have put in the work (like getting into the datasheet) that you have.

    SteveB

  12. #12
    Join Date
    Feb 2013
    Posts
    883


    Did you find this post helpful? Yes | No

    Default Re: Hardware I2C

    I tried to use above code with 24C32 and PIC16F887 but it does not works. It stuck on this loop: while SSPCON2.0 = 1 : wend

    Here's complete code:

    Code:
    '****************************************************************
    '*  Name    : I2C EEPROM                                        *
    '*  Author  : Daniel T. Barber                                  *
    '*  Notice  : Copyright (c) 2018                                *
    '****************************************************************
    
    @ ERRORLEVEL -306   ' turn off crossing page boundary message
     
    '************ Config Settings for 16F877A *************
    #CONFIG
    cfg1 = _INTRC_OSC_NOCLKOUT    ; INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
    cfg1&= _WDT_ON                ; WDT enabled
    cfg1&= _PWRTE_OFF             ; PWRT disabled
    cfg1&= _MCLRE_OFF             ; RE3/MCLR pin function is digital input, MCLR internally tied to VDD
    cfg1&= _CP_OFF                ; Program memory code protection is disabled
    cfg1&= _CPD_OFF               ; Data memory code protection is disabled
    cfg1&= _BOR_OFF               ; BOR disabled
    cfg1&= _IESO_ON               ; Internal/External Switchover mode is enabled
    cfg1&= _FCMEN_ON              ; Fail-Safe Clock Monitor is enabled
    cfg1&= _LVP_OFF               ; RB3 pin has digital I/O, HV on MCLR must be used for programming
    cfg1&= _DEBUG_OFF             ; In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
      __CONFIG _CONFIG1, cfg1
    
    cfg2 = _BOR40V                ; Brown-out Reset set to 4.0V
    cfg2&= _WRT_OFF               ; Write protection off
      __CONFIG _CONFIG2, cfg2
    
    #ENDCONFIG
     
    TRISA=%00000000  'SET A TO OUTPUT   1=input
    TRISC=%00011000   'set C 3 4  input
    TRISB=%00000000   'set PortB to output
    ANSELH=%00000000   ' ADC OFF B
    ANSEL=%00000000 'configure PortA as digital except first 2
    ADCON1=%10000000  'adc justify
    OSCCON=%01110101  'SET FREQUENCY TO 8MHZ
    WPUB=%00000000    'turn off Pullups
    CM1CON0=0         'DISABLE COMPARATORS
    CM2CON0=0         'SAME HERE
      
    Define OSC 8 'Adjust consistent with oscillator speed being used
    
    ADCON1 = 7      ' Set PORTA and PORTE to digital
    
    DEFINE LCD_DREG PORTB  
    DEFINE LCD_DBIT 4  
    DEFINE LCD_RSREG PORTB 
    DEFINE LCD_RSBIT 2  
    DEFINE LCD_EREG PORTB  
    DEFINE LCD_EBIT 3  
    DEFINE LCD_BITS 4  
    DEFINE LCD_LINES 2  
    DEFINE LCD_COMMANDUS 1500  
    DEFINE LCD_DATAUS 44
    'clear
    
    
    I2CBufferSize  con 64
    
    Reg_Pointer	Var Byte 	 ; Address register
    I2CDATA		Var Byte 	 ; data to read/write
    I2CAddr		Var Byte 	 ; Device address
    
    I2C_Wait	     var byte 
    countI2C	     var byte 
    I2CWRBuff	     var byte (I2CBufferSize) 
    I2CWRsize	     Var Byte 
    I2CRDBuff	     var byte (I2CBufferSize) 
    I2CRDsize	     Var Byte 
    
    I2CErrCode     Var Byte 
    I2CErrCode     = 0
    
    x var byte 'temp var
    
    SSPSTAT.7 = 0       ; SMP<7> - Slew rate control Enabled (400kHz)
    SSPCON = %00101000
              ; | ''''--  SSPM<3:0> - I2C Master mode, clock = FOSC / (4 * (SSPADD+1))
              ; '-------- SSPEN<5> - Synchronous Serial Port Enable bit
    
    SSPADD = $0E        ; set I2C clock rate to 400kHz
    'SSPADD = $59		; set I2C clock rate to 100kHz
    
    
    
    for x=0 to 255
    lcdout $fe, $2, "wait..."
    I2CAddr=x
    gosub read1byte
    lcdout $fe, $2, "data=", dec i2cdata
    pause 1000
    next
    stop
    
    
    
    
    
    ;-----------------------------------------------------------
    ; Main Routines
    ;-----------------------------------------------------------
    Write1Byte:
         I2CErrCode.1 = 0
    	I2CAddr.0	=	0	;Set Write Bit
    	Gosub StartI2C      ;Send Start, Addr, Wait for Ack
    	if I2CErrCode.1	=	1 then RETURN
    		I2CDATA = I2CWRBuff(0) 
    	gosub I2CWRByte	    ;Send I2CDATA Byte
    	Gosub SendStopBit	;Send Stop Bit
    Return
    ;-----------------------------------------------------------
    WriteXBytes:
         I2CErrCode.1 = 0
    	I2CAddr.0	=	0	;Set Write Bit
    	Gosub StartI2C      ;Send Start, Addr, Wait for Ack
    	if I2CErrCode.1	=	1 then RETURN
    	For countI2C = 0 to I2CWRsize-1
    		I2CDATA = I2CWRBuff(countI2C)
    ;          hserout [dec countI2C,"-",ihex2 I2CDATA," ",13,10] 
    		gosub I2CWRByte	    ;Send I2CDATA Byte
    	next countI2C      
    	Gosub SendStopBit	;Send Stop Bit
    Return
    ;-----------------------------------------------------------
    Read1Byte:
         I2CErrCode.1 = 0
    	I2CAddr.0	=	1	;Set Read Bit
    	Gosub StartI2C      ;Send Start, Addr, Wait for Ack
    	if I2CErrCode.1	=	1 then RETURN
        gosub I2CRDByte
    	I2CRDBuff(0) = 	I2CDATA 
        gosub Send_NO_Ack
        Gosub SendStopBit
    Return
    ;-----------------------------------------------------------
    ReadXBytes:
         I2CErrCode.1 = 0
    	I2CAddr.0	=	1	;Set Read Bit
    	Gosub StartI2C      ;Send Start, Addr, Wait for Ack
    	if I2CErrCode.1	=	1 then RETURN
         for countI2C = 0 to I2CRDsize-2
              gosub I2CRDByte
              gosub Send_Ack
    		I2CRDBuff(countI2C) = 	I2CDATA 
         next  countI2C
         countI2C = I2CRDsize - 1
         gosub I2CRDByte
         gosub Send_NO_ACK
         Gosub SendStopBit
         I2CRDBuff(countI2C) = 	I2CDATA 
    Return
    ;-----------------------------------------------------------
    ; Process Routines
    ;-----------------------------------------------------------
    StartI2C:
    
         ;Send Start Bit
         SSPCON2.0 = 1                 ; SEN<0> - Send start bit
         while SSPCON2.0 = 1 : wend    ; Wait for completion
         ;Send Slave Address
         PIR1.3 = 0                    ; SSPIF - Clear interrupt Flag
         SSPBUF = I2CAddr              ; move slave address to SSPBUF
         While PIR1.3 = 0 : Wend       ; SSPIF - Wait for SSP to complete sending slave address
         ;Wait for Acknowledge or Restart
         i2c_wait = 0                  ; Reset wait counter
         While SSPCON2.6 = 1           ; Wait for Acknowledge from slave  1=NotAck
              I2C_Wait = I2C_Wait + 1  ; Increment wait counter
              if I2C_Wait = 0 then     ; Wait for 256 counts
                   goto I2CResError    ; Acknowledge "Time Out" - Report error and RETURN      
              else
                   ; Send Repeated Start
                   SSPCON2.1 = 1       ; RSEN - Send Repeated Start
                   while SSPCON2.1 = 1 : wend    ; Wait for completion
                   ; Resend the Slave Address
                   PIR1.3 = 0                    ; SSPIF - Clear interrupt Flag
                   SSPBUF = I2CAddr              ; move slave address to SSPBUF
                   While PIR1.3 = 0 : Wend       ; SSPIF - Wait to complete sending Slave Address
              endif 
         wend
         RETURN                        ; Acknowledge recieved
    Return
    ;-----------------------------------------------------------
    I2CWRByte:
         PIR1.3 = 0                    ; SSPIF - Clear interrupt Flag
         SSPBUF = I2CDATA              ; Move data to SSPBUF
         While PIR1.3 = 0 : Wend       ; SSPIF - Wait for SSP to complete sending
    
         ;Wait for Acknowledge or Abort
         i2c_wait = 0                  ; Reset wait counter
         While SSPCON2.6 = 1           ; Wait for Acknowledge from slave  1=NotAck
              I2C_Wait = I2C_Wait + 1  ; Increment wait counter
              if I2C_Wait = 0 then     ; Wait for 256 counts
                   goto I2CResError    ; Acknowledge "Time Out" - Report error and RETURN      
              endif 
         wend
         RETURN                        ; Acknowledge recieved
    Return
    ;-----------------------------------------------------------
    I2CRDByte:
         PIR1.3 = 0                    ; SSPIF - Clear interrupt Flag
         SSPCON2.3 = 1                 ; RCEN - Enable receive mode
    
         While PIR1.3 = 0 : Wend       ; SSPIF - Wait for SSP to complete receiving
         
         I2CDATA = SSPBUF
    
    Return
    ;-----------------------------------------------------------
    SendStopBit
         SSPCON2.2 = 1                 ; PEN - send stop bit
         While SSPCON2.2 = 1 : Wend    ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------
    Send_NO_Ack:
         SSPCON2.5 = 1                 ; ACKDT - Set Ack bit to NotAck
         SSPCON2.4 = 1                 ; ACKEN - send ACKDT bit
         While SSPCON2.4 = 1 : Wend    ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------
    Send_Ack:
         SSPCON2.5 = 0                 ; ACKDT - Set Ack bit to Ack
         SSPCON2.4 = 1                 ; ACKEN - send ACKDT bit
         While SSPCON2.4 = 1 : Wend    ; Wait for SSP to complete
    Return
    ;-----------------------------------------------------------
    I2CResError:
    	I2CErrCode.1	=	1
    	lcdout $fe, $2, "I2C Error!!!"
    Return
    ;-----------------------------------------------------------

Similar Threads

  1. I2C Master/Slave 16F88/16F767 working code
    By DanPBP in forum Code Examples
    Replies: 2
    Last Post: - 23rd October 2012, 22:31
  2. HARDWARE I2C SAMPLE CODE question
    By Michael Wakileh in forum Code Examples
    Replies: 2
    Last Post: - 16th June 2009, 21:07
  3. I2C Master Slave issues.
    By cpayne in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 29th March 2008, 19:33
  4. Hardware I2C
    By Kamikaze47 in forum mel PIC BASIC Pro
    Replies: 21
    Last Post: - 13th March 2008, 13:24
  5. Please help with i2cslave i2c slave
    By cycle_girl in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 1st December 2005, 13:55

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts