IIS2DLPC I2C Register Read
I am working with an IIS2DLPC. Using i2c I can write to and receive ACKs from the accelerometer as expected. I can also view this on my o'scope. However, when I request a read of any register I always get 0x0. I am using a PIC16F1503 microprocessor running at 16MHz. At this point all that is in my code is my i2c bit banging code. I assume I have some sort of timing issue on the read but I am not sure how to find it or determine my issue.
One thing to note, I have a function to wait for the bus to become idle. In this function there is a timeout in the event the clock is never released by the IIS2DLPC. This timeout seems to have no impact on the write operations. Again, I assume, because the clock is never released by the IIS2DLPC, I never receive the read.
I inherited this code from a prior project with a different accelerometer. However, everything looks right. Any help you can provide is appreciated.
void main(void) {
OSCCON = 0x7A; //16 Mhz
//RS this was not setting in the simulator
while(!OSCSTATbits.HFIOFR){
__delay_us(100);
}
CLRWDT();
Init();
I2c_Start(); // v51
review[0] = I2c_Write(0x30);
review[1] = I2c_Write(0x20);
review[2] = I2c_Write(0x97);
I2c_Stop();
I2c_Start(); // v51
review[3] = I2c_Write(0x30);
review[4] = I2c_Write(0x25);
review[5] = I2c_Write(0x44);
I2c_Stop();
while(1){
CLRWDT();
I2c_Start();
review[6] = I2c_Write(0x30);
review[7] = I2c_Write(0x0f);
I2c_Repeat_Start();
review[8] = I2c_Write(0x31);
review[9] = I2c_Read(0); // looking for low
if(review[9]==0x00){
review[10] = I2c_Read(0);
}
I2c_Stop();
__delay_ms(2);
}
}
void Init(){
PWM4CON0bits.PWM4OE = 0;
APFCONbits.NCO1SEL = 1;
CLC2CONbits.LC2EN = 0;
CLC2CONbits.LC2OE = 0;
ANSELC = 0B00000000;
TRISCbits.TRISC0 = 1;
TRISCbits.TRISC1 = 1;
}/******************************************************************************************/
// Initialize the I2C functions.
void I2c_Init()
{
i2c_error = FALSE;
// configure SCL and SDA pins as low (when configured as outputs)
// use pins as open drain outputs
i2c_sda = LOW;
i2c_scl = LOW;
// configure SCL and SDA pins as inputs
i2c_scl_dir = INPUT;
i2c_sda_dir = INPUT;
}
/******************************************************************************************/
/******************************************************************************************/
void I2c_Wait_For_Idle(void)
{
#define IDLE_TIMEOUT_COUNT 250
unsigned char temp;
// wait for bus to be idle
while ((i2c_scl == 0) && (temp < IDLE_TIMEOUT_COUNT))
temp++;
if (temp >= IDLE_TIMEOUT_COUNT)
i2c_error = TRUE;
}
/******************************************************************************************/
/******************************************************************************************/
// Issue start condition
void I2c_Start(void)
{
i2c_sda_dir = INPUT; // make sure sda is input and recessive high
i2c_scl_dir = INPUT; // make sure scl is input and recessive high
__delay_us(1);
// wait for scl to be released by slave
I2c_Wait_For_Idle();
i2c_sda_dir = OUTPUT; // move SDA low during SCL high (START CONDITION)
i2c_sda = LOW;
__delay_us(1);
i2c_scl_dir = OUTPUT; // move SCL low
i2c_scl = LOW;
}
/******************************************************************************************/
/******************************************************************************************/
// Issue repeated start condition
void I2c_Repeat_Start(void)
{
i2c_sda_dir = INPUT; // make sure sda is input and recessive high
i2c_scl_dir = INPUT; // make sure scl is input and recessive high
__delay_us(1);
// wait for scl to be released by slave
I2c_Wait_For_Idle();
i2c_sda_dir = OUTPUT; // move SDA low during SCL high (START CONDITION)
i2c_sda = LOW;
__delay_us(1);
i2c_scl_dir = OUTPUT; // move SCL low
i2c_scl = LOW;
}
/******************************************************************************************/
/******************************************************************************************/
void I2c_Stop(void)
{
i2c_sda_dir = OUTPUT; // move SDA low
i2c_sda = LOW;
i2c_scl_dir = INPUT; // make SCL high
__delay_us(2);
// wait for scl to be released by slave
I2c_Wait_For_Idle();
i2c_sda_dir = INPUT; // move SDA high druing SCL high (STOP CONDITION)
__delay_us(2);
}
/******************************************************************************************/
/******************************************************************************************/
// Read a byte. acknowledge indicates whether or not to acknowledge the reception
unsigned char I2c_Read( unsigned char acknowledge )
{
unsigned char i;
unsigned char data;
for (i=0; i<8; i++) /* read 8 bit data */
{
data = (data << 1); /* roll the bits one place to the left */
i2c_scl_dir = INPUT; /* make scl high, clock the data out on the rising edge */
__delay_us(1); /* 600 nsec < clock high min < infinity */
data = (data + i2c_sda); /* bring in the data bit */
i2c_scl_dir = OUTPUT; // make scl low
i2c_scl = LOW;
__delay_us(1); /* 1300 nsec < clock low min < infinity */
};
// do we need to acknowledge the reception?
if ( acknowledge )
{
// ack the reception
i2c_sda_dir = OUTPUT; // move sda low
i2c_sda = LOW;
}
else
// nack the reception
i2c_sda_dir = INPUT; // move sda high
__delay_us(1); /* maximum ee_sda fall time <= 300 nsec */
i2c_scl_dir = INPUT; // make scl high
__delay_us(1); /* 600 nsec < clock high min < infinity */
i2c_scl_dir = OUTPUT; /* make scl low */
i2c_scl = LOW; /* make scl low */
__delay_us(1);
return( data );
};
/******************************************************************************************/
/******************************************************************************************/
// write a byte. Returns Ack or Nack.
unsigned char I2c_Write( unsigned char data )
{
unsigned char i;
i2c_sda_dir = OUTPUT; // move SDA low
i2c_sda = LOW;
for (i=0; i<8; i++)
{
if (data & BIT7) /* (load the data) - mask all but MSB */
i2c_sda_dir = INPUT; // make sda high
else
{
i2c_sda_dir = OUTPUT; // make sda low
i2c_sda = LOW;
};
data = (data << 1); /* roll the bits one place to the left. */
i2c_scl_dir = INPUT; /* clock the data on the rising edge */
__delay_us(1); /* 600 nsec < clock high min < infinity */
i2c_scl_dir = OUTPUT;
i2c_scl = LOW;
__delay_us(1); /* 1300 nsec < clock low min < infinity */
};
// determine if slave ack'd or nack'd this byte
i2c_sda_dir = INPUT;
__delay_us(1);
i2c_scl_dir = INPUT;
__delay_us(1);
if (i2c_sda)
i = NACK_CODE;
else
i = ACK_CODE;
i2c_scl_dir = OUTPUT; // move scl low
i2c_scl = LOW;
return i;
}
/******************************************************************************************/
/* end of file */
//#endif