is I2C slave necessary?

This may seem like a silly question but do I have to create an I2C slave driver for every master driver that I create?

Example: I have written an I2C master reader program for a Leonardo. It reads data from an AMC7812B and an INA3221. Do I need to write slave writer programs for each of the slave devices? I don’t see data specifying the answer to this question in either datasheet, only how I2C works.

I thought the I2C bus had each slave device with it’s own device number and the master device sent commands on the bus with the device number. Upon seeing its device number, that slave device then processed the command.

econjack: I thought the I2C bus had each slave device with it's own device number and the master device sent commands on the bus with the device number. Upon seeing its device number, that slave device then processed the command.

Right, but what I am wondering is if the slave devices already come loaded with slave code.

(deleted)

You only need to write a "slave driver" if your slave is another Arduino or other microcontroller.

KeithRB: You only need to write a "slave driver" if your slave is another Arduino or other microcontroller.

Thank you. I should have figured that...

You have to write some code (or find a library) that uses Wire.h command to write & read the registers of the slave device. See pages 49 on for example: http://www.ti.com/lit/ds/symlink/amc7812b.pdf That tells you what registers to write & read to get the data you want. You don't load any code into the slave, it has it's own processing to respond to what's requested via the registers. You may have to monitor/control other signals as well depend on you're doing.

Personally, I would the faster SPI interface instead at the expense of having to drive a slave select pin. You can achieve 2 MHz SPI clock vs 400 KHz I2C clock.

CrossRoads:
You have to write some code (or find a library) that uses Wire.h command to write & read the registers of the slave device.

That is what I have done here:

/*
 *    SDT_LP_Arduino_I2C_Master
 *    
 *    Demonstrates how the Arduino Leonardo integrated within the LattePanda
 *    will read data from peripheral devices on the PCB. Specifically, this 
 *    reader will use the I2C communication protocol to read data from an 
 *    analog-to-digital converter and from a current sensing IC.
 *    
 *    The Circuit:
 *      - Arduino Leonardo (LattePanda)
 *          SDA: 6
 *          SCL: 8
 *      - AMC7812B High Precision ADC
 *          SDA: 4
 *          SCL: 5
 *      - INA3221 High Precision I-Sense
 *          SDA: 7
 *          SCL: 6
 *      
 *    Created 16 February 2017
 *    By Dennis Sabene
 *    Modified XXXXXXXXXXX
 *    By XXXXXXXXXXX
 *    
 */
#include <Wire.h>

#define V_REF       2.50    // Internal reference voltage for AMC7812B
#define I2C_SPEED   400000L // 100000L for 100kbps clock speed     
#define ADC_ADDR    0x5F    // A0-A2 tied to GND, B1100001 for binary 0x61
#define ADC_CONFIG  0x3c    // AMC7812B configuration register 0 address 
#define ADC_CTRL    0x50    // AMC7812B control register 0 address   
#define INA_ADDR    0x40    // A0 tied to GND, B1000000 for binary   
#define INA_CONFIG  0x00    // INA3221 configuration register address   

unsigned int adcData[16];  
unsigned int inaBus[3];   
unsigned int inaShunt[3];   
byte  adcChannel      = 0x23; // Counter  
byte  inaShuntChannel = 0x01; // Counter    
byte  inaBusChannel   = 0x02; // Counter    
float analogValue     = 0;    // Used for formatting analog output
int   serialBaud      = 9600;  
int   oneSecDelay     = 1000;

void setup() 
{
  Serial.begin(serialBaud); // Serial output for test and debug       
  Wire.begin();
  Wire.setClock(I2C_SPEED); // 400kbps clock speed
  init_devices(); 
}

void loop() 
{
  Serial.println("Reading ADC, please wait...");
  Serial.println();
  delay(3000); // Delay 1 second
  read_ADC();
  delay(3000); // Delay 1 second
  read_INA();
}

/*
 * Sends a command byte to both peripheral devices.
 * Used for configuring the devices.
 */
void init_devices() 
{
  Wire.beginTransmission(ADC_ADDR);
  Wire.write(ADC_CONFIG);   
  Wire.write(0x2C);   // Command byte [binary: B00101100]
  Wire.endTransmission(); 

  Wire.beginTransmission (ADC_ADDR);
  Wire.write(ADC_CTRL);
  Wire.write(0x6DFF); // Command byte [binary: B0110110111111111]
  Wire.endTransmission();

  Wire.beginTransmission(INA_ADDR);
  Wire.write(INA_CONFIG);
  Wire.write(0x71B7); // Command byte [binary: B0111000110110111]
  Wire.endTransmission();
}

/*
 * Reads the 16 ADC data channel registers on the AMC7812B device.
 * Converts digital data to analog values for ouput only.
 */
