Still trying to understand I2C addressing.

I am trying to modify a sketch that uses PWM to communicate with 4 devices that I can see.
I am trying to understand the structure of the I2C addresses as they select a device.

The 4 devices that I see are:

  1. BNO055, 9 DOF orientation
  2. PCA 9668, I2C Address buss
  3. Servo motor
  4. Servo motor

And here is how I think that the programmer began talking to the BNO055.
Wire.beginTransmission((uint8_t)BNO055_I2CADDR);
Where BNO055_I2CADDR = 0x28

And somewhere in the code is something similar to begin talking to the I2C Address buss.
Wire.beginTransmission((uint8_t)PCA9668_I2CADDR);
Where PCA9668_I2CADDR = 0x40

I am trying to understand what the 8 bit byte structure would be for the 2 servos
0x000000100 ( 40)
0x000000101 ( 41)

Here is the code that I think addresses the servos:

// I2C servo interface
	Adafruit_PWMServoDriver *pwm;
	static const uint8_t GIMBAL_I2C_ADDR = 0x40;	// I2C bus address of servo controller
	static const uint8_t SERVO_FREQ = 50;		// typical servo pulse frequency, Hz
	static constexpr float US_PER_BIT = (1e6/SERVO_FREQ/4096);	// usec per bit @ 12 bit resolution
	static const uint8_t MOT1_UNIT = 0;		// motor 1 I2C unit number
	static const uint8_t MOT2_UNIT = 1;		// motor 2 I2C unit number

And herein is where I get stumped.

Is the 7 bit byte going to be either 0x40 or 0x41, though there seems to be a conflict between the PCA9668 and servo number 0.

Or am I totally confused ? (likely ).

An I2C address is always 7 bits. When the I2C master sends that address, an 8th bit is appended to it. If the 8th bit is a 1, it’s a read operation. Otherwise, it’s a write operation.

So, what appears on the data line during those 8 bits is: (I2C Address)<<1 | (Read / Write-bar).

Let us take the following code:

Wire.beginTransmission(0x40);      //I2C address of the device: 0x40 =  1000000

The address is always 7-bit as is shown above.

Before the device address is asserted on the I2C Bus, the controller shifts the address to the left by 1-bit position and then appends a 0 (zero) at the right-most position. As a result, the operands appears as 10000000 (0x80). A 0 (zero) is appended to indicate "data write operation" to begin from Master to Slave.

During data read operation, the following code is executed:
Wire.requestFrom(0x40, 3);    //3-byte to read from device with address: 1000000

In the above case, the operation to begin is: "read data from Slave to Master".

Before the device address is asserted on the I2C Bus, the controller shifts the address to the left by 1-bit position and then appends a 1(one) at the right-most position. As a result, the operands appears as 10000001 (0x81).

It is necessary to transform the 7-bit address into an 8-bit format as the I2C Bus is a byte oriented protocol. This is also needed to include the sense of "the direction of data movement".

0x000000100 ( 40)
0x000000101 ( 41)

No those binary numbers can be expressed in hex but you have them wrong.

 0x000000100 ( 0x04)
0x000000101 ( 0x05)

But do you have a servo that has an I2C address? I have never come across one.

I am trying to modify a sketch that uses PWM to communicate with 4 devices that I can see.
I am trying to understand the structure of the I2C addresses as they select a device.

PWM and I2C are two different things and are in no way connected.

If you're using Adafruit_PWMServoDriver then you're presumably using their PCA9685 boards. I guess where your confusion arises is that the board has an I2C address, the default being 0x40. The servos connected to the board do NOT have I2C addresses.

They are addressed as part of the message content sent to the board so the MOT1_UNIT = 0 etc is just an internal board device number. The 16 devices on the board are called 0 -15 but they are just numbers internal to that board. That's why pwm.setPWM() has a first argument which is the device number within that board.

Steve

Grumpy_Mike:
No those binary numbers can be expressed in hex but you have them wrong.

 0x000000100 ( 0x04)

0x000000101 ( 0x05)

oops, sorry about that.
40 is 0101000
41 is 0101001
if it makes any difference.

Grumpy_Mike:
But do you have a servo that has an I2C address? I have never come across one.
PWM and I2C are two different things and are in no way connected.

For some reason I thought they were connected. Thank you for the clarification.
And I thought that the I2C addresses were assigned rather than built in.
So much to learn.

Hmmm, then the SDA and SCL signals are generated as a result of PWM or I2C or something else that I am very confused about.

My head hurts !

40 is 0101000 → 0x50
41 is 0101001 → 0x51

CrossRoads:
40 is 0101000 -> 0x50
41 is 0101001 -> 0x51

AHA, hexadecimal bites me again, I think.
Thank you Xroads.

And the reason I started this post has to do with me changing some of the hardware and subsequent Arduino code that controls 2, servo motors.
I am not sure this is the proper place to post this but it kinda follows along with my I2C confusion.
Board is a Feather Huzzah

Original sketch drove 2, Model airplane, servo motors using this controller board.

If possible, I would like to do away with this board due to space considerations in the project box.
PCA9685.
This board is driven as device 0x40 and the 2-motors were on pins 0 and 1.
This device has an SDA and SCL connection to the Arduino and outputs a PWM connection to the servos. The servo motors are a 3-wire connection to this board. Pins are PWM, V+, and GND

Modified sketch will drive 2, DC motors using this controller.
L298


and I am stuck as to how it is to be attached to the Arduino

There is one more device, a BNO055 which I think is SDA, SCL controlled so I need to worry about it as well.

I had thought to incorporate much of this sample program as it controls 2 DC motors via an L298.

