From 3f148d79f2df75922da6e1007cccaf2a1c2cdb5c Mon Sep 17 00:00:00 2001
From: Rob Tillaart <rob.tillaart@gmail.com>
Date: Mon, 5 Jul 2021 11:41:06 +0200
Subject: [PATCH] Fix #20 add multi-Wire support (#23)

* Fix #20 add multi-Wire support
---
 GY521.cpp                                     | 80 +++++++++++--------
 GY521.h                                       | 27 +++++--
 GY521_registers.h                             |  2 +-
 README.md                                     | 49 +++++++-----
 .../GY521_performance/GY521_performance.ino   | 47 +++++++++++
 library.json                                  |  2 +-
 library.properties                            |  2 +-
 7 files changed, 145 insertions(+), 64 deletions(-)
 create mode 100644 examples/GY521_performance/GY521_performance.ino

diff --git a/GY521.cpp b/GY521.cpp
index 2c8ea4f..eccd52a 100644
--- a/GY521.cpp
+++ b/GY521.cpp
@@ -1,7 +1,7 @@
 //
 //    FILE: GY521.cpp
 //  AUTHOR: Rob Tillaart
-// VERSION: 0.3.1
+// VERSION: 0.3.2
 // PURPOSE: Arduino library for I2C GY521 accelerometer-gyroscope sensor
 //     URL: https://github.com/RobTillaart/GY521
 //
@@ -11,14 +11,15 @@
 //  0.1.2   2020-08-06  fix setAccelSensitivity + add getters
 //  0.1.3   2020-08-07  fix ESP support + pitch roll yaw demo
 //  0.1.4   2020-09-29  fix #5 missing ;
-//  0.1.5   2020-09-29  fix #6 fix math for Teensy
+//  0.1.5   2020-09-29  fix #6 fix maths for Teensy
 //  0.2.0   2020-11-03  improve error handling
-//  0.2.1   2020-12-24  arduino-ci + unit tests
-//  0.2.2   2021-01-24  add interface part to readme.md 
+//  0.2.1   2020-12-24  Arduino-CI + unit tests
+//  0.2.2   2021-01-24  add interface part to readme.md
 //                      add GY521_registers.h
 //  0.2.3   2021-01-26  align version numbers (oops)
 //  0.3.0   2021-04-07  fix #18 acceleration error correction (kudo's to Merkxic)
 //  0.3.1   2021-06-13  added more unit test + some initialization
+//  0.3.2   2021-07-05  fix #20 support multiWire
 
 
 #include "GY521.h"
@@ -35,9 +36,10 @@
 //
 // PUBLIC
 //
-GY521::GY521(uint8_t address)
+GY521::GY521(uint8_t address, TwoWire *wire)
 {
   _address = address;
+  _wire    = wire;
   reset();
 }
 
@@ -45,7 +47,7 @@ GY521::GY521(uint8_t address)
 #if defined (ESP8266) || defined(ESP32)
 bool GY521::begin(uint8_t sda, uint8_t scl)
 {
-  Wire.begin(sda, scl);
+  _wire->begin(sda, scl);
   return isConnected();
 }
 #endif
@@ -53,15 +55,15 @@ bool GY521::begin(uint8_t sda, uint8_t scl)
 
 bool GY521::begin()
 {
-  Wire.begin();
+  _wire->begin();
   return isConnected();
 }
 
 
 bool GY521::isConnected()
 {
-  Wire.beginTransmission(_address);
-  return (Wire.endTransmission() == 0);
+  _wire->beginTransmission(_address);
+  return (_wire->endTransmission() == 0);
 }
 
 void GY521::reset()
@@ -79,10 +81,10 @@ void GY521::reset()
 
 bool GY521::wakeup()
 {
-  Wire.beginTransmission(_address);
-  Wire.write(GY521_PWR_MGMT_1);
-  Wire.write(GY521_WAKEUP);
-  return (Wire.endTransmission() == 0);
+  _wire->beginTransmission(_address);
+  _wire->write(GY521_PWR_MGMT_1);
+  _wire->write(GY521_WAKEUP);
+  return (_wire->endTransmission() == 0);
 }
 
 
@@ -92,18 +94,27 @@ int16_t GY521::read()
   {
     if ((millis() - _lastTime) < _throttleTime)
     {
+      // not an error.
       return GY521_THROTTLED;
     }
   }
 
   // Connected ?
-  Wire.beginTransmission(_address);
-  Wire.write(GY521_ACCEL_XOUT_H);
-  if (Wire.endTransmission() != 0) return GY521_ERROR_WRITE;
+  _wire->beginTransmission(_address);
+  _wire->write(GY521_ACCEL_XOUT_H);
+  if (_wire->endTransmission() != 0)
+  {
+    _error = GY521_ERROR_WRITE;
+    return _error;
+  }
 
   // Get the data