void read_ADC() 
{
  // Each iteration requests 2 bytes from the specified address.
  // Reads data from register 0x23 through 0x32.
  for (int chan = 0; chan < 16; chan++) 
  { 
    Wire.beginTransmission(ADC_ADDR);            
    Wire.write(adcChannel);                      
    Wire.endTransmission();                       

    Wire.requestFrom(ADC_ADDR, 2);              
    while (Wire.available())                    
    {
      adcData[chan] = Wire.read();                
      adcData[chan] = adcData[chan] << 8;          
      adcData[chan] = adcData[chan] + Wire.read(); 
    }
    adcChannel++;                                  

    // Digital to analog conversion for output to user
    analogValue = (adcData[chan] * V_REF * 2) / 4096;
    Serial.print("Channel "); Serial.print(chan); Serial.println(":");
    Serial.print("Digital value: "); Serial.println(adcData[chan]);    
    Serial.print("Analog value: "); Serial.print(analogValue); Serial.println("V");
    Serial.println();

    delay(500);
  }
}

/*
 * Reads the bus and shunt voltage registers for each channel on the INA3221 device.
 * Displays both voltages per channel to the serial port.
 */
void read_INA() 
{
  // Each iteration requests 2 bytes from the specified address.
  // Reads data from register 0x01, 0x03, 0x05 (shunt voltage registers)
  for (int i = 0; i < 3; i++) 
  {
    Wire.beginTransmission(INA_ADDR);
    Wire.write(inaShuntChannel);
    Wire.endTransmission();

    Wire.requestFrom(INA_ADDR, 2);
    while (Wire.available()) 
    {
      inaShunt[i] = Wire.read();
      inaShunt[i] = inaShunt[i] << 8;
      inaShunt[i] = inaShunt[i] + Wire.read(); 
    }
    inaShuntChannel += 2; // increment by 2 instead of 1
  }

  // Each iteration requests 2 bytes from the specified address.
  // Reads data from register 0x02, 0x04, 0x06 (bus voltage registers)
  for (int j = 0; j < 3; j++) 
  {
    Wire.beginTransmission(INA_ADDR);
    Wire.write(inaBusChannel);
    Wire.endTransmission();

    Wire.requestFrom(INA_ADDR, 2);
    while (Wire.available()) 
    {
      inaBus[j] = Wire.read();
      inaBus[j] = inaBus[j] << 8;
      inaBus[j] = inaBus[j] + Wire.read(); 
    }
    inaBusChannel += 2; // increment by 2 instead of 1   
  }

  // Used for displaying output to user
  for (int i = 0; i < 3; i++)
  {
    Serial.print("Channel "); Serial.print(i); 
    Serial.print(" Shunt Voltage: "); Serial.println(inaShunt[i]);
    Serial.print("Channel "); Serial.print(i); 
    Serial.print(" Bus Voltage: "); Serial.println(inaBus[i]);
  }
}

I am having trouble reading the data off of an AMC7812EVMPDK evaluation board. I have written some data to the ADC registers but when I hook up the Arduino master and try to read the registers, the data that I know is in the registers is not being read.

CrossRoads:
Personally, I would the faster SPI interface instead at the expense of having to drive a slave select pin.
You can achieve 2 MHz SPI clock vs 400 KHz I2C clock.

I have considered this and I am using SPI on this same Leonardo as master to two ATmega32M1’s that will be CAN/LIN masters…Time is my enemy though as this is a work project and I need to get this done by March.

I am having trouble reading the data off of an AMC7812EVMPDK evaluation board. I have written some data to the ADC registers but when I hook up the Arduino master and try to read the registers, the data that I know is in the registers is not being read.

All the ADC registers 0x23 >0x32 are read only. Are you saying that when you apply a known voltage to the input you don't get the correct digital data?

Or is there some other R/W register you are talking about? What code are you using to write to the register, and what code are you using to read it?

cattledog: All the ADC registers 0x23 >0x32 are read only. Are you saying that when you apply a known voltage to the input you don't get the correct digital data?

Yes, the software that comes with the eval kit lets me put data into the registers of the AMC. When I try to read those registers I get nothing. I just tested it on one of the DAC registers which are R/W and it worked fine. This means that I cannot read read only registers? Is it because the slave must be able to write the data in that register to the master?

cattledog: What code are you using to write to the register, and what code are you using to read it?

I am using the code that I just posted previous to your response.

This means that I cannot read read only registers? Is it because the slave must be able to write the data in that register to the master?

You certainly should be able to read a read only register.

But, I don't understand how you can write to them or put data in them, but then again, I don't understand the eval kit and what any custom software allows you to do. Normally, the output data gets written into those registers from the internal workings of the ADC.

When you apply a test voltage to the ADC inputs, can you read the converted digital value out with the i2c code you have posted?

Technically, no. Any device on an i2c bus can initiate communication. Contention is resolved - in theory - by the fact that anyone on the i2c bus can ground the line. If you are trying to send a high bit, and the line is being held low by something, then you didn't really acquire the bus like you thought you did.

In practise, this might be a little iffy. It's best to have one device co-oordinate all communication, and the other devices only respond to requests.

cattledog: You certainly should be able to read a read only register.

Thats what I thought.

cattledog: But, I don't understand how you can write to them or put data in them, but then again, I don't understand the eval kit and what any custom software allows you to do. Normally, the output data gets written into those registers from the internal workings of the ADC.

The software that comes with the eval kit allows us to write to the read only register. My thought is that the software has authority to change the configuration of the AMC registers so that we can input test voltages.

cattledog: When you apply a test voltage to the ADC inputs, can you read the converted digital value out with the i2c code you have posted?

I could when I re wrote the program slightly. I think the issue may be the way I am reading the 16 channels.