├── LICENSE.md ├── README.md ├── examples ├── LSM9DS1_Basic_I2C │ └── LSM9DS1_Basic_I2C.ino ├── LSM9DS1_Basic_SPI │ └── LSM9DS1_Basic_SPI.ino ├── LSM9DS1_Interrupts │ └── LSM9DS1_Interrupts.ino └── LSM9DS1_Settings │ └── LSM9DS1_Settings.ino ├── extras ├── LSM9DS1 Datasheet.pdf └── SparkFun-LSM9DS1-Breakout-schematic.pdf ├── keywords.txt ├── library.properties └── src ├── LSM9DS1_Registers.h ├── LSM9DS1_Types.h ├── SparkFunLSM9DS1.cpp └── SparkFunLSM9DS1.h /LICENSE.md: -------------------------------------------------------------------------------- 1 | License Information 2 | ------------------- 3 | 4 | The hardware is released under [Creative Commons Share-alike 3.0](http://creativecommons.org/licenses/by-sa/3.0/). 5 | 6 | All other code is open source so please feel free to do anything you want with it; you buy me a beer if you use this and we meet someday ([Beerware license](http://en.wikipedia.org/wiki/Beerware)). 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun LSM9DS1 Arduino Library 2 | ====================== 3 | 4 | [![Breakout Board ISO](https://cdn.sparkfun.com//assets/parts/1/0/5/3/3/13284-02.jpg)](https://www.sparkfun.com/products/13284) 5 | 6 | _[LSM9DS1 Breakout Board (SEN-13284)](https://www.sparkfun.com/products/13284)_ 7 | 8 | This is a breakout board for ST Micro's LSM9DS1 -- a 3D accelerometer, gyroscope, and magnetometer. 9 | 10 | Repository Contents 11 | ------------------- 12 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 13 | * **/extras** - LSM9DS1 documentation. 14 | * **/src** - Source files for the library (.cpp, .h). 15 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 16 | * **library.properties** - General library properties for the Arduino package manager. 17 | 18 | Documentation 19 | -------------- 20 | 21 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 22 | * **9DoF Sensor Stick** 23 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/9dof-sensor-stick-hookup-guide)** - Basic hookup guide for the 9DoF Sensor Stick. 24 | * **[Product Repository](https://github.com/sparkfun/9DOF_Sensor_Stick)** - Main repository (including hardware files) for the 9DoF sensor stick. 25 | * **LSM9DS1 Breakout** 26 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/lsm9ds1-breakout-hookup-guide)** - Basic hookup guide for the LSM9DS1 Breakout. 27 | * **[Product Repository](https://github.com/sparkfun/LSM9DS1_Breakout)** - Main repository (including hardware files) for the LSM9DS1 Breakout. 28 | 29 | 30 | Products that use this Library 31 | --------------------------------- 32 | * [SparkFun 9DoF Sensor Stick (SEN-13944)](https://www.sparkfun.com/products/13944) - LSM9DS1 Sensor Stick (smaller board but less pinouts compared to the breakout board) 33 | * [SparkFun 9DoF IMU Breakout - LSM9DS1 (SEN-13284)](https://www.sparkfun.com/products/13284) - LSM9DS1 Breakout board. 34 | 35 | Version History 36 | --------------- 37 | 38 | * [V 1.0.0](https://github.com/sparkfun/SparkFun_LSM9DS1_Arduino_Library/releases/tag/V_1.0.0) - Initial release 39 | 40 | License Information 41 | ------------------- 42 | 43 | This product is _**open source**_! 44 | 45 | The **code** is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! 46 | 47 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. 48 | 49 | Distributed as-is; no warranty is given. 50 | 51 | - Your friends at SparkFun. 52 | -------------------------------------------------------------------------------- /examples/LSM9DS1_Basic_I2C/LSM9DS1_Basic_I2C.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | LSM9DS1_Basic_I2C.ino 3 | SFE_LSM9DS1 Library Simple Example Code - I2C Interface 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: April 30, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | The LSM9DS1 is a versatile 9DOF sensor. It has a built-in 9 | accelerometer, gyroscope, and magnetometer. Very cool! Plus it 10 | functions over either SPI or I2C. 11 | 12 | This Arduino sketch is a demo of the simple side of the 13 | SFE_LSM9DS1 library. It'll demo the following: 14 | How to create a LSM9DS1 object, using a constructor (global 15 | variables section). 16 | How to use the begin() function of the LSM9DS1 class. 17 | How to read the gyroscope, accelerometer, and magnetometer 18 | using the readGryo(), readAccel(), readMag() functions and 19 | the gx, gy, gz, ax, ay, az, mx, my, and mz variables. 20 | How to calculate actual acceleration, rotation speed, 21 | magnetic field strength using the calcAccel(), calcGyro() 22 | and calcMag() functions. 23 | How to use the data from the LSM9DS1 to calculate 24 | orientation and heading. 25 | 26 | Hardware setup: This library supports communicating with the 27 | LSM9DS1 over either I2C or SPI. This example demonstrates how 28 | to use I2C. The pin-out is as follows: 29 | LSM9DS1 --------- Arduino 30 | SCL ---------- SCL (A5 on older 'Duinos') 31 | SDA ---------- SDA (A4 on older 'Duinos') 32 | VDD ------------- 3.3V 33 | GND ------------- GND 34 | (CSG, CSXM, SDOG, and SDOXM should all be pulled high. 35 | Jumpers on the breakout board will do this for you.) 36 | 37 | The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it 38 | off the 3.3V rail! I2C pins are open-drain, so you'll be 39 | (mostly) safe connecting the LSM9DS1's SCL and SDA pins 40 | directly to the Arduino. 41 | 42 | Development environment specifics: 43 | IDE: Arduino 1.6.3 44 | Hardware Platform: SparkFun Redboard 45 | LSM9DS1 Breakout Version: 1.0 46 | 47 | This code is beerware. If you see me (or any other SparkFun 48 | employee) at the local, and you've found our code helpful, 49 | please buy us a round! 50 | 51 | Distributed as-is; no warranty is given. 52 | *****************************************************************/ 53 | // The SFE_LSM9DS1 library requires both Wire and SPI be 54 | // included BEFORE including the 9DS1 library. 55 | #include 56 | #include 57 | #include 58 | 59 | ////////////////////////// 60 | // LSM9DS1 Library Init // 61 | ////////////////////////// 62 | // Use the LSM9DS1 class to create an object. [imu] can be 63 | // named anything, we'll refer to that throught the sketch. 64 | LSM9DS1 imu; 65 | 66 | /////////////////////// 67 | // Example I2C Setup // 68 | /////////////////////// 69 | // SDO_XM and SDO_G are both pulled high, so our addresses are: 70 | // #define LSM9DS1_M 0x1E // Would be 0x1C if SDO_M is LOW 71 | // #define LSM9DS1_AG 0x6B // Would be 0x6A if SDO_AG is LOW 72 | 73 | //////////////////////////// 74 | // Sketch Output Settings // 75 | //////////////////////////// 76 | #define PRINT_CALCULATED 77 | //#define PRINT_RAW 78 | #define PRINT_SPEED 250 // 250 ms between prints 79 | static unsigned long lastPrint = 0; // Keep track of print time 80 | 81 | // Earth's magnetic field varies by location. Add or subtract 82 | // a declination to get a more accurate heading. Calculate 83 | // your's here: 84 | // http://www.ngdc.noaa.gov/geomag-web/#declination 85 | #define DECLINATION -8.58 // Declination (degrees) in Boulder, CO. 86 | 87 | //Function definitions 88 | void printGyro(); 89 | void printAccel(); 90 | void printMag(); 91 | void printAttitude(float ax, float ay, float az, float mx, float my, float mz); 92 | 93 | void setup() 94 | { 95 | Serial.begin(115200); 96 | 97 | Wire.begin(); 98 | 99 | if (imu.begin() == false) // with no arguments, this uses default addresses (AG:0x6B, M:0x1E) and i2c port (Wire). 100 | { 101 | Serial.println("Failed to communicate with LSM9DS1."); 102 | Serial.println("Double-check wiring."); 103 | Serial.println("Default settings in this sketch will " \ 104 | "work for an out of the box LSM9DS1 " \ 105 | "Breakout, but may need to be modified " \ 106 | "if the board jumpers are."); 107 | while (1); 108 | } 109 | } 110 | 111 | void loop() 112 | { 113 | // Update the sensor values whenever new data is available 114 | if ( imu.gyroAvailable() ) 115 | { 116 | // To read from the gyroscope, first call the 117 | // readGyro() function. When it exits, it'll update the 118 | // gx, gy, and gz variables with the most current data. 119 | imu.readGyro(); 120 | } 121 | if ( imu.accelAvailable() ) 122 | { 123 | // To read from the accelerometer, first call the 124 | // readAccel() function. When it exits, it'll update the 125 | // ax, ay, and az variables with the most current data. 126 | imu.readAccel(); 127 | } 128 | if ( imu.magAvailable() ) 129 | { 130 | // To read from the magnetometer, first call the 131 | // readMag() function. When it exits, it'll update the 132 | // mx, my, and mz variables with the most current data. 133 | imu.readMag(); 134 | } 135 | 136 | if ((lastPrint + PRINT_SPEED) < millis()) 137 | { 138 | printGyro(); // Print "G: gx, gy, gz" 139 | printAccel(); // Print "A: ax, ay, az" 140 | printMag(); // Print "M: mx, my, mz" 141 | // Print the heading and orientation for fun! 142 | // Call print attitude. The LSM9DS1's mag x and y 143 | // axes are opposite to the accelerometer, so my, mx are 144 | // substituted for each other. 145 | printAttitude(imu.ax, imu.ay, imu.az, 146 | -imu.my, -imu.mx, imu.mz); 147 | Serial.println(); 148 | 149 | lastPrint = millis(); // Update lastPrint time 150 | } 151 | } 152 | 153 | void printGyro() 154 | { 155 | // Now we can use the gx, gy, and gz variables as we please. 156 | // Either print them as raw ADC values, or calculated in DPS. 157 | Serial.print("G: "); 158 | #ifdef PRINT_CALCULATED 159 | // If you want to print calculated values, you can use the 160 | // calcGyro helper function to convert a raw ADC value to 161 | // DPS. Give the function the value that you want to convert. 162 | Serial.print(imu.calcGyro(imu.gx), 2); 163 | Serial.print(", "); 164 | Serial.print(imu.calcGyro(imu.gy), 2); 165 | Serial.print(", "); 166 | Serial.print(imu.calcGyro(imu.gz), 2); 167 | Serial.println(" deg/s"); 168 | #elif defined PRINT_RAW 169 | Serial.print(imu.gx); 170 | Serial.print(", "); 171 | Serial.print(imu.gy); 172 | Serial.print(", "); 173 | Serial.println(imu.gz); 174 | #endif 175 | } 176 | 177 | void printAccel() 178 | { 179 | // Now we can use the ax, ay, and az variables as we please. 180 | // Either print them as raw ADC values, or calculated in g's. 181 | Serial.print("A: "); 182 | #ifdef PRINT_CALCULATED 183 | // If you want to print calculated values, you can use the 184 | // calcAccel helper function to convert a raw ADC value to 185 | // g's. Give the function the value that you want to convert. 186 | Serial.print(imu.calcAccel(imu.ax), 2); 187 | Serial.print(", "); 188 | Serial.print(imu.calcAccel(imu.ay), 2); 189 | Serial.print(", "); 190 | Serial.print(imu.calcAccel(imu.az), 2); 191 | Serial.println(" g"); 192 | #elif defined PRINT_RAW 193 | Serial.print(imu.ax); 194 | Serial.print(", "); 195 | Serial.print(imu.ay); 196 | Serial.print(", "); 197 | Serial.println(imu.az); 198 | #endif 199 | 200 | } 201 | 202 | void printMag() 203 | { 204 | // Now we can use the mx, my, and mz variables as we please. 205 | // Either print them as raw ADC values, or calculated in Gauss. 206 | Serial.print("M: "); 207 | #ifdef PRINT_CALCULATED 208 | // If you want to print calculated values, you can use the 209 | // calcMag helper function to convert a raw ADC value to 210 | // Gauss. Give the function the value that you want to convert. 211 | Serial.print(imu.calcMag(imu.mx), 2); 212 | Serial.print(", "); 213 | Serial.print(imu.calcMag(imu.my), 2); 214 | Serial.print(", "); 215 | Serial.print(imu.calcMag(imu.mz), 2); 216 | Serial.println(" gauss"); 217 | #elif defined PRINT_RAW 218 | Serial.print(imu.mx); 219 | Serial.print(", "); 220 | Serial.print(imu.my); 221 | Serial.print(", "); 222 | Serial.println(imu.mz); 223 | #endif 224 | } 225 | 226 | // Calculate pitch, roll, and heading. 227 | // Pitch/roll calculations take from this app note: 228 | // https://web.archive.org/web/20190824101042/http://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf 229 | // Heading calculations taken from this app note: 230 | // https://web.archive.org/web/20150513214706/http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf 231 | void printAttitude(float ax, float ay, float az, float mx, float my, float mz) 232 | { 233 | float roll = atan2(ay, az); 234 | float pitch = atan2(-ax, sqrt(ay * ay + az * az)); 235 | 236 | float heading; 237 | if (my == 0) 238 | heading = (mx < 0) ? PI : 0; 239 | else 240 | heading = atan2(mx, my); 241 | 242 | heading -= DECLINATION * PI / 180; 243 | 244 | if (heading > PI) heading -= (2 * PI); 245 | else if (heading < -PI) heading += (2 * PI); 246 | 247 | // Convert everything from radians to degrees: 248 | heading *= 180.0 / PI; 249 | pitch *= 180.0 / PI; 250 | roll *= 180.0 / PI; 251 | 252 | Serial.print("Pitch, Roll: "); 253 | Serial.print(pitch, 2); 254 | Serial.print(", "); 255 | Serial.println(roll, 2); 256 | Serial.print("Heading: "); Serial.println(heading, 2); 257 | } 258 | -------------------------------------------------------------------------------- /examples/LSM9DS1_Basic_SPI/LSM9DS1_Basic_SPI.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | LSM9DS1_Basic_SPI.ino 3 | SFE_LSM9DS1 Library Simple Example Code - SPI Interface 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: April 29, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | The LSM9DS1 is a versatile 9DOF sensor. It has a built-in 9 | accelerometer, gyroscope, and magnetometer. Very cool! Plus it 10 | functions over either SPI or I2C. 11 | 12 | This Arduino sketch is a demo of the simple side of the 13 | SFE_LSM9DS1 library. It'll demo the following: 14 | * How to create a LSM9DS1 object, using a constructor (global 15 | variables section). 16 | * How to use the begin() function of the LSM9DS1 class. 17 | * How to read the gyroscope, accelerometer, and magnetometer 18 | using the readGryo(), readAccel(), readMag() functions and 19 | the gx, gy, gz, ax, ay, az, mx, my, and mz variables. 20 | * How to calculate actual acceleration, rotation speed, 21 | magnetic field strength using the calcAccel(), calcGyro() 22 | and calcMag() functions. 23 | * How to use the data from the LSM9DS1 to calculate 24 | orientation and heading. 25 | 26 | Hardware setup: This example demonstrates how to use the 27 | LSM9DS1 with an SPI interface. The pin-out is as follows: 28 | LSM9DS1 --------- Arduino 29 | CS_AG ------------- 9 30 | CS_M ------------- 10 31 | SDO_AG ----------- 12 32 | SDO_M ------------ 12 (tied to SDO_AG) 33 | SCL -------------- 13 34 | SDA -------------- 11 35 | VDD -------------- 3.3V 36 | GND -------------- GND 37 | 38 | The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it 39 | off the 3.3V rail! Signals going into the LSM9DS1, at least, 40 | should be level shifted down to 3.3V - that's CSG, CSXM, 41 | SCL, and SDA. 42 | 43 | Better yet, use a 3.3V Arduino (e.g. the Pro or Pro Mini)! 44 | 45 | Development environment specifics: 46 | IDE: Arduino 1.6.3 47 | Hardware Platform: Arduino Pro 3.3V 48 | LSM9DS1 Breakout Version: 1.0 49 | 50 | This code is beerware. If you see me (or any other SparkFun 51 | employee) at the local, and you've found our code helpful, 52 | please buy us a round! 53 | 54 | Distributed as-is; no warranty is given. 55 | *****************************************************************/ 56 | // The SFE_LSM9DS1 library requires both Wire and SPI be 57 | // included BEFORE including the 9DS1 library. 58 | #include 59 | #include 60 | #include 61 | 62 | ////////////////////////// 63 | // LSM9DS1 Library Init // 64 | ////////////////////////// 65 | // Use the LSM9DS1 class to create an object. [imu] can be 66 | // named anything, we'll refer to that throught the sketch. 67 | LSM9DS1 imu; 68 | 69 | /////////////////////// 70 | // Example SPI Setup // 71 | /////////////////////// 72 | // Define the pins used for our SPI chip selects. We're 73 | // using hardware SPI, so other signal pins are set in stone. 74 | #define LSM9DS1_M_CS 10 // Can be any digital pin 75 | #define LSM9DS1_AG_CS 9 // Can be any other digital pin 76 | 77 | //////////////////////////// 78 | // Sketch Output Settings // 79 | //////////////////////////// 80 | #define PRINT_CALCULATED 81 | //#define PRINT_RAW 82 | #define PRINT_SPEED 250 // 250 ms between prints 83 | 84 | // Earth's magnetic field varies by location. Add or subtract 85 | // a declination to get a more accurate heading. Calculate 86 | // your's here: 87 | // http://www.ngdc.noaa.gov/geomag-web/#declination 88 | #define DECLINATION -8.58 // Declination (degrees) in Boulder, CO. 89 | 90 | //Function definitions 91 | void printGyro(); 92 | void printAccel(); 93 | void printMag(); 94 | void printAttitude(float ax, float ay, float az, float mx, float my, float mz); 95 | 96 | void setup() 97 | { 98 | Serial.begin(115200); 99 | 100 | // imu.beginSPI(), which verifies communication with the IMU 101 | // and turns it on. 102 | if (imu.beginSPI(LSM9DS1_AG_CS, LSM9DS1_M_CS) == false) // note, we need to sent this our CS pins (defined above) 103 | { 104 | Serial.println("Failed to communicate with LSM9DS1."); 105 | Serial.println("Double-check wiring."); 106 | Serial.println("Default settings in this sketch will " \ 107 | "work for an out of the box LSM9DS1 " \ 108 | "Breakout, but may need to be modified " \ 109 | "if the board jumpers are."); 110 | while (1) 111 | ; 112 | } 113 | } 114 | 115 | void loop() 116 | { 117 | printGyro(); // Print "G: gx, gy, gz" 118 | printAccel(); // Print "A: ax, ay, az" 119 | printMag(); // Print "M: mx, my, mz" 120 | 121 | // Print the heading and orientation for fun! 122 | // Call print attitude. The LSM9DS1's magnetometer x and y 123 | // axes are opposite to the accelerometer, so my and mx are 124 | // substituted for each other. 125 | printAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz); 126 | Serial.println(); 127 | 128 | delay(PRINT_SPEED); 129 | } 130 | 131 | void printGyro() 132 | { 133 | // To read from the gyroscope, you must first call the 134 | // readGyro() function. When this exits, it'll update the 135 | // gx, gy, and gz variables with the most current data. 136 | imu.readGyro(); 137 | 138 | // Now we can use the gx, gy, and gz variables as we please. 139 | // Either print them as raw ADC values, or calculated in DPS. 140 | Serial.print("G: "); 141 | #ifdef PRINT_CALCULATED 142 | // If you want to print calculated values, you can use the 143 | // calcGyro helper function to convert a raw ADC value to 144 | // DPS. Give the function the value that you want to convert. 145 | Serial.print(imu.calcGyro(imu.gx), 2); 146 | Serial.print(", "); 147 | Serial.print(imu.calcGyro(imu.gy), 2); 148 | Serial.print(", "); 149 | Serial.println(imu.calcGyro(imu.gz), 2); 150 | #elif defined PRINT_RAW 151 | Serial.print(imu.gx); 152 | Serial.print(", "); 153 | Serial.print(imu.gy); 154 | Serial.print(", "); 155 | Serial.println(imu.gz); 156 | #endif 157 | } 158 | 159 | void printAccel() 160 | { 161 | // To read from the accelerometer, you must first call the 162 | // readAccel() function. When this exits, it'll update the 163 | // ax, ay, and az variables with the most current data. 164 | imu.readAccel(); 165 | 166 | // Now we can use the ax, ay, and az variables as we please. 167 | // Either print them as raw ADC values, or calculated in g's. 168 | Serial.print("A: "); 169 | #ifdef PRINT_CALCULATED 170 | // If you want to print calculated values, you can use the 171 | // calcAccel helper function to convert a raw ADC value to 172 | // g's. Give the function the value that you want to convert. 173 | Serial.print(imu.calcAccel(imu.ax), 2); 174 | Serial.print(", "); 175 | Serial.print(imu.calcAccel(imu.ay), 2); 176 | Serial.print(", "); 177 | Serial.println(imu.calcAccel(imu.az), 2); 178 | #elif defined PRINT_RAW 179 | Serial.print(imu.ax); 180 | Serial.print(", "); 181 | Serial.print(imu.ay); 182 | Serial.print(", "); 183 | Serial.println(imu.az); 184 | #endif 185 | 186 | } 187 | 188 | void printMag() 189 | { 190 | // To read from the magnetometer, you must first call the 191 | // readMag() function. When this exits, it'll update the 192 | // mx, my, and mz variables with the most current data. 193 | imu.readMag(); 194 | 195 | // Now we can use the mx, my, and mz variables as we please. 196 | // Either print them as raw ADC values, or calculated in Gauss. 197 | Serial.print("M: "); 198 | #ifdef PRINT_CALCULATED 199 | // If you want to print calculated values, you can use the 200 | // calcMag helper function to convert a raw ADC value to 201 | // Gauss. Give the function the value that you want to convert. 202 | Serial.print(imu.calcMag(imu.mx), 2); 203 | Serial.print(", "); 204 | Serial.print(imu.calcMag(imu.my), 2); 205 | Serial.print(", "); 206 | Serial.println(imu.calcMag(imu.mz), 2); 207 | #elif defined PRINT_RAW 208 | Serial.print(imu.mx); 209 | Serial.print(", "); 210 | Serial.print(imu.my); 211 | Serial.print(", "); 212 | Serial.println(imu.mz); 213 | #endif 214 | } 215 | 216 | // Calculate pitch, roll, and heading. 217 | // Pitch/roll calculations take from this app note: 218 | // http://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf?fpsp=1 219 | // Heading calculations taken from this app note: 220 | // http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf 221 | void printAttitude(float ax, float ay, float az, float mx, float my, float mz) 222 | { 223 | float roll = atan2(ay, az); 224 | float pitch = atan2(-ax, sqrt(ay * ay + az * az)); 225 | 226 | float heading; 227 | if (my == 0) 228 | heading = (mx < 0) ? PI : 0; 229 | else 230 | heading = atan2(mx, my); 231 | 232 | heading -= DECLINATION * PI / 180; 233 | 234 | if (heading > PI) heading -= (2 * PI); 235 | else if (heading < -PI) heading += (2 * PI); 236 | 237 | // Convert everything from radians to degrees: 238 | heading *= 180.0 / PI; 239 | pitch *= 180.0 / PI; 240 | roll *= 180.0 / PI; 241 | 242 | Serial.print("Pitch, Roll: "); 243 | Serial.print(pitch, 2); 244 | Serial.print(", "); 245 | Serial.println(roll, 2); 246 | Serial.print("Heading: "); Serial.println(heading, 2); 247 | } -------------------------------------------------------------------------------- /examples/LSM9DS1_Interrupts/LSM9DS1_Interrupts.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | LSM9DS1_Interrups.ino 3 | SparkFunLSM9DS1 Library Interrupt Example 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: August 13, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This Arduino sketch demonstrates how to use all four of the 9 | LSM9DS1's interrupt outputs: INT1, INT2, INTM and DRDY_M. 10 | 11 | - INT1 is configured to interrupt when accelerometer or 12 | gyroscope values exceed a set threshold. 13 | - INT2 is configured to interrupt when new accelerometer or 14 | gyroscope values are available 15 | - INTM is configured to interrupt when the magnetometer 16 | exceeds a set threshold. 17 | - DRDY_M (doesn't need configuring) is used to alert when 18 | new magnetometer data is available. 19 | 20 | After uploading the sketch, accel/gyro/mag values will 21 | stream by every second, but that's not really what we're 22 | looking for. Try rotating the sensor along the z-axis - an 23 | interrupt should fire if you rotate fast enough - exceeding 24 | the gyroscope threshold. 25 | Then try rotating along the y-axis. The accelerometer int 26 | is configured to fire when the x-axis acceleration exceeds 27 | a threshold. 28 | Finally, try bringing something magnetic near the sensor. 29 | The magnetometer interrupt is calibrated to fire when the 30 | x-axis mag reading gets too high. 31 | 32 | Hardware setup: This library supports communicating with the 33 | LSM9DS1 over either I2C or SPI. This example demonstrates how 34 | to use I2C. The pin-out is as follows: 35 | LSM9DS1 --------- Arduino 36 | SCL ---------- SCL (A5 on older 'Duinos') 37 | SDA ---------- SDA (A4 on older 'Duinos') 38 | VDD ------------- 3.3V 39 | GND ------------- GND 40 | INT2 ------------- D4 41 | INT1 ------------- D3 42 | INTM ------------- D5 43 | RDY -------------- D6 44 | (CSG, CSXM, SDOG, and SDOXM should all be pulled high. 45 | Jumpers on the breakout board will do this for you.) 46 | 47 | The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it 48 | off the 3.3V rail! I2C pins are open-drain, so you'll be 49 | (mostly) safe connecting the LSM9DS1's SCL and SDA pins 50 | directly to the Arduino. 51 | 52 | Development environment specifics: 53 | IDE: Arduino 1.6.3 54 | Hardware Platform: SparkFun Redboard 55 | LSM9DS1 Breakout Version: 1.0 56 | 57 | This code is beerware. If you see me (or any other SparkFun 58 | employee) at the local, and you've found our code helpful, 59 | please buy us a round! 60 | 61 | Distributed as-is; no warranty is given. 62 | *****************************************************************/ 63 | 64 | // Include the SparkFunLSM9DS1 library and its dependencies. 65 | #include 66 | #include 67 | #include 68 | 69 | LSM9DS1 imu; // Create an LSM9DS1 object to use from here on. 70 | 71 | /////////////////////////////// 72 | // Interrupt Pin Definitions // 73 | /////////////////////////////// 74 | // These can be swapped to any available digital pin: 75 | const int INT1_PIN_THS = 3; // INT1 pin to D3 - will be attached to gyro 76 | const int INT2_PIN_DRDY = 4; // INT2 pin to D4 - attached to accel 77 | const int INTM_PIN_THS = 5; // INTM_PIN_THS pin to D5 78 | const int RDYM_PIN = 6; // RDY pin to D6 79 | 80 | // Variable to keep track of when we print sensor readings: 81 | unsigned long lastPrint = 0; 82 | 83 | //Function Definitions 84 | void printStats(); 85 | 86 | // configureIMU sets up our LSM9DS1 interface, sensor scales 87 | // and sample rates. 88 | uint16_t configureIMU() 89 | { 90 | // gyro.latchInterrupt controls the latching of the 91 | // gyro and accelerometer interrupts (INT1 and INT2). 92 | // false = no latching 93 | imu.settings.gyro.latchInterrupt = false; 94 | 95 | // Set gyroscope scale to +/-245 dps: 96 | imu.settings.gyro.scale = 245; 97 | // Set gyroscope (and accel) sample rate to 14.9 Hz 98 | imu.settings.gyro.sampleRate = 1; 99 | // Set accelerometer scale to +/-2g 100 | imu.settings.accel.scale = 2; 101 | // Set magnetometer scale to +/- 4g 102 | imu.settings.mag.scale = 4; 103 | // Set magnetometer sample rate to 0.625 Hz 104 | imu.settings.mag.sampleRate = 0; 105 | 106 | // Call imu.begin() to initialize the sensor and instill 107 | // it with our new settings. 108 | return imu.begin(LSM9DS1_AG_ADDR(1), LSM9DS1_M_ADDR(1), Wire); // set addresses and wire port 109 | } 110 | 111 | void configureLSM9DS1Interrupts() 112 | { 113 | ///////////////////////////////////////////// 114 | // Configure INT1 - Gyro & Accel Threshold // 115 | ///////////////////////////////////////////// 116 | // For more information on setting gyro interrupt, threshold, 117 | // and configuring the intterup, see the datasheet. 118 | // We'll configure INT_GEN_CFG_G, INT_GEN_THS_??_G, 119 | // INT_GEN_DUR_G, and INT1_CTRL. 120 | // 1. Configure the gyro interrupt generator: 121 | // - ZHIE_G: Z-axis high event (more can be or'd together) 122 | // - false: and/or (false = OR) (not applicable) 123 | // - false: latch interrupt (false = not latched) 124 | imu.configGyroInt(ZHIE_G, false, false); 125 | // 2. Configure the gyro threshold 126 | // - 500: Threshold (raw value from gyro) 127 | // - Z_AXIS: Z-axis threshold 128 | // - 10: duration (based on ODR) 129 | // - true: wait (wait duration before interrupt goes low) 130 | imu.configGyroThs(500, Z_AXIS, 10, true); 131 | // 3. Configure accelerometer interrupt generator: 132 | // - XHIE_XL: x-axis high event 133 | // More axis events can be or'd together 134 | // - false: OR interrupts (N/A, since we only have 1) 135 | imu.configAccelInt(XHIE_XL, false); 136 | // 4. Configure accelerometer threshold: 137 | // - 20: Threshold (raw value from accel) 138 | // Multiply this value by 128 to get threshold value. 139 | // (20 = 2600 raw accel value) 140 | // - X_AXIS: Write to X-axis threshold 141 | // - 10: duration (based on ODR) 142 | // - false: wait (wait [duration] before interrupt goes low) 143 | imu.configAccelThs(20, X_AXIS, 1, false); 144 | // 5. Configure INT1 - assign it to gyro interrupt 145 | // - XG_INT1: Says we're configuring INT1 146 | // - INT1_IG_G | INT1_IG_XL: Sets interrupt source to 147 | // both gyro interrupt and accel 148 | // - INT_ACTIVE_LOW: Sets interrupt to active low. 149 | // (Can otherwise be set to INT_ACTIVE_HIGH.) 150 | // - INT_PUSH_PULL: Sets interrupt to a push-pull. 151 | // (Can otherwise be set to INT_OPEN_DRAIN.) 152 | imu.configInt(XG_INT1, INT1_IG_G | INT_IG_XL, INT_ACTIVE_LOW, INT_PUSH_PULL); 153 | 154 | //////////////////////////////////////////////// 155 | // Configure INT2 - Gyro and Accel Data Ready // 156 | //////////////////////////////////////////////// 157 | // Configure interrupt 2 to fire whenever new accelerometer 158 | // or gyroscope data is available. 159 | // Note XG_INT2 means configuring interrupt 2. 160 | // INT_DRDY_XL is OR'd with INT_DRDY_G 161 | imu.configInt(XG_INT2, INT_DRDY_XL | INT_DRDY_G, INT_ACTIVE_LOW, INT_PUSH_PULL); 162 | 163 | ////////////////////////////////////// 164 | // Configure Magnetometer Interrupt // 165 | ////////////////////////////////////// 166 | // 1. Configure magnetometer interrupt: 167 | // - XIEN: axis to be monitored. Can be an or'd combination 168 | // of XIEN, YIEN, or ZIEN. 169 | // - INT_ACTIVE_LOW: Interrupt goes low when active. 170 | // - true: Latch interrupt 171 | imu.configMagInt(XIEN, INT_ACTIVE_LOW, true); 172 | // 2. Configure magnetometer threshold. 173 | // There's only one threshold value for all 3 mag axes. 174 | // This is the raw mag value that must be exceeded to 175 | // generate an interrupt. 176 | imu.configMagThs(10000); 177 | 178 | } 179 | 180 | void setup() 181 | { 182 | Serial.begin(115200); 183 | // Set up our Arduino pins connected to interrupts. 184 | // We configured all of these interrupts in the LSM9DS1 185 | // to be active-low. 186 | pinMode(INT2_PIN_DRDY, INPUT_PULLUP); 187 | pinMode(INT1_PIN_THS, INPUT_PULLUP); 188 | pinMode(INTM_PIN_THS, INPUT_PULLUP); 189 | // The magnetometer DRDY pin (RDY) is not configurable. 190 | // It is active high and always turned on. 191 | pinMode(RDYM_PIN, INPUT); 192 | 193 | Wire.begin(); 194 | 195 | // Turn on the IMU with configureIMU() (defined above) 196 | // check the return status of imu.begin() to make sure 197 | // it's connected. 198 | uint16_t status = configureIMU(); 199 | if (status == false) 200 | { 201 | Serial.print("Failed to connect to IMU: 0x"); 202 | Serial.println(status, HEX); 203 | while (1) ; 204 | } 205 | 206 | // After turning the IMU on, configure the interrupts: 207 | configureLSM9DS1Interrupts(); 208 | } 209 | 210 | void loop() 211 | { 212 | // Every 1 second (1000 ms), print the last sensor values 213 | // that were read: 214 | if (millis() > (lastPrint + 1000)) 215 | { 216 | printStats(); 217 | lastPrint = millis(); 218 | } 219 | 220 | // INT2 fires when new accelerometer or gyroscope data 221 | // is available. 222 | // It's configured to be active LOW: 223 | if (digitalRead(INT2_PIN_DRDY) == LOW) 224 | { 225 | // We don't know if accelerometer or gyroscope data is 226 | // available. 227 | // Use accelAvailable and gyroAvailable to check, then 228 | // read from those sensors if it's new data. 229 | if (imu.accelAvailable()) 230 | imu.readAccel(); 231 | if (imu.gyroAvailable()) 232 | imu.readGyro(); 233 | } 234 | 235 | // INT1 fires when our gyro or accelerometer thresholds 236 | // are exceeded. 237 | // It's configured to be active LOW: 238 | if (digitalRead(INT1_PIN_THS) == LOW) 239 | { 240 | // Let's keep track of how long the interrupt is active. 241 | // We turned off latching, so this pin will stay low 242 | // as long as the threshold is exceeded: 243 | unsigned long durationStart = millis(); 244 | 245 | // Call getGyroIntSrc() and getAccelIntSrc() to determine 246 | // if the gyro or accel generated the input (and why). 247 | Serial.println("\tINT1 Active!"); 248 | Serial.print("\t\tGyro int: 0x"); 249 | Serial.println(imu.getGyroIntSrc(), HEX); 250 | Serial.print("\t\tAccel int: 0x"); 251 | Serial.println(imu.getAccelIntSrc(), HEX); 252 | 253 | // While the interrupt remains active, loop: 254 | while (digitalRead(INT1_PIN_THS) == LOW) 255 | { 256 | //imu.getGyroIntSrc(); 257 | //imu.getAccelIntSrc(); 258 | } 259 | Serial.print("\tINT1 Duration: "); 260 | Serial.println(millis() - durationStart); 261 | } 262 | 263 | // INTM fires when the magnetometer exceeds our set 264 | // threshold. 265 | // It's configured to be active LOW: 266 | if (digitalRead(INTM_PIN_THS) == LOW) 267 | { 268 | // Once again, we'll keep track of how line the interrupt 269 | // stays low 270 | unsigned long durationStart = millis(); 271 | 272 | // Read getMagIntSrc() to see why the interrupt was 273 | // generated. 274 | Serial.print("\t\tMag int: 0x"); 275 | Serial.println(imu.getMagIntSrc(), HEX); 276 | 277 | // Loop until the interrupt stops firing 278 | while (digitalRead(INTM_PIN_THS) == LOW) 279 | { 280 | } 281 | Serial.print("\t\tINTM_PIN_THS Duration: "); 282 | Serial.println(millis() - durationStart); 283 | } 284 | 285 | // RDY goes HIGH when new magnetometer is available. 286 | // AFAICT the active high/low isn't configurable: 287 | if (digitalRead(RDYM_PIN) == HIGH) 288 | { 289 | if (imu.magAvailable()) 290 | { 291 | imu.readMag(); 292 | } 293 | } 294 | } 295 | 296 | // Print the last read accelerometer, gyro, and mag values: 297 | void printStats() 298 | { 299 | Serial.println(); 300 | Serial.print("A: "); 301 | Serial.print(imu.ax); Serial.print(", "); 302 | Serial.print(imu.ay); Serial.print(", "); 303 | Serial.println(imu.az); 304 | Serial.print("G: "); 305 | Serial.print(imu.gx); Serial.print(", "); 306 | Serial.print(imu.gy); Serial.print(", "); 307 | Serial.println(imu.gz); 308 | Serial.print("M: "); 309 | Serial.print(imu.mx); Serial.print(", "); 310 | Serial.print(imu.my); Serial.print(", "); 311 | Serial.println(imu.mz); 312 | } 313 | -------------------------------------------------------------------------------- /examples/LSM9DS1_Settings/LSM9DS1_Settings.ino: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | LSM9DS1_Settings.ino 3 | SFE_LSM9DS1 Library Settings Configuration Example 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: August 13, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This Arduino sketch demonstrates how to configure every 9 | possible configuration value in the SparkFunLSM9DS1 library. 10 | 11 | It demonstrates how to set the output data rates and scales 12 | for each sensor, along with other settings like LPF cutoff 13 | frequencies and low-power settings. 14 | 15 | It also demonstrates how to turn various sensors in the 16 | LSM9DS1 on or off. 17 | 18 | Hardware setup: This library supports communicating with the 19 | LSM9DS1 over either I2C or SPI. This example demonstrates how 20 | to use I2C. The pin-out is as follows: 21 | LSM9DS1 --------- Arduino 22 | SCL ---------- SCL (A5 on older 'Duinos') 23 | SDA ---------- SDA (A4 on older 'Duinos') 24 | VDD ------------- 3.3V 25 | GND ------------- GND 26 | (CSG, CSXM, SDOG, and SDOXM should all be pulled high. 27 | Jumpers on the breakout board will do this for you.) 28 | 29 | The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it 30 | off the 3.3V rail! I2C pins are open-drain, so you'll be 31 | (mostly) safe connecting the LSM9DS1's SCL and SDA pins 32 | directly to the Arduino. 33 | 34 | Development environment specifics: 35 | IDE: Arduino 1.6.3 36 | Hardware Platform: SparkFun Redboard 37 | LSM9DS1 Breakout Version: 1.0 38 | 39 | This code is beerware. If you see me (or any other SparkFun 40 | employee) at the local, and you've found our code helpful, 41 | please buy us a round! 42 | 43 | Distributed as-is; no warranty is given. 44 | *****************************************************************/ 45 | // Include SparkFunLSM9DS1 library and its dependencies 46 | #include 47 | #include 48 | #include 49 | 50 | LSM9DS1 imu; // Create an LSM9DS1 object 51 | 52 | // SDO_XM and SDO_G are both pulled high, so our addresses are: 53 | #define LSM9DS1_M 0x1E // Would be 0x1C if SDO_M is LOW 54 | #define LSM9DS1_AG 0x6B // Would be 0x6A if SDO_AG is LOW 55 | 56 | // Global variables to keep track of update rates 57 | unsigned long startTime; 58 | unsigned int accelReadCounter = 0; 59 | unsigned int gyroReadCounter = 0; 60 | unsigned int magReadCounter = 0; 61 | unsigned int tempReadCounter = 0; 62 | 63 | // Global variables to print to serial monitor at a steady rate 64 | unsigned long lastPrint = 0; 65 | const unsigned int PRINT_RATE = 500; 66 | 67 | //Function definitions 68 | void printSensorReadings(); 69 | 70 | void setupGyro() 71 | { 72 | // [enabled] turns the gyro on or off. 73 | imu.settings.gyro.enabled = true; // Enable the gyro 74 | // [scale] sets the full-scale range of the gyroscope. 75 | // scale can be set to either 245, 500, or 2000 76 | imu.settings.gyro.scale = 245; // Set scale to +/-245dps 77 | // [sampleRate] sets the output data rate (ODR) of the gyro 78 | // sampleRate can be set between 1-6 79 | // 1 = 14.9 4 = 238 80 | // 2 = 59.5 5 = 476 81 | // 3 = 119 6 = 952 82 | imu.settings.gyro.sampleRate = 3; // 59.5Hz ODR 83 | // [bandwidth] can set the cutoff frequency of the gyro. 84 | // Allowed values: 0-3. Actual value of cutoff frequency 85 | // depends on the sample rate. (Datasheet section 7.12) 86 | imu.settings.gyro.bandwidth = 0; 87 | // [lowPowerEnable] turns low-power mode on or off. 88 | imu.settings.gyro.lowPowerEnable = false; // LP mode off 89 | // [HPFEnable] enables or disables the high-pass filter 90 | imu.settings.gyro.HPFEnable = true; // HPF disabled 91 | // [HPFCutoff] sets the HPF cutoff frequency (if enabled) 92 | // Allowable values are 0-9. Value depends on ODR. 93 | // (Datasheet section 7.14) 94 | imu.settings.gyro.HPFCutoff = 1; // HPF cutoff = 4Hz 95 | // [flipX], [flipY], and [flipZ] are booleans that can 96 | // automatically switch the positive/negative orientation 97 | // of the three gyro axes. 98 | imu.settings.gyro.flipX = false; // Don't flip X 99 | imu.settings.gyro.flipY = false; // Don't flip Y 100 | imu.settings.gyro.flipZ = false; // Don't flip Z 101 | } 102 | 103 | void setupAccel() 104 | { 105 | // [enabled] turns the acclerometer on or off. 106 | imu.settings.accel.enabled = true; // Enable accelerometer 107 | // [enableX], [enableY], and [enableZ] can turn on or off 108 | // select axes of the acclerometer. 109 | imu.settings.accel.enableX = true; // Enable X 110 | imu.settings.accel.enableY = true; // Enable Y 111 | imu.settings.accel.enableZ = true; // Enable Z 112 | // [scale] sets the full-scale range of the accelerometer. 113 | // accel scale can be 2, 4, 8, or 16 114 | imu.settings.accel.scale = 8; // Set accel scale to +/-8g. 115 | // [sampleRate] sets the output data rate (ODR) of the 116 | // accelerometer. ONLY APPLICABLE WHEN THE GYROSCOPE IS 117 | // DISABLED! Otherwise accel sample rate = gyro sample rate. 118 | // accel sample rate can be 1-6 119 | // 1 = 10 Hz 4 = 238 Hz 120 | // 2 = 50 Hz 5 = 476 Hz 121 | // 3 = 119 Hz 6 = 952 Hz 122 | imu.settings.accel.sampleRate = 1; // Set accel to 10Hz. 123 | // [bandwidth] sets the anti-aliasing filter bandwidth. 124 | // Accel cutoff freqeuncy can be any value between -1 - 3. 125 | // -1 = bandwidth determined by sample rate 126 | // 0 = 408 Hz 2 = 105 Hz 127 | // 1 = 211 Hz 3 = 50 Hz 128 | imu.settings.accel.bandwidth = 0; // BW = 408Hz 129 | // [highResEnable] enables or disables high resolution 130 | // mode for the acclerometer. 131 | imu.settings.accel.highResEnable = false; // Disable HR 132 | // [highResBandwidth] sets the LP cutoff frequency of 133 | // the accelerometer if it's in high-res mode. 134 | // can be any value between 0-3 135 | // LP cutoff is set to a factor of sample rate 136 | // 0 = ODR/50 2 = ODR/9 137 | // 1 = ODR/100 3 = ODR/400 138 | imu.settings.accel.highResBandwidth = 0; 139 | } 140 | 141 | void setupMag() 142 | { 143 | // [enabled] turns the magnetometer on or off. 144 | imu.settings.mag.enabled = true; // Enable magnetometer 145 | // [scale] sets the full-scale range of the magnetometer 146 | // mag scale can be 4, 8, 12, or 16 147 | imu.settings.mag.scale = 12; // Set mag scale to +/-12 Gs 148 | // [sampleRate] sets the output data rate (ODR) of the 149 | // magnetometer. 150 | // mag data rate can be 0-7: 151 | // 0 = 0.625 Hz 4 = 10 Hz 152 | // 1 = 1.25 Hz 5 = 20 Hz 153 | // 2 = 2.5 Hz 6 = 40 Hz 154 | // 3 = 5 Hz 7 = 80 Hz 155 | imu.settings.mag.sampleRate = 5; // Set OD rate to 20Hz 156 | // [tempCompensationEnable] enables or disables 157 | // temperature compensation of the magnetometer. 158 | imu.settings.mag.tempCompensationEnable = false; 159 | // [XYPerformance] sets the x and y-axis performance of the 160 | // magnetometer to either: 161 | // 0 = Low power mode 2 = high performance 162 | // 1 = medium performance 3 = ultra-high performance 163 | imu.settings.mag.XYPerformance = 3; // Ultra-high perform. 164 | // [ZPerformance] does the same thing, but only for the z 165 | imu.settings.mag.ZPerformance = 3; // Ultra-high perform. 166 | // [lowPowerEnable] enables or disables low power mode in 167 | // the magnetometer. 168 | imu.settings.mag.lowPowerEnable = false; 169 | // [operatingMode] sets the operating mode of the 170 | // magnetometer. operatingMode can be 0-2: 171 | // 0 = continuous conversion 172 | // 1 = single-conversion 173 | // 2 = power down 174 | imu.settings.mag.operatingMode = 0; // Continuous mode 175 | } 176 | 177 | void setupTemperature() 178 | { 179 | // [enabled] turns the temperature sensor on or off. 180 | imu.settings.temp.enabled = true; 181 | } 182 | 183 | uint16_t initLSM9DS1() 184 | { 185 | setupGyro(); // Set up gyroscope parameters 186 | setupAccel(); // Set up accelerometer parameters 187 | setupMag(); // Set up magnetometer parameters 188 | setupTemperature(); // Set up temp sensor parameter 189 | 190 | return imu.begin(LSM9DS1_AG, LSM9DS1_M, Wire); // for SPI use beginSPI() 191 | } 192 | 193 | void setup() 194 | { 195 | Serial.begin(115200); 196 | 197 | Wire.begin(); 198 | 199 | Serial.println("Initializing the LSM9DS1"); 200 | uint16_t status = initLSM9DS1(); 201 | Serial.print("LSM9DS1 WHO_AM_I's returned: 0x"); 202 | Serial.println(status, HEX); 203 | Serial.println("Should be 0x683D"); 204 | Serial.println(); 205 | 206 | startTime = millis(); 207 | } 208 | 209 | void loop() 210 | { 211 | // imu.accelAvailable() returns 1 if new accelerometer 212 | // data is ready to be read. 0 otherwise. 213 | if (imu.accelAvailable()) 214 | { 215 | imu.readAccel(); 216 | accelReadCounter++; 217 | } 218 | 219 | // imu.gyroAvailable() returns 1 if new gyroscope 220 | // data is ready to be read. 0 otherwise. 221 | if (imu.gyroAvailable()) 222 | { 223 | imu.readGyro(); 224 | gyroReadCounter++; 225 | } 226 | 227 | // imu.magAvailable() returns 1 if new magnetometer 228 | // data is ready to be read. 0 otherwise. 229 | if (imu.magAvailable()) 230 | { 231 | imu.readMag(); 232 | magReadCounter++; 233 | } 234 | 235 | // imu.tempAvailable() returns 1 if new temperature sensor 236 | // data is ready to be read. 0 otherwise. 237 | if (imu.tempAvailable()) 238 | { 239 | imu.readTemp(); 240 | tempReadCounter++; 241 | } 242 | 243 | // Every PRINT_RATE milliseconds, print sensor data: 244 | if ((lastPrint + PRINT_RATE) < millis()) 245 | { 246 | printSensorReadings(); 247 | lastPrint = millis(); 248 | } 249 | } 250 | 251 | // printSensorReadings prints the latest IMU readings 252 | // along with a calculated update rate. 253 | void printSensorReadings() 254 | { 255 | float runTime = (float)(millis() - startTime) / 1000.0; 256 | float accelRate = (float)accelReadCounter / runTime; 257 | float gyroRate = (float)gyroReadCounter / runTime; 258 | float magRate = (float)magReadCounter / runTime; 259 | float tempRate = (float)tempReadCounter / runTime; 260 | Serial.print("A: "); 261 | Serial.print(imu.calcAccel(imu.ax)); 262 | Serial.print(", "); 263 | Serial.print(imu.calcAccel(imu.ay)); 264 | Serial.print(", "); 265 | Serial.print(imu.calcAccel(imu.az)); 266 | Serial.print(" g \t| "); 267 | Serial.print(accelRate); 268 | Serial.println(" Hz"); 269 | Serial.print("G: "); 270 | Serial.print(imu.calcGyro(imu.gx)); 271 | Serial.print(", "); 272 | Serial.print(imu.calcGyro(imu.gy)); 273 | Serial.print(", "); 274 | Serial.print(imu.calcGyro(imu.gz)); 275 | Serial.print(" dps \t| "); 276 | Serial.print(gyroRate); 277 | Serial.println(" Hz"); 278 | Serial.print("M: "); 279 | Serial.print(imu.calcMag(imu.mx)); 280 | Serial.print(", "); 281 | Serial.print(imu.calcMag(imu.my)); 282 | Serial.print(", "); 283 | Serial.print(imu.calcMag(imu.mz)); 284 | Serial.print(" Gs \t| "); 285 | Serial.print(magRate); 286 | Serial.println(" Hz"); 287 | Serial.print("T: "); 288 | Serial.print(imu.temperature); 289 | Serial.print(" \t\t\t| "); 290 | Serial.print(tempRate); 291 | Serial.println(" Hz"); 292 | Serial.println(); 293 | } 294 | -------------------------------------------------------------------------------- /extras/LSM9DS1 Datasheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/SparkFun_LSM9DS1_Arduino_Library/18d3181c2bf2826c85b819079e3e626d12ab763b/extras/LSM9DS1 Datasheet.pdf -------------------------------------------------------------------------------- /extras/SparkFun-LSM9DS1-Breakout-schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/SparkFun_LSM9DS1_Arduino_Library/18d3181c2bf2826c85b819079e3e626d12ab763b/extras/SparkFun-LSM9DS1-Breakout-schematic.pdf -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ######################################################### 2 | # Syntax Coloring Map for SparkFun LSM9DS1 9DOF Library # 3 | ######################################################### 4 | # Class 5 | ######################################################### 6 | 7 | SparkFunLSM9DS1 KEYWORD1 8 | LSM9DS1 KEYWORD1 9 | 10 | ######################################################### 11 | # Methods and Functions 12 | ######################################################### 13 | 14 | ax KEYWORD2 15 | ay KEYWORD2 16 | az KEYWORD2 17 | gx KEYWORD2 18 | gy KEYWORD2 19 | gz KEYWORD2 20 | mx KEYWORD2 21 | my KEYWORD2 22 | mz KEYWORD2 23 | temperature KEYWORD2 24 | gBias KEYWORD2 25 | aBias KEYWORD2 26 | mBias KEYWORD2 27 | gBiasRaw KEYWORD2 28 | aBiasRaw KEYWORD2 29 | mBiasRaw KEYWORD2 30 | begin KEYWORD2 31 | beginSPI KEYWORD2 32 | calibrate KEYWORD2 33 | calibrateMag KEYWORD2 34 | magOffset KEYWORD2 35 | accelAvailable KEYWORD2 36 | gyroAvailable KEYWORD2 37 | tempAvailable KEYWORD2 38 | magAvailable KEYWORD2 39 | readGyro KEYWORD2 40 | readAccel KEYWORD2 41 | readMag KEYWORD2 42 | readTemp KEYWORD2 43 | calcGyro KEYWORD2 44 | calcAccel KEYWORD2 45 | calcMag KEYWORD2 46 | setGyroScale KEYWORD2 47 | setAccelScale KEYWORD2 48 | setMagScale KEYWORD2 49 | setGyroODR KEYWORD2 50 | setAccelODR KEYWORD2 51 | setMagODR KEYWORD2 52 | configInactivity KEYWORD2 53 | configAccelInt KEYWORD2 54 | configAccelThs KEYWORD2 55 | configGyroInt KEYWORD2 56 | configGyroThs KEYWORD2 57 | configInt KEYWORD2 58 | configMagInt KEYWORD2 59 | getGyroIntSrc KEYWORD2 60 | getAccelIntSrc KEYWORD2 61 | getMagIntSrc KEYWORD2 62 | getInactivity KEYWORD2 63 | sleepGyro KEYWORD2 64 | enableFIFO KEYWORD2 65 | setFIFO KEYWORD2 66 | getFIFOSamples KEYWORD2 67 | device KEYWORD2 68 | gyro KEYWORD2 69 | accel KEYWORD2 70 | mag KEYWORD2 71 | temp KEYWORD2 72 | enabled KEYWORD2 73 | operatingMode KEYWORD2 74 | scale KEYWORD2 75 | sampleRate KEYWORD2 76 | tempCompensationEnable KEYWORD2 77 | XYPerformance KEYWORD2 78 | ZPerformance KEYWORD2 79 | lowPowerEnable KEYWORD2 80 | enableX KEYWORD2 81 | enableY KEYWORD2 82 | enableZ KEYWORD2 83 | bandwidth KEYWORD2 84 | highResEnable KEYWORD2 85 | highResBandwidth KEYWORD2 86 | commInterface KEYWORD2 87 | agAddress KEYWORD2 88 | mAddress KEYWORD2 89 | HPFEnable KEYWORD2 90 | HPFCutoff KEYWORD2 91 | flipX KEYWORD2 92 | flipY KEYWORD2 93 | flipZ KEYWORD2 94 | orientation KEYWORD2 95 | latchInterrupt KEYWORD2 96 | settings KEYWORD2 97 | 98 | ######################################################### 99 | # Constants 100 | ######################################################### 101 | 102 | X_AXIS LITERAL2 103 | Y_AXIS LITERAL1 104 | Z_AXIS LITERAL1 105 | ALL_AXIS LITERAL1 106 | LSM9DS1_AG_ADDR LITERAL1 107 | LSM9DS1_M_ADDR LITERAL1 108 | IMU_MODE_SPI LITERAL1 109 | IMU_MODE_I2C LITERAL1 110 | XG_INT1 LITERAL1 111 | XG_INT2 LITERAL1 112 | INT_DRDY_XL LITERAL1 113 | INT_DRDY_G LITERAL1 114 | INT1_BOOT LITERAL1 115 | INT2_DRDY_TEMP LITERAL1 116 | INT_FTH LITERAL1 117 | INT_OVR LITERAL1 118 | INT_FSS5 LITERAL1 119 | INT_IG_XL LITERAL1 120 | INT1_IG_G LITERAL1 121 | INT2_INACT LITERAL1 122 | XLIE_XL LITERAL1 123 | XHIE_XL LITERAL1 124 | YLIE_XL LITERAL1 125 | YHIE_XL LITERAL1 126 | ZLIE_XL LITERAL1 127 | ZHIE_XL LITERAL1 128 | XLIE_G LITERAL1 129 | XHIE_G LITERAL1 130 | YLIE_G LITERAL1 131 | YHIE_G LITERAL1 132 | ZLIE_G LITERAL1 133 | ZHIE_G LITERAL1 134 | XIEN LITERAL1 135 | YIEN LITERAL1 136 | ZIEN LITERAL1 137 | INT_ACTIVE_HIGH LITERAL1 138 | INT_ACTIVE_LOW LITERAL1 139 | INT_PUSH_PULL LITERAL1 140 | INT_OPEN_DRAIN LITERAL1 141 | FIFO_OFF LITERAL1 142 | FIFO_THS LITERAL1 143 | FIFO_CONT_TRIGGER LITERAL1 144 | FIFO_OFF_TRIGGER LITERAL1 145 | FIFO_CONT LITERAL1 146 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun LSM9DS1 IMU 2 | version=2.0.0 3 | author=SparkFun Electronics 4 | maintainer=Jim Lindblom 5 | sentence=A driver library for the LSM9DS1 IMU. 6 | paragraph=Communicates with the LSM9DS1 over either SPI or I2C, so you can painlessly integrate an accelerometer, magnetometer, and gyroscope into your project. 7 | category=Sensors 8 | url=https://www.sparkfun.com/products/13284 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/LSM9DS1_Registers.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | LSM9DS1_Registers.h 3 | SFE_LSM9DS1 Library - LSM9DS1 Register Map 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: April 21, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This file defines all registers internal to the gyro/accel and magnetometer 9 | devices in the LSM9DS1. 10 | 11 | Development environment specifics: 12 | IDE: Arduino 1.6.0 13 | Hardware Platform: Arduino Uno 14 | LSM9DS1 Breakout Version: 1.0 15 | 16 | This code is beerware; if you see me (or any other SparkFun employee) at the 17 | local, and you've found our code helpful, please buy us a round! 18 | 19 | Distributed as-is; no warranty is given. 20 | ******************************************************************************/ 21 | 22 | #ifndef __LSM9DS1_Registers_H__ 23 | #define __LSM9DS1_Registers_H__ 24 | 25 | ///////////////////////////////////////// 26 | // LSM9DS1 Accel/Gyro (XL/G) Registers // 27 | ///////////////////////////////////////// 28 | #define ACT_THS 0x04 29 | #define ACT_DUR 0x05 30 | #define INT_GEN_CFG_XL 0x06 31 | #define INT_GEN_THS_X_XL 0x07 32 | #define INT_GEN_THS_Y_XL 0x08 33 | #define INT_GEN_THS_Z_XL 0x09 34 | #define INT_GEN_DUR_XL 0x0A 35 | #define REFERENCE_G 0x0B 36 | #define INT1_CTRL 0x0C 37 | #define INT2_CTRL 0x0D 38 | #define WHO_AM_I_XG 0x0F 39 | #define CTRL_REG1_G 0x10 40 | #define CTRL_REG2_G 0x11 41 | #define CTRL_REG3_G 0x12 42 | #define ORIENT_CFG_G 0x13 43 | #define INT_GEN_SRC_G 0x14 44 | #define OUT_TEMP_L 0x15 45 | #define OUT_TEMP_H 0x16 46 | #define STATUS_REG_0 0x17 47 | #define OUT_X_L_G 0x18 48 | #define OUT_X_H_G 0x19 49 | #define OUT_Y_L_G 0x1A 50 | #define OUT_Y_H_G 0x1B 51 | #define OUT_Z_L_G 0x1C 52 | #define OUT_Z_H_G 0x1D 53 | #define CTRL_REG4 0x1E 54 | #define CTRL_REG5_XL 0x1F 55 | #define CTRL_REG6_XL 0x20 56 | #define CTRL_REG7_XL 0x21 57 | #define CTRL_REG8 0x22 58 | #define CTRL_REG9 0x23 59 | #define CTRL_REG10 0x24 60 | #define INT_GEN_SRC_XL 0x26 61 | #define STATUS_REG_1 0x27 62 | #define OUT_X_L_XL 0x28 63 | #define OUT_X_H_XL 0x29 64 | #define OUT_Y_L_XL 0x2A 65 | #define OUT_Y_H_XL 0x2B 66 | #define OUT_Z_L_XL 0x2C 67 | #define OUT_Z_H_XL 0x2D 68 | #define FIFO_CTRL 0x2E 69 | #define FIFO_SRC 0x2F 70 | #define INT_GEN_CFG_G 0x30 71 | #define INT_GEN_THS_XH_G 0x31 72 | #define INT_GEN_THS_XL_G 0x32 73 | #define INT_GEN_THS_YH_G 0x33 74 | #define INT_GEN_THS_YL_G 0x34 75 | #define INT_GEN_THS_ZH_G 0x35 76 | #define INT_GEN_THS_ZL_G 0x36 77 | #define INT_GEN_DUR_G 0x37 78 | 79 | /////////////////////////////// 80 | // LSM9DS1 Magneto Registers // 81 | /////////////////////////////// 82 | #define OFFSET_X_REG_L_M 0x05 83 | #define OFFSET_X_REG_H_M 0x06 84 | #define OFFSET_Y_REG_L_M 0x07 85 | #define OFFSET_Y_REG_H_M 0x08 86 | #define OFFSET_Z_REG_L_M 0x09 87 | #define OFFSET_Z_REG_H_M 0x0A 88 | #define WHO_AM_I_M 0x0F 89 | #define CTRL_REG1_M 0x20 90 | #define CTRL_REG2_M 0x21 91 | #define CTRL_REG3_M 0x22 92 | #define CTRL_REG4_M 0x23 93 | #define CTRL_REG5_M 0x24 94 | #define STATUS_REG_M 0x27 95 | #define OUT_X_L_M 0x28 96 | #define OUT_X_H_M 0x29 97 | #define OUT_Y_L_M 0x2A 98 | #define OUT_Y_H_M 0x2B 99 | #define OUT_Z_L_M 0x2C 100 | #define OUT_Z_H_M 0x2D 101 | #define INT_CFG_M 0x30 102 | #define INT_SRC_M 0x31 103 | #define INT_THS_L_M 0x32 104 | #define INT_THS_H_M 0x33 105 | 106 | //////////////////////////////// 107 | // LSM9DS1 WHO_AM_I Responses // 108 | //////////////////////////////// 109 | #define WHO_AM_I_AG_RSP 0x68 110 | #define WHO_AM_I_M_RSP 0x3D 111 | 112 | #endif -------------------------------------------------------------------------------- /src/LSM9DS1_Types.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | LSM9DS1_Types.h 3 | SFE_LSM9DS1 Library - LSM9DS1 Types and Enumerations 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: April 21, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This file defines all types and enumerations used by the LSM9DS1 class. 9 | 10 | Development environment specifics: 11 | IDE: Arduino 1.6.0 12 | Hardware Platform: Arduino Uno 13 | LSM9DS1 Breakout Version: 1.0 14 | 15 | This code is beerware; if you see me (or any other SparkFun employee) at the 16 | local, and you've found our code helpful, please buy us a round! 17 | 18 | Distributed as-is; no warranty is given. 19 | ******************************************************************************/ 20 | 21 | #ifndef __LSM9DS1_Types_H__ 22 | #define __LSM9DS1_Types_H__ 23 | 24 | #include "LSM9DS1_Registers.h" 25 | #include 26 | 27 | // The LSM9DS1 functions over both I2C or SPI. This library supports both. 28 | // But the interface mode used must be sent to the LSM9DS1 constructor. Use 29 | // one of these two as the first parameter of the constructor. 30 | enum interface_mode 31 | { 32 | IMU_MODE_SPI, 33 | IMU_MODE_I2C, 34 | }; 35 | 36 | // accel_scale defines all possible FSR's of the accelerometer: 37 | enum accel_scale 38 | { 39 | A_SCALE_2G, // 00: 2g 40 | A_SCALE_16G, // 01: 16g 41 | A_SCALE_4G, // 10: 4g 42 | A_SCALE_8G // 11: 8g 43 | }; 44 | 45 | // gyro_scale defines the possible full-scale ranges of the gyroscope: 46 | enum gyro_scale 47 | { 48 | G_SCALE_245DPS, // 00: 245 degrees per second 49 | G_SCALE_500DPS, // 01: 500 dps 50 | G_SCALE_2000DPS, // 11: 2000 dps 51 | }; 52 | 53 | // mag_scale defines all possible FSR's of the magnetometer: 54 | enum mag_scale 55 | { 56 | M_SCALE_4GS, // 00: 4Gs 57 | M_SCALE_8GS, // 01: 8Gs 58 | M_SCALE_12GS, // 10: 12Gs 59 | M_SCALE_16GS, // 11: 16Gs 60 | }; 61 | 62 | // gyro_odr defines all possible data rate/bandwidth combos of the gyro: 63 | enum gyro_odr 64 | { 65 | //! TODO 66 | G_ODR_PD, // Power down (0) 67 | G_ODR_149, // 14.9 Hz (1) 68 | G_ODR_595, // 59.5 Hz (2) 69 | G_ODR_119, // 119 Hz (3) 70 | G_ODR_238, // 238 Hz (4) 71 | G_ODR_476, // 476 Hz (5) 72 | G_ODR_952 // 952 Hz (6) 73 | }; 74 | // accel_oder defines all possible output data rates of the accelerometer: 75 | enum accel_odr 76 | { 77 | XL_POWER_DOWN, // Power-down mode (0x0) 78 | XL_ODR_10, // 10 Hz (0x1) 79 | XL_ODR_50, // 50 Hz (0x02) 80 | XL_ODR_119, // 119 Hz (0x3) 81 | XL_ODR_238, // 238 Hz (0x4) 82 | XL_ODR_476, // 476 Hz (0x5) 83 | XL_ODR_952 // 952 Hz (0x6) 84 | }; 85 | 86 | // accel_abw defines all possible anti-aliasing filter rates of the accelerometer: 87 | enum accel_abw 88 | { 89 | A_ABW_408, // 408 Hz (0x0) 90 | A_ABW_211, // 211 Hz (0x1) 91 | A_ABW_105, // 105 Hz (0x2) 92 | A_ABW_50, // 50 Hz (0x3) 93 | }; 94 | 95 | // mag_odr defines all possible output data rates of the magnetometer: 96 | enum mag_odr 97 | { 98 | M_ODR_0625, // 0.625 Hz (0) 99 | M_ODR_125, // 1.25 Hz (1) 100 | M_ODR_250, // 2.5 Hz (2) 101 | M_ODR_5, // 5 Hz (3) 102 | M_ODR_10, // 10 Hz (4) 103 | M_ODR_20, // 20 Hz (5) 104 | M_ODR_40, // 40 Hz (6) 105 | M_ODR_80 // 80 Hz (7) 106 | }; 107 | 108 | enum interrupt_select 109 | { 110 | XG_INT1 = INT1_CTRL, 111 | XG_INT2 = INT2_CTRL 112 | }; 113 | 114 | enum interrupt_generators 115 | { 116 | INT_DRDY_XL = (1 << 0), // Accelerometer data ready (INT1 & INT2) 117 | INT_DRDY_G = (1 << 1), // Gyroscope data ready (INT1 & INT2) 118 | INT1_BOOT = (1 << 2), // Boot status (INT1) 119 | INT2_DRDY_TEMP = (1 << 2), // Temp data ready (INT2) 120 | INT_FTH = (1 << 3), // FIFO threshold interrupt (INT1 & INT2) 121 | INT_OVR = (1 << 4), // Overrun interrupt (INT1 & INT2) 122 | INT_FSS5 = (1 << 5), // FSS5 interrupt (INT1 & INT2) 123 | INT_IG_XL = (1 << 6), // Accel interrupt generator (INT1) 124 | INT1_IG_G = (1 << 7), // Gyro interrupt enable (INT1) 125 | INT2_INACT = (1 << 7), // Inactivity interrupt output (INT2) 126 | }; 127 | 128 | enum accel_interrupt_generator 129 | { 130 | XLIE_XL = (1 << 0), 131 | XHIE_XL = (1 << 1), 132 | YLIE_XL = (1 << 2), 133 | YHIE_XL = (1 << 3), 134 | ZLIE_XL = (1 << 4), 135 | ZHIE_XL = (1 << 5), 136 | GEN_6D = (1 << 6) 137 | }; 138 | 139 | enum gyro_interrupt_generator 140 | { 141 | XLIE_G = (1 << 0), 142 | XHIE_G = (1 << 1), 143 | YLIE_G = (1 << 2), 144 | YHIE_G = (1 << 3), 145 | ZLIE_G = (1 << 4), 146 | ZHIE_G = (1 << 5) 147 | }; 148 | 149 | enum mag_interrupt_generator 150 | { 151 | ZIEN = (1 << 5), 152 | YIEN = (1 << 6), 153 | XIEN = (1 << 7) 154 | }; 155 | 156 | enum h_lactive 157 | { 158 | INT_ACTIVE_HIGH, 159 | INT_ACTIVE_LOW 160 | }; 161 | 162 | enum pp_od 163 | { 164 | INT_PUSH_PULL, 165 | INT_OPEN_DRAIN 166 | }; 167 | 168 | enum fifoMode_type 169 | { 170 | FIFO_OFF = 0, 171 | FIFO_THS = 1, 172 | FIFO_CONT_TRIGGER = 3, 173 | FIFO_OFF_TRIGGER = 4, 174 | FIFO_CONT = 6 175 | }; 176 | 177 | struct gyroSettings 178 | { 179 | // Gyroscope settings: 180 | uint8_t enabled; 181 | uint16_t scale; // Changed this to 16-bit 182 | uint8_t sampleRate; 183 | // New gyro stuff: 184 | uint8_t bandwidth; 185 | uint8_t lowPowerEnable; 186 | uint8_t HPFEnable; 187 | uint8_t HPFCutoff; 188 | uint8_t flipX; 189 | uint8_t flipY; 190 | uint8_t flipZ; 191 | uint8_t orientation; 192 | uint8_t enableX; 193 | uint8_t enableY; 194 | uint8_t enableZ; 195 | uint8_t latchInterrupt; 196 | }; 197 | 198 | struct deviceSettings 199 | { 200 | uint8_t commInterface; // Can be I2C, SPI 4-wire or SPI 3-wire 201 | uint8_t agAddress; // I2C address or SPI CS pin 202 | uint8_t mAddress; // I2C address or SPI CS pin 203 | TwoWire* i2c; // pointer to an instance of I2C interface 204 | }; 205 | 206 | struct accelSettings 207 | { 208 | // Accelerometer settings: 209 | uint8_t enabled; 210 | uint8_t scale; 211 | uint8_t sampleRate; 212 | // New accel stuff: 213 | uint8_t enableX; 214 | uint8_t enableY; 215 | uint8_t enableZ; 216 | int8_t bandwidth; 217 | uint8_t highResEnable; 218 | uint8_t highResBandwidth; 219 | }; 220 | 221 | struct magSettings 222 | { 223 | // Magnetometer settings: 224 | uint8_t enabled; 225 | uint8_t scale; 226 | uint8_t sampleRate; 227 | // New mag stuff: 228 | uint8_t tempCompensationEnable; 229 | uint8_t XYPerformance; 230 | uint8_t ZPerformance; 231 | uint8_t lowPowerEnable; 232 | uint8_t operatingMode; 233 | }; 234 | 235 | struct temperatureSettings 236 | { 237 | // Temperature settings 238 | uint8_t enabled; 239 | }; 240 | 241 | struct IMUSettings 242 | { 243 | deviceSettings device; 244 | 245 | gyroSettings gyro; 246 | accelSettings accel; 247 | magSettings mag; 248 | 249 | temperatureSettings temp; 250 | }; 251 | 252 | #endif 253 | -------------------------------------------------------------------------------- /src/SparkFunLSM9DS1.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SFE_LSM9DS1.cpp 3 | SFE_LSM9DS1 Library Source File 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: February 27, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This file implements all functions of the LSM9DS1 class. Functions here range 9 | from higher level stuff, like reading/writing LSM9DS1 registers to low-level, 10 | hardware reads and writes. Both SPI and I2C handler functions can be found 11 | towards the bottom of this file. 12 | 13 | Development environment specifics: 14 | IDE: Arduino 1.6 15 | Hardware Platform: Arduino Uno 16 | LSM9DS1 Breakout Version: 1.0 17 | 18 | This code is beerware; if you see me (or any other SparkFun employee) at the 19 | local, and you've found our code helpful, please buy us a round! 20 | 21 | Distributed as-is; no warranty is given. 22 | ******************************************************************************/ 23 | 24 | #include "SparkFunLSM9DS1.h" 25 | #include "LSM9DS1_Registers.h" 26 | #include "LSM9DS1_Types.h" 27 | #include // Wire library is used for I2C 28 | #include // SPI library is used for...SPI. 29 | 30 | #if defined(ARDUINO) && ARDUINO >= 100 31 | #include "Arduino.h" 32 | #else 33 | #include "WProgram.h" 34 | #endif 35 | 36 | // Sensor Sensitivity Constants 37 | // Values set according to the typical specifications provided in 38 | // table 3 of the LSM9DS1 datasheet. (pg 12) 39 | #define SENSITIVITY_ACCELEROMETER_2 0.000061 40 | #define SENSITIVITY_ACCELEROMETER_4 0.000122 41 | #define SENSITIVITY_ACCELEROMETER_8 0.000244 42 | #define SENSITIVITY_ACCELEROMETER_16 0.000732 43 | #define SENSITIVITY_GYROSCOPE_245 0.00875 44 | #define SENSITIVITY_GYROSCOPE_500 0.0175 45 | #define SENSITIVITY_GYROSCOPE_2000 0.07 46 | #define SENSITIVITY_MAGNETOMETER_4 0.00014 47 | #define SENSITIVITY_MAGNETOMETER_8 0.00029 48 | #define SENSITIVITY_MAGNETOMETER_12 0.00043 49 | #define SENSITIVITY_MAGNETOMETER_16 0.00058 50 | 51 | LSM9DS1::LSM9DS1() 52 | { 53 | } 54 | 55 | void LSM9DS1::init() 56 | { 57 | settings.gyro.enabled = true; 58 | settings.gyro.enableX = true; 59 | settings.gyro.enableY = true; 60 | settings.gyro.enableZ = true; 61 | // gyro scale can be 245, 500, or 2000 62 | settings.gyro.scale = 245; 63 | // gyro sample rate: value between 1-6 64 | // 1 = 14.9 4 = 238 65 | // 2 = 59.5 5 = 476 66 | // 3 = 119 6 = 952 67 | settings.gyro.sampleRate = 6; 68 | // gyro cutoff frequency: value between 0-3 69 | // Actual value of cutoff frequency depends 70 | // on sample rate. 71 | settings.gyro.bandwidth = 0; 72 | settings.gyro.lowPowerEnable = false; 73 | settings.gyro.HPFEnable = false; 74 | // Gyro HPF cutoff frequency: value between 0-9 75 | // Actual value depends on sample rate. Only applies 76 | // if gyroHPFEnable is true. 77 | settings.gyro.HPFCutoff = 0; 78 | settings.gyro.flipX = false; 79 | settings.gyro.flipY = false; 80 | settings.gyro.flipZ = false; 81 | settings.gyro.orientation = 0; 82 | settings.gyro.latchInterrupt = true; 83 | 84 | settings.accel.enabled = true; 85 | settings.accel.enableX = true; 86 | settings.accel.enableY = true; 87 | settings.accel.enableZ = true; 88 | // accel scale can be 2, 4, 8, or 16 89 | settings.accel.scale = 2; 90 | // accel sample rate can be 1-6 91 | // 1 = 10 Hz 4 = 238 Hz 92 | // 2 = 50 Hz 5 = 476 Hz 93 | // 3 = 119 Hz 6 = 952 Hz 94 | settings.accel.sampleRate = 6; 95 | // Accel cutoff freqeuncy can be any value between -1 - 3. 96 | // -1 = bandwidth determined by sample rate 97 | // 0 = 408 Hz 2 = 105 Hz 98 | // 1 = 211 Hz 3 = 50 Hz 99 | settings.accel.bandwidth = -1; 100 | settings.accel.highResEnable = false; 101 | // accelHighResBandwidth can be any value between 0-3 102 | // LP cutoff is set to a factor of sample rate 103 | // 0 = ODR/50 2 = ODR/9 104 | // 1 = ODR/100 3 = ODR/400 105 | settings.accel.highResBandwidth = 0; 106 | 107 | settings.mag.enabled = true; 108 | // mag scale can be 4, 8, 12, or 16 109 | settings.mag.scale = 4; 110 | // mag data rate can be 0-7 111 | // 0 = 0.625 Hz 4 = 10 Hz 112 | // 1 = 1.25 Hz 5 = 20 Hz 113 | // 2 = 2.5 Hz 6 = 40 Hz 114 | // 3 = 5 Hz 7 = 80 Hz 115 | settings.mag.sampleRate = 7; 116 | settings.mag.tempCompensationEnable = false; 117 | // magPerformance can be any value between 0-3 118 | // 0 = Low power mode 2 = high performance 119 | // 1 = medium performance 3 = ultra-high performance 120 | settings.mag.XYPerformance = 3; 121 | settings.mag.ZPerformance = 3; 122 | settings.mag.lowPowerEnable = false; 123 | // magOperatingMode can be 0-2 124 | // 0 = continuous conversion 125 | // 1 = single-conversion 126 | // 2 = power down 127 | settings.mag.operatingMode = 0; 128 | 129 | settings.temp.enabled = true; 130 | for (int i=0; i<3; i++) 131 | { 132 | gBias[i] = 0; 133 | aBias[i] = 0; 134 | mBias[i] = 0; 135 | gBiasRaw[i] = 0; 136 | aBiasRaw[i] = 0; 137 | mBiasRaw[i] = 0; 138 | } 139 | _autoCalc = false; 140 | } 141 | 142 | 143 | uint16_t LSM9DS1::begin(uint8_t agAddress, uint8_t mAddress, TwoWire &wirePort) 144 | { 145 | // Set device settings, they are used in many other places 146 | settings.device.commInterface = IMU_MODE_I2C; 147 | settings.device.agAddress = agAddress; 148 | settings.device.mAddress = mAddress; 149 | settings.device.i2c = &wirePort; 150 | 151 | //! Todo: don't use _xgAddress or _mAddress, duplicating memory 152 | _xgAddress = settings.device.agAddress; 153 | _mAddress = settings.device.mAddress; 154 | 155 | init(); 156 | 157 | constrainScales(); 158 | // Once we have the scale values, we can calculate the resolution 159 | // of each sensor. That's what these functions are for. One for each sensor 160 | calcgRes(); // Calculate DPS / ADC tick, stored in gRes variable 161 | calcmRes(); // Calculate Gs / ADC tick, stored in mRes variable 162 | calcaRes(); // Calculate g / ADC tick, stored in aRes variable 163 | 164 | // We expect caller to begin their I2C port, with the speed of their choice external to the library 165 | // But if they forget, we could start the hardware here. 166 | // settings.device.i2c->begin(); // Initialize I2C library 167 | 168 | // To verify communication, we can read from the WHO_AM_I register of 169 | // each device. Store those in a variable so we can return them. 170 | uint8_t mTest = mReadByte(WHO_AM_I_M); // Read the gyro WHO_AM_I 171 | uint8_t xgTest = xgReadByte(WHO_AM_I_XG); // Read the accel/mag WHO_AM_I 172 | uint16_t whoAmICombined = (xgTest << 8) | mTest; 173 | 174 | if (whoAmICombined != ((WHO_AM_I_AG_RSP << 8) | WHO_AM_I_M_RSP)) 175 | return 0; 176 | 177 | // Gyro initialization stuff: 178 | initGyro(); // This will "turn on" the gyro. Setting up interrupts, etc. 179 | 180 | // Accelerometer initialization stuff: 181 | initAccel(); // "Turn on" all axes of the accel. Set up interrupts, etc. 182 | 183 | // Magnetometer initialization stuff: 184 | initMag(); // "Turn on" all axes of the mag. Set up interrupts, etc. 185 | 186 | // Once everything is initialized, return the WHO_AM_I registers we read: 187 | return whoAmICombined; 188 | } 189 | 190 | uint16_t LSM9DS1::beginSPI(uint8_t ag_CS_pin, uint8_t m_CS_pin) 191 | { 192 | // Set device settings, they are used in many other places 193 | settings.device.commInterface = IMU_MODE_SPI; 194 | settings.device.agAddress = ag_CS_pin; 195 | settings.device.mAddress = m_CS_pin; 196 | 197 | //! Todo: don't use _xgAddress or _mAddress, duplicating memory 198 | _xgAddress = settings.device.agAddress; 199 | _mAddress = settings.device.mAddress; 200 | 201 | init(); 202 | 203 | constrainScales(); 204 | // Once we have the scale values, we can calculate the resolution 205 | // of each sensor. That's what these functions are for. One for each sensor 206 | calcgRes(); // Calculate DPS / ADC tick, stored in gRes variable 207 | calcmRes(); // Calculate Gs / ADC tick, stored in mRes variable 208 | calcaRes(); // Calculate g / ADC tick, stored in aRes variable 209 | 210 | // Now, initialize our hardware interface. 211 | initSPI(); // Initialize SPI 212 | 213 | // To verify communication, we can read from the WHO_AM_I register of 214 | // each device. Store those in a variable so we can return them. 215 | uint8_t mTest = mReadByte(WHO_AM_I_M); // Read the gyro WHO_AM_I 216 | uint8_t xgTest = xgReadByte(WHO_AM_I_XG); // Read the accel/mag WHO_AM_I 217 | uint16_t whoAmICombined = (xgTest << 8) | mTest; 218 | 219 | if (whoAmICombined != ((WHO_AM_I_AG_RSP << 8) | WHO_AM_I_M_RSP)) 220 | return 0; 221 | 222 | // Gyro initialization stuff: 223 | initGyro(); // This will "turn on" the gyro. Setting up interrupts, etc. 224 | 225 | // Accelerometer initialization stuff: 226 | initAccel(); // "Turn on" all axes of the accel. Set up interrupts, etc. 227 | 228 | // Magnetometer initialization stuff: 229 | initMag(); // "Turn on" all axes of the mag. Set up interrupts, etc. 230 | 231 | // Once everything is initialized, return the WHO_AM_I registers we read: 232 | return whoAmICombined; 233 | } 234 | 235 | void LSM9DS1::initGyro() 236 | { 237 | uint8_t tempRegValue = 0; 238 | 239 | // CTRL_REG1_G (Default value: 0x00) 240 | // [ODR_G2][ODR_G1][ODR_G0][FS_G1][FS_G0][0][BW_G1][BW_G0] 241 | // ODR_G[2:0] - Output data rate selection 242 | // FS_G[1:0] - Gyroscope full-scale selection 243 | // BW_G[1:0] - Gyroscope bandwidth selection 244 | 245 | // To disable gyro, set sample rate bits to 0. We'll only set sample 246 | // rate if the gyro is enabled. 247 | if (settings.gyro.enabled) 248 | { 249 | tempRegValue = (settings.gyro.sampleRate & 0x07) << 5; 250 | } 251 | switch (settings.gyro.scale) 252 | { 253 | case 500: 254 | tempRegValue |= (0x1 << 3); 255 | break; 256 | case 2000: 257 | tempRegValue |= (0x3 << 3); 258 | break; 259 | // Otherwise we'll set it to 245 dps (0x0 << 4) 260 | } 261 | tempRegValue |= (settings.gyro.bandwidth & 0x3); 262 | xgWriteByte(CTRL_REG1_G, tempRegValue); 263 | 264 | // CTRL_REG2_G (Default value: 0x00) 265 | // [0][0][0][0][INT_SEL1][INT_SEL0][OUT_SEL1][OUT_SEL0] 266 | // INT_SEL[1:0] - INT selection configuration 267 | // OUT_SEL[1:0] - Out selection configuration 268 | xgWriteByte(CTRL_REG2_G, 0x00); 269 | 270 | // CTRL_REG3_G (Default value: 0x00) 271 | // [LP_mode][HP_EN][0][0][HPCF3_G][HPCF2_G][HPCF1_G][HPCF0_G] 272 | // LP_mode - Low-power mode enable (0: disabled, 1: enabled) 273 | // HP_EN - HPF enable (0:disabled, 1: enabled) 274 | // HPCF_G[3:0] - HPF cutoff frequency 275 | tempRegValue = settings.gyro.lowPowerEnable ? (1<<7) : 0; 276 | if (settings.gyro.HPFEnable) 277 | { 278 | tempRegValue |= (1<<6) | (settings.gyro.HPFCutoff & 0x0F); 279 | } 280 | xgWriteByte(CTRL_REG3_G, tempRegValue); 281 | 282 | // CTRL_REG4 (Default value: 0x38) 283 | // [0][0][Zen_G][Yen_G][Xen_G][0][LIR_XL1][4D_XL1] 284 | // Zen_G - Z-axis output enable (0:disable, 1:enable) 285 | // Yen_G - Y-axis output enable (0:disable, 1:enable) 286 | // Xen_G - X-axis output enable (0:disable, 1:enable) 287 | // LIR_XL1 - Latched interrupt (0:not latched, 1:latched) 288 | // 4D_XL1 - 4D option on interrupt (0:6D used, 1:4D used) 289 | tempRegValue = 0; 290 | if (settings.gyro.enableZ) tempRegValue |= (1<<5); 291 | if (settings.gyro.enableY) tempRegValue |= (1<<4); 292 | if (settings.gyro.enableX) tempRegValue |= (1<<3); 293 | if (settings.gyro.latchInterrupt) tempRegValue |= (1<<1); 294 | xgWriteByte(CTRL_REG4, tempRegValue); 295 | 296 | // ORIENT_CFG_G (Default value: 0x00) 297 | // [0][0][SignX_G][SignY_G][SignZ_G][Orient_2][Orient_1][Orient_0] 298 | // SignX_G - Pitch axis (X) angular rate sign (0: positive, 1: negative) 299 | // Orient [2:0] - Directional user orientation selection 300 | tempRegValue = 0; 301 | if (settings.gyro.flipX) tempRegValue |= (1<<5); 302 | if (settings.gyro.flipY) tempRegValue |= (1<<4); 303 | if (settings.gyro.flipZ) tempRegValue |= (1<<3); 304 | xgWriteByte(ORIENT_CFG_G, tempRegValue); 305 | } 306 | 307 | void LSM9DS1::initAccel() 308 | { 309 | uint8_t tempRegValue = 0; 310 | 311 | // CTRL_REG5_XL (0x1F) (Default value: 0x38) 312 | // [DEC_1][DEC_0][Zen_XL][Yen_XL][Zen_XL][0][0][0] 313 | // DEC[0:1] - Decimation of accel data on OUT REG and FIFO. 314 | // 00: None, 01: 2 samples, 10: 4 samples 11: 8 samples 315 | // Zen_XL - Z-axis output enabled 316 | // Yen_XL - Y-axis output enabled 317 | // Xen_XL - X-axis output enabled 318 | if (settings.accel.enableZ) tempRegValue |= (1<<5); 319 | if (settings.accel.enableY) tempRegValue |= (1<<4); 320 | if (settings.accel.enableX) tempRegValue |= (1<<3); 321 | 322 | xgWriteByte(CTRL_REG5_XL, tempRegValue); 323 | 324 | // CTRL_REG6_XL (0x20) (Default value: 0x00) 325 | // [ODR_XL2][ODR_XL1][ODR_XL0][FS1_XL][FS0_XL][BW_SCAL_ODR][BW_XL1][BW_XL0] 326 | // ODR_XL[2:0] - Output data rate & power mode selection 327 | // FS_XL[1:0] - Full-scale selection 328 | // BW_SCAL_ODR - Bandwidth selection 329 | // BW_XL[1:0] - Anti-aliasing filter bandwidth selection 330 | tempRegValue = 0; 331 | // To disable the accel, set the sampleRate bits to 0. 332 | if (settings.accel.enabled) 333 | { 334 | tempRegValue |= (settings.accel.sampleRate & 0x07) << 5; 335 | } 336 | switch (settings.accel.scale) 337 | { 338 | case 4: 339 | tempRegValue |= (0x2 << 3); 340 | break; 341 | case 8: 342 | tempRegValue |= (0x3 << 3); 343 | break; 344 | case 16: 345 | tempRegValue |= (0x1 << 3); 346 | break; 347 | // Otherwise it'll be set to 2g (0x0 << 3) 348 | } 349 | if (settings.accel.bandwidth >= 0) 350 | { 351 | tempRegValue |= (1<<2); // Set BW_SCAL_ODR 352 | tempRegValue |= (settings.accel.bandwidth & 0x03); 353 | } 354 | xgWriteByte(CTRL_REG6_XL, tempRegValue); 355 | 356 | // CTRL_REG7_XL (0x21) (Default value: 0x00) 357 | // [HR][DCF1][DCF0][0][0][FDS][0][HPIS1] 358 | // HR - High resolution mode (0: disable, 1: enable) 359 | // DCF[1:0] - Digital filter cutoff frequency 360 | // FDS - Filtered data selection 361 | // HPIS1 - HPF enabled for interrupt function 362 | tempRegValue = 0; 363 | if (settings.accel.highResEnable) 364 | { 365 | tempRegValue |= (1<<7); // Set HR bit 366 | tempRegValue |= (settings.accel.highResBandwidth & 0x3) << 5; 367 | } 368 | xgWriteByte(CTRL_REG7_XL, tempRegValue); 369 | } 370 | 371 | // This is a function that uses the FIFO to accumulate sample of accelerometer and gyro data, average 372 | // them, scales them to gs and deg/s, respectively, and then passes the biases to the main sketch 373 | // for subtraction from all subsequent data. There are no gyro and accelerometer bias registers to store 374 | // the data as there are in the ADXL345, a precursor to the LSM9DS0, or the MPU-9150, so we have to 375 | // subtract the biases ourselves. This results in a more accurate measurement in general and can 376 | // remove errors due to imprecise or varying initial placement. Calibration of sensor data in this manner 377 | // is good practice. 378 | void LSM9DS1::calibrate(bool autoCalc) 379 | { 380 | uint8_t samples = 0; 381 | int ii; 382 | int32_t aBiasRawTemp[3] = {0, 0, 0}; 383 | int32_t gBiasRawTemp[3] = {0, 0, 0}; 384 | 385 | // Turn on FIFO and set threshold to 32 samples 386 | enableFIFO(true); 387 | setFIFO(FIFO_THS, 0x1F); 388 | while (samples < 0x1F) 389 | { 390 | samples = (xgReadByte(FIFO_SRC) & 0x3F); // Read number of stored samples 391 | } 392 | for(ii = 0; ii < samples ; ii++) 393 | { // Read the gyro data stored in the FIFO 394 | readGyro(); 395 | gBiasRawTemp[0] += gx; 396 | gBiasRawTemp[1] += gy; 397 | gBiasRawTemp[2] += gz; 398 | readAccel(); 399 | aBiasRawTemp[0] += ax; 400 | aBiasRawTemp[1] += ay; 401 | aBiasRawTemp[2] += az - (int16_t)(1./aRes); // Assumes sensor facing up! 402 | } 403 | for (ii = 0; ii < 3; ii++) 404 | { 405 | gBiasRaw[ii] = gBiasRawTemp[ii] / samples; 406 | gBias[ii] = calcGyro(gBiasRaw[ii]); 407 | aBiasRaw[ii] = aBiasRawTemp[ii] / samples; 408 | aBias[ii] = calcAccel(aBiasRaw[ii]); 409 | } 410 | 411 | enableFIFO(false); 412 | setFIFO(FIFO_OFF, 0x00); 413 | 414 | if (autoCalc) _autoCalc = true; 415 | } 416 | 417 | void LSM9DS1::calibrateMag(bool loadIn) 418 | { 419 | int i, j; 420 | int16_t magMin[3] = {0, 0, 0}; 421 | int16_t magMax[3] = {0, 0, 0}; // The road warrior 422 | 423 | for (i=0; i<128; i++) 424 | { 425 | while (!magAvailable()) 426 | ; 427 | readMag(); 428 | int16_t magTemp[3] = {0, 0, 0}; 429 | magTemp[0] = mx; 430 | magTemp[1] = my; 431 | magTemp[2] = mz; 432 | for (j = 0; j < 3; j++) 433 | { 434 | if (magTemp[j] > magMax[j]) magMax[j] = magTemp[j]; 435 | if (magTemp[j] < magMin[j]) magMin[j] = magTemp[j]; 436 | } 437 | } 438 | for (j = 0; j < 3; j++) 439 | { 440 | mBiasRaw[j] = (magMax[j] + magMin[j]) / 2; 441 | mBias[j] = calcMag(mBiasRaw[j]); 442 | if (loadIn) 443 | magOffset(j, mBiasRaw[j]); 444 | } 445 | 446 | } 447 | void LSM9DS1::magOffset(uint8_t axis, int16_t offset) 448 | { 449 | if (axis > 2) 450 | return; 451 | uint8_t msb, lsb; 452 | msb = (offset & 0xFF00) >> 8; 453 | lsb = offset & 0x00FF; 454 | mWriteByte(OFFSET_X_REG_L_M + (2 * axis), lsb); 455 | mWriteByte(OFFSET_X_REG_H_M + (2 * axis), msb); 456 | } 457 | 458 | void LSM9DS1::initMag() 459 | { 460 | uint8_t tempRegValue = 0; 461 | 462 | // CTRL_REG1_M (Default value: 0x10) 463 | // [TEMP_COMP][OM1][OM0][DO2][DO1][DO0][0][ST] 464 | // TEMP_COMP - Temperature compensation 465 | // OM[1:0] - X & Y axes op mode selection 466 | // 00:low-power, 01:medium performance 467 | // 10: high performance, 11:ultra-high performance 468 | // DO[2:0] - Output data rate selection 469 | // ST - Self-test enable 470 | if (settings.mag.tempCompensationEnable) tempRegValue |= (1<<7); 471 | tempRegValue |= (settings.mag.XYPerformance & 0x3) << 5; 472 | tempRegValue |= (settings.mag.sampleRate & 0x7) << 2; 473 | mWriteByte(CTRL_REG1_M, tempRegValue); 474 | 475 | // CTRL_REG2_M (Default value 0x00) 476 | // [0][FS1][FS0][0][REBOOT][SOFT_RST][0][0] 477 | // FS[1:0] - Full-scale configuration 478 | // REBOOT - Reboot memory content (0:normal, 1:reboot) 479 | // SOFT_RST - Reset config and user registers (0:default, 1:reset) 480 | tempRegValue = 0; 481 | switch (settings.mag.scale) 482 | { 483 | case 8: 484 | tempRegValue |= (0x1 << 5); 485 | break; 486 | case 12: 487 | tempRegValue |= (0x2 << 5); 488 | break; 489 | case 16: 490 | tempRegValue |= (0x3 << 5); 491 | break; 492 | // Otherwise we'll default to 4 gauss (00) 493 | } 494 | mWriteByte(CTRL_REG2_M, tempRegValue); // +/-4Gauss 495 | 496 | // CTRL_REG3_M (Default value: 0x03) 497 | // [I2C_DISABLE][0][LP][0][0][SIM][MD1][MD0] 498 | // I2C_DISABLE - Disable I2C interace (0:enable, 1:disable) 499 | // LP - Low-power mode cofiguration (1:enable) 500 | // SIM - SPI mode selection (0:write-only, 1:read/write enable) 501 | // MD[1:0] - Operating mode 502 | // 00:continuous conversion, 01:single-conversion, 503 | // 10,11: Power-down 504 | tempRegValue = 0; 505 | if (settings.mag.lowPowerEnable) tempRegValue |= (1<<5); 506 | tempRegValue |= (settings.mag.operatingMode & 0x3); 507 | mWriteByte(CTRL_REG3_M, tempRegValue); // Continuous conversion mode 508 | 509 | // CTRL_REG4_M (Default value: 0x00) 510 | // [0][0][0][0][OMZ1][OMZ0][BLE][0] 511 | // OMZ[1:0] - Z-axis operative mode selection 512 | // 00:low-power mode, 01:medium performance 513 | // 10:high performance, 10:ultra-high performance 514 | // BLE - Big/little endian data 515 | tempRegValue = 0; 516 | tempRegValue = (settings.mag.ZPerformance & 0x3) << 2; 517 | mWriteByte(CTRL_REG4_M, tempRegValue); 518 | 519 | // CTRL_REG5_M (Default value: 0x00) 520 | // [0][BDU][0][0][0][0][0][0] 521 | // BDU - Block data update for magnetic data 522 | // 0:continuous, 1:not updated until MSB/LSB are read 523 | tempRegValue = 0; 524 | mWriteByte(CTRL_REG5_M, tempRegValue); 525 | } 526 | 527 | uint8_t LSM9DS1::accelAvailable() 528 | { 529 | uint8_t status = xgReadByte(STATUS_REG_1); 530 | 531 | return (status & (1<<0)); 532 | } 533 | 534 | uint8_t LSM9DS1::gyroAvailable() 535 | { 536 | uint8_t status = xgReadByte(STATUS_REG_1); 537 | 538 | return ((status & (1<<1)) >> 1); 539 | } 540 | 541 | uint8_t LSM9DS1::tempAvailable() 542 | { 543 | uint8_t status = xgReadByte(STATUS_REG_1); 544 | 545 | return ((status & (1<<2)) >> 2); 546 | } 547 | 548 | uint8_t LSM9DS1::magAvailable(lsm9ds1_axis axis) 549 | { 550 | uint8_t status; 551 | status = mReadByte(STATUS_REG_M); 552 | 553 | return ((status & (1<> axis); 554 | } 555 | 556 | void LSM9DS1::readAccel() 557 | { 558 | uint8_t temp[6]; // We'll read six bytes from the accelerometer into temp 559 | if ( xgReadBytes(OUT_X_L_XL, temp, 6) == 6 ) // Read 6 bytes, beginning at OUT_X_L_XL 560 | { 561 | ax = (temp[1] << 8) | temp[0]; // Store x-axis values into ax 562 | ay = (temp[3] << 8) | temp[2]; // Store y-axis values into ay 563 | az = (temp[5] << 8) | temp[4]; // Store z-axis values into az 564 | if (_autoCalc) 565 | { 566 | ax -= aBiasRaw[X_AXIS]; 567 | ay -= aBiasRaw[Y_AXIS]; 568 | az -= aBiasRaw[Z_AXIS]; 569 | } 570 | } 571 | } 572 | 573 | int16_t LSM9DS1::readAccel(lsm9ds1_axis axis) 574 | { 575 | uint8_t temp[2]; 576 | int16_t value; 577 | if ( xgReadBytes(OUT_X_L_XL + (2 * axis), temp, 2) == 2) 578 | { 579 | value = (temp[1] << 8) | temp[0]; 580 | 581 | if (_autoCalc) 582 | value -= aBiasRaw[axis]; 583 | 584 | return value; 585 | } 586 | return 0; 587 | } 588 | 589 | void LSM9DS1::readMag() 590 | { 591 | uint8_t temp[6]; // We'll read six bytes from the mag into temp 592 | if ( mReadBytes(OUT_X_L_M, temp, 6) == 6) // Read 6 bytes, beginning at OUT_X_L_M 593 | { 594 | mx = (temp[1] << 8) | temp[0]; // Store x-axis values into mx 595 | my = (temp[3] << 8) | temp[2]; // Store y-axis values into my 596 | mz = (temp[5] << 8) | temp[4]; // Store z-axis values into mz 597 | } 598 | } 599 | 600 | int16_t LSM9DS1::readMag(lsm9ds1_axis axis) 601 | { 602 | uint8_t temp[2]; 603 | if ( mReadBytes(OUT_X_L_M + (2 * axis), temp, 2) == 2) 604 | { 605 | return (temp[1] << 8) | temp[0]; 606 | } 607 | return 0; 608 | } 609 | 610 | void LSM9DS1::readTemp() 611 | { 612 | uint8_t temp[2]; // We'll read two bytes from the temperature sensor into temp 613 | if ( xgReadBytes(OUT_TEMP_L, temp, 2) == 2 ) // Read 2 bytes, beginning at OUT_TEMP_L 614 | { 615 | int16_t offset = 25; // Per datasheet sensor outputs 0 typically @ 25 degrees centigrade 616 | temperature = offset + ((((int16_t)temp[1] << 8) | temp[0]) >> 8) ; 617 | } 618 | } 619 | 620 | void LSM9DS1::readGyro() 621 | { 622 | uint8_t temp[6]; // We'll read six bytes from the gyro into temp 623 | if ( xgReadBytes(OUT_X_L_G, temp, 6) == 6) // Read 6 bytes, beginning at OUT_X_L_G 624 | { 625 | gx = (temp[1] << 8) | temp[0]; // Store x-axis values into gx 626 | gy = (temp[3] << 8) | temp[2]; // Store y-axis values into gy 627 | gz = (temp[5] << 8) | temp[4]; // Store z-axis values into gz 628 | if (_autoCalc) 629 | { 630 | gx -= gBiasRaw[X_AXIS]; 631 | gy -= gBiasRaw[Y_AXIS]; 632 | gz -= gBiasRaw[Z_AXIS]; 633 | } 634 | } 635 | } 636 | 637 | int16_t LSM9DS1::readGyro(lsm9ds1_axis axis) 638 | { 639 | uint8_t temp[2]; 640 | int16_t value; 641 | 642 | if ( xgReadBytes(OUT_X_L_G + (2 * axis), temp, 2) == 2) 643 | { 644 | value = (temp[1] << 8) | temp[0]; 645 | 646 | if (_autoCalc) 647 | value -= gBiasRaw[axis]; 648 | 649 | return value; 650 | } 651 | return 0; 652 | } 653 | 654 | float LSM9DS1::calcGyro(int16_t gyro) 655 | { 656 | // Return the gyro raw reading times our pre-calculated DPS / (ADC tick): 657 | return gRes * gyro; 658 | } 659 | 660 | float LSM9DS1::calcAccel(int16_t accel) 661 | { 662 | // Return the accel raw reading times our pre-calculated g's / (ADC tick): 663 | return aRes * accel; 664 | } 665 | 666 | float LSM9DS1::calcMag(int16_t mag) 667 | { 668 | // Return the mag raw reading times our pre-calculated Gs / (ADC tick): 669 | return mRes * mag; 670 | } 671 | 672 | void LSM9DS1::setGyroScale(uint16_t gScl) 673 | { 674 | // Read current value of CTRL_REG1_G: 675 | uint8_t ctrl1RegValue = xgReadByte(CTRL_REG1_G); 676 | // Mask out scale bits (3 & 4): 677 | ctrl1RegValue &= 0xE7; 678 | switch (gScl) 679 | { 680 | case 500: 681 | ctrl1RegValue |= (0x1 << 3); 682 | settings.gyro.scale = 500; 683 | break; 684 | case 2000: 685 | ctrl1RegValue |= (0x3 << 3); 686 | settings.gyro.scale = 2000; 687 | break; 688 | default: // Otherwise we'll set it to 245 dps (0x0 << 4) 689 | settings.gyro.scale = 245; 690 | break; 691 | } 692 | xgWriteByte(CTRL_REG1_G, ctrl1RegValue); 693 | 694 | calcgRes(); 695 | } 696 | 697 | void LSM9DS1::setAccelScale(uint8_t aScl) 698 | { 699 | // We need to preserve the other bytes in CTRL_REG6_XL. So, first read it: 700 | uint8_t tempRegValue = xgReadByte(CTRL_REG6_XL); 701 | // Mask out accel scale bits: 702 | tempRegValue &= 0xE7; 703 | 704 | switch (aScl) 705 | { 706 | case 4: 707 | tempRegValue |= (0x2 << 3); 708 | settings.accel.scale = 4; 709 | break; 710 | case 8: 711 | tempRegValue |= (0x3 << 3); 712 | settings.accel.scale = 8; 713 | break; 714 | case 16: 715 | tempRegValue |= (0x1 << 3); 716 | settings.accel.scale = 16; 717 | break; 718 | default: // Otherwise it'll be set to 2g (0x0 << 3) 719 | settings.accel.scale = 2; 720 | break; 721 | } 722 | xgWriteByte(CTRL_REG6_XL, tempRegValue); 723 | 724 | // Then calculate a new aRes, which relies on aScale being set correctly: 725 | calcaRes(); 726 | } 727 | 728 | void LSM9DS1::setMagScale(uint8_t mScl) 729 | { 730 | // We need to preserve the other bytes in CTRL_REG6_XM. So, first read it: 731 | uint8_t temp = mReadByte(CTRL_REG2_M); 732 | // Then mask out the mag scale bits: 733 | temp &= 0xFF^(0x3 << 5); 734 | 735 | switch (mScl) 736 | { 737 | case 8: 738 | temp |= (0x1 << 5); 739 | settings.mag.scale = 8; 740 | break; 741 | case 12: 742 | temp |= (0x2 << 5); 743 | settings.mag.scale = 12; 744 | break; 745 | case 16: 746 | temp |= (0x3 << 5); 747 | settings.mag.scale = 16; 748 | break; 749 | default: // Otherwise we'll default to 4 gauss (00) 750 | settings.mag.scale = 4; 751 | break; 752 | } 753 | 754 | // And write the new register value back into CTRL_REG6_XM: 755 | mWriteByte(CTRL_REG2_M, temp); 756 | 757 | // We've updated the sensor, but we also need to update our class variables 758 | // First update mScale: 759 | //mScale = mScl; 760 | // Then calculate a new mRes, which relies on mScale being set correctly: 761 | calcmRes(); 762 | } 763 | 764 | void LSM9DS1::setGyroODR(uint8_t gRate) 765 | { 766 | // Only do this if gRate is not 0 (which would disable the gyro) 767 | if ((gRate & 0x07) != 0) 768 | { 769 | // We need to preserve the other bytes in CTRL_REG1_G. So, first read it: 770 | uint8_t temp = xgReadByte(CTRL_REG1_G); 771 | // Then mask out the gyro ODR bits: 772 | temp &= 0xFF^(0x7 << 5); 773 | temp |= (gRate & 0x07) << 5; 774 | // Update our settings struct 775 | settings.gyro.sampleRate = gRate & 0x07; 776 | // And write the new register value back into CTRL_REG1_G: 777 | xgWriteByte(CTRL_REG1_G, temp); 778 | } 779 | } 780 | 781 | void LSM9DS1::setAccelODR(uint8_t aRate) 782 | { 783 | // Only do this if aRate is not 0 (which would disable the accel) 784 | if ((aRate & 0x07) != 0) 785 | { 786 | // We need to preserve the other bytes in CTRL_REG1_XM. So, first read it: 787 | uint8_t temp = xgReadByte(CTRL_REG6_XL); 788 | // Then mask out the accel ODR bits: 789 | temp &= 0x1F; 790 | // Then shift in our new ODR bits: 791 | temp |= ((aRate & 0x07) << 5); 792 | settings.accel.sampleRate = aRate & 0x07; 793 | // And write the new register value back into CTRL_REG1_XM: 794 | xgWriteByte(CTRL_REG6_XL, temp); 795 | } 796 | } 797 | 798 | void LSM9DS1::setMagODR(uint8_t mRate) 799 | { 800 | // We need to preserve the other bytes in CTRL_REG5_XM. So, first read it: 801 | uint8_t temp = mReadByte(CTRL_REG1_M); 802 | // Then mask out the mag ODR bits: 803 | temp &= 0xFF^(0x7 << 2); 804 | // Then shift in our new ODR bits: 805 | temp |= ((mRate & 0x07) << 2); 806 | settings.mag.sampleRate = mRate & 0x07; 807 | // And write the new register value back into CTRL_REG5_XM: 808 | mWriteByte(CTRL_REG1_M, temp); 809 | } 810 | 811 | void LSM9DS1::calcgRes() 812 | { 813 | switch (settings.gyro.scale) 814 | { 815 | case 245: 816 | gRes = SENSITIVITY_GYROSCOPE_245; 817 | break; 818 | case 500: 819 | gRes = SENSITIVITY_GYROSCOPE_500; 820 | break; 821 | case 2000: 822 | gRes = SENSITIVITY_GYROSCOPE_2000; 823 | break; 824 | default: 825 | break; 826 | } 827 | } 828 | 829 | void LSM9DS1::calcaRes() 830 | { 831 | switch (settings.accel.scale) 832 | { 833 | case 2: 834 | aRes = SENSITIVITY_ACCELEROMETER_2; 835 | break; 836 | case 4: 837 | aRes = SENSITIVITY_ACCELEROMETER_4; 838 | break; 839 | case 8: 840 | aRes = SENSITIVITY_ACCELEROMETER_8; 841 | break; 842 | case 16: 843 | aRes = SENSITIVITY_ACCELEROMETER_16; 844 | break; 845 | default: 846 | break; 847 | } 848 | } 849 | 850 | void LSM9DS1::calcmRes() 851 | { 852 | switch (settings.mag.scale) 853 | { 854 | case 4: 855 | mRes = SENSITIVITY_MAGNETOMETER_4; 856 | break; 857 | case 8: 858 | mRes = SENSITIVITY_MAGNETOMETER_8; 859 | break; 860 | case 12: 861 | mRes = SENSITIVITY_MAGNETOMETER_12; 862 | break; 863 | case 16: 864 | mRes = SENSITIVITY_MAGNETOMETER_16; 865 | break; 866 | } 867 | } 868 | 869 | void LSM9DS1::configInt(interrupt_select interrupt, uint8_t generator, 870 | h_lactive activeLow, pp_od pushPull) 871 | { 872 | // Write to INT1_CTRL or INT2_CTRL. [interupt] should already be one of 873 | // those two values. 874 | // [generator] should be an OR'd list of values from the interrupt_generators enum 875 | xgWriteByte(interrupt, generator); 876 | 877 | // Configure CTRL_REG8 878 | uint8_t temp; 879 | temp = xgReadByte(CTRL_REG8); 880 | 881 | if (activeLow) temp |= (1<<5); 882 | else temp &= ~(1<<5); 883 | 884 | if (pushPull) temp &= ~(1<<4); 885 | else temp |= (1<<4); 886 | 887 | xgWriteByte(CTRL_REG8, temp); 888 | } 889 | 890 | void LSM9DS1::configInactivity(uint8_t duration, uint8_t threshold, bool sleepOn) 891 | { 892 | uint8_t temp = 0; 893 | 894 | temp = threshold & 0x7F; 895 | if (sleepOn) temp |= (1<<7); 896 | xgWriteByte(ACT_THS, temp); 897 | 898 | xgWriteByte(ACT_DUR, duration); 899 | } 900 | 901 | uint8_t LSM9DS1::getInactivity() 902 | { 903 | uint8_t temp = xgReadByte(STATUS_REG_0); 904 | temp &= (0x10); 905 | return temp; 906 | } 907 | 908 | void LSM9DS1::configAccelInt(uint8_t generator, bool andInterrupts) 909 | { 910 | // Use variables from accel_interrupt_generator, OR'd together to create 911 | // the [generator]value. 912 | uint8_t temp = generator; 913 | if (andInterrupts) temp |= 0x80; 914 | xgWriteByte(INT_GEN_CFG_XL, temp); 915 | } 916 | 917 | void LSM9DS1::configAccelThs(uint8_t threshold, lsm9ds1_axis axis, uint8_t duration, bool wait) 918 | { 919 | // Write threshold value to INT_GEN_THS_?_XL. 920 | // axis will be 0, 1, or 2 (x, y, z respectively) 921 | xgWriteByte(INT_GEN_THS_X_XL + axis, threshold); 922 | 923 | // Write duration and wait to INT_GEN_DUR_XL 924 | uint8_t temp; 925 | temp = (duration & 0x7F); 926 | if (wait) temp |= 0x80; 927 | xgWriteByte(INT_GEN_DUR_XL, temp); 928 | } 929 | 930 | uint8_t LSM9DS1::getAccelIntSrc() 931 | { 932 | uint8_t intSrc = xgReadByte(INT_GEN_SRC_XL); 933 | 934 | // Check if the IA_XL (interrupt active) bit is set 935 | if (intSrc & (1<<6)) 936 | { 937 | return (intSrc & 0x3F); 938 | } 939 | 940 | return 0; 941 | } 942 | 943 | void LSM9DS1::configGyroInt(uint8_t generator, bool aoi, bool latch) 944 | { 945 | // Use variables from accel_interrupt_generator, OR'd together to create 946 | // the [generator]value. 947 | uint8_t temp = generator; 948 | if (aoi) temp |= 0x80; 949 | if (latch) temp |= 0x40; 950 | xgWriteByte(INT_GEN_CFG_G, temp); 951 | } 952 | 953 | void LSM9DS1::configGyroThs(int16_t threshold, lsm9ds1_axis axis, uint8_t duration, bool wait) 954 | { 955 | uint8_t buffer[2]; 956 | buffer[0] = (threshold & 0x7F00) >> 8; 957 | buffer[1] = (threshold & 0x00FF); 958 | // Write threshold value to INT_GEN_THS_?H_G and INT_GEN_THS_?L_G. 959 | // axis will be 0, 1, or 2 (x, y, z respectively) 960 | xgWriteByte(INT_GEN_THS_XH_G + (axis * 2), buffer[0]); 961 | xgWriteByte(INT_GEN_THS_XH_G + 1 + (axis * 2), buffer[1]); 962 | 963 | // Write duration and wait to INT_GEN_DUR_XL 964 | uint8_t temp; 965 | temp = (duration & 0x7F); 966 | if (wait) temp |= 0x80; 967 | xgWriteByte(INT_GEN_DUR_G, temp); 968 | } 969 | 970 | uint8_t LSM9DS1::getGyroIntSrc() 971 | { 972 | uint8_t intSrc = xgReadByte(INT_GEN_SRC_G); 973 | 974 | // Check if the IA_G (interrupt active) bit is set 975 | if (intSrc & (1<<6)) 976 | { 977 | return (intSrc & 0x3F); 978 | } 979 | 980 | return 0; 981 | } 982 | 983 | void LSM9DS1::configMagInt(uint8_t generator, h_lactive activeLow, bool latch) 984 | { 985 | // Mask out non-generator bits (0-4) 986 | uint8_t config = (generator & 0xE0); 987 | // IEA bit is 0 for active-low, 1 for active-high. 988 | if (activeLow == INT_ACTIVE_HIGH) config |= (1<<2); 989 | // IEL bit is 0 for latched, 1 for not-latched 990 | if (!latch) config |= (1<<1); 991 | // As long as we have at least 1 generator, enable the interrupt 992 | if (generator != 0) config |= (1<<0); 993 | 994 | mWriteByte(INT_CFG_M, config); 995 | } 996 | 997 | void LSM9DS1::configMagThs(uint16_t threshold) 998 | { 999 | // Write high eight bits of [threshold] to INT_THS_H_M 1000 | mWriteByte(INT_THS_H_M, uint8_t((threshold & 0x7F00) >> 8)); 1001 | // Write low eight bits of [threshold] to INT_THS_L_M 1002 | mWriteByte(INT_THS_L_M, uint8_t(threshold & 0x00FF)); 1003 | } 1004 | 1005 | uint8_t LSM9DS1::getMagIntSrc() 1006 | { 1007 | uint8_t intSrc = mReadByte(INT_SRC_M); 1008 | 1009 | // Check if the INT (interrupt active) bit is set 1010 | if (intSrc & (1<<0)) 1011 | { 1012 | return (intSrc & 0xFE); 1013 | } 1014 | 1015 | return 0; 1016 | } 1017 | 1018 | void LSM9DS1::sleepGyro(bool enable) 1019 | { 1020 | uint8_t temp = xgReadByte(CTRL_REG9); 1021 | if (enable) temp |= (1<<6); 1022 | else temp &= ~(1<<6); 1023 | xgWriteByte(CTRL_REG9, temp); 1024 | } 1025 | 1026 | void LSM9DS1::enableFIFO(bool enable) 1027 | { 1028 | uint8_t temp = xgReadByte(CTRL_REG9); 1029 | if (enable) temp |= (1<<1); 1030 | else temp &= ~(1<<1); 1031 | xgWriteByte(CTRL_REG9, temp); 1032 | } 1033 | 1034 | void LSM9DS1::setFIFO(fifoMode_type fifoMode, uint8_t fifoThs) 1035 | { 1036 | // Limit threshold - 0x1F (31) is the maximum. If more than that was asked 1037 | // limit it to the maximum. 1038 | uint8_t threshold = fifoThs <= 0x1F ? fifoThs : 0x1F; 1039 | xgWriteByte(FIFO_CTRL, ((fifoMode & 0x7) << 5) | (threshold & 0x1F)); 1040 | } 1041 | 1042 | uint8_t LSM9DS1::getFIFOSamples() 1043 | { 1044 | return (xgReadByte(FIFO_SRC) & 0x3F); 1045 | } 1046 | 1047 | void LSM9DS1::constrainScales() 1048 | { 1049 | if ((settings.gyro.scale != 245) && (settings.gyro.scale != 500) && 1050 | (settings.gyro.scale != 2000)) 1051 | { 1052 | settings.gyro.scale = 245; 1053 | } 1054 | 1055 | if ((settings.accel.scale != 2) && (settings.accel.scale != 4) && 1056 | (settings.accel.scale != 8) && (settings.accel.scale != 16)) 1057 | { 1058 | settings.accel.scale = 2; 1059 | } 1060 | 1061 | if ((settings.mag.scale != 4) && (settings.mag.scale != 8) && 1062 | (settings.mag.scale != 12) && (settings.mag.scale != 16)) 1063 | { 1064 | settings.mag.scale = 4; 1065 | } 1066 | } 1067 | 1068 | void LSM9DS1::xgWriteByte(uint8_t subAddress, uint8_t data) 1069 | { 1070 | // Whether we're using I2C or SPI, write a byte using the 1071 | // gyro-specific I2C address or SPI CS pin. 1072 | if (settings.device.commInterface == IMU_MODE_I2C) 1073 | I2CwriteByte(_xgAddress, subAddress, data); 1074 | else if (settings.device.commInterface == IMU_MODE_SPI) 1075 | SPIwriteByte(_xgAddress, subAddress, data); 1076 | } 1077 | 1078 | void LSM9DS1::mWriteByte(uint8_t subAddress, uint8_t data) 1079 | { 1080 | // Whether we're using I2C or SPI, write a byte using the 1081 | // accelerometer-specific I2C address or SPI CS pin. 1082 | if (settings.device.commInterface == IMU_MODE_I2C) 1083 | return I2CwriteByte(_mAddress, subAddress, data); 1084 | else if (settings.device.commInterface == IMU_MODE_SPI) 1085 | return SPIwriteByte(_mAddress, subAddress, data); 1086 | } 1087 | 1088 | uint8_t LSM9DS1::xgReadByte(uint8_t subAddress) 1089 | { 1090 | // Whether we're using I2C or SPI, read a byte using the 1091 | // gyro-specific I2C address or SPI CS pin. 1092 | if (settings.device.commInterface == IMU_MODE_I2C) 1093 | return I2CreadByte(_xgAddress, subAddress); 1094 | else if (settings.device.commInterface == IMU_MODE_SPI) 1095 | return SPIreadByte(_xgAddress, subAddress); 1096 | return -1; 1097 | } 1098 | 1099 | uint8_t LSM9DS1::xgReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count) 1100 | { 1101 | // Whether we're using I2C or SPI, read multiple bytes using the 1102 | // gyro-specific I2C address or SPI CS pin. 1103 | if (settings.device.commInterface == IMU_MODE_I2C) 1104 | return I2CreadBytes(_xgAddress, subAddress, dest, count); 1105 | else if (settings.device.commInterface == IMU_MODE_SPI) 1106 | return SPIreadBytes(_xgAddress, subAddress, dest, count); 1107 | return -1; 1108 | } 1109 | 1110 | uint8_t LSM9DS1::mReadByte(uint8_t subAddress) 1111 | { 1112 | // Whether we're using I2C or SPI, read a byte using the 1113 | // accelerometer-specific I2C address or SPI CS pin. 1114 | if (settings.device.commInterface == IMU_MODE_I2C) 1115 | return I2CreadByte(_mAddress, subAddress); 1116 | else if (settings.device.commInterface == IMU_MODE_SPI) 1117 | return SPIreadByte(_mAddress, subAddress); 1118 | return -1; 1119 | } 1120 | 1121 | uint8_t LSM9DS1::mReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count) 1122 | { 1123 | // Whether we're using I2C or SPI, read multiple bytes using the 1124 | // accelerometer-specific I2C address or SPI CS pin. 1125 | if (settings.device.commInterface == IMU_MODE_I2C) 1126 | return I2CreadBytes(_mAddress, subAddress, dest, count); 1127 | else if (settings.device.commInterface == IMU_MODE_SPI) 1128 | return SPIreadBytes(_mAddress, subAddress, dest, count); 1129 | return -1; 1130 | } 1131 | 1132 | void LSM9DS1::initSPI() 1133 | { 1134 | pinMode(_xgAddress, OUTPUT); 1135 | digitalWrite(_xgAddress, HIGH); 1136 | pinMode(_mAddress, OUTPUT); 1137 | digitalWrite(_mAddress, HIGH); 1138 | 1139 | SPI.begin(); 1140 | // Maximum SPI frequency is 10MHz 1141 | // Data is read and written MSb first. 1142 | // Data is read and written MSb first. 1143 | // Data is captured on rising edge of clock (CPHA = 0) 1144 | // Base value of the clock is HIGH (CPOL = 1) 1145 | SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 1146 | } 1147 | 1148 | void LSM9DS1::SPIwriteByte(uint8_t csPin, uint8_t subAddress, uint8_t data) 1149 | { 1150 | digitalWrite(csPin, LOW); // Initiate communication 1151 | 1152 | // If write, bit 0 (MSB) should be 0 1153 | // If single write, bit 1 should be 0 1154 | SPI.transfer(subAddress & 0x3F); // Send Address 1155 | SPI.transfer(data); // Send data 1156 | 1157 | digitalWrite(csPin, HIGH); // Close communication 1158 | } 1159 | 1160 | uint8_t LSM9DS1::SPIreadByte(uint8_t csPin, uint8_t subAddress) 1161 | { 1162 | uint8_t temp; 1163 | // Use the multiple read function to read 1 byte. 1164 | // Value is returned to `temp`. 1165 | SPIreadBytes(csPin, subAddress, &temp, 1); 1166 | return temp; 1167 | } 1168 | 1169 | uint8_t LSM9DS1::SPIreadBytes(uint8_t csPin, uint8_t subAddress, 1170 | uint8_t * dest, uint8_t count) 1171 | { 1172 | // To indicate a read, set bit 0 (msb) of first byte to 1 1173 | uint8_t rAddress = 0x80 | (subAddress & 0x3F); 1174 | // Mag SPI port is different. If we're reading multiple bytes, 1175 | // set bit 1 to 1. The remaining six bytes are the address to be read 1176 | if ((csPin == _mAddress) && count > 1) 1177 | rAddress |= 0x40; 1178 | 1179 | digitalWrite(csPin, LOW); // Initiate communication 1180 | SPI.transfer(rAddress); 1181 | for (int i=0; ibeginTransmission(address); // Initialize the Tx buffer 1194 | settings.device.i2c->write(subAddress); // Put slave register address in Tx buffer 1195 | settings.device.i2c->write(data); // Put data in Tx buffer 1196 | settings.device.i2c->endTransmission(); // Send the Tx buffer 1197 | } 1198 | 1199 | uint8_t LSM9DS1::I2CreadByte(uint8_t address, uint8_t subAddress) 1200 | { 1201 | uint8_t data; // `data` will store the register data 1202 | 1203 | settings.device.i2c->beginTransmission(address); // Initialize the Tx buffer 1204 | settings.device.i2c->write(subAddress); // Put slave register address in Tx buffer 1205 | settings.device.i2c->endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 1206 | settings.device.i2c->requestFrom(address, (uint8_t) 1); // Read one byte from slave register address 1207 | 1208 | data = settings.device.i2c->read(); // Fill Rx buffer with result 1209 | return data; // Return data read from slave register 1210 | } 1211 | 1212 | uint8_t LSM9DS1::I2CreadBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t count) 1213 | { 1214 | byte retVal; 1215 | settings.device.i2c->beginTransmission(address); // Initialize the Tx buffer 1216 | // Next send the register to be read. OR with 0x80 to indicate multi-read. 1217 | settings.device.i2c->write(subAddress | 0x80); // Put slave register address in Tx buffer 1218 | retVal = settings.device.i2c->endTransmission(false); // Send Tx buffer, send a restart to keep connection alive 1219 | if (retVal != 0) // endTransmission should return 0 on success 1220 | return 0; 1221 | 1222 | retVal = settings.device.i2c->requestFrom(address, count); // Read bytes from slave register address 1223 | if (retVal != count) 1224 | return 0; 1225 | 1226 | for (int i=0; iread(); 1228 | 1229 | return count; 1230 | } 1231 | -------------------------------------------------------------------------------- /src/SparkFunLSM9DS1.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SFE_LSM9DS1.h 3 | SFE_LSM9DS1 Library Header File 4 | Jim Lindblom @ SparkFun Electronics 5 | Original Creation Date: February 27, 2015 6 | https://github.com/sparkfun/LSM9DS1_Breakout 7 | 8 | This file prototypes the LSM9DS1 class, implemented in SFE_LSM9DS1.cpp. In 9 | addition, it defines every register in the LSM9DS1 (both the Gyro and Accel/ 10 | Magnetometer registers). 11 | 12 | Development environment specifics: 13 | IDE: Arduino 1.6.0 14 | Hardware Platform: Arduino Uno 15 | LSM9DS1 Breakout Version: 1.0 16 | 17 | This code is beerware; if you see me (or any other SparkFun employee) at the 18 | local, and you've found our code helpful, please buy us a round! 19 | 20 | Distributed as-is; no warranty is given. 21 | ******************************************************************************/ 22 | #ifndef __SparkFunLSM9DS1_H__ 23 | #define __SparkFunLSM9DS1_H__ 24 | 25 | #if defined(ARDUINO) && ARDUINO >= 100 26 | #include "Arduino.h" 27 | #else 28 | #include "WProgram.h" 29 | #include "pins_arduino.h" 30 | #endif 31 | 32 | #include "LSM9DS1_Registers.h" 33 | #include "LSM9DS1_Types.h" 34 | 35 | #define LSM9DS1_AG_ADDR(sa0) ((sa0) == 0 ? 0x6A : 0x6B) 36 | #define LSM9DS1_M_ADDR(sa1) ((sa1) == 0 ? 0x1C : 0x1E) 37 | 38 | enum lsm9ds1_axis { 39 | X_AXIS, 40 | Y_AXIS, 41 | Z_AXIS, 42 | ALL_AXIS 43 | }; 44 | 45 | class LSM9DS1 46 | { 47 | public: 48 | IMUSettings settings; 49 | 50 | // We'll store the gyro, accel, and magnetometer readings in a series of 51 | // public class variables. Each sensor gets three variables -- one for each 52 | // axis. Call readGyro(), readAccel(), and readMag() first, before using 53 | // these variables! 54 | // These values are the RAW signed 16-bit readings from the sensors. 55 | int16_t gx, gy, gz; // x, y, and z axis readings of the gyroscope 56 | int16_t ax, ay, az; // x, y, and z axis readings of the accelerometer 57 | int16_t mx, my, mz; // x, y, and z axis readings of the magnetometer 58 | int16_t temperature; // Chip temperature 59 | float gBias[3], aBias[3], mBias[3]; 60 | int16_t gBiasRaw[3], aBiasRaw[3], mBiasRaw[3]; 61 | 62 | // LSM9DS1 -- LSM9DS1 class constructor 63 | // The constructor will set up a handful of private variables, and set the 64 | // communication mode as well. 65 | // Input: 66 | // - interface = Either IMU_MODE_SPI or IMU_MODE_I2C, whichever you're using 67 | // to talk to the IC. 68 | // - xgAddr = If IMU_MODE_I2C, this is the I2C address of the accel/gyroscope. 69 | // If IMU_MODE_SPI, this is the chip select pin of the gyro (CS_AG) 70 | // - mAddr = If IMU_MODE_I2C, this is the I2C address of the magnetometer. 71 | // If IMU_MODE_SPI, this is the cs pin of the magnetometer (CS_M) 72 | LSM9DS1(); 73 | 74 | // begin() and beginSPI() -- Initialize the gyro, accelerometer, and magnetometer. 75 | // This will set up the scale and output rate of each sensor. The values set 76 | // in the IMUSettings struct will take effect after calling this function. 77 | // INPUTS: 78 | // - agAddress - Sets either the I2C address of the accel/gyro or SPI chip 79 | // select pin connected to the CS_XG pin. 80 | // - mAddress - Sets either the I2C address of the magnetometer or SPI chip 81 | // select pin connected to the CS_M pin. 82 | // - i2C port (Note, only on "begin()" funtion, for use with I2C com interface) 83 | // defaults to Wire, but if hardware supports it, can use other TwoWire ports. 84 | // **For SPI use "beginSPI()", and only send first two address arguments. 85 | uint16_t begin(uint8_t agAddress = LSM9DS1_AG_ADDR(1), uint8_t mAddress = LSM9DS1_M_ADDR(1), TwoWire &wirePort = Wire); //By default use the default I2C addres, and use Wire port 86 | uint16_t beginSPI(uint8_t ag_CS_pin, uint8_t m_CS_pin); 87 | 88 | void calibrate(bool autoCalc = true); 89 | void calibrateMag(bool loadIn = true); 90 | void magOffset(uint8_t axis, int16_t offset); 91 | 92 | // accelAvailable() -- Polls the accelerometer status register to check 93 | // if new data is available. 94 | // Output: 1 - New data available 95 | // 0 - No new data available 96 | uint8_t accelAvailable(); 97 | 98 | // gyroAvailable() -- Polls the gyroscope status register to check 99 | // if new data is available. 100 | // Output: 1 - New data available 101 | // 0 - No new data available 102 | uint8_t gyroAvailable(); 103 | 104 | // tempAvailable() -- Polls the temperature status register to check 105 | // if new data is available. 106 | // Output: 1 - New data available 107 | // 0 - No new data available 108 | uint8_t tempAvailable(); 109 | 110 | // magAvailable() -- Polls the accelerometer status register to check 111 | // if new data is available. 112 | // Input: 113 | // - axis can be either X_AXIS, Y_AXIS, Z_AXIS, to check for new data 114 | // on one specific axis. Or ALL_AXIS (default) to check for new data 115 | // on all axes. 116 | // Output: 1 - New data available 117 | // 0 - No new data available 118 | uint8_t magAvailable(lsm9ds1_axis axis = ALL_AXIS); 119 | 120 | // readGyro() -- Read the gyroscope output registers. 121 | // This function will read all six gyroscope output registers. 122 | // The readings are stored in the class' gx, gy, and gz variables. Read 123 | // those _after_ calling readGyro(). 124 | void readGyro(); 125 | 126 | // int16_t readGyro(axis) -- Read a specific axis of the gyroscope. 127 | // [axis] can be any of X_AXIS, Y_AXIS, or Z_AXIS. 128 | // Input: 129 | // - axis: can be either X_AXIS, Y_AXIS, or Z_AXIS. 130 | // Output: 131 | // A 16-bit signed integer with sensor data on requested axis. 132 | int16_t readGyro(lsm9ds1_axis axis); 133 | 134 | // readAccel() -- Read the accelerometer output registers. 135 | // This function will read all six accelerometer output registers. 136 | // The readings are stored in the class' ax, ay, and az variables. Read 137 | // those _after_ calling readAccel(). 138 | void readAccel(); 139 | 140 | // int16_t readAccel(axis) -- Read a specific axis of the accelerometer. 141 | // [axis] can be any of X_AXIS, Y_AXIS, or Z_AXIS. 142 | // Input: 143 | // - axis: can be either X_AXIS, Y_AXIS, or Z_AXIS. 144 | // Output: 145 | // A 16-bit signed integer with sensor data on requested axis. 146 | int16_t readAccel(lsm9ds1_axis axis); 147 | 148 | // readMag() -- Read the magnetometer output registers. 149 | // This function will read all six magnetometer output registers. 150 | // The readings are stored in the class' mx, my, and mz variables. Read 151 | // those _after_ calling readMag(). 152 | void readMag(); 153 | 154 | // int16_t readMag(axis) -- Read a specific axis of the magnetometer. 155 | // [axis] can be any of X_AXIS, Y_AXIS, or Z_AXIS. 156 | // Input: 157 | // - axis: can be either X_AXIS, Y_AXIS, or Z_AXIS. 158 | // Output: 159 | // A 16-bit signed integer with sensor data on requested axis. 160 | int16_t readMag(lsm9ds1_axis axis); 161 | 162 | // readTemp() -- Read the temperature output register. 163 | // This function will read two temperature output registers. 164 | // The combined readings are stored in the class' temperature variables. Read 165 | // those _after_ calling readTemp(). 166 | void readTemp(); 167 | 168 | // calcGyro() -- Convert from RAW signed 16-bit value to degrees per second 169 | // This function reads in a signed 16-bit value and returns the scaled 170 | // DPS. This function relies on gScale and gRes being correct. 171 | // Input: 172 | // - gyro = A signed 16-bit raw reading from the gyroscope. 173 | float calcGyro(int16_t gyro); 174 | 175 | // calcAccel() -- Convert from RAW signed 16-bit value to gravity (g's). 176 | // This function reads in a signed 16-bit value and returns the scaled 177 | // g's. This function relies on aScale and aRes being correct. 178 | // Input: 179 | // - accel = A signed 16-bit raw reading from the accelerometer. 180 | float calcAccel(int16_t accel); 181 | 182 | // calcMag() -- Convert from RAW signed 16-bit value to Gauss (Gs) 183 | // This function reads in a signed 16-bit value and returns the scaled 184 | // Gs. This function relies on mScale and mRes being correct. 185 | // Input: 186 | // - mag = A signed 16-bit raw reading from the magnetometer. 187 | float calcMag(int16_t mag); 188 | 189 | // setGyroScale() -- Set the full-scale range of the gyroscope. 190 | // This function can be called to set the scale of the gyroscope to 191 | // 245, 500, or 200 degrees per second. 192 | // Input: 193 | // - gScl = The desired gyroscope scale. Must be one of three possible 194 | // values from the gyro_scale. 195 | void setGyroScale(uint16_t gScl); 196 | 197 | // setAccelScale() -- Set the full-scale range of the accelerometer. 198 | // This function can be called to set the scale of the accelerometer to 199 | // 2, 4, 6, 8, or 16 g's. 200 | // Input: 201 | // - aScl = The desired accelerometer scale. Must be one of five possible 202 | // values from the accel_scale. 203 | void setAccelScale(uint8_t aScl); 204 | 205 | // setMagScale() -- Set the full-scale range of the magnetometer. 206 | // This function can be called to set the scale of the magnetometer to 207 | // 2, 4, 8, or 12 Gs. 208 | // Input: 209 | // - mScl = The desired magnetometer scale. Must be one of four possible 210 | // values from the mag_scale. 211 | void setMagScale(uint8_t mScl); 212 | 213 | // setGyroODR() -- Set the output data rate and bandwidth of the gyroscope 214 | // Input: 215 | // - gRate = The desired output rate and cutoff frequency of the gyro. 216 | void setGyroODR(uint8_t gRate); 217 | 218 | // setAccelODR() -- Set the output data rate of the accelerometer 219 | // Input: 220 | // - aRate = The desired output rate of the accel. 221 | void setAccelODR(uint8_t aRate); 222 | 223 | // setMagODR() -- Set the output data rate of the magnetometer 224 | // Input: 225 | // - mRate = The desired output rate of the mag. 226 | void setMagODR(uint8_t mRate); 227 | 228 | // configInactivity() -- Configure inactivity interrupt parameters 229 | // Input: 230 | // - duration = Inactivity duration - actual value depends on gyro ODR 231 | // - threshold = Activity Threshold 232 | // - sleepOn = Gyroscope operating mode during inactivity. 233 | // true: gyroscope in sleep mode 234 | // false: gyroscope in power-down 235 | void configInactivity(uint8_t duration, uint8_t threshold, bool sleepOn); 236 | 237 | // configAccelInt() -- Configure Accelerometer Interrupt Generator 238 | // Input: 239 | // - generator = Interrupt axis/high-low events 240 | // Any OR'd combination of ZHIE_XL, ZLIE_XL, YHIE_XL, YLIE_XL, XHIE_XL, XLIE_XL 241 | // - andInterrupts = AND/OR combination of interrupt events 242 | // true: AND combination 243 | // false: OR combination 244 | void configAccelInt(uint8_t generator, bool andInterrupts = false); 245 | 246 | // configAccelThs() -- Configure the threshold of an accelereomter axis 247 | // Input: 248 | // - threshold = Interrupt threshold. Possible values: 0-255. 249 | // Multiply by 128 to get the actual raw accel value. 250 | // - axis = Axis to be configured. Either X_AXIS, Y_AXIS, or Z_AXIS 251 | // - duration = Duration value must be above or below threshold to trigger interrupt 252 | // - wait = Wait function on duration counter 253 | // true: Wait for duration samples before exiting interrupt 254 | // false: Wait function off 255 | void configAccelThs(uint8_t threshold, lsm9ds1_axis axis, uint8_t duration = 0, bool wait = 0); 256 | 257 | // configGyroInt() -- Configure Gyroscope Interrupt Generator 258 | // Input: 259 | // - generator = Interrupt axis/high-low events 260 | // Any OR'd combination of ZHIE_G, ZLIE_G, YHIE_G, YLIE_G, XHIE_G, XLIE_G 261 | // - aoi = AND/OR combination of interrupt events 262 | // true: AND combination 263 | // false: OR combination 264 | // - latch: latch gyroscope interrupt request. 265 | void configGyroInt(uint8_t generator, bool aoi, bool latch); 266 | 267 | // configGyroThs() -- Configure the threshold of a gyroscope axis 268 | // Input: 269 | // - threshold = Interrupt threshold. Possible values: 0-0x7FF. 270 | // Value is equivalent to raw gyroscope value. 271 | // - axis = Axis to be configured. Either X_AXIS, Y_AXIS, or Z_AXIS 272 | // - duration = Duration value must be above or below threshold to trigger interrupt 273 | // - wait = Wait function on duration counter 274 | // true: Wait for duration samples before exiting interrupt 275 | // false: Wait function off 276 | void configGyroThs(int16_t threshold, lsm9ds1_axis axis, uint8_t duration, bool wait); 277 | 278 | // configInt() -- Configure INT1 or INT2 (Gyro and Accel Interrupts only) 279 | // Input: 280 | // - interrupt = Select INT1 or INT2 281 | // Possible values: XG_INT1 or XG_INT2 282 | // - generator = Or'd combination of interrupt generators. 283 | // Possible values: INT_DRDY_XL, INT_DRDY_G, INT1_BOOT (INT1 only), INT2_DRDY_TEMP (INT2 only) 284 | // INT_FTH, INT_OVR, INT_FSS5, INT_IG_XL (INT1 only), INT1_IG_G (INT1 only), INT2_INACT (INT2 only) 285 | // - activeLow = Interrupt active configuration 286 | // Can be either INT_ACTIVE_HIGH or INT_ACTIVE_LOW 287 | // - pushPull = Push-pull or open drain interrupt configuration 288 | // Can be either INT_PUSH_PULL or INT_OPEN_DRAIN 289 | void configInt(interrupt_select interupt, uint8_t generator, 290 | h_lactive activeLow = INT_ACTIVE_LOW, pp_od pushPull = INT_PUSH_PULL); 291 | 292 | // configMagInt() -- Configure Magnetometer Interrupt Generator 293 | // Input: 294 | // - generator = Interrupt axis/high-low events 295 | // Any OR'd combination of ZIEN, YIEN, XIEN 296 | // - activeLow = Interrupt active configuration 297 | // Can be either INT_ACTIVE_HIGH or INT_ACTIVE_LOW 298 | // - latch: latch gyroscope interrupt request. 299 | void configMagInt(uint8_t generator, h_lactive activeLow, bool latch = true); 300 | 301 | // configMagThs() -- Configure the threshold of a gyroscope axis 302 | // Input: 303 | // - threshold = Interrupt threshold. Possible values: 0-0x7FF. 304 | // Value is equivalent to raw magnetometer value. 305 | void configMagThs(uint16_t threshold); 306 | 307 | // getGyroIntSrc() -- Get contents of Gyroscope interrupt source register 308 | uint8_t getGyroIntSrc(); 309 | 310 | // getGyroIntSrc() -- Get contents of accelerometer interrupt source register 311 | uint8_t getAccelIntSrc(); 312 | 313 | // getGyroIntSrc() -- Get contents of magnetometer interrupt source register 314 | uint8_t getMagIntSrc(); 315 | 316 | // getGyroIntSrc() -- Get status of inactivity interrupt 317 | uint8_t getInactivity(); 318 | 319 | // sleepGyro() -- Sleep or wake the gyroscope 320 | // Input: 321 | // - enable: True = sleep gyro. False = wake gyro. 322 | void sleepGyro(bool enable = true); 323 | 324 | // enableFIFO() - Enable or disable the FIFO 325 | // Input: 326 | // - enable: true = enable, false = disable. 327 | void enableFIFO(bool enable = true); 328 | 329 | // setFIFO() - Configure FIFO mode and Threshold 330 | // Input: 331 | // - fifoMode: Set FIFO mode to off, FIFO (stop when full), continuous, bypass 332 | // Possible inputs: FIFO_OFF, FIFO_THS, FIFO_CONT_TRIGGER, FIFO_OFF_TRIGGER, FIFO_CONT 333 | // - fifoThs: FIFO threshold level setting 334 | // Any value from 0-0x1F is acceptable. 335 | void setFIFO(fifoMode_type fifoMode, uint8_t fifoThs); 336 | 337 | // getFIFOSamples() - Get number of FIFO samples 338 | uint8_t getFIFOSamples(); 339 | 340 | 341 | protected: 342 | // x_mAddress and gAddress store the I2C address or SPI chip select pin 343 | // for each sensor. 344 | uint8_t _mAddress, _xgAddress; 345 | 346 | // gRes, aRes, and mRes store the current resolution for each sensor. 347 | // Units of these values would be DPS (or g's or Gs's) per ADC tick. 348 | // This value is calculated as (sensor scale) / (2^15). 349 | float gRes, aRes, mRes; 350 | 351 | // _autoCalc keeps track of whether we're automatically subtracting off 352 | // accelerometer and gyroscope bias calculated in calibrate(). 353 | bool _autoCalc; 354 | 355 | // init() -- Sets up gyro, accel, and mag settings to default. 356 | // to set com interface and/or addresses see begin() and beginSPI(). 357 | void init(); 358 | 359 | // initGyro() -- Sets up the gyroscope to begin reading. 360 | // This function steps through all five gyroscope control registers. 361 | // Upon exit, the following parameters will be set: 362 | // - CTRL_REG1_G = 0x0F: Normal operation mode, all axes enabled. 363 | // 95 Hz ODR, 12.5 Hz cutoff frequency. 364 | // - CTRL_REG2_G = 0x00: HPF set to normal mode, cutoff frequency 365 | // set to 7.2 Hz (depends on ODR). 366 | // - CTRL_REG3_G = 0x88: Interrupt enabled on INT_G (set to push-pull and 367 | // active high). Data-ready output enabled on DRDY_G. 368 | // - CTRL_REG4_G = 0x00: Continuous update mode. Data LSB stored in lower 369 | // address. Scale set to 245 DPS. SPI mode set to 4-wire. 370 | // - CTRL_REG5_G = 0x00: FIFO disabled. HPF disabled. 371 | void initGyro(); 372 | 373 | // initAccel() -- Sets up the accelerometer to begin reading. 374 | // This function steps through all accelerometer related control registers. 375 | // Upon exit these registers will be set as: 376 | // - CTRL_REG0_XM = 0x00: FIFO disabled. HPF bypassed. Normal mode. 377 | // - CTRL_REG1_XM = 0x57: 100 Hz data rate. Continuous update. 378 | // all axes enabled. 379 | // - CTRL_REG2_XM = 0x00: 2g scale. 773 Hz anti-alias filter BW. 380 | // - CTRL_REG3_XM = 0x04: Accel data ready signal on INT1_XM pin. 381 | void initAccel(); 382 | 383 | // initMag() -- Sets up the magnetometer to begin reading. 384 | // This function steps through all magnetometer-related control registers. 385 | // Upon exit these registers will be set as: 386 | // - CTRL_REG4_XM = 0x04: Mag data ready signal on INT2_XM pin. 387 | // - CTRL_REG5_XM = 0x14: 100 Hz update rate. Low resolution. Interrupt 388 | // requests don't latch. Temperature sensor disabled. 389 | // - CTRL_REG6_XM = 0x00: 2 Gs scale. 390 | // - CTRL_REG7_XM = 0x00: Continuous conversion mode. Normal HPF mode. 391 | // - INT_CTRL_REG_M = 0x09: Interrupt active-high. Enable interrupts. 392 | void initMag(); 393 | 394 | // gReadByte() -- Reads a byte from a specified gyroscope register. 395 | // Input: 396 | // - subAddress = Register to be read from. 397 | // Output: 398 | // - An 8-bit value read from the requested address. 399 | uint8_t mReadByte(uint8_t subAddress); 400 | 401 | // gReadBytes() -- Reads a number of bytes -- beginning at an address 402 | // and incrementing from there -- from the gyroscope. 403 | // Input: 404 | // - subAddress = Register to be read from. 405 | // - * dest = A pointer to an array of uint8_t's. Values read will be 406 | // stored in here on return. 407 | // - count = The number of bytes to be read. 408 | // Output: No value is returned, but the `dest` array will store 409 | // the data read upon exit. 410 | uint8_t mReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count); 411 | 412 | // gWriteByte() -- Write a byte to a register in the gyroscope. 413 | // Input: 414 | // - subAddress = Register to be written to. 415 | // - data = data to be written to the register. 416 | void mWriteByte(uint8_t subAddress, uint8_t data); 417 | 418 | // xmReadByte() -- Read a byte from a register in the accel/mag sensor 419 | // Input: 420 | // - subAddress = Register to be read from. 421 | // Output: 422 | // - An 8-bit value read from the requested register. 423 | uint8_t xgReadByte(uint8_t subAddress); 424 | 425 | // xmReadBytes() -- Reads a number of bytes -- beginning at an address 426 | // and incrementing from there -- from the accelerometer/magnetometer. 427 | // Input: 428 | // - subAddress = Register to be read from. 429 | // - * dest = A pointer to an array of uint8_t's. Values read will be 430 | // stored in here on return. 431 | // - count = The number of bytes to be read. 432 | // Output: No value is returned, but the `dest` array will store 433 | // the data read upon exit. 434 | uint8_t xgReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count); 435 | 436 | // xmWriteByte() -- Write a byte to a register in the accel/mag sensor. 437 | // Input: 438 | // - subAddress = Register to be written to. 439 | // - data = data to be written to the register. 440 | void xgWriteByte(uint8_t subAddress, uint8_t data); 441 | 442 | // calcgRes() -- Calculate the resolution of the gyroscope. 443 | // This function will set the value of the gRes variable. gScale must 444 | // be set prior to calling this function. 445 | void calcgRes(); 446 | 447 | // calcmRes() -- Calculate the resolution of the magnetometer. 448 | // This function will set the value of the mRes variable. mScale must 449 | // be set prior to calling this function. 450 | void calcmRes(); 451 | 452 | // calcaRes() -- Calculate the resolution of the accelerometer. 453 | // This function will set the value of the aRes variable. aScale must 454 | // be set prior to calling this function. 455 | void calcaRes(); 456 | 457 | ////////////////////// 458 | // Helper Functions // 459 | ////////////////////// 460 | void constrainScales(); 461 | 462 | /////////////////// 463 | // SPI Functions // 464 | /////////////////// 465 | // initSPI() -- Initialize the SPI hardware. 466 | // This function will setup all SPI pins and related hardware. 467 | void initSPI(); 468 | 469 | // SPIwriteByte() -- Write a byte out of SPI to a register in the device 470 | // Input: 471 | // - csPin = The chip select pin of the slave device. 472 | // - subAddress = The register to be written to. 473 | // - data = Byte to be written to the register. 474 | void SPIwriteByte(uint8_t csPin, uint8_t subAddress, uint8_t data); 475 | 476 | // SPIreadByte() -- Read a single byte from a register over SPI. 477 | // Input: 478 | // - csPin = The chip select pin of the slave device. 479 | // - subAddress = The register to be read from. 480 | // Output: 481 | // - The byte read from the requested address. 482 | uint8_t SPIreadByte(uint8_t csPin, uint8_t subAddress); 483 | 484 | // SPIreadBytes() -- Read a series of bytes, starting at a register via SPI 485 | // Input: 486 | // - csPin = The chip select pin of a slave device. 487 | // - subAddress = The register to begin reading. 488 | // - * dest = Pointer to an array where we'll store the readings. 489 | // - count = Number of registers to be read. 490 | // Output: No value is returned by the function, but the registers read are 491 | // all stored in the *dest array given. 492 | uint8_t SPIreadBytes(uint8_t csPin, uint8_t subAddress, 493 | uint8_t * dest, uint8_t count); 494 | 495 | /////////////////// 496 | // I2C Functions // 497 | /////////////////// 498 | 499 | // I2CwriteByte() -- Write a byte out of I2C to a register in the device 500 | // Input: 501 | // - address = The 7-bit I2C address of the slave device. 502 | // - subAddress = The register to be written to. 503 | // - data = Byte to be written to the register. 504 | void I2CwriteByte(uint8_t address, uint8_t subAddress, uint8_t data); 505 | 506 | // I2CreadByte() -- Read a single byte from a register over I2C. 507 | // Input: 508 | // - address = The 7-bit I2C address of the slave device. 509 | // - subAddress = The register to be read from. 510 | // Output: 511 | // - The byte read from the requested address. 512 | uint8_t I2CreadByte(uint8_t address, uint8_t subAddress); 513 | 514 | // I2CreadBytes() -- Read a series of bytes, starting at a register via SPI 515 | // Input: 516 | // - address = The 7-bit I2C address of the slave device. 517 | // - subAddress = The register to begin reading. 518 | // - * dest = Pointer to an array where we'll store the readings. 519 | // - count = Number of registers to be read. 520 | // Output: No value is returned by the function, but the registers read are 521 | // all stored in the *dest array given. 522 | uint8_t I2CreadBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t count); 523 | }; 524 | 525 | #endif // SFE_LSM9DS1_H // 526 | --------------------------------------------------------------------------------