Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC18F14K50 and 24lc64 I2C

Status
Not open for further replies.

immortal13

New Member
Hello!

I need help with I2C Master.
I want to write/read bytes to/from 24LC64 EEPROM. Frequency of I2C module is 100 kHz, pull-up resistors are 4k7 Ohm.
Oscillator frequency Fosc = 48 MHz.
The code is taken from MPLAB C18 files, but I send 2 bytes with address instead of 1 byte as in MPLAB C18's program.
And function EEByteWrite returns a write collision error.
EERandomRead function returns a value 0xFF.

Few times ago, I tryed to leave 1-byte sending to EEPROM. EERandomRead function returned 0xFF value, EEByteWrite didn't return any errors, but I didn't know, if it worked.
Code:
#define MASTER 0b1000 
#define SLEW_OFF 0 
#define SSPENB 0b00100000 
void OpenI2C1( unsigned char sync_mode, unsigned char slew ) 
{ 
  SSPSTAT &= 0x3F;                // power on state  
  SSPCON1 = 0x00;                 // power on state 
  SSPCON2 = 0x00;                 // power on state 
  SSPCON1 |= sync_mode;           // select serial mode  
  SSPSTAT |= slew;                // slew rate on/off  
  SSPADD = 0x77; 
    TRISBbits.TRISB4 = 1; 
    TRISBbits.TRISB6 = 1; 
  SSPCON1 |= SSPENB;              // enable synchronous serial port  
} 
void AckI2C1(void) 
{ 
  SSPCON2bits.ACKDT = 0;           // set acknowledge bit state for ACK 
  SSPCON2bits.ACKEN = 1;           // initiate bus acknowledge sequence 
} 
void CloseI2C1( void ) 
{ 
    TRISBbits.TRISB4 = 0; 
    TRISBbits.TRISB6 = 0; 
    SSPCON1 = 0;                // disable synchronous serial port 
} 
unsigned char DataRdyI2C1( void ) 
{ 
  if ( SSPSTATbits.BF )           // test if buffer full bit is set      
    return ( +1 );                // data in SSPBUF register 
  else 
    return ( 0 );                 // no data in SSPBUF register 
} 
unsigned char ReadI2C1( void ) 
{ 
if( ((SSPCON1&0x0F)==0x08) || ((SSPCON1&0x0F)==0x0B) )   //master mode only 
  SSPCON2bits.RCEN = 1;           // enable master for 1 byte reception 
  while ( !SSPSTATbits.BF );      // wait until byte received   
  return ( SSPBUF );              // return with read byte  
} 
void IdleI2C1( void ) 
{ 
  while ( ( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_W ) ) 
     continue; 
} 
void NotAckI2C1( void ) 
{ 
  SSPCON2bits.ACKDT = 1;          // set acknowledge bit for not ACK 
  SSPCON2bits.ACKEN = 1;          // initiate bus acknowledge sequence 
} 
void RestartI2C1( void ) 
{ 
  SSPCON2bits.RSEN = 1;           // initiate bus restart condition 
} 
void StopI2C1( void ) 
{ 
  SSPCON2bits.PEN = 1;            // initiate bus stop condition 
} 
void StartI2C1( void ) 
{ 
  SSPCON2bits.SEN = 1;            // initiate bus start condition 
} 
unsigned char WriteI2C( unsigned char data_out ) 
{ 
  SSPBUF = data_out;           // write single byte to SSPBUF 
  if ( SSPCON1bits.WCOL )      // test if write collision occurred 
   return ( -1 );              // if WCOL bit is set return negative # 
  else 
  { 
   if( ((SSPCON1&0x0F)!=0x08) && ((SSPCON1&0x0F)!=0x0B) )   //Slave mode only 
   { 
         SSPCON1bits.CKP = 1;        // release clock line  
         while ( !PIR1bits.SSPIF );  // wait until ninth clock pulse received 
         if ( ( !SSPSTATbits.R_W ) && ( !SSPSTATbits.BF ) )// if R/W=0 and BF=0, NOT ACK was received 
         { 
           return ( -2 );           //return NACK 
         } 
        else 
        { 
         return ( 0 );            //return ACK 
        }    
   } 
   else if( ((SSPCON1&0x0F)==0x08) || ((SSPCON1&0x0F)==0x0B) )   //master mode only 
   {  
       while( SSPSTATbits.BF );   // wait until write cycle is complete    
       IdleI2C1();                 // ensure module is idle 
       if ( SSPCON2bits.ACKSTAT ) // test for ACK condition received 
           return ( -2 );         // return NACK 
      else return ( 0 );              //return ACK 
   } 
    
  } 
} 
unsigned char EEByteWrite( unsigned char control, unsigned char address_high, unsigned char address_low, unsigned char data ) 
{ 
    int i; 
  IdleI2C1();                      // ensure module is idle 
  StartI2C1();                     // initiate START condition 
  while ( SSPCON2bits.SEN );      // wait until start condition is over  
  if ( PIR2bits.BCLIF )           // test for bus collision 
  { 
    return ( -1 );                // return with Bus Collision error  
  } 
  else                            // start condition successful 
  { 
    if ( WriteI2C( control ) )    // write byte - R/W bit should be 0 
    { 
     StopI2C1();  
      
      return ( -3 );              // set error for write collision 
    } 
    IdleI2C1();                    // ensure module is idle 
    if ( !SSPCON2bits.ACKSTAT )   // test for ACK condition received 
    {  
      if ( WriteI2C( address_high ) )  // address_high for EEPROM 
      { 
       StopI2C1();  
        return ( -3 );            // set error for write collision 
      } 
       IdleI2C1();                  // ensure module is idle 
      if ( !SSPCON2bits.ACKSTAT ) // test for ACK condition received 
      {  
        if ( WriteI2C( address_low ) )   // address_low for EEPROM 
        { 
        StopI2C1();  
          return ( -3 );          // set error for write collision 
        } 
         
        IdleI2C1();                     // ensure module is idle 
        if ( !SSPCON2bits.ACKSTAT )     // test for ACK condition received 
        { 
            IdleI2C1(); 
            if ( WriteI2C ( data ) )    //data byte for EEPROM 
            { 
                StopI2C1();    
                //LATC = 3; 
                return ( -3 );          //set error for write collision 
            } 
            // i = WriteI2C (data); 
            // LATC = i; 
        } 
        else 
        { 
            StopI2C1(); 
            return ( -2 );          //return with Not Ack error condition 
        } 
      } 
      else 
      { 
       StopI2C1();  
        return ( -2 );            // return with Not Ack error condition    
        } 
    } 
    else 
    { 
     StopI2C1();  
      return ( -2 );              // return with Not Ack error condition    
    } 
  } 
  IdleI2C1();                      // ensure module is idle   
  StopI2C1();                      // send STOP condition 
  while ( SSPCON2bits.PEN );      // wait until stop condition is over  
  if ( PIR2bits.BCLIF )           // test for bus collision 
  { 
    return ( -1 );                // return with Bus Collision error  
   } 
  return ( 0 );                   // return with no error 
} 
unsigned int EERandomRead( unsigned char control, unsigned char address_high, unsigned char address_low ) 
{ 
  IdleI2C1();                      // ensure module is idle 
  StartI2C1();                     // initiate START condition 
  while ( SSPCON2bits.SEN );      // wait until start condition is over  
  if ( PIR2bits.BCLIF )           // test for bus collision 
  { 
    return ( -1 );                // return with Bus Collision error  
  } 
  else 
  { 
    if ( WriteI2C( control ) )    // write 1 byte 
    { 
     StopI2C1();  
      return ( -3 );              // return with write collision error 
    } 
    //IdleI2C1();                    // ensure module is idle 
    if ( !SSPCON2bits.ACKSTAT )   // test for ACK condition, if received 
    { 
        if ( WriteI2C( address_high ) )  // write word address for EEPROM 
        { 
            StopI2C1();  
            return ( -3 );            // set error for write collision 
        } 
        IdleI2C1();                  // ensure module is idle 
        if ( !SSPCON2bits.ACKSTAT ) // test for ACK condition received 
        {  
            if ( WriteI2C( address_low ) )   // data byte for EEPROM 
            { 
                StopI2C1();  
                return ( -3 );          // set error for write collision 
            } 
        
      //IdleI2C1();                  // ensure module is idle 
            if ( !SSPCON2bits.ACKSTAT ) // test for ACK condition, if received 
            { 
                RestartI2C1();             // generate I2C bus restart condition 
                while ( SSPCON2bits.RSEN );// wait until re-start condition is over  
                if ( PIR2bits.BCLIF )     // test for bus collision 
                { 
                    return ( -1 );          // return with Bus Collision error  
                } 
         
                if ( WriteI2C( control+1 ) )// write 1 byte - R/W bit should be 1 
                { 
                    StopI2C1();  
                    return ( -3 );          // return with write collision error 
                } 
            //IdleI2C1();                // ensure module is idle 
                if ( !SSPCON2bits.ACKSTAT )// test for ACK condition, if received 
                { 
                    SSPCON2bits.RCEN = 1;       // enable master for 1 byte reception 
                    while ( SSPCON2bits.RCEN ); // check that receive sequence is over 
                    NotAckI2C1();              // send ACK condition 
                    while ( SSPCON2bits.ACKEN ); // wait until ACK sequence is over  
                    StopI2C1();              // send STOP condition 
                    while ( SSPCON2bits.PEN ); // wait until stop condition is over  
                    if ( PIR2bits.BCLIF )   // test for bus collision 
                    { 
                        return ( -1 );         // return with Bus Collision error  
                    } 
                 
                     
                } 
                else 
                { 
                    StopI2C1();  
                    return ( -2 );              // return with Not Ack error 
                } 
            } 
            else 
            { 
                StopI2C1();  
                return ( -2 );          // return with Not Ack error 
            } 
        } 
        else 
        { 
        StopI2C1();  
          return ( -2 );          // return with Not Ack error 
        } 
    } 
    else 
    { 
        StopI2C1();  
        return ( -2 );            // return with Not Ack error 
    } 
  } 
    //  
  // return 3; 
  return (  (unsigned int) SSPBUF );     // return with data 
} 
void main(void) 
{ 
    int i; 
    TRISC = 0; 
    LATC = 0; 
    while(1) 
    { 
        OpenI2C1(MASTER, SLEW_OFF); 
        i = EEByteWrite( 0b10100000, 0x01, 0x10, 0x03); 
        LATC = i; 

        i = EERandomRead(0b10100000, 0x01, 0x10); 
        //LATC = i; 
        CloseI2C1(); 
    } 
}