/*  
  L298N Motor Demonstration
  L298N-Motor-Demo.ino
  Demonstrates functions of L298N Motor Controller
  
  DroneBot Workshop 2017
  http://dronebotworkshop.com
*/
  

// Motor A

int enA = 9;
int in1 = 8;
int in2 = 7;

// Motor B

int enB = 3;
int in3 = 5;
int in4 = 4;

void setup()

{

  // Set all the motor control pins to outputs

  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);

}

void demoOne()

{

  // This function will run the motors in both directions at a fixed speed

  // Turn on motor A

  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);

  // Set speed to 200 out of possible range 0~255

  analogWrite(enA, 200);

  // Turn on motor B

  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);

  // Set speed to 200 out of possible range 0~255

  analogWrite(enB, 200);

  delay(2000);

  // Now change motor directions

  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH); 

  delay(2000);

  // Now turn off motors

  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);

}

void demoTwo()

{

  // This function will run the motors across the range of possible speeds
  // Note that maximum speed is determined by the motor itself and the operating voltage

  // Turn on motors

  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH); 

  // Accelerate from zero to maximum speed

  for (int i = 0; i < 256; i++)

  {

    analogWrite(enA, i);
    analogWrite(enB, i);

    delay(20);

  } 

  // Decelerate from maximum speed to zero

  for (int i = 255; i >= 0; --i)

  {

    analogWrite(enA, i);
    analogWrite(enB, i);

    delay(20);

  } 

  // Now turn off motors

  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);  

}

void loop()

{

  demoOne();

  delay(1000);

  demoTwo();

  delay(1000);

}

Hmmm, then the SDA and SCL signals are generated as a result of PWM or I2C or something else that I am very confused about.

The SDA and SCL are only ever generated by the I2C interface. They have absolutely nothing to do with PWM.

And I thought that the I2C addresses were assigned rather than built in.

Some I2C devices have external pins where some bits of the built in address can be changed by placing them high or low. But basically the address is built in when the chip is made. Hence the odd problem where two very different devices can end up with the same address. On any I2C bus all addresses must be unique.

and I am stuck as to how it is to be attached to the Arduino

With normal digital output pins, you set them high and low to to make the motor run and change direction. If you feed the stop / go signal with a PWM signal generated by a PWM capable pin then you can change the speed of he motor. The L298 is not a very good chip especially if the motor voltage is low, as it looses a lot of voltage when turning on. There are much more modern motor controls you can use.

The servo motors can be driven by any pin if you use the servo library. While this is a form of PWM it is not the same sort of PWM that is produced by the analogWrite of the Arduino. See the servo library documentation for details of how to use it.

This is a sketch that I found that is helping me understand I2C “stuff” and I have 1 question and 1 comment from looking at it.
I highlighted 2 statements that seem redundant. Is there any need for the 2nd
Wire.beginTransmission(ADXLAddress)

and it took all these statements to read the 2 registers ? And is it correct that you do a write in order to read ?

//Ask the particular registers for data
  Wire.write(X_Axis_Register_DATAX0);
  Wire.write(X_Axis_Register_DATAX1);

  Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers

  Wire.requestFrom(ADXLAddress, 2); // Request the transmitted two bytes from the two registers

  if (Wire.available() <= 2) { //
    X0 = Wire.read(); // Reads the data from the register
    X1 = Wire.read();
/*
    How I2C Communication Protocol Works - Arduino I2C Tutorial

     by Dejan, www.HowToMechatronics.com

*/

#include <Wire.h>

int ADXLAddress = 0x53; // Device address in which is also included the 8th bit for selecting the mode, read in this case.

#define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register.
#define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register.
#define Power_Register 0x2D // Power Control Register

int X0, X1, X_out;

void setup() {
  Wire.begin(); // Initiate the Wire library
  Serial.begin(9600);
  delay(100);
  // Enable measurement
  Wire.beginTransmission(ADXLAddress); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< here is 1
  Wire.write(Power_Register);
  // Bit D3 High for measuring enable (0000 1000)
  Wire.write(8);
  Wire.endTransmission();
}

void loop() {
  Wire.beginTransmission(ADXLAddress); // Begin transmission to the Sensor <<<<<<<<<<<<<<<<<<<<<<<<<< here is 2
  //Ask the particular registers for data
  Wire.write(X_Axis_Register_DATAX0);
  Wire.write(X_Axis_Register_DATAX1);

  Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers

  Wire.requestFrom(ADXLAddress, 2); // Request the transmitted two bytes from the two registers

  if (Wire.available() <= 2) { //
    X0 = Wire.read(); // Reads the data from the register
    X1 = Wire.read();
  }

  Serial.print("X0= ");
  Serial.print(X0);
  Serial.print("   X1= ");
  Serial.println(X1);
}

Your first port of call when trying to understand anything is always the official documentation. With regards to I2C ( pronounced eye squared cee ) It is here:-
https://www.arduino.cc/en/Reference/WireBegin

You will see it has two forms with an address and without an address. This is because there are two types of I2C device master and a slave. Normally a master is the computer and a slave is the chip you are trying to communicate with. Occasionally you want to use I2C to communicate between two computers, when you do this one of the computers must be the slave and the other the master.

Some computers like the Raspberry Pi can not be a slave, so if you want to talk between the two then the Arduino has to be a slave. When it is a slave the slave address you want it to have is given in the Wire.begin call, when the Arduino is a master then there is nothing passed into the Wire.begin call.

You will note this page says:-

Initiate the Wire library and join the I2C bus as a master or slave. This should normally be called only once.

.

I have no idea what the second code is trying to do as it is burried in a large site and I couldn't find it.

The documentation for the Wire library is found at:-
https://www.arduino.cc/en/reference/wire
And that contains examples of using it.
Look at the examples there for your basic information.