Hello JackITB,
Thank you Jaques for your reply. I am working on PIC24fj64ga004 MCU, Here i
am communicating with 3 slaves (MAX30100,MMA9555L & OLED) by i2c
communication. while communicating with slaves am passing device
address(slave address) to following functions (ie : int I2C1_M_Poll(0X4C)
then it is not reading data it is directly coming out of loop. If i pass
slave address of (MAX30100(ie =0XAE)) code is working, but i pass device
address for MMA9555L (ie= 0X4C)then it is not detecting anything. my
question is why this device address (ox4c) is not detecting what is my
mistake i code. please tell the proper way to write it.
As you mentioned in data sheet like (MMA9555l device address is 0x4c
and Pedometer Application Identifier is 0x15 this am considering
as sub-address ) and these parameters am passing in my I2c communication
what parameters i need to pass in these function so it work properly as am
passing
I2C1_M_Poll(unsigned int DevAddr); EX: (I2C1_M_Poll(0X4C);)
I2C1_M_Read(unsigned int DevAddr,unsigned int SubAddr, int ByteCnt, char
*buffer); EX: ( I2C1_M_Read(0X4D,0X15,1,bufffer))
I2C1_M_ReadByte(unsigned int);
I2C1_M_Write(0X4C,0X15,1,bufffer);
I2C1_M_WriteByte('a');
This is first time i am implimenting this i2c communication .Here
somewhere am doing wrong please explain steps what should i do after this
i2c communication.Hope this time you replay quickly.
#include <p24FJ64GA004.h>
#include "i2c.h"
#include "delay.h"
//Variables//
unsigned int I2Cflags;
//Function prototype;
void I2C_HWini(void);
void I2C_ModuleStart(void);
void I2C_SWini(void);
int I2C1_M_BusReset(void);
void I2C1_M_ClearErrors(void);
int I2C1_M_Poll(unsigned int);
int I2C1_M_Read(unsigned int, unsigned int, int, char *);
int I2C1_M_ReadByte(unsigned int);
int I2C1_M_RecoverBus(void);
int I2C1_M_Restart(void);
int I2C1_M_Start(void);
int I2C1_M_Stop(void);
int I2C1_M_Write(unsigned int,unsigned int, int, char *);
int I2C1_M_WriteByte(char);
//int MMMA9555L_data_Tx(char*,int);
void I2C_HWini() //Set pin drive modes //I2C - drive outputs so we can
manually clear lines
{
LATBbits.LATB8 = 1;
LATBbits.LATB9 = 1; //Start with bus in idle mode - both lines hig
ODCBbits.ODB2 = 1; //Open drain mode
ODCBbits.ODB3 = 1;
// TRISBbits.TRISB8 = 0; //SCL1 output
// TRISBbits.TRISB9 = 0; //SDA1
output
}
void I2C_ModuleStart()
{
OSCCON = 0X2200;
// OSCTUN = 0X0000;
CLKDIV = 0X0000;
I2C1CON = 0x1000; //Set all bits to known state
I2C1CONbits.I2CEN = 0; //Disable until everything set up. Pins will be std
IO.
I2C1BRG = 39; //I2C1BRG = (Fcy/Fscl-FCY/10E6)
I2C1CONbits.DISSLW = 0; //Enable slew rate control for 400kHz operation
IFS1bits.MI2C1IF = 0; //Clear I2C master int flag
I2C1CONbits.I2CEN = 1; //Enable I2C //For interrupt driven code
IEC1bits.MI2C1IE = 1; //Enable I2C master interrupt
}
void I2C_SWini()
{
unsigned int I2Cflags = 0;
SetI2C1BusDirty; //I2C bus in unknown state, go ahead and clear it
}
int I2C1_M_BusReset()
{
int i;
//Start with lines high - sets SCL high if not already there
LATBbits.LATB8 = 1; //PORTBbits.RG2 = 1 is equivalent
LATBbits.LATB9 = 1;
delay(1); //Need 5uS delay
if(PORTBbits.RB2 == 0) //Read if line actually went high
{
return I2C_Err_SCL_low; //SCL stuck low - is the pullup resistor loaded?
}
i=10; //SCL ok, toggle until SDA goes high.
while(i>0)
{
if(PORTBbits.RB3 == 1) //If SDA is high, then we are done
{
break;
}
LATBbits.LATB8 = 0; //SCL low
delay(1); //Need 5uS delay
LATBbits.LATB8 = 1; //SCL high
delay(1); //Need 5uS delay
i--;
}
if((PORTB & 0x000C) != 0x000C) //We are ok if SCL and SDA high
{
return I2C_Err_SDA_low;
}
LATBbits.LATB9 = 0; //SDA LOW while SCL HIGH -> START
delay(1); //Need 5uS delay
LATBbits.LATB9 = 1; //SDA HIGH while SCL HIGH -> STOP
delay(1); //Need 5uS delay
return I2C_OK;
}
void I2C1_M_ClearErrors()
{
I2C1CONbits.RCEN = 0; //Cancel receive request
I2C1STATbits.IWCOL = 0; //Clear write-collision flag
I2C1STATbits.BCL = 0; //Clear bus-collision flag
}
int I2C1_M_Poll(unsigned int DevAddr)
{
int retval;
int SlaveAddr;
SlaveAddr = (DevAddr << 1) | 0;
if(IsI2C1BusDirty)
{
I2C1_M_ClearErrors();
if(I2C1_M_RecoverBus()==I2C_OK)
{//Recovered
ClrI2C1BusDirty;
}
else
{
return I2C_Err_Hardware;
}
}
if(I2C1_M_Start() == I2C_OK)
{
retval = I2C1_M_WriteByte((char)SlaveAddr);
if(I2C1_M_Stop() == I2C_OK) //Even if we have an error sending, try to
close I2C
{
if(retval == I2C_ACK)
{
return I2C_OK;
}
else if(retval == I2C_Err_NAK)
{
return I2C_Err_BadAddr; //Check that correct device address is being used
}
else
{
return I2C_Err_CommFail;
}
}
}
//Get here then we had an error
SetI2C1BusDirty; //Set error flag
return I2C_Err_CommFail;
}
int I2C1_M_Read(unsigned int DevAddr,unsigned int SubAddr, int ByteCnt,
char *buffer)
{
int SlaveAddr;
int retval;
int i;
if(IsI2C1BusDirty) //Ignore requests until Poll cmd is called to fix err.
return I2C_Err_BusDirty;
if(I2C1_M_Start() != I2C_OK) //Start
{//Failed to open bus
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
SlaveAddr = (DevAddr << 1) | 0; //Device Address + Write bit
retval = I2C1_M_WriteByte((char)SlaveAddr);
if(retval == I2C_Err_NAK)
{
//Bad Slave Address or I2C slave device stopped responding
I2C1_M_Stop();
SetI2C1BusDirty; //Will reset slave device
return I2C_Err_BadAddr;
}
else if(retval<0)
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
if( I2C1_M_WriteByte((char)SubAddr) != I2C_OK) //Sub Addr
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
if( I2C1_M_Restart() != I2C_OK) //Repeated start - switch to read mode
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
SlaveAddr = (DevAddr << 1) | 0x01; //Device Address + Read bit
if( I2C1_M_WriteByte((char)SlaveAddr) != I2C_OK) //Slave Addr
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
for(i=0;i<ByteCnt;i++) //Data
{
if(i==(ByteCnt-1) )
{
retval = I2C1_M_ReadByte(I2C_M_NACK); //NACK on last byte so slave knows
this is it
}
else
{
retval = I2C1_M_ReadByte(I2C_M_ACK);
}
if(retval >= 0)
{
buffer[i] = retval;
}
else
{
//Error while reading byte. Close connection and set error
flag.
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
}
if(I2C1_M_Stop() != I2C_OK)
{//Failed to close bus
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
return I2C_OK; //Success
}
int I2C1_M_ReadByte(unsigned int ACKflag)
{
int t;
if(ACKflag == I2C_M_NACK) //Set state in preparation for TX below
{
I2C1CONbits.ACKDT = 1;//NACK
}
else
{
I2C1CONbits.ACKDT = 0;//ACK
}
I2C1CONbits.RCEN = 1; //Start receive
t=0;//Timeout is processor speed dependent. @(4*8Mhz=16MIPS) and 8 bits, I
expect <=320.
//We could wait for RCEN to be cleared, but are really interested in
incoming byte, so look for I2C1STAT.RBF
while(!I2C1STATbits.RBF) //HW cleared when receive complete
{
t++;
if(t>8000)
{ //SCL stuck low
//RCEN cannot be cleared in SW. Will need to reset I2C interface, or wait
until SCL goes high.
return I2C_Err_RcvTimeout;
}
} //Tested: t=30
//I2C1STATbits.RBF will likely be set
//As the master we must ACK or NACK every byte, so slave knows if it
will send another byte.
//We have set the bit above, just need to send it
I2C1CONbits.ACKEN = 1; //Send ACK bit now
t=0; //Timeout is processor speed dependent.
@(4*8Mhz=16MIPS), I expect <=40.
while(I2C1CONbits.ACKEN) //HW cleared when complete
{
t++;
if(t>1000)
{//This will timeout if SCL stuck low
//ACKEN cannot be cleared in SW. I2C interface must be reset after this
error.
return I2C_Err_SCL_low;
}
}//Tested: t=4
if(I2C1STATbits.I2COV) //If an overflow occurred, it means we received a
new byte before reading last one
{
I2C1STATbits.I2COV = 0;
return I2C_Err_Overflow;
}
return I2C1RCV; //Reading this register clears RBF
}
int I2C1_M_RecoverBus()
{
int status;
I2C1CONbits.I2CEN = 0;
status = I2C1_M_BusReset();
if(status>0)
{//Fatal I2C error, nothing we can do about it
return I2C_Err_Hardware;
}
//That worked, bring I2C back online
I2C1CONbits.I2CEN = 1;
return I2C_OK;
}
int I2C1_M_Restart()
{
int t;
I2C1CONbits.RSEN = 1; //Initiate restart condition
t=0;
while(I2C1CONbits.RSEN) //HW cleared when complete
{
t++;
if(t>1000)
{
return I2C_Err_SCL_low;
}
}//Tested: t=5
if(I2C1STATbits.BCL)
{//SDA stuck low
I2C1STATbits.BCL = 0; //Clear error to regain control of I2C
return I2C_Err_BCL;
}
return I2C_OK;
}
int I2C1_M_Start()
{
int t;
I2C1CONbits.SEN = 1; //Initiate Start condition
Nop();
if(I2C1STATbits.BCL)
{//SCL or SDA stuck low
I2C1CONbits.SEN = 0; //Cancel request (will still be set if we had previous
BCL)
I2C1STATbits.BCL = 0; //Clear error to regain control of I2C
return I2C_Err_BCL;
}
if(I2C1STATbits.IWCOL)
{//Not sure how this happens but it occurred once, so trap here
I2C1CONbits.SEN = 0; //Clear just in case set
I2C1STATbits.IWCOL = 0; //Clear error
return I2C_Err_IWCOL;
}
t=0;
while(I2C1CONbits.SEN) //HW cleared when complete
{
t++;
if(t>1000)
{//Since SCL and SDA errors are trapped by BCL error above, this should
never happen
return I2C_Err_TimeoutHW;
}
}
if(I2C1STATbits.BCL)
{
I2C1STATbits.BCL = 0; //Clear error to regain control of I2C
return I2C_Err_BCL;
}
return I2C_OK;
}
int I2C1_M_Stop()
{
int t;
I2C1CONbits.PEN = 1; //Initiate stop condition
Nop();
if(I2C1STATbits.BCL)
{//Not sure if this can ever happen here
I2C1STATbits.BCL = 0; //Clear error
return I2C_Err_BCL; //Will need to reset I2C interface.
}
t=0;//Timeout is processor speed dependent. @(4*8Mhz=16MIPS), I expect
<=40.
while(I2C1CONbits.PEN) //HW cleared when complete
{
t++;
if(t>1000)
{//Will timeout if SCL stuck low
//PEN cannot be cleared in SW. Will need to reset I2C interface.
return I2C_Err_SCL_low;
}
}//Tested: t=5
return I2C_OK;
}
int I2C1_M_Write(unsigned int DevAddr,unsigned int SubAddr, int
ByteCnt, char *buffer)
{
int i;
int retval;
unsigned int SlaveAddr;
if(IsI2C1BusDirty) //Ignore requests until Poll cmd is called to fix err.
return I2C_Err_BusDirty;
if(I2C1_M_Start() != 0) //Start
{//Failed to open bus
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
SlaveAddr = (DevAddr << 1) | 0; //Device Address + Write bit
retval = I2C1_M_WriteByte((char)SlaveAddr);
if(retval == I2C_Err_NAK)
{//Bad Slave Address or I2C slave device stopped responding
I2C1_M_Stop();
SetI2C1BusDirty; //Will reset slave device
return I2C_Err_BadAddr;
}
else if(retval<0)
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
if( I2C1_M_WriteByte((char)SubAddr) != I2C_ACK) //Sub Addr
{
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
for(i=0;i<ByteCnt;i++) //Data
{
if( I2C1_M_WriteByte(buffer[i]) != I2C_ACK)
{//Error while writing byte. Close connection and set error flag.
I2C1_M_Stop();
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
}
if(I2C1_M_Stop() != I2C_OK)
{//Failed to close bus
SetI2C1BusDirty;
return I2C_Err_CommFail;
}
return I2C_OK;
}
int I2C1_M_WriteByte(char cData)
{
int t;
if(I2C1STATbits.TBF) //Is there already a byte waiting to send? //TBF
Transmission Buffer full
{
return I2C_Err_TBF;
}
I2C1TRN = cData; //Send byte
t=0;
while(I2C1STATbits.TRSTAT) //HW cleared when TX complete
{
t++;
if(t>8000)
{//This is bad because TRSTAT will still be set
return I2C_Err_SCL_low; //Must reset I2C interface, and possibly slave
devices
}
}//Testing: t=31
if(I2C1STATbits.BCL)
{
I2C1STATbits.BCL = 0; //Clear error to regain control of I2C
return I2C_Err_BCL;
}
//Done, now how did slave respond?
if(I2C1STATbits.ACKSTAT) //1=NACK
return I2C_Err_NAK; // NACK
else
return I2C_ACK; // ACK
}
Thanks & Regards
satish
On Fri, Apr 8, 2016 at 8:01 PM, JackITB <admin@community.freescale.com>