-  int8_t n = Wire.requestFrom(_address, (uint8_t)14);
-  if (n != 14) return GY521_ERROR_READ;
+  int8_t n = _wire->requestFrom(_address, (uint8_t)14);
+  if (n != 14)
+  {
+    _error = GY521_ERROR_READ;
+    return _error;
+  }
   // ACCELEROMETER
   _ax = _WireRead2();  // ACCEL_XOUT_H  ACCEL_XOUT_L
   _ay = _WireRead2();  // ACCEL_YOUT_H  ACCEL_YOUT_L
@@ -142,19 +153,19 @@ int16_t GY521::read()
   _gx *= _raw2dps;
   _gy *= _raw2dps;
   _gz *= _raw2dps;
-  
+
   // Error correct raw gyro measurements.
   _gx += gxe;
   _gy += gye;
   _gz += gze;
-  
+
   _gax += _gx * duration;
   _gay += _gy * duration;
   _gaz += _gz * duration;
 
-  _yaw = _gaz;
+  _yaw   = _gaz;
   _pitch = 0.96 * _gay + 0.04 * _aay;
-  _roll = 0.96 * _gax + 0.04 * _aax;
+  _roll  = 0.96 * _gax + 0.04 * _aax;
 
   return GY521_OK;
 }
@@ -236,11 +247,11 @@ uint8_t GY521::getGyroSensitivity()
 
 uint8_t GY521::setRegister(uint8_t reg, uint8_t value)
 {
-  Wire.beginTransmission(_address);
-  Wire.write(reg);
-  Wire.write(value);
+  _wire->beginTransmission(_address);
+  _wire->write(reg);
+  _wire->write(value);
   // no need to do anything if not connected.
-  if (Wire.endTransmission() != 0) 
+  if (_wire->endTransmission() != 0)
   {
     _error = GY521_ERROR_WRITE;
     return _error;
@@ -251,20 +262,20 @@ uint8_t GY521::setRegister(uint8_t reg, uint8_t value)
 
 uint8_t GY521::getRegister(uint8_t reg)
 {
-  Wire.beginTransmission(_address);
-  Wire.write(reg);
-  if (Wire.endTransmission() != 0)
+  _wire->beginTransmission(_address);
+  _wire->write(reg);
+  if (_wire->endTransmission() != 0)
   {
     _error = GY521_ERROR_WRITE;
     return _error;
   }
-  uint8_t n = Wire.requestFrom(_address, (uint8_t) 1);
-  if (n != 1) 
+  uint8_t n = _wire->requestFrom(_address, (uint8_t) 1);
+  if (n != 1)
   {
     _error = GY521_ERROR_READ;
     return _error;
   }
-  uint8_t val = Wire.read();
+  uint8_t val = _wire->read();
   return val;
 }
 
@@ -272,10 +283,11 @@ uint8_t GY521::getRegister(uint8_t reg)
 // to read register of 2 bytes.
 int16_t GY521::_WireRead2()
 {
-  int16_t tmp = Wire.read();
+  int16_t tmp = _wire->read();
   tmp <<= 8;
-  tmp |= Wire.read();
+  tmp |= _wire->read();
   return tmp;
 }
 
+
 // -- END OF FILE --
diff --git a/GY521.h b/GY521.h
index 1b83573..b18ffe9 100644
--- a/GY521.h
+++ b/GY521.h
@@ -2,7 +2,7 @@
 //
 //    FILE: GY521.h
 //  AUTHOR: Rob Tillaart
-// VERSION: 0.3.1
+// VERSION: 0.3.2
 // PURPOSE: Arduino library for I2C GY521 accelerometer-gyroscope sensor
 //     URL: https://github.com/RobTillaart/GY521
 //
@@ -15,7 +15,7 @@
 #include "Wire.h"
 
 
-#define GY521_LIB_VERSION           (F("0.3.1"))
+#define GY521_LIB_VERSION           (F("0.3.2"))
 
 
 #ifndef GY521_THROTTLE_TIME
@@ -34,7 +34,8 @@
 class GY521
 {
 public:
-  GY521(uint8_t address = 0x69); // 0x68 or 0x69
+  GY521(uint8_t address = 0x69, TwoWire *wire = &Wire); // 0x68 or 0x69
+
 
 #if defined (ESP8266) || defined(ESP32)
   bool     begin(uint8_t sda, uint8_t scl);
@@ -43,14 +44,16 @@ class GY521
   bool     isConnected();
   void     reset();
 
+
   bool     wakeup();
   // throttle to force delay between reads.
   void     setThrottle(bool throttle = true) { _throttle = throttle; };
   bool     getThrottle()                     { return _throttle; };
-  // 0..65535 millis == roughly 1 minute.
+  // 0..65535 (max milliseconds == roughly 1 minute.
   void     setThrottleTime(uint16_t ti )     { _throttleTime = ti; };
   uint16_t getThrottleTime()                 { return _throttleTime; };
 
+
   // returns GY521_OK or one of the error codes above.
   int16_t  read();
 
@@ -60,8 +63,8 @@ class GY521
   uint8_t  getAccelSensitivity();          // returns 0,1,2,3
   // gs = 0,1,2,3  ==>  250, 500, 1000, 2000 degrees/second
   bool     setGyroSensitivity(uint8_t gs);
-  uint8_t  getGyroSensitivity();           // returns 0,1,2,3  
-  
+  uint8_t  getGyroSensitivity();           // returns 0,1,2,3
+
   // CALL AFTER READ
   float    getAccelX()   { return _ax; };
   float    getAccelY()   { return _ay; };
@@ -77,16 +80,21 @@ class GY521
   float    getRoll()     { return _roll; };
   float    getYaw()      { return _yaw; };
 
+
   // last time sensor is actually read.
   uint32_t lastTime()    { return _lastTime; };
 
+
   // generic worker to get access to all functionality
   uint8_t  setRegister(uint8_t reg, uint8_t value);
   uint8_t  getRegister(uint8_t reg);
+
+
   // get last error and reset error to OK.
   int16_t  getError()    { return _error; _error = GY521_OK; };
 
-  // callibration errors
+
+  // calibration errors
   float    axe = 0, aye = 0, aze = 0;  // accelerometer errors
   float    gxe = 0, gye = 0, gze = 0;  // gyro errors
 
@@ -110,9 +118,12 @@ class GY521
   float    _pitch, _roll, _yaw;     // used by user
 
   float    _temperature = 0;
-  
+
   // to read register of 2 bytes.
   int16_t  _WireRead2();
+
+  TwoWire*  _wire;
 };
 
+
 // -- END OF FILE --
diff --git a/GY521_registers.h b/GY521_registers.h
index a503a62..88154d1 100644
--- a/GY521_registers.h
+++ b/GY521_registers.h
@@ -1,7 +1,7 @@
 //
 //    FILE: GY521_registers.h
 //  AUTHOR: Rob Tillaart
-// VERSION: 0.3.0
+// VERSION: 0.3.2
 // PURPOSE: Arduino library for I2C GY521 accelerometer-gyroscope sensor
 //     URL: https://github.com/RobTillaart/GY521
 //
diff --git a/README.md b/README.md
index 8d7b9f0..22880dc 100644
--- a/README.md
+++ b/README.md
@@ -12,20 +12,24 @@ Arduino library for I2C GY521 accelerometer-gyroscope sensor a.k.a. MCU-6050
 
 Experimental library for GY521 a.k.a. MCU-6050
 
-Library is work in progress, in fact extracted and extended from an old project.
+Library is work in progress, in fact it is extracted and extended from an old project.
 It needs to be tested a lot more.
 
-It has three examples
+
+#### Examples
+
 - calibration example to determine the offsets needed
 - example to read values.
 - test sketch to test get / set values.
+- example to get pitch roll yaw.
+- performance sketch.
 
 
 ## Breakout board
 
-left to right
+From left to right
 
-|  pin | pinname | description     |
+|  pin | pinName | description     |
 |:----:|:--------|:----------------|
 |  0   |  VCC    | +5V             |
 |  1   |  GND    | ground          |
@@ -36,7 +40,9 @@ left to right
 |  6   |  AD0    | address         | 
 |  7   |  INT    | interrupt       |
 
+
 #### Address
+
 AD0 connected to GND => 0x68 
 AD0 connected to VCC => 0x69
 
@@ -54,25 +60,27 @@ AD0 connected to VCC => 0x69
 
 ### Constructor
 
-- **GY521(uint8_t address = 0x69)** Constructor with default address. 0x68 is also valid.
-- **bool begin(uint8_t sda, uint8_t scl)** begin for ESP32 et al.
-- **bool begin()**
-- **bool isConnected()** device can be found on I2C bus.
+- **GY521(uint8_t address = 0x69, , TwoWire \*wire = &Wire)** Constructor with default address. 
+0x68 is also a valid address. The wire argument is optional to select Wire1 Wire2 etc. on some boards.
+- **bool begin(uint8_t sda, uint8_t scl)** begin for ESP32 et al. Returns true if address can be found on I2C bus.
+- **bool begin()** Returns true if address can be found on I2C bus.
+- **bool isConnected()** returns true if device can be found on I2C bus.
 - **void reset()** set all internal values to 0 and throttle time to 10 ms.
 - **bool wakeUp()**
 
 
 ### Throttle
 
-- **void setThrottle(bool throttle = true)** throttle to force delay between reads.
-- **bool getThrottle()** idem
-- **void     setThrottleTime(uint16_t ti )** milliseconds, max = 65535 = 1++ minute
-- **uint16_t getThrottleTime()** idem
+- **void setThrottle(bool throttle = true)** throttle to force "delay" between reads.
+- **bool getThrottle()** returns true if throttle mode is set.
+- **void setThrottleTime(uint16_t ti )** throttle time in milliseconds, max = 65535 = 1++ minute
+- **uint16_t getThrottleTime()** returns throttle time set.
 
 
-### Read
+### READ
+
+#### Set before read
 
-#### SET BEFORE READ
   // as = 0,1,2,3 ==> 2g 4g 8g 16g
 - **bool setAccelSensitivity(uint8_t as)** as = 0, 1, 2, 3 ==> 2g 4g 8g 16g
 - **uint8_t getAccelSensitivity()** returns 0, 1, 2, 3
@@ -83,11 +91,13 @@ AD0 connected to VCC => 0x69
 #### Actual read
 
 - **int16_t read()** returns ...
-- **uint32_t lastTime()** last time sensor is actually read. In millis().
+- **uint32_t lastTime()** last time sensor is actually read. In milliseconds.
 
 
 #### Call after read
 
+Note that multiple calls will return the same value. One must explicitly call **read()** to get new values. 
+
 - **float getAccelX()** idem
 - **float getAccelY()** idem
 - **float getAccelZ()** idem
@@ -105,7 +115,7 @@ AD0 connected to VCC => 0x69
 
 ### Register access
 
-Read the register PDF for the specific 
+Read the register PDF for the specific value and meaning of registers.
 
 - **uint8_t setRegister(uint8_t reg, uint8_t value)**
 - **uint8_t getRegister(uint8_t reg)**
@@ -116,13 +126,14 @@ Read the register PDF for the specific
 **Should**
 - test test and test ...(ESP too)
 - improve documentation
-- look for math optimizations  (atan, hypot, performance)
-- multi Wire interface (e.g Wire1, Wire2 etc)
+- look for maths optimizations  (atan, hypot, performance)
+
 
 **Could**
 - calibrate function in the lib ?  (think not as lib might grow?)
 - calibrate sketch could print code snippet to include...
-
+- option to read only Accel?
+- option to read only Gyro?
 
 ## documents
 
diff --git a/examples/GY521_performance/GY521_performance.ino b/examples/GY521_performance/GY521_performance.ino
new file mode 100644
index 0000000..f3388c1
--- /dev/null
+++ b/examples/GY521_performance/GY521_performance.ino
@@ -0,0 +1,47 @@
+//
+//    FILE: GY521_performance.ino
+//  AUTHOR: Rob Tillaart
+// VERSION: 0.1.0
+// PURPOSE: minimal demo
+//    DATE: 2021-06-13
+
+
+#include "GY521.h"
+
+
+GY521 sensor(0x69);
+
+uint32_t counter = 0;
+
+
+void setup()
+{
+  Serial.begin(115200);
+  Serial.println(__FILE__);
+
+  Wire.begin();
+
+  delay(100);
+  while (sensor.wakeup() == false)
+  {
+    Serial.print(millis());
+    Serial.println("\tCould not connect to GY521");
+    delay(1000);
+  }
+}
+
+void loop()
+{
+  uint32_t start = micros();
+  int16_t x = sensor.read();
+  uint32_t duration = micros() - start;
+  
+  Serial.print(x);
+  Serial.print('\t');
+  Serial.print(duration);
+  Serial.println();
+  
+  delay(1000);
+}
+
+// -- END OF FILE --
\ No newline at end of file
diff --git a/library.json b/library.json
index 2dcc777..1c98f83 100644
--- a/library.json
+++ b/library.json
@@ -15,7 +15,7 @@
     "type": "git",
     "url": "https://github.com/RobTillaart/GY521.git"
   },
-  "version": "0.3.1",
+  "version": "0.3.2",
   "license": "MIT",
   "frameworks": "arduino",
   "platforms": "*"
diff --git a/library.properties b/library.properties
index 99ca66f..40676e8 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=GY521
-version=0.3.1
+version=0.3.2
 author=Rob Tillaart <rob.tillaart@gmail.com>
 maintainer=Rob Tillaart <rob.tillaart@gmail.com>
 sentence=Arduino library for GY521 angle measurement