Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable bypass in MPU6050 driver and expose I2C Master Bus #194

Open
wants to merge 3 commits into
base: public
Choose a base branch
from

Conversation

zBuffer
Copy link

@zBuffer zBuffer commented May 17, 2019

Enabling bypass in MPU6050 causes problems for non-SMBus devices sitting on the I2C bus, as seen in #192 . The slave devices connected to MPU6050 can be accessed indirectly using MPU6050.I2CMasterBus, which the prototype is similar to SMBHold.

@phoddie
Copy link
Collaborator

phoddie commented Jun 26, 2019

The implementation is using more memory than needed. Since it targets microcontrollers, I would like to look at rearranging the code a bit to reduce that. The I2CMasterBus getter creates the class dynamically, which requires RAM for each method of the class, plus execution time at runtime to build the complete class. Instead, I think you can declare the class at the top level as usual:

class I2CMasterBus {
	constructor(dictionary, i2c) {
	 this.config = dictionary;
  	 this.i2c = i2c;
	}

	calcLength(value) {
	 let len = 0;
	 for(let i in value) {
		 switch(typeof(value[i])) {
			 case "number":
				 len++;
				 break;
			 case "string":
				 len += value[i].length;
				 break;
			 default:
				 if(value[i] instanceof(ArrayBuffer))
					 len += value[i].byteLength;
				 else if(value[i].length !== undefined)
					 len += value[i].length;
				 else
					 throw "MPU I2CMasterBus unsupported type";
		 }
	 }

	  return len;
	}

	readBlock(register, count, buffer) {
	 if(count > 24)
		 throw "MPU I2CMasterBus readBlock maximum length is 24 bytes";
	 this.i2c.writeByte(REGISTERS.I2C_SLV0_ADDR, this.config.address | 0x80);
	 this.i2c.writeByte(REGISTERS.I2C_SLV0_REG, register);
	 this.i2c.writeByte(REGISTERS.I2C_SLV0_CTRL, I2C_SLV0_EN | count);
	 Timer.delay(1);
	 return this.i2c.readBlock(REGISTERS.EXT_SENS_DATA_00, count, buffer);
	}

	writeBlock(register, ...value) {
	 let count = this.calcLength(value);
	 if(count > 4)
		 throw "MPU I2CMasterBus writeBlock maximum length is 4 bytes";
	 this.i2c.writeByte(REGISTERS.I2C_SLV0_ADDR, this.config.address);
	 this.i2c.writeByte(REGISTERS.I2C_SLV0_REG, register);
	 this.i2c.writeBlock(REGISTERS.I2C_SLV0_DO, ...value);
	 return this.i2c.writeByte(REGISTERS.I2C_SLV0_CTRL, I2C_SLV0_EN | count);
	}

	writeByte(register, value) {
	 return this.writeBlock(register, value & 0xFF);
	}

	writeWord(register, value, endian) {
	 if (endian)
		 return this.write(register, (value >> 8) & 255, value & 255);
	 else
		 return this.write(register, value & 255, (value >> 8) & 255);
	}

	readByte(register) {
	 return this.readBlock(register, 1)[0];
	}

	readWord(register, endian) {
	 let value = this.readBlock(register, 2);
	 return endian ? (value[1] | (value[0] << 8)) : (value[0] | (value[1] << 8));
	}
};

Notice that the i2c instance is passed to the constructor and stored in this.i2c, so all occurrences of that are replaced with this.i2c.

Then the getter just needs to connect the i2c instanced to the class constructor returned, something like this:

    get I2CMasterBus() {
         const i2c = this;
         return class extends I2CMasterBus {
             constructor(dictionary) {
                 super(dictionary, i2c);
             }
      }

I don't have the hardware to run this myself, so I can't try it out. If you can, please let me know how it goes. Thanks.

@andycarle
Copy link
Member

Hi @zBuffer,

I'm unable to test this change, because the revision of the M5Stack Fire hardware that I have is the one with the MAG3110 sensor connected directly to the ESP32's i2c bus. (See this note in the M5Stack schematics repo: Be careful, the early version of M5Fire was built in MPU6050 + MAG3110, but we change MPU6050 + MAG3110 to MPU9250.)

I had initially configured the MPU6050 driver to use the bypass mode so that the various revisions of the M5Stack Fire (and Gray, etc.) hardware could use the same MPU6050 and MAG3110 drivers as each other. But, as you note, this seems to not work with all of the M5Stack accessories.

Given the wide array of M5Stack configurations and revisions (and the variety of projects developers are building with them), I think it would be best to organize this change so that it is optional for users of the mpu6050 module and so that we can easily turn the i2c bypass on and off for the different development targets.

I suggest that by default we leave the configuration as it was, with the bypass enabled and the internal i2c master turned off. Then modify the configure(dictionary) function in the Gyro_Accelerometer class to optionally turn off the bypass and enable the internal i2c bus functionality.

Cheers,
 - Andy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants