SCL3300 sensor 3-axis inclinometer with angle output and digital SPI interface
SCL3300.cpp@1:52b1117c65ea, 2022-09-05 (annotated)
- Committer:
- metronix
- Date:
- Mon Sep 05 15:56:44 2022 +0000
- Revision:
- 1:52b1117c65ea
- Parent:
- 0:e8ba98a758d0
modified scl3300 Library test program
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
sameera0824 | 0:e8ba98a758d0 | 1 | /****************************************************************************** |
sameera0824 | 0:e8ba98a758d0 | 2 | SCL3300.cpp |
sameera0824 | 0:e8ba98a758d0 | 3 | David Armstrong |
sameera0824 | 0:e8ba98a758d0 | 4 | Version 3.3.0 - September 13, 2021 |
sameera0824 | 0:e8ba98a758d0 | 5 | https://github.com/DavidArmstrong/SCL3300 |
sameera0824 | 0:e8ba98a758d0 | 6 | |
metronix | 1:52b1117c65ea | 7 | MODIFIDER BY METRONICA (METRONIX) |
metronix | 1:52b1117c65ea | 8 | |
sameera0824 | 0:e8ba98a758d0 | 9 | Resources: |
sameera0824 | 0:e8ba98a758d0 | 10 | Uses SPI.h for SPI operation |
sameera0824 | 0:e8ba98a758d0 | 11 | |
sameera0824 | 0:e8ba98a758d0 | 12 | Development environment specifics: |
metronix | 1:52b1117c65ea | 13 | MBED OS |
sameera0824 | 0:e8ba98a758d0 | 14 | |
sameera0824 | 0:e8ba98a758d0 | 15 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). |
sameera0824 | 0:e8ba98a758d0 | 16 | Please review the LICENSE.md file included with this example. |
sameera0824 | 0:e8ba98a758d0 | 17 | Distributed as-is; no warranty is given. |
sameera0824 | 0:e8ba98a758d0 | 18 | |
metronix | 1:52b1117c65ea | 19 | |
sameera0824 | 0:e8ba98a758d0 | 20 | ******************************************************************************/ |
sameera0824 | 0:e8ba98a758d0 | 21 | |
sameera0824 | 0:e8ba98a758d0 | 22 | // include this library's description file |
sameera0824 | 0:e8ba98a758d0 | 23 | #include "SCL3300.h" |
sameera0824 | 0:e8ba98a758d0 | 24 | |
metronix | 1:52b1117c65ea | 25 | SCL3300::SCL3300(PinName mosi, PinName miso, PinName sclk, PinName scl3300_csPin) : _spi(mosi, miso, sclk), _scl3300_csPin(scl3300_csPin) { |
metronix | 1:52b1117c65ea | 26 | _scl3300_csPin = 1; |
metronix | 1:52b1117c65ea | 27 | |
metronix | 1:52b1117c65ea | 28 | // Set default to and 4MHz for data transfer |
metronix | 1:52b1117c65ea | 29 | _transfer_sck = 4000000; |
metronix | 1:52b1117c65ea | 30 | |
metronix | 1:52b1117c65ea | 31 | modeCMD[0] = 0; |
metronix | 1:52b1117c65ea | 32 | modeCMD[1] = ChgMode1; |
metronix | 1:52b1117c65ea | 33 | modeCMD[2] = ChgMode2; |
metronix | 1:52b1117c65ea | 34 | modeCMD[3] = ChgMode3; |
metronix | 1:52b1117c65ea | 35 | modeCMD[4] = ChgMode4; |
metronix | 1:52b1117c65ea | 36 | |
metronix | 1:52b1117c65ea | 37 | scl3300_mode=4; |
metronix | 1:52b1117c65ea | 38 | } |
metronix | 1:52b1117c65ea | 39 | |
metronix | 1:52b1117c65ea | 40 | |
sameera0824 | 0:e8ba98a758d0 | 41 | // Public Methods ////////////////////////////////////////////////////////// |
sameera0824 | 0:e8ba98a758d0 | 42 | // Set the sensor mode to the number provided as modeNum. |
metronix | 1:52b1117c65ea | 43 | bool SCL3300::setMode(int modeNum) { |
sameera0824 | 0:e8ba98a758d0 | 44 | // Set Sensor mode - If not called, the default is mode 4, as set in header file |
sameera0824 | 0:e8ba98a758d0 | 45 | // Only allowed values are: 1,2,3,4 |
sameera0824 | 0:e8ba98a758d0 | 46 | if (modeNum > 0 && modeNum < 5) { |
sameera0824 | 0:e8ba98a758d0 | 47 | scl3300_mode = modeNum; |
sameera0824 | 0:e8ba98a758d0 | 48 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 49 | transfer(modeCMD[scl3300_mode]); //Set mode on hardware |
sameera0824 | 0:e8ba98a758d0 | 50 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 51 | if (crcerr || statuserr) { |
sameera0824 | 0:e8ba98a758d0 | 52 | reset(); //Reset chip to fix the error state |
sameera0824 | 0:e8ba98a758d0 | 53 | return false; //Let the caller know something went wrong |
sameera0824 | 0:e8ba98a758d0 | 54 | } else return true; // Valid value, and chip was set to that mode |
sameera0824 | 0:e8ba98a758d0 | 55 | } else |
sameera0824 | 0:e8ba98a758d0 | 56 | return false; // Invalid value |
sameera0824 | 0:e8ba98a758d0 | 57 | } |
sameera0824 | 0:e8ba98a758d0 | 58 | |
sameera0824 | 0:e8ba98a758d0 | 59 | // Current Version of begin() to initialize the library and the SCL3300 |
metronix | 1:52b1117c65ea | 60 | bool SCL3300::begin(void) { |
sameera0824 | 0:e8ba98a758d0 | 61 | //This is the updated Version 3 begin function |
metronix | 1:52b1117c65ea | 62 | |
sameera0824 | 0:e8ba98a758d0 | 63 | //Wait the required 1 ms before initializing the SCL3300 inclinomenter |
metronix | 1:52b1117c65ea | 64 | timer2.start(); |
metronix | 1:52b1117c65ea | 65 | unsigned long startmillis = timer2.read_ms(); |
metronix | 1:52b1117c65ea | 66 | while (timer2.read_ms() - startmillis < 1) ; |
metronix | 1:52b1117c65ea | 67 | timer2.stop(); |
sameera0824 | 0:e8ba98a758d0 | 68 | |
sameera0824 | 0:e8ba98a758d0 | 69 | initSPI(); // Initialize SPI Library |
sameera0824 | 0:e8ba98a758d0 | 70 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 71 | //Write SW Reset command |
sameera0824 | 0:e8ba98a758d0 | 72 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 73 | transfer(SWreset); |
metronix | 1:52b1117c65ea | 74 | timer2.start(); |
metronix | 1:52b1117c65ea | 75 | startmillis = timer2.read_ms(); |
metronix | 1:52b1117c65ea | 76 | while (timer2.read_ms() - startmillis < 1) ; |
metronix | 1:52b1117c65ea | 77 | timer2.stop(); |
sameera0824 | 0:e8ba98a758d0 | 78 | //Set measurement mode |
sameera0824 | 0:e8ba98a758d0 | 79 | transfer(modeCMD[scl3300_mode]); //Set mode on hardware |
sameera0824 | 0:e8ba98a758d0 | 80 | //We're good, so Enable angle outputs |
sameera0824 | 0:e8ba98a758d0 | 81 | transfer(EnaAngOut); |
sameera0824 | 0:e8ba98a758d0 | 82 | //The first response after reset is undefined and shall be discarded |
sameera0824 | 0:e8ba98a758d0 | 83 | //wait 5 ms to stablize |
metronix | 1:52b1117c65ea | 84 | timer2.start(); |
metronix | 1:52b1117c65ea | 85 | startmillis = timer2.read_ms(); |
metronix | 1:52b1117c65ea | 86 | while (timer2.read_ms() - startmillis < 100) ; |
metronix | 1:52b1117c65ea | 87 | timer2.stop(); |
sameera0824 | 0:e8ba98a758d0 | 88 | |
sameera0824 | 0:e8ba98a758d0 | 89 | //Read Status to clear the status summary |
sameera0824 | 0:e8ba98a758d0 | 90 | transfer(RdStatSum); |
sameera0824 | 0:e8ba98a758d0 | 91 | transfer(RdStatSum); //Again, due to off-response protocol used |
sameera0824 | 0:e8ba98a758d0 | 92 | transfer(RdStatSum); //And now we can get the real status |
sameera0824 | 0:e8ba98a758d0 | 93 | |
sameera0824 | 0:e8ba98a758d0 | 94 | //Read the WHOAMI register |
sameera0824 | 0:e8ba98a758d0 | 95 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 96 | //And again |
sameera0824 | 0:e8ba98a758d0 | 97 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 98 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 99 | //We now wait until the end of begin() to report if an error occurred |
sameera0824 | 0:e8ba98a758d0 | 100 | if (crcerr || statuserr) return false; |
sameera0824 | 0:e8ba98a758d0 | 101 | // Once everything is initialized, return a known expected value |
sameera0824 | 0:e8ba98a758d0 | 102 | // The WHOAMI command should give an 8 bit value of 0xc1 |
sameera0824 | 0:e8ba98a758d0 | 103 | return (SCL3300_DATA == 0xc1); //Let the caller know if this worked |
sameera0824 | 0:e8ba98a758d0 | 104 | } |
sameera0824 | 0:e8ba98a758d0 | 105 | |
sameera0824 | 0:e8ba98a758d0 | 106 | |
sameera0824 | 0:e8ba98a758d0 | 107 | //Check to validate that the sensor is still reachable and ready to provide data |
metronix | 1:52b1117c65ea | 108 | bool SCL3300::isConnected() { |
sameera0824 | 0:e8ba98a758d0 | 109 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 110 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 111 | //Read the WHOAMI register |
sameera0824 | 0:e8ba98a758d0 | 112 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 113 | //And again |
sameera0824 | 0:e8ba98a758d0 | 114 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 115 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 116 | if (crcerr || statuserr) return false; |
sameera0824 | 0:e8ba98a758d0 | 117 | // Once everything is initialized, return a known expected value |
sameera0824 | 0:e8ba98a758d0 | 118 | // The WHOAMI command should give an 8 bit value of 0xc1 |
sameera0824 | 0:e8ba98a758d0 | 119 | return (SCL3300_DATA == 0xc1); //Let the caller know if this worked |
sameera0824 | 0:e8ba98a758d0 | 120 | } |
sameera0824 | 0:e8ba98a758d0 | 121 | |
sameera0824 | 0:e8ba98a758d0 | 122 | //Read all the sensor data together to keep it consistent |
sameera0824 | 0:e8ba98a758d0 | 123 | //This is required according to the datasheet |
metronix | 1:52b1117c65ea | 124 | bool SCL3300::available(void) { |
sameera0824 | 0:e8ba98a758d0 | 125 | //Version 3 of this function |
metronix | 1:52b1117c65ea | 126 | bool errorflag = false; |
sameera0824 | 0:e8ba98a758d0 | 127 | //Read all Sensor Data, as per Datasheet requirements |
sameera0824 | 0:e8ba98a758d0 | 128 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 129 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 130 | transfer(RdAccX); |
sameera0824 | 0:e8ba98a758d0 | 131 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 132 | transfer(RdAccY); |
sameera0824 | 0:e8ba98a758d0 | 133 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 134 | sclData.AccX = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 135 | transfer(RdAccZ); |
sameera0824 | 0:e8ba98a758d0 | 136 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 137 | sclData.AccY = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 138 | transfer(RdSTO); |
sameera0824 | 0:e8ba98a758d0 | 139 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 140 | sclData.AccZ = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 141 | transfer(RdTemp); |
sameera0824 | 0:e8ba98a758d0 | 142 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 143 | sclData.STO = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 144 | transfer(RdAngX); |
sameera0824 | 0:e8ba98a758d0 | 145 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 146 | sclData.TEMP = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 147 | transfer(RdAngY); |
sameera0824 | 0:e8ba98a758d0 | 148 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 149 | sclData.AngX = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 150 | transfer(RdAngZ); |
sameera0824 | 0:e8ba98a758d0 | 151 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 152 | sclData.AngY = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 153 | transfer(RdStatSum); |
sameera0824 | 0:e8ba98a758d0 | 154 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 155 | sclData.AngZ = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 156 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 157 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 158 | sclData.StatusSum = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 159 | transfer(RdWHOAMI); |
sameera0824 | 0:e8ba98a758d0 | 160 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 161 | sclData.WHOAMI = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 162 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 163 | if (errorflag) return false; //Inform caller that something went wrong |
sameera0824 | 0:e8ba98a758d0 | 164 | // The WHOAMI command should give an 8 bit value of 0xc1 |
sameera0824 | 0:e8ba98a758d0 | 165 | return (SCL3300_DATA == 0xc1); //Let the caller know this worked |
sameera0824 | 0:e8ba98a758d0 | 166 | } |
sameera0824 | 0:e8ba98a758d0 | 167 | |
sameera0824 | 0:e8ba98a758d0 | 168 | /* Set SCL3300 library into Fast Read Mode |
sameera0824 | 0:e8ba98a758d0 | 169 | * Warning: Using Fast Read Mode in the library works by keeping the |
sameera0824 | 0:e8ba98a758d0 | 170 | * SPI connection continuously open. This may or may not affect |
sameera0824 | 0:e8ba98a758d0 | 171 | * the behavior of other hardware interactions, depending on the |
sameera0824 | 0:e8ba98a758d0 | 172 | * sketch design. Fast Read Mode is considered an advanced use case, |
sameera0824 | 0:e8ba98a758d0 | 173 | * and not recommended for the beginner. |
sameera0824 | 0:e8ba98a758d0 | 174 | */ |
sameera0824 | 0:e8ba98a758d0 | 175 | void SCL3300::setFastReadMode() { |
sameera0824 | 0:e8ba98a758d0 | 176 | setFastRead = true; |
sameera0824 | 0:e8ba98a758d0 | 177 | beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 178 | begin(); //Re-init chip |
sameera0824 | 0:e8ba98a758d0 | 179 | } |
sameera0824 | 0:e8ba98a758d0 | 180 | |
sameera0824 | 0:e8ba98a758d0 | 181 | /* Stop Fast Read Mode |
sameera0824 | 0:e8ba98a758d0 | 182 | * Warning: Using Fast Read Mode in the library works by keeping the |
sameera0824 | 0:e8ba98a758d0 | 183 | * SPI connection continuously open. This may or may not affect |
sameera0824 | 0:e8ba98a758d0 | 184 | * the behavior of other hardware interactions, depending on the |
sameera0824 | 0:e8ba98a758d0 | 185 | * sketch design. Fast Read Mode is considered an advanced use case, |
sameera0824 | 0:e8ba98a758d0 | 186 | * and not recommended for the beginner. |
sameera0824 | 0:e8ba98a758d0 | 187 | */ |
sameera0824 | 0:e8ba98a758d0 | 188 | void SCL3300::stopFastReadMode() { |
sameera0824 | 0:e8ba98a758d0 | 189 | setFastRead = false; |
sameera0824 | 0:e8ba98a758d0 | 190 | endTransmission(); //Close connection to SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 191 | begin(); //Re-init chip |
sameera0824 | 0:e8ba98a758d0 | 192 | } |
sameera0824 | 0:e8ba98a758d0 | 193 | |
sameera0824 | 0:e8ba98a758d0 | 194 | //Return the calculated X axis tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 195 | double SCL3300::getCalculatedAngleX() { |
sameera0824 | 0:e8ba98a758d0 | 196 | double tempX = angle(sclData.AngX); |
sameera0824 | 0:e8ba98a758d0 | 197 | if (tempX < 0.) tempX += 360.; |
sameera0824 | 0:e8ba98a758d0 | 198 | return tempX; |
sameera0824 | 0:e8ba98a758d0 | 199 | } |
sameera0824 | 0:e8ba98a758d0 | 200 | |
sameera0824 | 0:e8ba98a758d0 | 201 | //Return the calculated Y axis tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 202 | double SCL3300::getCalculatedAngleY() { |
sameera0824 | 0:e8ba98a758d0 | 203 | double tempY = angle(sclData.AngY); |
sameera0824 | 0:e8ba98a758d0 | 204 | if (tempY < 0.) tempY += 360.; |
sameera0824 | 0:e8ba98a758d0 | 205 | return tempY; |
sameera0824 | 0:e8ba98a758d0 | 206 | } |
sameera0824 | 0:e8ba98a758d0 | 207 | |
sameera0824 | 0:e8ba98a758d0 | 208 | //Return the calculated Z axis tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 209 | double SCL3300::getCalculatedAngleZ() { |
sameera0824 | 0:e8ba98a758d0 | 210 | double tempZ = angle(sclData.AngZ); |
sameera0824 | 0:e8ba98a758d0 | 211 | if (tempZ < 0.) tempZ += 360.; |
sameera0824 | 0:e8ba98a758d0 | 212 | return tempZ; |
sameera0824 | 0:e8ba98a758d0 | 213 | } |
sameera0824 | 0:e8ba98a758d0 | 214 | |
sameera0824 | 0:e8ba98a758d0 | 215 | //Return the calculated X axis offset tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 216 | double SCL3300::getTiltLevelOffsetAngleX() { |
sameera0824 | 0:e8ba98a758d0 | 217 | return angle(sclData.AngX); |
sameera0824 | 0:e8ba98a758d0 | 218 | } |
sameera0824 | 0:e8ba98a758d0 | 219 | |
sameera0824 | 0:e8ba98a758d0 | 220 | //Return the calculated Y axis offset tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 221 | double SCL3300::getTiltLevelOffsetAngleY() { |
sameera0824 | 0:e8ba98a758d0 | 222 | return angle(sclData.AngY); |
sameera0824 | 0:e8ba98a758d0 | 223 | } |
sameera0824 | 0:e8ba98a758d0 | 224 | |
sameera0824 | 0:e8ba98a758d0 | 225 | //Return the calculated Z axis offset tilt angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 226 | double SCL3300::getTiltLevelOffsetAngleZ() { |
sameera0824 | 0:e8ba98a758d0 | 227 | return angle(sclData.AngZ); |
sameera0824 | 0:e8ba98a758d0 | 228 | } |
sameera0824 | 0:e8ba98a758d0 | 229 | |
sameera0824 | 0:e8ba98a758d0 | 230 | //Return the calculated X axis accelerometer value in units of 'g' |
sameera0824 | 0:e8ba98a758d0 | 231 | double SCL3300::getCalculatedAccelerometerX(void) { |
sameera0824 | 0:e8ba98a758d0 | 232 | return acceleration(sclData.AccX); |
sameera0824 | 0:e8ba98a758d0 | 233 | } |
sameera0824 | 0:e8ba98a758d0 | 234 | |
sameera0824 | 0:e8ba98a758d0 | 235 | //Return the calculated Y axis accelerometer value in units of 'g' |
sameera0824 | 0:e8ba98a758d0 | 236 | double SCL3300::getCalculatedAccelerometerY(void) { |
sameera0824 | 0:e8ba98a758d0 | 237 | return acceleration(sclData.AccY); |
sameera0824 | 0:e8ba98a758d0 | 238 | } |
sameera0824 | 0:e8ba98a758d0 | 239 | |
sameera0824 | 0:e8ba98a758d0 | 240 | //Return the calculated Z axis accelerometer value in units of 'g' |
sameera0824 | 0:e8ba98a758d0 | 241 | double SCL3300::getCalculatedAccelerometerZ(void) { |
sameera0824 | 0:e8ba98a758d0 | 242 | return acceleration(sclData.AccZ); |
sameera0824 | 0:e8ba98a758d0 | 243 | } |
sameera0824 | 0:e8ba98a758d0 | 244 | |
sameera0824 | 0:e8ba98a758d0 | 245 | //Return value of Error Flag 1 register |
sameera0824 | 0:e8ba98a758d0 | 246 | uint16_t SCL3300::getErrFlag1(void) { |
sameera0824 | 0:e8ba98a758d0 | 247 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 248 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 249 | transfer(RdErrFlg1); |
sameera0824 | 0:e8ba98a758d0 | 250 | transfer(RdErrFlg1); |
sameera0824 | 0:e8ba98a758d0 | 251 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 252 | //Since we are fetching the Error Flag 1 value, we want to return what we got |
sameera0824 | 0:e8ba98a758d0 | 253 | //to the caller, regardless of whether or not there was an error |
sameera0824 | 0:e8ba98a758d0 | 254 | //if (crcerr || statuserr) return ((uint16_t)(SCL3300_CMD) & 0xff); //check CRC and RS bits |
sameera0824 | 0:e8ba98a758d0 | 255 | return SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 256 | } |
sameera0824 | 0:e8ba98a758d0 | 257 | |
sameera0824 | 0:e8ba98a758d0 | 258 | //Return value of Error Flag 2 register |
sameera0824 | 0:e8ba98a758d0 | 259 | uint16_t SCL3300::getErrFlag2(void) { |
sameera0824 | 0:e8ba98a758d0 | 260 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 261 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 262 | transfer(RdErrFlg2); |
sameera0824 | 0:e8ba98a758d0 | 263 | transfer(RdErrFlg2); |
sameera0824 | 0:e8ba98a758d0 | 264 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 265 | //Since we are fetching the Error Flag 2 value, we want to return what we got |
sameera0824 | 0:e8ba98a758d0 | 266 | //to the caller, regardless of whether or not there was an error |
sameera0824 | 0:e8ba98a758d0 | 267 | //if (crcerr || statuserr) return ((uint16_t)(SCL3300_CMD) & 0xff); //check CRC and RS bits |
sameera0824 | 0:e8ba98a758d0 | 268 | return SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 269 | } |
sameera0824 | 0:e8ba98a758d0 | 270 | |
sameera0824 | 0:e8ba98a758d0 | 271 | // Read the sensor Serial Number as created by the manufacturer |
sameera0824 | 0:e8ba98a758d0 | 272 | unsigned long SCL3300::getSerialNumber(void) { |
sameera0824 | 0:e8ba98a758d0 | 273 | //Return Device Serial number |
metronix | 1:52b1117c65ea | 274 | bool errorflag = false; |
sameera0824 | 0:e8ba98a758d0 | 275 | unsigned long serialNum = 0; |
sameera0824 | 0:e8ba98a758d0 | 276 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 277 | transfer(SwtchBnk1); |
sameera0824 | 0:e8ba98a758d0 | 278 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 279 | transfer(RdSer1); |
sameera0824 | 0:e8ba98a758d0 | 280 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 281 | transfer(RdSer2); |
sameera0824 | 0:e8ba98a758d0 | 282 | serialNum = SCL3300_DATA; |
sameera0824 | 0:e8ba98a758d0 | 283 | if (crcerr || statuserr) errorflag = true; |
sameera0824 | 0:e8ba98a758d0 | 284 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 285 | serialNum = ((unsigned long)SCL3300_DATA << 16) | serialNum; |
sameera0824 | 0:e8ba98a758d0 | 286 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 287 | //We wait until now to return an error code |
sameera0824 | 0:e8ba98a758d0 | 288 | //In this case we send a 0 since a real serial number will never be 0 |
sameera0824 | 0:e8ba98a758d0 | 289 | if (crcerr || statuserr || errorflag) return 0; |
sameera0824 | 0:e8ba98a758d0 | 290 | return serialNum; |
sameera0824 | 0:e8ba98a758d0 | 291 | } |
sameera0824 | 0:e8ba98a758d0 | 292 | |
sameera0824 | 0:e8ba98a758d0 | 293 | // Place the sensor in a Powered Down mode to save power |
sameera0824 | 0:e8ba98a758d0 | 294 | uint16_t SCL3300::powerDownMode(void) { |
sameera0824 | 0:e8ba98a758d0 | 295 | //Software power down of sensor |
sameera0824 | 0:e8ba98a758d0 | 296 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 297 | transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 298 | transfer(SetPwrDwn); |
sameera0824 | 0:e8ba98a758d0 | 299 | endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 300 | //Since an error is non-zero, we will return 0 if there was no error |
sameera0824 | 0:e8ba98a758d0 | 301 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits |
sameera0824 | 0:e8ba98a758d0 | 302 | return 0; |
sameera0824 | 0:e8ba98a758d0 | 303 | } |
sameera0824 | 0:e8ba98a758d0 | 304 | |
sameera0824 | 0:e8ba98a758d0 | 305 | // Revive the sensor from a power down mode so we can start getting data again |
sameera0824 | 0:e8ba98a758d0 | 306 | uint16_t SCL3300::WakeMeUp(void) { |
sameera0824 | 0:e8ba98a758d0 | 307 | //Software Wake Up of sensor |
sameera0824 | 0:e8ba98a758d0 | 308 | beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 309 | transfer(WakeUp); |
sameera0824 | 0:e8ba98a758d0 | 310 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 311 | //Since an error is non-zero, we will return 0 if there was no error |
sameera0824 | 0:e8ba98a758d0 | 312 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits |
sameera0824 | 0:e8ba98a758d0 | 313 | return 0; |
sameera0824 | 0:e8ba98a758d0 | 314 | } |
sameera0824 | 0:e8ba98a758d0 | 315 | |
sameera0824 | 0:e8ba98a758d0 | 316 | // Hardware reset of the sensor electronics |
sameera0824 | 0:e8ba98a758d0 | 317 | uint16_t SCL3300::reset(void) { |
sameera0824 | 0:e8ba98a758d0 | 318 | //Software reset of sensor |
sameera0824 | 0:e8ba98a758d0 | 319 | //beginTransmission(); //Set up this SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 320 | //transfer(SwtchBnk0); |
sameera0824 | 0:e8ba98a758d0 | 321 | //transfer(SWreset); |
sameera0824 | 0:e8ba98a758d0 | 322 | //endTransmission(); //Let go of SPI port/bus |
sameera0824 | 0:e8ba98a758d0 | 323 | //we have to call begin() to set up the SCL3300 to the same state as before it was reset |
sameera0824 | 0:e8ba98a758d0 | 324 | begin(); //Re-init chip |
sameera0824 | 0:e8ba98a758d0 | 325 | //Since an error is non-zero, we will return 0 if there was no error |
sameera0824 | 0:e8ba98a758d0 | 326 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits |
sameera0824 | 0:e8ba98a758d0 | 327 | return 0; |
sameera0824 | 0:e8ba98a758d0 | 328 | } |
sameera0824 | 0:e8ba98a758d0 | 329 | |
sameera0824 | 0:e8ba98a758d0 | 330 | // Routine to get temperature in degrees Celsius |
sameera0824 | 0:e8ba98a758d0 | 331 | double SCL3300::getCalculatedTemperatureCelsius(void) { |
sameera0824 | 0:e8ba98a758d0 | 332 | // Return calculated temperature in degrees C |
sameera0824 | 0:e8ba98a758d0 | 333 | double Temperature = -273. + (sclData.TEMP / 18.9); |
sameera0824 | 0:e8ba98a758d0 | 334 | return Temperature; |
sameera0824 | 0:e8ba98a758d0 | 335 | } |
sameera0824 | 0:e8ba98a758d0 | 336 | |
sameera0824 | 0:e8ba98a758d0 | 337 | // Routine to get temperature in degrees Farenheit |
sameera0824 | 0:e8ba98a758d0 | 338 | double SCL3300::getCalculatedTemperatureFarenheit(void) { |
sameera0824 | 0:e8ba98a758d0 | 339 | // Return calculated temperature in degrees F |
sameera0824 | 0:e8ba98a758d0 | 340 | double Temperature = -273. + (sclData.TEMP / 18.9); |
sameera0824 | 0:e8ba98a758d0 | 341 | Temperature = (Temperature * 9./5.) + 32.; |
sameera0824 | 0:e8ba98a758d0 | 342 | return Temperature; |
sameera0824 | 0:e8ba98a758d0 | 343 | } |
sameera0824 | 0:e8ba98a758d0 | 344 | |
sameera0824 | 0:e8ba98a758d0 | 345 | //Convert raw angle value to degrees tilt |
sameera0824 | 0:e8ba98a758d0 | 346 | double SCL3300::angle(int16_t SCL3300_ANG) { //two's complement value expected |
sameera0824 | 0:e8ba98a758d0 | 347 | // Return Angle in degrees |
sameera0824 | 0:e8ba98a758d0 | 348 | double Angle = (SCL3300_ANG / 16384.) * 90.; // 16384 = 2^14 |
sameera0824 | 0:e8ba98a758d0 | 349 | return Angle; |
sameera0824 | 0:e8ba98a758d0 | 350 | } |
sameera0824 | 0:e8ba98a758d0 | 351 | |
sameera0824 | 0:e8ba98a758d0 | 352 | //Convert raw accelerometer value to g's of acceleration |
sameera0824 | 0:e8ba98a758d0 | 353 | double SCL3300::acceleration(int16_t SCL3300_ACC) { //two's complement value expected |
sameera0824 | 0:e8ba98a758d0 | 354 | // Return acceleration in g |
sameera0824 | 0:e8ba98a758d0 | 355 | if (scl3300_mode == 1) return (double)SCL3300_ACC / 6000.; |
sameera0824 | 0:e8ba98a758d0 | 356 | if (scl3300_mode == 2) return (double)SCL3300_ACC / 3000.; |
sameera0824 | 0:e8ba98a758d0 | 357 | if (scl3300_mode == 3) return (double)SCL3300_ACC / 12000.; |
sameera0824 | 0:e8ba98a758d0 | 358 | if (scl3300_mode == 4) return (double)SCL3300_ACC / 12000.; |
sameera0824 | 0:e8ba98a758d0 | 359 | return (double)SCL3300_ACC / 12000.; //Default should never be reached |
sameera0824 | 0:e8ba98a758d0 | 360 | } |
sameera0824 | 0:e8ba98a758d0 | 361 | |
sameera0824 | 0:e8ba98a758d0 | 362 | //private functions for serial transmission |
sameera0824 | 0:e8ba98a758d0 | 363 | // Begin SPI bus transmission to the device |
sameera0824 | 0:e8ba98a758d0 | 364 | void SCL3300::beginTransmission() { |
metronix | 1:52b1117c65ea | 365 | _scl3300_csPin=0; |
sameera0824 | 0:e8ba98a758d0 | 366 | } //beginTransmission |
sameera0824 | 0:e8ba98a758d0 | 367 | |
sameera0824 | 0:e8ba98a758d0 | 368 | // End SPI bus transmission to the device |
sameera0824 | 0:e8ba98a758d0 | 369 | void SCL3300::endTransmission() { |
sameera0824 | 0:e8ba98a758d0 | 370 | // take the chip/slave select high to de-select: |
metronix | 1:52b1117c65ea | 371 | _scl3300_csPin=1; |
metronix | 1:52b1117c65ea | 372 | timer2.start(); |
metronix | 1:52b1117c65ea | 373 | unsigned long startmillis = timer2.read_ms(); |
metronix | 1:52b1117c65ea | 374 | while (timer2.read_ms() - startmillis < 1) ; //wait a bit |
metronix | 1:52b1117c65ea | 375 | timer2.stop(); |
sameera0824 | 0:e8ba98a758d0 | 376 | } //endTransmission |
sameera0824 | 0:e8ba98a758d0 | 377 | |
sameera0824 | 0:e8ba98a758d0 | 378 | //Initialize the Arduino SPI library for the SCL3300 hardware |
sameera0824 | 0:e8ba98a758d0 | 379 | void SCL3300::initSPI() { |
sameera0824 | 0:e8ba98a758d0 | 380 | //Initialize the Arduino SPI library for the SCL3300 hardware |
metronix | 1:52b1117c65ea | 381 | _spi.frequency(_transfer_sck); |
sameera0824 | 0:e8ba98a758d0 | 382 | // Maximum SPI frequency is 2 MHz - 4 MHz to achieve the best performance |
sameera0824 | 0:e8ba98a758d0 | 383 | // initialize the chip select pin: |
metronix | 1:52b1117c65ea | 384 | _scl3300_csPin=1; |
sameera0824 | 0:e8ba98a758d0 | 385 | // Data is read and written MSb first. |
sameera0824 | 0:e8ba98a758d0 | 386 | // Data is captured on rising edge of clock (CPHA = 0) |
sameera0824 | 0:e8ba98a758d0 | 387 | // Data is propagated on the falling edge (MISO line) of the SCK. (CPOL = 0) |
sameera0824 | 0:e8ba98a758d0 | 388 | } |
sameera0824 | 0:e8ba98a758d0 | 389 | |
sameera0824 | 0:e8ba98a758d0 | 390 | // The following is taken directly from the Murata SCL3300 datasheet |
sameera0824 | 0:e8ba98a758d0 | 391 | // Calculate CRC for 24 MSB's of the 32 bit dword |
sameera0824 | 0:e8ba98a758d0 | 392 | // (8 LSB's are the CRC field and are not included in CRC calculation) |
sameera0824 | 0:e8ba98a758d0 | 393 | uint8_t SCL3300::CalculateCRC(uint32_t Data) |
sameera0824 | 0:e8ba98a758d0 | 394 | { |
sameera0824 | 0:e8ba98a758d0 | 395 | uint8_t BitIndex; |
sameera0824 | 0:e8ba98a758d0 | 396 | uint8_t BitValue; |
sameera0824 | 0:e8ba98a758d0 | 397 | uint8_t SCL3300_CRC; |
sameera0824 | 0:e8ba98a758d0 | 398 | |
sameera0824 | 0:e8ba98a758d0 | 399 | SCL3300_CRC = 0xFF; |
sameera0824 | 0:e8ba98a758d0 | 400 | for (BitIndex = 31; BitIndex > 7; BitIndex--) { |
sameera0824 | 0:e8ba98a758d0 | 401 | BitValue = (uint8_t)((Data >> BitIndex) & 0x01); |
sameera0824 | 0:e8ba98a758d0 | 402 | SCL3300_CRC = CRC8(BitValue, SCL3300_CRC); |
sameera0824 | 0:e8ba98a758d0 | 403 | } |
sameera0824 | 0:e8ba98a758d0 | 404 | SCL3300_CRC = (uint8_t)~SCL3300_CRC; |
sameera0824 | 0:e8ba98a758d0 | 405 | return SCL3300_CRC; |
sameera0824 | 0:e8ba98a758d0 | 406 | } |
sameera0824 | 0:e8ba98a758d0 | 407 | uint8_t SCL3300::CRC8(uint8_t BitValue, uint8_t SCL3300_CRC) |
sameera0824 | 0:e8ba98a758d0 | 408 | { |
sameera0824 | 0:e8ba98a758d0 | 409 | uint8_t Temp; |
sameera0824 | 0:e8ba98a758d0 | 410 | Temp = (uint8_t)(SCL3300_CRC & 0x80); |
sameera0824 | 0:e8ba98a758d0 | 411 | if (BitValue == 0x01) { |
sameera0824 | 0:e8ba98a758d0 | 412 | Temp ^= 0x80; |
sameera0824 | 0:e8ba98a758d0 | 413 | } |
sameera0824 | 0:e8ba98a758d0 | 414 | SCL3300_CRC <<= 1; |
sameera0824 | 0:e8ba98a758d0 | 415 | if (Temp > 0) { |
sameera0824 | 0:e8ba98a758d0 | 416 | SCL3300_CRC ^= 0x1D; |
sameera0824 | 0:e8ba98a758d0 | 417 | } |
sameera0824 | 0:e8ba98a758d0 | 418 | return SCL3300_CRC; |
sameera0824 | 0:e8ba98a758d0 | 419 | } |
sameera0824 | 0:e8ba98a758d0 | 420 | |
sameera0824 | 0:e8ba98a758d0 | 421 | // Routine to transfer a 32-bit integer to the SCL3300, and return the 32-bit data read |
sameera0824 | 0:e8ba98a758d0 | 422 | unsigned long SCL3300::transfer(unsigned long value) { |
sameera0824 | 0:e8ba98a758d0 | 423 | FourByte dataorig; |
sameera0824 | 0:e8ba98a758d0 | 424 | unsigned long startmicros; |
sameera0824 | 0:e8ba98a758d0 | 425 | |
sameera0824 | 0:e8ba98a758d0 | 426 | dataorig.bit32 = value; //Allow 32 bit value to be sent 8 bits at a time |
sameera0824 | 0:e8ba98a758d0 | 427 | #ifdef debug_scl3300 |
metronix | 1:52b1117c65ea | 428 | _spi.print(dataorig.bit32, HEX); |
metronix | 1:52b1117c65ea | 429 | _spi.print(" "); |
sameera0824 | 0:e8ba98a758d0 | 430 | for (int j = 3; j >= 0; j--) { |
metronix | 1:52b1117c65ea | 431 | _spi.print(dataorig.bit8[j], HEX); |
metronix | 1:52b1117c65ea | 432 | _spi.print(" "); |
sameera0824 | 0:e8ba98a758d0 | 433 | } |
sameera0824 | 0:e8ba98a758d0 | 434 | #endif |
sameera0824 | 0:e8ba98a758d0 | 435 | //Must allow at least 10 uSec between SPI transfers |
sameera0824 | 0:e8ba98a758d0 | 436 | //The datasheet shows the CS line must be high during this time |
metronix | 1:52b1117c65ea | 437 | timer1.start(); |
metronix | 1:52b1117c65ea | 438 | if (!setFastRead) startmicros = timer1.read_us(); |
sameera0824 | 0:e8ba98a758d0 | 439 | //while ((micros() - startmicros < 10) && (micros() > 10)) ; |
metronix | 1:52b1117c65ea | 440 | if (!setFastRead) while ((timer1.read_us() - startmicros < 10)) ; |
metronix | 1:52b1117c65ea | 441 | timer1.stop(); |
metronix | 1:52b1117c65ea | 442 | _scl3300_csPin=0; //Now chip select can be enabled for the full 32 bit xfer |
sameera0824 | 0:e8ba98a758d0 | 443 | SCL3300_DATA = 0; |
sameera0824 | 0:e8ba98a758d0 | 444 | for (int i = 3; i >= 0; i--) { //Xfers are done MSB first |
metronix | 1:52b1117c65ea | 445 | dataorig.bit8[i] = transfer(dataorig.bit8[i]); |
sameera0824 | 0:e8ba98a758d0 | 446 | } |
sameera0824 | 0:e8ba98a758d0 | 447 | SCL3300_DATA = dataorig.bit8[1] + (dataorig.bit8[2] << 8); |
sameera0824 | 0:e8ba98a758d0 | 448 | SCL3300_CRC = dataorig.bit8[0]; |
sameera0824 | 0:e8ba98a758d0 | 449 | SCL3300_CMD = dataorig.bit8[3]; |
metronix | 1:52b1117c65ea | 450 | _scl3300_csPin=1; //And we are done |
sameera0824 | 0:e8ba98a758d0 | 451 | #ifdef debug_scl3300 |
sameera0824 | 0:e8ba98a758d0 | 452 | for (int i = 3; i >= 0; i--) { |
metronix | 1:52b1117c65ea | 453 | _spi.print(" "); |
metronix | 1:52b1117c65ea | 454 | _spi.print(dataorig.bit8[i], HEX); |
sameera0824 | 0:e8ba98a758d0 | 455 | } |
metronix | 1:52b1117c65ea | 456 | _spi.print(" "); |
sameera0824 | 0:e8ba98a758d0 | 457 | #endif |
sameera0824 | 0:e8ba98a758d0 | 458 | if (SCL3300_CRC == CalculateCRC(dataorig.bit32)) |
sameera0824 | 0:e8ba98a758d0 | 459 | crcerr = false; |
sameera0824 | 0:e8ba98a758d0 | 460 | else |
sameera0824 | 0:e8ba98a758d0 | 461 | crcerr = true; |
sameera0824 | 0:e8ba98a758d0 | 462 | //check RS bits |
sameera0824 | 0:e8ba98a758d0 | 463 | if ((SCL3300_CMD & 0x03) == 0x01) |
sameera0824 | 0:e8ba98a758d0 | 464 | statuserr = false; |
sameera0824 | 0:e8ba98a758d0 | 465 | else |
sameera0824 | 0:e8ba98a758d0 | 466 | statuserr = true; |
sameera0824 | 0:e8ba98a758d0 | 467 | #ifdef debug_scl3300 |
metronix | 1:52b1117c65ea | 468 | _spi.print((SCL3300_CMD & 0x03)); |
metronix | 1:52b1117c65ea | 469 | _spi.print(" "); |
metronix | 1:52b1117c65ea | 470 | _spi.print(SCL3300_DATA, HEX); |
metronix | 1:52b1117c65ea | 471 | _spi.print(" "); |
metronix | 1:52b1117c65ea | 472 | _spi.print(SCL3300_CRC, HEX); |
metronix | 1:52b1117c65ea | 473 | _spi.print(" "); |
metronix | 1:52b1117c65ea | 474 | _spi.print(CalculateCRC(dataorig.bit32), HEX); |
metronix | 1:52b1117c65ea | 475 | _spi.print(" "); |
metronix | 1:52b1117c65ea | 476 | _spi.println(crcerr); |
sameera0824 | 0:e8ba98a758d0 | 477 | #endif |
sameera0824 | 0:e8ba98a758d0 | 478 | return dataorig.bit32; |
sameera0824 | 0:e8ba98a758d0 | 479 | } |