Thanks in advance,
Vyacheslav.
 
Last edited:
Code:
if ( WriteI2C( address_low ) )   // address_low for EEPROM 
        { 
        StopI2C1();  
          return ( -3 );          // set error for write collision 
        } 
 
        IdleI2C1();                     // ensure module is idle 
        if ( !SSPCON2bits.ACKSTAT )     // test for ACK condition received

Testing for NACK in writeI2C() then you make the bus Idle.. Then you test again....

If you are going to check ack or nack do it once only..
 
Thank you very much, Ian!
I have corrected this code and deleted unnecessary testings for Ack and Nack conditions, but it still doesn't work..

This is my corrected EEByteWrite function:
Code:
unsigned char EEByteWrite( unsigned char control, unsigned char address_high, unsigned char address_low, unsigned char data )
{
    int i;
    IdleI2C1();                      // ensure module is idle
    StartI2C1();                     // initiate START condition
    while ( SSPCON2bits.SEN );      // wait until start condition is over 
    if ( PIR2bits.BCLIF )           // test for bus collision
    {
        return ( -1 );                // return with Bus Collision error 
    }
    else                            // start condition successful
    {
        if ( WriteI2C( control ) )    // write byte - R/W bit should be 0
        {
            StopI2C1(); 
            return ( -3 );              // set error for write collision
        }
        else    
            if( WriteI2C( address_high ) )  // address_high for EEPROM
            {
                StopI2C1(); 
                return ( -3 );            // set error for write collision
            }
            else
                if ( WriteI2C( address_low ) )   // address_low for EEPROM
                {
                    StopI2C1(); 
                    return ( -3 );          // set error for write collision
                }
                else
                    if ( WriteI2C ( data ) )    //data byte for EEPROM
                    {
                        StopI2C1();   
                        return ( -3 );          //set error for write collision
                    }

    }

    StopI2C1();                      // send STOP condition
    while ( SSPCON2bits.PEN );      // wait until stop condition is over 
    if ( PIR2bits.BCLIF )           // test for bus collision
    {
        return ( -1 );                // return with Bus Collision error 
    }
    return ( 0 );                   // return with no error
}
 
