Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] I2c Inteface with PIC18F24k40

Status
Not open for further replies.

ajit_nayak87

Member level 5
Joined
Oct 30, 2017
Messages
86
Helped
1
Reputation
2
Reaction score
1
Trophy points
8
Activity points
981
View attachment test.X.zip

I am trying to interface MCP3425 with PIC18F24K40. I am using mplab x ide v4.51 with compiler Xc8 1.41
I am using mssp based I2c driver.c file generated from MSSP. I have attached complete code for reference.
Below file generated from MSSP code configrator. I could not able to generated start & stop bit using below library.

I have written code for PIC16F886 where it work very well. But due new ide and config version it not working as expected


Code:
bool i2c_master_read(uint8_t* data, uint8_t length, uint8_t address) {
    uint8_t n;
   // I2C_INTERRUPT_FLAG = 0;
    //I2C_COLLISION_FLAG = 0;
    
    // Start condition
    i2c1_driver_start();
    while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
    
    // If no collision occurred
    if(I2C_INTERRUPT_FLAG) {
        // Send read address
        I2C_INTERRUPT_FLAG = 0;
        i2c1_driver_TXData(address | 0x01);
        while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
        
        // No collision occurred?
        if(I2C_INTERRUPT_FLAG) {
            I2C_INTERRUPT_FLAG = 0;
            // Check the ACK status from the slave. If ACK was received, continue
            if(!i2c1_driver_isNACK()) {
                
                // Read all the bytes
                for(n = 0; n < length; ++n) {
                    i2c1_driver_startRX();
                    while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
                    I2C_INTERRUPT_FLAG = 0;
                    
                    data[n] = i2c1_driver_getRXData();
                    
                    // Collision? Return
                    if(I2C_COLLISION_FLAG) {
                        i2c1_driver_stop();
                        return false;
                    }
                    
                    // If this is the last byte we should read, send a NACK to the
                    //  slave device now
                    if(n == length - 1) {
                        i2c1_driver_sendNACK();
                    }
                    else {
                        // Send ACK to keep receiving data
                        i2c1_driver_sendACK();
                    }
                    while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
                    
                    // Collision? Return
                    if(I2C_COLLISION_FLAG) {
                        i2c1_driver_stop();
                        return false;
                    }
                    
                    I2C_INTERRUPT_FLAG = 0;
                }
                
                // Generate the stop condition
                i2c1_driver_stop();
                while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
                if(I2C_INTERRUPT_FLAG) {
                    return true;
                }
            }
        }
    }
    
    return false;
}










bool i2c_master_open(void) {
    return i2c1_driver_open();
}


void Test_code()

{
    
    
   i2c1_driver_start();
    //while(!I2C_INTERRUPT_FLAG && !I2C_COLLISION_FLAG);
    
    i2c1_driver_restart(); 
    i2c1_driver_setAddr(0X68); 
    i2c1_driver_sendACK();
    i2c1_driver_stop();
    
    
     i2c1_driver_restart(); 
    i2c1_driver_setAddr(0X68); 
    i2c1_driver_sendACK();
    i2c1_driver_stop();
    
    
}


void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
  i2c_master_open();
 
   CONTROLREG =0X01; 
    
    while (1)
    {
        //data=i2c_master_read(0X00,2,0X01);
     //   Average();
        
            
       Test_code();
       __delay_ms(100);
        
        
     /*   
      CountsToDegree();
       ConvertInValue();
      // Delay(1000);
       __delay_ms(500);
         Dissect(ProDegrs);*/
        
    }
}






i2c driver.c


Code:
/*
    (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this
    software and any derivatives exclusively with Microchip products.

    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
    PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
    WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

    IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
    WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
    BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
    FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
    ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
    THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
    TERMS.
*/


#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "mcc.h"
#include "i2c1_driver.h"

#pragma warning disable 520        

inline void i2c1_driver_close(void)
{
    SSP1CON1bits.SSPEN = 0;
}

/* Interrupt Control */
inline void mssp1_enableIRQ(void)
{
    PIE3bits.SSP1IE = 1;
}

inline bit mssp1_IRQisEnabled(void)
{
    return PIE3bits.SSP1IE;
}

inline void mssp1_disableIRQ(void)
{
    PIE3bits.SSP1IE = 0;
}

inline void mssp1_clearIRQ(void)
{
    PIR3bits.SSP1IF = 0;
}

inline void mssp1_setIRQ(void)
{
    PIR3bits.SSP1IF = 1;
}

inline bit mssp1_IRQisSet(void)
{
    return PIR3bits.SSP1IF;
}

inline void mssp1_waitForEvent(uint16_t *timeout)
{
    //uint16_t to = (timeout!=NULL)?*timeout:100;
    //to <<= 8;

    if(PIR3bits.SSP1IF == 0)
    {
        while(1)// to--)
        {
            if(PIR3bits.SSP1IF) break;
            __delay_us(100);
        }
    }
}

bit i2c1_driver_open(void)
{
    if(!SSP1CON1bits.SSPEN)
    {
        SSP1STAT = 0x00;
        SSP1CON1 = 0x28;
        SSP1CON2 = 0x00;
        SSP1ADD = 0x13;
        return true;
    }
    else
        return false;
}

bit i2c1_driver_initSlaveHardware(void)
{
    if(!SSP1CON1bits.SSPEN)
    {
/* NOTE on AHEN:
 * If multiple slaves are to be emulated, then AHEN must be set.  It must be set
 * because the driver needs to selectively ACK/NACK the address depending on its
 * ability to handle the address.
*/

/* NOTE on DHEN:
 * DHEN must be set so that the data is not automatically NACK'ed if it is not read
 * from the SSPBUF.  This driver will ALWAYS read the SSPBUF so that it can pass
 * the value to the appropriate slave handler.  Because the data is ALWAYS read
 * the data will always be ACK'd if DHEN is cleared.  If the slave does not want
 * the data byte from the master then it will return false and a NACK will be returned.
 */

/* NOTE on SEN:
 * SEN will be set enabling clock stretching.  This is because we don't know how
 * long the user will take to process data bytes in their callbacks.  If they are fast,
 * we may not need to stretch the clock.  If they are slow, we need to stretch the clock.
 * If we ALWAYS stretch the clock, we will release the clock when the ISR is complete.
 */

/* NOTE on PCIE:
 * PCIE will be set to enable interrupts on STOP.  This will allow us know when
 * the master is finished
 */
        
/* NOTE on SCIE:
 * SCIE will be set to enable interrupts on START.  This will allow us to detect
 * both a START and a RESTART event and prepare to restart communications.
 */
        SSP1CON1 |= 0x06; //setup I2C Slave (7-bit Addressing)
        SSP1STAT = 0x00;
        SSP1CON2 = 0x00;
        
        SSP1CON1bits.SSPEN = 1;
        return true;
    }
    return false;
}

inline void i2c1_driver_resetBus(void)
{
    
}

inline void i2c1_driver_start(void)
{
    SSP1CON2bits.SEN = 1;
}

inline void i2c1_driver_restart(void)
{
    SSP1CON2bits.RSEN = 1;
}

inline void i2c1_driver_stop(void)
{
    SSP1CON2bits.PEN = 1;
}

inline bit i2c1_driver_isNACK(void)
{
    return SSP1CON2bits.ACKSTAT;
}

inline void i2c1_driver_startRX(void)
{
    SSP1CON2bits.RCEN = 1;
}

inline char i2c1_driver_getRXData(void)
{
    return SSP1BUF;
}

inline void i2c1_driver_setAddr(char addr)
{
    SSP1ADD = addr;
}

inline void i2c1_driver_setMask(char mask)
{
    SSP1MSK = mask;
}

inline void i2c1_driver_TXData(char d)
{
    SSP1BUF = d;
}

inline char i2c1_driver_getAddr(void)
{
    return SSP1ADD;
}

inline void i2c1_driver_sendACK(void)
{
    SSP1CON2bits.ACKDT = 0;
    SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
}

inline void i2c1_driver_sendNACK(void)
{
    SSP1CON2bits.ACKDT = 1;
    SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
}

inline void i2c1_driver_releaseClock(void)
{
    SSP1CON1bits.CKP = 1;
}

inline bit i2c1_driver_isBufferFull(void)
{
    return SSP1STATbits.BF;
}

inline bit i2c1_driver_isStart(void)
{
    return SSP1STATbits.S;
}

inline bit i2c1_driver_isAddress(void)
{
    return !SSP1STATbits.D_nA;
}

inline bit i2c1_driver_isStop(void)
{
    return SSP1STATbits.P;
}

inline bit i2c1_driver_isData(void)
{
    return SSP1STATbits.D_nA;
}

inline bit i2c1_driver_isRead(void)
{
    return SSP1STATbits.R_nW;
}

inline bit i2c1_driver_isWriteCollision(void)
{
    return SSP1CON1bits.WCOL;
}

inline bit i2c1_driver_isReceiveOverflow(void)
{
    return SSP1CON1bits.SSPOV;
}

inline void i2c1_driver_clearBusCollision(void)
{
    PIR3bits.BCL1IF = 0; // clear the bus collision.
}

inline void i2c1_driver_setBusCollisionISR(void *f){
    i2c1_driver_busCollisionISR = f;
}

inline void i2c1_driver_setI2cISR(void *f){
    i2c1_driver_i2cISR = f;
}
 

I have modofied code little bit by updating IDE and compiler version.
code as below.

With this below peice of code i could able to generate Clock, start & stop Pulse as per waveform. I am facing problem while reading i2c data.

1) When i use I2C_Master_Wait(); in below part of section . There will be No ack after higher byte of data
Code:
I2C_Master_Wait();
     ADCValue[0]=i2c_read(0); I2C_Master_Wait();


      ADCValue[1]=i2c_read(1);   I2C_Master_Wait();


2) If i comment I2C_Master_Wait(); after higher byte NA symbol seen but for lower byte there will be no clock pulse and lower byter stop at 2 pulse. This cycle continues repeat. kindly refer attached waveform for reference. Read_MCP3425_Data_functionout1.jpgRead_MCP3425.jpgMCP3425 waveform.JPG


Code:
 void i2c1_driver_close(void)
{
    SSP1CON1bits.SSPEN = 0;
}

/* Interrupt Control */
 void mssp1_enableIRQ(void)
{
    PIE3bits.SSP1IE = 1;
}

 bit mssp1_IRQisEnabled(void)
{
    return PIE3bits.SSP1IE;
}

 void mssp1_disableIRQ(void)
{
    PIE3bits.SSP1IE = 0;
}

 void mssp1_clearIRQ(void)
{
    PIR3bits.SSP1IF = 0;
}

 void mssp1_setIRQ(void)
{
    PIR3bits.SSP1IF = 1;
}

 bit mssp1_IRQisSet(void)
{
    return PIR3bits.SSP1IF;
}

 void mssp1_waitForEvent(uint16_t *timeout)
{
    //uint16_t to = (timeout!=NULL)?*timeout:100;
    //to <<= 8;

    if(PIR3bits.SSP1IF == 0)
    {
        while(1)// to--)
        {
            if(PIR3bits.SSP1IF) break;
            __delay_us(100);
        }
    }
}

bit i2c1_driver_open(void)
{
    if(!SSP1CON1bits.SSPEN)
    {
        SSP1STAT = 0x00;
        SSP1CON1 = 0x28;
        SSP1CON2 = 0x00;
        SSP1ADD = 0x13;
        return true;
    }
    else
        return false;
}

bit i2c1_driver_initSlaveHardware(void)
{
    if(!SSP1CON1bits.SSPEN)
    {
/* NOTE on AHEN:
 * If multiple slaves are to be emulated, then AHEN must be set.  It must be set
 * because the driver needs to selectively ACK/NACK the address depending on its
 * ability to handle the address.
*/

/* NOTE on DHEN:
 * DHEN must be set so that the data is not automatically NACK'ed if it is not read
 * from the SSPBUF.  This driver will ALWAYS read the SSPBUF so that it can pass
 * the value to the appropriate slave handler.  Because the data is ALWAYS read
 * the data will always be ACK'd if DHEN is cleared.  If the slave does not want
 * the data byte from the master then it will return false and a NACK will be returned.
 */

/* NOTE on SEN:
 * SEN will be set enabling clock stretching.  This is because we don't know how
 * long the user will take to process data bytes in their callbacks.  If they are fast,
 * we may not need to stretch the clock.  If they are slow, we need to stretch the clock.
 * If we ALWAYS stretch the clock, we will release the clock when the ISR is complete.
 */

/* NOTE on PCIE:
 * PCIE will be set to enable interrupts on STOP.  This will allow us know when
 * the master is finished
 */
        
/* NOTE on SCIE:
 * SCIE will be set to enable interrupts on START.  This will allow us to detect
 * both a START and a RESTART event and prepare to restart communications.
 */
        SSP1CON1 |= 0x06; //setup I2C Slave (7-bit Addressing)
        SSP1STAT = 0x00;
        SSP1CON2 = 0x00;
        
        SSP1CON1bits.SSPEN = 1;
        return true;
    }
    return false;
}

 void i2c1_driver_resetBus(void)
{
    
}

 void i2c1_driver_start(void)
{
    SSP1CON2bits.SEN = 1;
}

 void i2c1_driver_restart(void)
{
    SSP1CON2bits.RSEN = 1;
}

 void i2c1_driver_stop(void)
{
    SSP1CON2bits.PEN = 1;
}

 bit i2c1_driver_isNACK(void)
{
    return SSP1CON2bits.ACKSTAT;
}

 void i2c1_driver_startRX(void)
{
    SSP1CON2bits.RCEN = 1;
}

 char i2c1_driver_getRXData(void)
{
    return SSP1BUF;
}

 void i2c1_driver_setAddr(char addr)
{
    SSP1ADD = addr;
}

 void i2c1_driver_setMask(char mask)
{
    SSP1MSK = mask;
}

 void i2c1_driver_TXData(char d)
{
    SSP1BUF = d;
}

 char i2c1_driver_getAddr(void)
{
    return SSP1ADD;
}

 void i2c1_driver_sendACK(void)
{
    SSP1CON2bits.ACKDT = 0;
    SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
}

 void i2c1_driver_sendNACK(void)
{
    SSP1CON2bits.ACKDT = 1;
    SSP1CON2bits.ACKEN = 1; // start the ACK/NACK
}

 void i2c1_driver_releaseClock(void)
{
    SSP1CON1bits.CKP = 1;
}

 bit i2c1_driver_isBufferFull(void)
{
    return SSP1STATbits.BF;
}

 bit i2c1_driver_isStart(void)
{
    return SSP1STATbits.S;
}

 bit i2c1_driver_isAddress(void)
{
    return !SSP1STATbits.D_nA;
}

 bit i2c1_driver_isStop(void)
{
    return SSP1STATbits.P;
}

 bit i2c1_driver_isData(void)
{
    return SSP1STATbits.D_nA;
}

 bit i2c1_driver_isRead(void)
{
    return SSP1STATbits.R_nW;
}

 bit i2c1_driver_isWriteCollision(void)
{
    return SSP1CON1bits.WCOL;
}

 bit i2c1_driver_isReceiveOverflow(void)
{
    return SSP1CON1bits.SSPOV;
}

 void i2c1_driver_clearBusCollision(void)
{
    PIR3bits.BCL1IF = 0; // clear the bus collision.
}

 void i2c1_driver_setBusCollisionISR(void *f){
    i2c1_driver_busCollisionISR = f;
}

 void i2c1_driver_setI2cISR(void *f){
    i2c1_driver_i2cISR = f;
}





