SBAA288A July   2018  – January 2019 ADS7142

 

  1.   TM4C1294 interface to ADS7142 software library
    1.     Trademarks
    2. 1 Introduction
    3. 2 Hardware
    4. 3 Software
      1. 3.1 Header Files
      2. 3.2 ADS7142 Device Functional Modes Overview
      3. 3.3 Software Functions
    5. 4 Using the Software
      1. 4.1 Prerequisites
      2. 4.2 Getting Started
      3. 4.3 Using the Library
    6. 5 Main Routines and Test Data
      1. 5.1 Manual Mode
      2. 5.2 Autonomous Mode With Pre-Alert
      3. 5.3 Autonomous Mode With Post-Alert
      4. 5.4 Autonomous Mode With Start Burst Data
      5. 5.5 Autonomous Mode With Stop Burst Data
      6. 5.6 High Precision Mode
    7. 6 References
  2.   Revision History

Software Functions

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.

Table 4. Functions Used in Main

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 4. TM4C1294NCPDT Multi-Byte Transmit Flowchart

Figure 5 shows that to write to a single register in the ADS7142 device, the I2C master (TM4C1294) must transmit four bytes over I2C.

I2C_write_command_sbas773.gifFigure 5. Writing a Single Register in the ADS7142 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.

I2C_read_command_sbas773.gifFigure 6. Setting Register Address for a Single Register Read From the ADS7142

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.

Figure 7. TM4C1294NCPDT Single-Byte Receive Flowchart

As Figure 8 shows, this software flow is also represented using I2C frames.

I2C_command_reg_read_sbas773.gifFigure 8. ADS7142 Single Register Read

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.

Figure 9. TM4C1294NCPDT Multi-Byte Receive Flowchart

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.

tim_data_ext_conv_sbas773.gifFigure 10. Reading ADS7142 Conversion Data in Manual Mode

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.