Hi, I am actually using ADC model ADS1110 with I2C communication on an active product.
To improve conversion stability vs temperature variation, I selected ADC ADS1114 to modify that existing product.
I have all proven I2C C language functions to communicate with existing ADS1110.
I am recycling the I2C functions to configure and read the new ADS1114.
I am refering to the datasheet SBAS444B (october 2009), page 11, section "Write to Pointer register".
When testing, the ADS1114 return a NAK (not acknowledge) right after sending "Second byte: 0b00000000 (points to Conversion register inside Read_ADS1114_Data_NR function)", while I expect an "ACK"), and while the previous "7-bits I2C address followed by a low read/write bit" returned an AK (acknowledge).
You may see below my i2c_write() function, written in CCS C and executed in a PIC18F67K22 Microchip.
While I review over and over my code for a "between the chair and the keyboard" mistake, I submit my question:
"Can somebody see something wrong in the code ( inside Read_ADS1114_Data_NR function) that fail for a ADS1114 in this function, when I attempt writing the 2nd byte to point to Conversion register, even if the same i2c_write() function works well with ADS1110" ?
Thanks
Code sample:
[…]
//----------------------------------------------------------------------------
// Function : Init_ADS1114
//
// Description : Initialize/Configure the ADS1114 A/D chip
//
// Input : None
//
// Output : None
//
// Return : OK (0x00): Operation completed OK
// : ERR_I2C (0x01): device not responding over i2c
//
// Globals : None
//----------------------------------------------------------------------------
BYTE Init_ADS1114(void )
{
BYTE byRet;
//Write to Config Register
byRet = Write_ADS1114_Cfg( OPTICS_BLCK_ADC_I2C_ADD, ADS1114_CFG );
//OPTICS_BLCK_ADC_I2C_ADD = 0x49 = 0b1001001 = byAdd
//ADS1114_CFG = 0x8483 = 0b0000010110000011 --> ADS1114 Config: BIT15:OS[1](0:no effect in //write;1:begin single conversion); BIT14-13-12:MUX INPUT[000](ADS1115 only) ; BIT11-10-//09:PGA[010](010:FS=+-2.048V (default)) ; BIT8:MODE[0](continuous conversion mode) ; BIT7-6-//5:DATA RATE[100](128SPS (default)) ; BIT4:COMP MODE[0](0:traditional comparator with hysteresis //(default)) ; BIT3:COMP POL[0](polarity, 0:active low (default)) ; BIT2:COMP LAT[0](non-latching //comparator (default)) ; BIT1-0:COMP QUEUE[11](11:disable comparator (default)
if (byRet != OK)
{
return( ERR_I2C ); // unable to Write CFG_REG of ADS1114 chip
}
return( OK );
}
//----------------------------------------------------------------------------
// Function : Write_ADS1114_Cfg
//
// Description : Write the Configuration register (16 bit) of A/D (ADS1114)
//
// This function RETRIES 2 times (3 attempts total)
// is case of error
//
//
// Input : byADD : Address of the ADS1114
//
// byCfg_Reg : The byte value to write to Cfg_Reg
//
// Output : None
//
// Return : OK (0x00): Operation completed OK
// : ERR_I2C (0x01): device not responding over i2c
//
// Globals : None
//----------------------------------------------------------------------------
BYTE Write_ADS1114_Cfg( WORD byAdd, WORD byCfg_Reg )
{
BYTE byRet;
BYTE byRetry_Cnt;
byRetry_Cnt = 3;
do
{
byRet = Write_ADS1114_Cfg_NR( byAdd, byCfg_Reg );
if (byRet != OK)
{
delay_ms(200);
init_i2c_port(); // re-init i2c_1 port
}
byRetry_Cnt--;
}
while ( (byRet != OK) && (byRetry_Cnt) );
if ( (byRet != OK) && (byRetry_Cnt == 0) )
return( ERR_I2C ); // unable to Write ADS1114 chip
return( OK );
}
//----------------------------------------------------------------------------
// Function : Write_ADS1114_Cfg_NR (No Retry)
//
// Description : Write the Configuration register (16 bit) of A/D (ADS1114)
//
// This function DOES NOT RETRY is case of error
//
//
// Input : byADD : Address of the ADS1114
//
// byCfg_Reg : The byte value to wrtie to Cfg_Reg
//
// Output : None
//
// Return : OK (0x00): Operation completed OK
// : ERR_I2C (0x00): device not responding over i2c
//
// Globals : None
//----------------------------------------------------------------------------
BYTE Write_ADS1114_Cfg_NR( WORD byAdd, WORD byCfg_Reg )
{
BYTE byRet;
byRet = i2c_start1();
if (byRet != OK)
return( ERR_I2C ); // unable to Write ADS1114 chip
byRet = i2c_write1( ADS1114_I2C_W_CMD | (byAdd<<1) );
//First byte = [low read/write bit] | [First 7-bit I2C address <<1 ]
// ADS1114_I2C_W_CMD = 0x00
if (byRet != I2C_ACK_OK)
{
return( ERR_I2C );
}
byRet = i2c_write1( 0b00000001 ); //POINTS TO CONFIG REGISTER
//Second byte = points to Config register
if (byRet != I2C_ACK_OK)
{
return( ERR_I2C );
}
byRet = i2c_write1( ADS1114_CFG_MSB ); //WRITE TO CONFIG REGISTER
//Third byte = [MSB of the Config register]
if (byRet != OK)
{
return( ERR_I2C ); // unable to Write ADS1114 chip after 2 retries (3 attempts total)
}
byRet = i2c_write1( ADS1114_CFG_LSB ); //WRITE TO CONFIG REGISTER
//Fourth byte = [LSB of the Config register]
if (byRet != OK)
return( ERR_I2C ); // unable to Write ADS1114 chip
byRet = i2c_stop1();
if (byRet != OK)
return( ERR_I2C ); // unable to Write ADS1114 chip
return( OK );
}
//----------------------------------------------------------------------------
// Function : Read_ADS1114_Data
//
// Description : Read the Output register (16 bit) of A/D (ADS1114)
//
// This function RETRIES 2 times (3 attempts total)
// is case of error
//
// Input : byADD : I2C Address of the ADS1114
//
// *pwAD_Data16 : pointer to a WORD where read A/D result
// will be returned
//
// Output : *pwAD_Data16 : A/D result (16 bits)
//
// Return : OK (0x00): Operation completed OK
// : NAK (0x01): Error with Optics Block ADC ADS1114 chip occured
//
// Globals : None
//----------------------------------------------------------------------------
BYTE Read_ADS1114_Data( BYTE byAdd, WORD *pwAD_Data16 )
{
BYTE byRet;
BYTE byRetry_Cnt;
byRetry_Cnt = 3;
do
{
byRet = Read_ADS1114_Data_NR( byAdd, pwAD_Data16 );
if (byRet != OK)
{
delay_ms(200);
init_i2c_port(); //re-init i2c port
}
byRetry_Cnt--;
}
while ( (byRet != OK) && (byRetry_Cnt) );
if ( (byRet != OK) && (byRetry_Cnt == 0) )
return( NAK ); //unable to Read ADS1114 chip
return( OK );
}
//----------------------------------------------------------------------------
// Function : Read_ADS1114_Data_NR (No Retry)
//
// Description : Read the Output register (16 bit) of A/D (ADS1114)
//
// This function DOES NOT RETRY is case of error
//
// Input : byADD : I2C Address of the ADS1114
//
// *pwAD_Data16 : pointer to a WORD where read A/D result
// will be stored
//
// Output : *pwAD_Data16 : A/D result (16 bits)
//
// Return : OK (0x00): Operation completed OK
//
// : ERR_I2C(0x01): device not responding over i2c
// : I2C_ACK_OK (0x01): i2c error (...redundant)
// Globals : None
//----------------------------------------------------------------------------
BYTE Read_ADS1114_Data_NR( BYTE byAdd, WORD *pwAD_Data16 )
{
BYTE byAD_Reg[3];
BYTE byRet;
byRet = i2c_start1();
if (byRet != OK)
return( ERR_I2C ); //i2c start error
byRet = i2c_write1( ADS1114_I2C_R_CMD | (byAdd<<1) );
//First byte = [high read/write bit] | [First 7-bit I2C address <<1 ]
// ADS1114_I2C_R_CMD = 0x01
if (byRet != I2C_ACK_OK)
return( ERR_I2C ); //i2c start error */
byRet = i2c_write1( ADS1114_I2C_W_CMD | (byAdd<<1) );
//WRITE TO POINTER REGISTER //First byte = [low read/write bit] | [First 7-bit I2C address<<1]
if (byRet != I2C_ACK_OK)
{
return( ERR_I2C );
// unable to Write ADS1114 chip after 2 retries (3 attempts total)
}
byRet = i2c_write1( 0b00000000 );
//Second byte = points to Conversion register
if (byRet != I2C_ACK_OK)
{
//Here is where it stop working. The code always enter in this loop
//ADS1114 always return 0x01 (NAK), while I expect 0x00 (ACK)
//and the PIC get out of the function before reading the ADC result into the conversion register.
//Even if I put in comment this error trap, I receive a NAK after the following “i2c_write1(…)”
return( ERR_I2C );
}
byRet = i2c_write1( ADS1114_I2C_R_CMD | (byAdd<<1) );
//READ CONVERSION REGISTER //First byte = [high read/write bit] | [First 7-bit I2C address<<1]
if (byRet != I2C_ACK_OK)
{
return( ERR_I2C ); // unable to Write ADS1114 chip
}
byRet = i2c_read1( &byAD_Reg[0], I2C_ACK_ADS1114_AFTER_RD );
//READ CONVERSION REGISTER
//Second byte = ADS1114 response with [MSB of the Conversion register]
if (byRet != OK)
return( ERR_I2C ); //i2c start error
byRet = i2c_read1( &byAD_Reg[1], I2C_ACK_ADS1114_AFTER_RD );
//READ CONVERSION REGISTER
//Third byte = ADS1114 response with [LSB of the Conversion register]
if (byRet != OK)
return( ERR_I2C ); //i2c start error
byRet = i2c_stop1();
if (byRet != OK)
return( ERR_I2C ); //i2c start error
*(BYTE *)pwAD_Data16 = byAD_Reg[1]; //LSB portion
*pwAD_Data16 = byAD_Reg[0]; //MSB portion
*pwAD_Data16 = (WORD)(*pwAD_Data16<<8) | (WORD)byAD_Reg[1];
return( OK );
}
//----------------------------------------------------------------------------
// Function : i2c_write1
//
// Description : Sends a single byte over the I2C port 1
//
// Input : bData : the byte to send
//
// Return : The ACK bit generated by the slave i2c device.
// or WCOL error.
//
// Usefull #define:
// I2C_ACK_OK 0x00 // ACK received OK from i2c slave
// I2C_NOACK 0x01 // No ACK Received from i2c slave
// I2C_WCOL_ERR 0x02 // A i2c write to SSPxBUF was...
// // attempted while i2c were...
// // not valid for Tx
// ERR_I2C_WR_TIMEOUT (0x04): I2C transmit timeout
//
// Globals : None
//----------------------------------------------------------------------------
BYTE i2c_write1( BYTE bData )
{
WORD wTimeout;
BYTE bAckState;
WCOL1 = 0; // clear bit
SSP1IF = 0; // clear bit
SSPBUF = bData;
if (WCOL1)
{
return( I2C_WCOL_ERR );
}
wTimeout=0x0444; //timeout: 1ms (or longer, approx for PIC18 Fosc=40MHz)
do
{
wTimeout--;
}
while( (SSP1IF==0) && wTimeout); // wait for transmit to complete
if ( wTimeout )
{
bAckState = ACKSTAT1; // I2C_ACK_OK(0) or I2C_NOACK(1)
return(bAckState);
}
else
{
return( ERR_I2C_WR_TIMEOUT ); // timeout error
}
}
[…]