void I2C1_Initialize(void)
{
    SSP1ADD=0x13;
    SSP1STAT = 0x80;
     SSP1CON1 = 0x28;
     SSP1CON2 = 0x00;
     SSP1CON3 = 0x00;
    
  

}


void I2C_Master_Wait()
{
  while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F)); //Transmit is in progress
  //PIR3bits.BCL1IF=0;
}


int i2c_read( unsigned char ack )
	{
 	unsigned char i2cReadData;
    i2c1_driver_startRX();
   I2C_Master_Wait();
    i2cReadData = i2c1_driver_getRXData();
	I2C_Master_Wait();
 	if(1==ack)
  		{
  		 SSP1CON2bits.ACKDT = 0;
          SSP1CON2bits.ACKEN = 1;
  		}
 	else
  		{
  		 SSP1CON2bits.ACKDT = 1;
          SSP1CON2bits.ACKEN = 1;
  		}
   
 	return( i2cReadData );
}

 // working code
void Read_MCP3425()
{
    i2c1_driver_restart();
    I2C_Master_Wait();
     i2c1_driver_TXData(0XD0);
     I2C_Master_Wait();
     
    if((CONTROLREG & 0x04) == 0x04)
      {
	        
              i2c1_driver_TXData(0X89);
              i2c1_driver_sendACK();
              
      }
	     else
         {
            i2c1_driver_TXData(0X8B);
            i2c1_driver_sendACK();
         }  
     I2C_Master_Wait();
     i2c1_driver_stop();
     I2C_Master_Wait();
     
     i2c1_driver_restart();
     i2c1_driver_TXData(0XD1);
    //i2c1_driver_sendACK();
  I2C_Master_Wait();
     ADCValue[0]=i2c_read(0); // I2C_Master_Wait();
     // i2c1_driver_TXData(0XD1);
    //  I2C_Master_Wait();
      ADCValue[1]=i2c_read(1);  // I2C_Master_Wait();
     
    I2C_Master_Wait();
    i2c1_driver_sendACK();
    
 ADCResult = (ADCResult << 8) | ADCValue[1];
	ADCaverage += ADCResult;
    
    I2C_Master_Wait();
i2c1_driver_stop();

   
}







void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
  i2c_master_open();
 
   CONTROLREG =0X01; 
    
    I2C1_Initialize();
   i2c1_driver_open();
   i2c1_driver_initSlaveHardware();
   i2c1_driver_close();
   I2C1_Initialize();
   //I2C_Init();
   
    while (1)
    {
        
       Read_MCP3425();
        
    }
}
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top