0
\$\begingroup\$

I am trying to poll a CAP188 sensor so I'm sending it read commands in a while loop, but the first read works and then on the second read when I send the slave address it detects a write collision.

To test my code I am trying to read the product ID which is a known value. Any help would be appreciated, thanks!

void chipWrite(unsigned char reg, unsigned char data){
//Start bit
I2C2CONbits.SEN = 1;
while(I2C2CONbits.SEN);
IFS3bits.MI2C2IF = 0;

//Slave address bit
I2C2TRN = 0b01010000;
while(!IFS3bits.MI2C2IF);
IFS3bits.MI2C2IF = 0;

//Register address
I2C2TRN = reg;
while(!IFS3bits.MI2C2IF);
IFS3bits.MI2C2IF = 0;

//Data
I2C2TRN = data;
while(!IFS3bits.MI2C2IF);
IFS3bits.MI2C2IF = 0;

//Stop bit
I2C2CONbits.PEN = 1;
IFS3bits.MI2C2IF = 0;
while(I2C2CONbits.PEN);
}

void initChip(){
CLKDIVbits.RCDIV = 0;
AD1PCFG = 0x9FFC;
I2C2CON = 0;
TRISBbits.TRISB3 = 0;
TRISBbits.TRISB2 = 0;
I2C2CONbits.ACKDT = 1;
I2C2BRG = 157;
I2C2CONbits.I2CEN = 1;
_MI2C2IF = 0;
}

 unsigned char chipRead(unsigned char reg){   
unsigned char msb = 0;
while(!I2C2STATbits.P);

 /*start*/   
I2C2CONbits.SEN = 1;   
while(I2C2CONbits.SEN);

/*sensor address*/   
I2C2TRN = 0b01010000; 
while(I2C2STATbits.TBF);   
while(I2C2STATbits.TRSTAT);
while(I2C2STATbits.ACKSTAT);

 /*Register for reading*/   
I2C2TRN = reg;
while(I2C2STATbits.TBF);  
while(I2C2STATbits.TRSTAT);   
while(I2C2STATbits.ACKSTAT);

 /*repeated start*/   
I2C2CONbits.RSEN = 1;   
while(I2C2CONbits.RSEN);

/*Slave address with read = 1*/
I2C2TRN = 0b01010001;       
while(I2C2STATbits.TBF); 
while(I2C2STATbits.TRSTAT);
while(I2C2STATbits.ACKSTAT);

 /*receiver enabled*/   
I2C2CONbits.RCEN = 1;

/*read first byte data*/   
//while(!I2C2STATbits.RBF);   
while(I2C2CONbits.RCEN);
msb = I2C2RCV;

/*send nack*/   
I2C2CONbits.ACKEN = 1;
while(I2C1CONbits.ACKEN);

/*send stop*/   
I2C2CONbits.PEN = 1;   
while(I2C2CONbits.PEN);

return msb; 
}


int main(void) {
initChip();
char key = 0b00000000;
chipWrite(0x72,0xFF);
chipWrite(0x2B, 0x80);
chipWrite(0x26, 0xFF);

while(1){
    key = chipRead(0xFD);
    asm("nop");
    if(key == 0b01010000){
        asm("nop");
    }
    else{
        asm("nop");
    }
    key = 0x00;
}


return 0;
}
\$\endgroup\$
4
  • \$\begingroup\$ the first read works .... how do you know if that is true? \$\endgroup\$
    – jsotola
    Dec 12, 2018 at 19:40
  • \$\begingroup\$ I'd start by putting in dwells much longer than a single NOP to see if that resolves the problem. \$\endgroup\$ Dec 12, 2018 at 21:29
  • 1
    \$\begingroup\$ please link a datasheet of the cap188 \$\endgroup\$
    – Damien
    Dec 13, 2018 at 16:11
  • \$\begingroup\$ "I am trying to poll a CAP188 sensor" Did you mean to say the CAP1188 touch sensor instead? \$\endgroup\$
    – SamGibson
    Dec 13, 2018 at 22:25

1 Answer 1

1
\$\begingroup\$

I can't find any CAP188 sensor datasheet online so I cannot verify that claim.

Some sensor will initiate measurement upon their call address, and they need some time to do so.

It's quite common that they will keep I2C line low during that time, until the measurement is ready to be read. Some chip can serialize the measurement during it's being measured, so the first read might work but not the second.

After your first address send, make a while(_RBx != 1); (rb being your I2C SDA or try as well SCL line) to wait the chip releases the line before the next write.

Other reasons can be: - I2C speed is too fast for the chip. - I2C delay between two write is too short.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.