SBAA288A July 2018 – January 2019 ADS7142
The main routines that place the ADS7142 into one of its functional modes call a set of functions that configure the registers of the device. Each function excluding TM4C1294Init() , ADS7142Calibrate(),ADS7142Reset(), and ADS7142HighSpeedEnable() is developed from pseudocode software flows in the TM4C1294 datasheet. Table 4 provides a brief description of these functions.
Function Name | Description |
int TM4C1294Init (uint8_t bFast) | Configures the TM4C1294 as the target device for the compiler, sets the clocking of the device, and enables peripherals to be used in this application. The bFast variable sets the I2C frequency (100kHz or 400kHz). |
int ADS7142SingleRegisterWrite(uint8_t RegisterAddress, uint8_RegisterData) | WritesRegisterData to RegisterAddress in order to configure the ADS7142. The ADS7142 slave address is set by hardware on the BoosterPack™ and is defined in ADS7142RegisterMap.h. |
int ADS7142SingleRegisterRead(uint8_t RegisterAddress, uint32_t *read) | Reads the data at RegisterAddress and places this data into the read variable for local use. |
void TM4C1294_ArbitrationLost_ErrorService(void) | This function performs an I2C SDA bus clear in the case that the host MCU loses arbitration. Arbitration loss in a single-master system is usually due to the slave device holding the bus at some undesirable state while the host attempts to perform some I2C function. This function configures SCL as a GPIO and toggles SCL nine times, after which the slave releases the bus |
int ADS7142Calibrate(void) | This function is called right after TM4C1294Init() to abort the present conversion sequence and calibrate any offset error out of the device. |
int ADS7142Reset(void) | This function gives the user the option of a software reset of the ADS7142. This function is not called in the functional modes firmware because the device calibrates its own offset and I2C address upon power-up. |
int ADS7142HighSpeedEnable(uint8_t HighSpeedMask) | This function enables the host MCU and ADS7142 to communicate at high speed I2C frequencies (1.7 MHz to 3.4 MHz). |
int ADS7142DataRead_count(uint64_t SampleCount) | This function takes a sample count as a user input: the ADS7142 only samples this specified number of samples from the desired input channels. This function is used in high precision mode and autonomous mode to count 16 12-bit conversions before placing them in either the data buffer or channel accumulators. |
int ADS7142DataRead_infinite(void) | Similar to ADS7142DataRead_count() , this function samples data from the ADS7142 input channels. However, this function infinitely provides sample data as opposed to a specified number of data samples. |
int ADS7142DataRead_autonomous(void) | This sampling function is specific to the pre-alert and post-alert autonomous modes of the ADS7142. Upon sampling, this function compares the digitized value of the sample to the digital window comparator settings for the high and low threshold alerts. |
The development of the functions ADS7142SingleRegisterWrite(), ADS7142SingleRegisterRead(), TM4C1294_ArbitrationLost_ErrorService, and ADS7142DataRead_infinite() are crucial to effectively placing the ADS7142 in the user's desired functional mode. ADS7142SingleDataRead_count() and ADS7142DataRead_autonomous() are derivatives of ADS7142DataRead_infinite(). Within each I2C module of the master TM4C1294 there is an I2CMasterSlaveAddress (I2CMSA) register that contains the slave address of the device that the host must communicate with over I2C. A low-level function named MasterSlaveAddrSet() in i2c.c is called to configure this address. When the slave address is properly configured, the first data byte can be put into the I2CMasterDataRegister (I2CMDR) via a call of the function MasterDataPut(). The I2CMasterDataRegister can be used to either write to or read from the slave device. A master command is then provided to the I2CMasterControlStatus (I2CMCS) register via function call I2CMasterControl() to send the data byte. A specific master command is used for multi-byte transmission.
The TM4C1294NCPDT datasheet provides a software flow that is used to develop the function ADS7142SingleRegisterWrite(). Figure 4 shows this flow.
Figure 5 shows that to write to a single register in the ADS7142 device, the I2C master (TM4C1294) must transmit four bytes over I2C.
The ADS7142SingleRegisterWrite() function code is the following:
int
ADS7142SingleRegisterWrite (uint8_t RegisterAddress, uint8_t RegisterData)
{
//
//ADS7142SingleRegisterWrite writes data to an ADS7142 register address
//ADS7142registermap.h contains all the device datasheet register map
//register addresses and register values for configuration.
//
//
// Tell the master module what address it will place on the bus when
// communicating with the slave. Set the address to ADS7142_I2C_ADDRESS
// (as set in the slave module). The receive parameter is set to false
// which indicates the I2C Master is initiating a write to the slave. If
// the receive parameter is true, that would indicate that the I2C Master
// is initiating reads from the slave.
//
I2CMasterSlaveAddrSet(I2C8_BASE, ADS7142_I2C_ADDRESS, false);
//Place the first byte to be transmitted into the I2CMDR Register of the TM4C1294
//The first byte to be transmitted following the SLAVE Address is the Single Register Write opcode
I2CMasterDataPut(I2C8_BASE, SINGLE_REG_WRITE);
//Check the I2C Bus to ensure it is not busy (Read I2CMCS)
//while(I2CMasterBusBusy(I2C8_BASE));
//I2C Master Command for the Start BURST Send of 3 bytes
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_START);
//Implement delay
SysCtlDelay(100);
//Read I2CMCS
//Wait for the I2CMaster to finish transmitting before moving to next byte
while(I2CMasterBusy(I2C8_BASE));
//Check for errors in the I2C8 Module
while (I2CMasterErr(I2C8_BASE))
//Error branching
{
//Check for I2C Bus arbitration loss error condition
if(I2CMasterErr(I2C8_BASE) == I2C_MASTER_ERR_ARB_LOST)
{
//Error Service
TM4C1294_ArbitrationLost_ErrorService();
//Return the error status
return -1;
}
//Write I2C Master Command for error stop if the error
//is not due to i2c bus arbitration loss
else I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
}
//Place the next byte into I2CMDR, which is the ADS7142 register address for the desired data write
I2CMasterDataPut(I2C8_BASE, RegisterAddress);
//I2C Master Command for continued BURST send of the next byte
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
//Implement Delay
SysCtlDelay(100);
//Read I2CMCS
//Wait for the I2CMaster to finish transmitting before moving to next byte
while(I2CMasterBusy(I2C8_BASE));
//Check for errors in the I2C8 Module
while (I2CMasterErr(I2C8_BASE))
//Error branching
{
//Check for I2C Bus arbitration loss error condition
if(I2CMasterErr(I2C8_BASE) == I2C_MASTER_ERR_ARB_LOST)
{
//Error Service for loss of bus arbitration
TM4C1294_ArbitrationLost_ErrorService();
//Return the error status
return -1;
}
//Write I2C Master Command for receive error stop if the error
//is not due to i2c bus arbitration loss
else I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
}
//Place the final byte into I2CMDR, which is the register data to be placed in the desired register address
I2CMasterDataPut(I2C8_BASE, RegisterData);
//I2C Master Command for the finished BURST send of the data
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
//Implement delay
SysCtlDelay(100);
//Read I2CMCS (I2C Master Control/Status)
//Wait for the I2C Master to finish transmitting
while(I2CMasterBusy(I2C8_BASE));
//Check the error flag in the I2C8 Module
while (I2CMasterErr(I2C8_BASE));
//Return no errors
return 0;
}
To read a single register from the ADS7142, the desired register address must first be set through a series of I2C writes. The ADS7142SingleRegisterRead() function first performs the multi-byte transmit software flow in Figure 4 to set the register that will be read from the ADS7142. Figure 6 shows the required I2C writes prior to register read.
When the required write operations are complete, the host MCU can read the register data. This operation is outlined as a master single byte receive software flow in the TM4C1294NCPDT datasheet. Figure 7 shows the TM4C1294NCPDT single byte receive software flow.
As Figure 8 shows, this software flow is also represented using I2C frames.
The function code for the operations required to perform a single register read is the following:
int
ADS7142SingleRegisterRead(uint8_t RegisterAddress, uint32_t *read)
{
//
//ADS7142SingleRegisterRead reads data from a single register
//in the ADS7142.
//
//
// Tell the master module what address it will place on the bus when
// communicating with the slave. Set the address to ADS7142_I2C_ADDRESS
// (as set in the slave module). The receive parameter is set to false
// which indicates the I2C Master is initiating a write to the slave.
// To perform a register read, the Master must first transmit the desired I2C address for communication.
// Following the I2C address transmission, the single register read opcode will be transmitted.
// The receive parameter is then set to true for read of register contents.
//
I2CMasterSlaveAddrSet(I2C8_BASE, ADS7142_I2C_ADDRESS, false);
//Place the Single Register Read opcode into the I2CMDR Register
I2CMasterDataPut(I2C8_BASE, SINGLE_REG_READ);
//Initiate the BURST Send of two data bytes
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_START);
//Implement Delay
SysCtlDelay(100);
//Wait for the I2C Master to finish transmitting
while(I2CMasterBusy(I2C8_BASE));
//Check for errors in the I2C8 Module
while (I2CMasterErr(I2C8_BASE))
//Error branching
{
//Check for I2C Bus arbitration loss error condition
if(I2CMasterErr(I2C8_BASE) == I2C_MASTER_ERR_ARB_LOST)
{
//Error service for loss of bus arbitration
TM4C1294_ArbitrationLost_ErrorService();
//Return the error status
return -1;
}
//Write I2C Master Command for receive error stop if the error
//is not due to i2c bus arbitration loss
else I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
}
//Place the Register Address to be communicated with into the I2CMDR Register
I2CMasterDataPut(I2C8_BASE,RegisterAddress);
//I2C Master Command for finished Burst Send of the two bytes required for register read
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
//Implement Delay
SysCtlDelay(100);
//Wait for the I2C Master to finish transmitting the data
while(I2CMasterBusy(I2C8_BASE));
//Check the error flag in the I2C8 Module
while(I2CMasterErr(I2C8_BASE))
{
//Error service for address ACK or data ACK
}
//Set the receive parameter to true in order to receive data from the desired register address
I2CMasterSlaveAddrSet(I2C8_BASE, ADS7142_I2C_ADDRESS, true);
//Check the I2C Bus to ensure it is not busy
while(I2CMasterBusBusy(I2C8_BASE));
//I2C Master Command for the Single Byte Receive from the register address
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
//Implement Delay
SysCtlDelay(100);
//Wait for the I2C Master to finish transmitting the data
while(I2CMasterBusy(I2C8_BASE));
//Check the error flag in the I2C8 Module
while(I2CMasterErr(I2C8_BASE))
{
//Error service for address ACK or data ACK
}
//Get the data placed into the I2CMDR Register from the ADS7142
//Place data into the read flag that contains the data for local use
read[0] = I2CMasterDataGet(I2C8_BASE);
//Return no errors
return 0;
}
In order for conversion data to be read continuously from the ADS7142, the TM4C1294 must perform a multi-byte receive operation over I2C. This software flow is the basis for the functions ADS7142DataRead_infinite(), ADS7142DataRead_count(), and ADS7142DataRead_autonomous().Figure 9 shows the pseudocode flow.
Let's take a look at the development of ADS7142DataRead_continuous(). This function is only used in manual mode because in this mode, the ADS7142 is continuously outputting sample data from the desired input channels. Figure 10 shows the continuous read of sample bytes.
The ADS7142DataRead_continuous() function code is the following:
int
ADS7142DataRead_continuous(void)
{
//
//ADS7142DataRead_continuous() continuously clocks out the data sampled by the ADS7142
//once it is placed in manual mode. The function provides
//continuous SCL to clock out the data
//
//Provide Device Address and Read Bit to Start Conversions
I2CMasterSlaveAddrSet(I2C8_BASE, ADS7142_I2C_ADDRESS, true);
//Check the I2C Bus to ensure it is not busy
//while(I2CMasterBusBusy(I2C8_BASE));
//Write the Burst receive I2C Master Command to I2CMCS
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
//Implement Delay
SysCtlDelay(100);
//Allow the Master to finish receiving the first byte
while(I2CMasterBusy(I2C8_BASE));
//Check for errors in the I2C8 Module
while (I2CMasterErr(I2C8_BASE))
//Error branching
{
//Check for I2C Bus arbitration loss error condition
if (I2CMasterErr(I2C8_BASE) == I2C_MASTER_ERR_ARB_LOST)
{
//Error service for loss of bus arbitration
TM4C1294_ArbitrationLost_ErrorService();
//Return the error status
return -1;
}
//Write I2C Master Command for receive error stop if the error
//is not due to i2c bus arbitration loss
else
{
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
{
//Error service for address ACK or data ACK
}
}
}
//Read data from I2CMDR
I2CMasterDataGet(I2C8_BASE);
//Provide Continuous SCL
while(1)
{
//Continue receiving the burst data
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
//Implement Delay
SysCtlDelay(100);
//Allow the Master to finish receiving each byte
while(I2CMasterBusy(I2C8_BASE));
//Check for errors in the I2C8 Module
while (I2CMasterErr(I2C8_BASE))
//Error branching
{
//Check for I2C Bus arbitration loss error condition
if(I2CMasterErr(I2C8_BASE) == I2C_MASTER_ERR_ARB_LOST)
{
//Error service for loss of bus arbitration
TM4C1294_ArbitrationLost_ErrorService();
//Return the error status
return -1;
}
//Write I2C Master Command for receive error stop if the error
//is not due to i2c bus arbitration loss
else
{
I2CMasterControl(I2C8_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
{
//Error Service for address ACK or data ACK
}
}
}
//Receive data in I2CMDR
I2CMasterDataGet(I2C8_BASE);
}
//Return no errors
return 0;
}
The ADS7142DataRead_count() and ADS7142DataRead_autonomous() functions are discussed and presented in Section 5 for sake of coherence to the functional modes they are used in.