Last edited:
It would be great! Thank you!

I really can't understand why does this program return error after the third transmitted byte.
 
Hello!
I have a problem with this inteface again, but now I'm trying to connect 24lc64 to PIC18F4550...
After sending START bit in EEByteWrite function, BCLIF flag value is '1'.

View attachment 67752

This is my scheme of 24lc64 connecting.
Could anybody tell me why may the Bus Collision Error be there?
 
Last edited:
Sorry for awaiting! My SCL and SDA pins are connected properly, 2k2 resistors were connected according to Microchip recommendations for 100 kHz frequency.

But I've tried to put 4k7 resistors and it is still not working.
 
Why can't I use the same name function? It is another project.. This code works fine on PIC18F14K50 but doesn't work on PIC18F4550 and I have no ideas why...

The same assembly code works fine!

This is C18 code:

Code:
unsigned char EEByteWrite( unsigned char control, unsigned char address_high, unsigned char address_low, unsigned char data )
{
    IdleI2C();          	            		
    StartI2C();                    			
    while ( SSPCON2bits.SEN );      			
    if ( PIR2bits.BCLIF )           			
    {
        return ( -1 );                		// return Bus Collision error 
    }
    else                            			
    {
        if ( WriteI2C( control ) )    		
        {
            StopI2C(); 
            return ( -3 );              		
        }
        else    
            if( WriteI2C( address_high ) )  		
            {
                StopI2C(); 
                return ( -3 );            
            }
            else
                if ( WriteI2C( address_low ) )   	
                {
                    StopI2C(); 
                    return ( -3 );          
                }
                
                else
                    if ( WriteI2C ( data ) )    	
                    {
                        StopI2C();   
                        return ( -3 );       
                    }

    }
    StopI2C();                      			
    while ( SSPCON2bits.PEN );      			
    if ( PIR2bits.BCLIF )           			
    {
        return ( -1 );                		// return Bus Collision error 
    }
    return ( 0 );                   			// return no error
}

And this is assembly code:

Code:
EEByteWrite:				
            CALL    IdleI2C		
            CALL    StartI2C		
Waiting2:
            BTFSC   SSPCON2, SEN	
            BRA     Waiting2		
            BTFSC   PIR2, BCLIF	
            RETLW   .255		
            MOVF    Control, W 
            CALL    WriteI2C		
            TSTFSZ  WREG           
            RETLW   .253		
            MOVF    Address_High, W	
            CALL    WriteI2C		
            TSTFSZ  WREG		
            RETLW   .253		
            MOVF    Address_Low, W	
            CALL    WriteI2C		
            TSTFSZ  WREG		
            RETLW   .253		
            MOVF    Dat, W		
            CALL    WriteI2C		
            TSTFSZ  WREG		
            RETLW   .253		
            CALL    StopI2C		
Waiting3:
            BTFSC   SSPCON2, PEN	
            BRA     Waiting3		
            BTFSC   PIR2, BCLIF	
            RETLW   .255		
            RETLW   .0
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top