├── LICENSE ├── README.md ├── examples ├── Example10_Mode1 │ └── Example10_Mode1.ino ├── Example1_BasicTiltLevelOffset │ └── Example1_BasicTiltLevelOffset.ino ├── Example2_BasicTiltReading │ └── Example2_BasicTiltReading.ino ├── Example3_BasicAccelerometerReading │ └── Example3_BasicAccelerometerReading.ino ├── Example4_BasicTemperatureReading │ └── Example4_BasicTemperatureReading.ino ├── Example5_RawDataReading │ └── Example5_RawDataReading.ino ├── Example6_FastReadMode │ └── Example6_FastReadMode.ino ├── Example7_FastReadModeContinuous │ └── Example7_FastReadModeContinuous.ino ├── Example8_TwoSensors │ └── Example8_TwoSensors.ino └── Example9_AlternateSPI │ └── Example9_AlternateSPI.ino ├── keywords.txt ├── library.properties └── src ├── SCL3300.cpp └── SCL3300.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dave Armstrong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SCL3300 2 | 3 | 4 | Arduino Library for Murata SCL3300 Inclinometer 5 | 6 | Version 3.3.1 - July 4, 2022
7 | Note: This is not a bug fix, nor a new feature release. The only change is adding the new Example10_Mode1 sketch, which is useful for more general tilt angle measurement needs. 8 | 9 | By David Armstrong
10 | https://github.com/DavidArmstrong/Arduino-SCL3300
11 | See MIT LICENSE.md file 12 | 13 | 14 | The Murata SCL3300 inclinometer sensor is a 3.3 volt device used to measure tilt in three axes simultaneously. 15 | 16 | Datasheet: https://www.murata.com/-/media/webrenewal/products/sensor/pdf/datasheet/datasheet_scl3300-d01.ashx?la=en-us 17 | 18 | Evaluation Board: https://www.murata.com/-/media/webrenewal/products/sensor/pdf/specification/pcbspec_scx3300.ashx?la=en-us 19 | 20 | Notes: 21 | 1) The SCL3300 inclinometer will require a bidrectional level shifter to interface the SPI pins to 5 volt devices, such as the Arduino Uno. 22 | 2) A pull-up resistor may be required on the Chip/Slave Select line of the SCL3300. A typical resistor value of 4.7k ohms should connect this pin to +3.3 volts. 23 | 3) Be sure to connect the SCL3300 DVIO pin to +3.3 volts as well. This pin powers the digital pins. 24 | 4) There is a small, but significant, library change starting with Version 3.0.0. This requires a one-line addition to any older sketches when using this updated SCL3300 library. All the example sketches have been updated to include the addtional code. (The backwards incompatibility is due to the improved error detection and handling design.) 25 | 26 | For an Arduino Uno, the default SPI pins are as follows: 27 | * SCK - Digital Pin 13 28 | * SDO - Digital Pin 12 (MISO) 29 | * SDI - Digital Pin 11 (MOSI) 30 | * CS - Digital Pin 10 (SS) 31 | 32 | For a SAMD-type Arduino, such as the Sparkfun Redboard Turbo or Arduino Zero, the default SPI pins are only available on the ICSP connector: 33 | * pin 22 (MISO) 34 | * pin 23 (MOSI) 35 | * pin 24 (SCK) 36 | * Chip/Slave Select uses digital Pin 10 as the default. 37 | 38 | ====================================== 39 | 40 | Basic SCL3300 Library Functions: 41 | 42 | begin()
43 | This initializes the library and the SPI chip, and by default assigns the SPI Chip Select Pin to Digital Pin 10. 44 | 45 | begin(csPinNum)
46 | This variation allows you to choose a different pin as the SPI Chip Select Pin. Replace 'csPinNum' with your pin number. 47 | 48 | begin(altSpiPort, csPinNum)
49 | This allows using an alternate SPI port definition for communication to the SCL3300. Please see Example9_AlternateSPI.ino 50 | 51 | isConnected()
52 | Returns 'true' if the sensor is still responding as expected, and able to provide valid data. It does not collect a data set from the sensor. 53 | 54 | available()
55 | Reads the raw SCL3300 sensor data as a group so that all the data is consistent. Call this first before using the functions below. Starting with Version 3.0.0, this call should be the conditional in an 'if' statement, and an 'else' clause included to call reset() when available() returns false. (See the example sketches in the library.) 56 | 57 | getTiltLevelOffsetAngleX()
58 | Returns a double float of the tilt offset from level value in degrees for the X direction. 59 | 60 | getTiltLevelOffsetAngleY()
61 | Returns a double float of the tilt offset from level value in degrees for the Y direction. 62 | 63 | getTiltLevelOffsetAngleZ()
64 | Returns a double float of the tilt offset from level value in degrees for the Z direction. 65 | 66 | getCalculatedAngleX()
67 | Returns a double float of the tilt value in degrees (0-360) for the X direction. 68 | 69 | getCalculatedAngleY()
70 | Returns a double float of the tilt value in degrees (0-360) for the Y direction. 71 | 72 | getCalculatedAngleZ()
73 | Returns a double float of the tilt value in degrees (0-360) for the Z direction. 74 | 75 | getCalculatedAccelerometerX()
76 | Returns a double float of the accelerometer value in units of 'g' for the X direction. 77 | 78 | getCalculatedAccelerometerY()
79 | Returns a double float of the accelerometer value in units of 'g' for the Y direction. 80 | 81 | getCalculatedAccelerometerZ()
82 | Returns a double float of the accelerometer value in units of 'g' for the Z direction. 83 | 84 | getTemperatureCelsius()
85 | Returns a double float of the temperature in Celsius. 86 | 87 | getTemperatureFarenheit()
88 | Returns a double float of the temperature in Farenheit. 89 | 90 | 91 | Utility Functions available: 92 | 93 | reset()
94 | Does a software reset of the SCL3300 sensor. 95 | 96 | getSerialNumber()
97 | Returns a long integer of the device Serial Number set by the manufacturer. 98 | 99 | powerDownMode()
100 | Puts the sensor in a power down mode to reduce power usage. 101 | 102 | WakeMeUp()
103 | Revives sensor from being powered down, so that it can start to generate sensor data. 104 | 105 | setMode(modeNum)
106 | Sets the sensor mode to the number provided as modeNum. The default mode is '4'. Valid values are 1, 2, 3, and 4. 107 | 108 | setFastReadMode()
109 | Using Fast Read Mode in the library works by keeping the SPI connection continuously open. This may or may not affect the behavior of other hardware interactions, depending on the sketch design. Fast Read Mode is considered an advanced use case, and not recommended for the beginner. 110 | 111 | stopFastReadMode()
112 | This stops the Fast Read Mode in the library by closing the SPI connection that was open, and doing a reset of the SCL3300. This may or may not affect the behavior of other hardware interactions, depending on the sketch design. Fast Read Mode is considered an advanced use case, and not recommended for the beginner. 113 | -------------------------------------------------------------------------------- /examples/Example10_Mode1/Example10_Mode1.ino: -------------------------------------------------------------------------------- 1 | /* Read Tilt angles from Murata SCL3300 Inclinometer using Mode 1 2 | * Version 3.3.1 - July 4, 2022 3 | * Example10_Mode1 4 | * 5 | * Modes 3 and 4 (default for library) are designed to be used when the inclinometer 6 | * will be kept within +-10 degrees of level. 7 | * However, if the inclinometer might be used outside of that range, then 8 | * it is required that either Mode 1 or 2 be used instead. 9 | * This sketch demonstrates how to use Mode 1 when that is needed. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | SCL3300 inclinometer; 16 | //Default SPI chip/slave select pin is D10 17 | 18 | // Need the following define for SAMD processors 19 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 20 | #define Serial SERIAL_PORT_USBVIRTUAL 21 | #endif 22 | 23 | void setup() { 24 | Serial.begin(9600); 25 | delay(2000); //SAMD boards may need a long time to init SerialUSB 26 | Serial.println("Reading basic Tilt Level Offset values from SCL3300 Inclinometer"); 27 | Serial.println("using Mode 1."); 28 | 29 | if (inclinometer.begin() == false) { 30 | Serial.println("Murata SCL3300 inclinometer not connected."); 31 | while(1); //Freeze 32 | } else { 33 | Serial.println("Murata SCL3300 inclinometer detected."); 34 | // Put this inclinometer into Mode 1, since we are using it to measure 0-90 Degree angles 35 | inclinometer.setMode(1); 36 | if (inclinometer.begin()) { 37 | Serial.println("Murata SCL3300 inclinometer now in Mode 1."); 38 | } else { 39 | Serial.println("Tube Murata SCL3300 inclinometer failed to transition to Mode 1."); 40 | while(1); //Freeze 41 | } 42 | } 43 | } 44 | 45 | void loop() { 46 | if (inclinometer.available()) { //Get next block of data from sensor 47 | Serial.print("X Tilt: "); 48 | Serial.print(inclinometer.getTiltLevelOffsetAngleX()); 49 | Serial.print("\t"); 50 | Serial.print("Y Tilt: "); 51 | Serial.print(inclinometer.getTiltLevelOffsetAngleY()); 52 | Serial.print("\t"); 53 | Serial.print("Z Tilt: "); 54 | Serial.println(inclinometer.getTiltLevelOffsetAngleZ()); 55 | delay(100); //Allow a little time to see the output 56 | } else inclinometer.reset(); 57 | } 58 | -------------------------------------------------------------------------------- /examples/Example1_BasicTiltLevelOffset/Example1_BasicTiltLevelOffset.ino: -------------------------------------------------------------------------------- 1 | /* Read Tilt angles from Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example1_BasicTiltLevelOffset 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | //Default SPI chip/slave select pin is D10 11 | 12 | // Need the following define for SAMD processors 13 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 14 | #define Serial SERIAL_PORT_USBVIRTUAL 15 | #endif 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | delay(2000); //SAMD boards may need a long time to init SerialUSB 20 | Serial.println("Reading basic Tilt Level Offset values from SCL3300 Inclinometer"); 21 | 22 | if (inclinometer.begin() == false) { 23 | Serial.println("Murata SCL3300 inclinometer not connected."); 24 | while(1); //Freeze 25 | } 26 | } 27 | 28 | void loop() { 29 | if (inclinometer.available()) { //Get next block of data from sensor 30 | Serial.print("X Tilt: "); 31 | Serial.print(inclinometer.getTiltLevelOffsetAngleX()); 32 | Serial.print("\t"); 33 | Serial.print("Y Tilt: "); 34 | Serial.print(inclinometer.getTiltLevelOffsetAngleY()); 35 | Serial.print("\t"); 36 | Serial.print("Z Tilt: "); 37 | Serial.println(inclinometer.getTiltLevelOffsetAngleZ()); 38 | delay(100); //Allow a little time to see the output 39 | } else inclinometer.reset(); 40 | } 41 | -------------------------------------------------------------------------------- /examples/Example2_BasicTiltReading/Example2_BasicTiltReading.ino: -------------------------------------------------------------------------------- 1 | /* Read Tilt angles from Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example2_BasicTiltReading 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | //Default SPI chip/slave select pin is D10 11 | 12 | // Need the following define for SAMD processors 13 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 14 | #define Serial SERIAL_PORT_USBVIRTUAL 15 | #endif 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | delay(2000); //SAMD boards may need a long time to init SerialUSB 20 | Serial.println("Reading basic Tilt values from SCL3300 Inclinometer"); 21 | 22 | if (inclinometer.begin() == false) { 23 | Serial.println("Murata SCL3300 inclinometer not connected."); 24 | while(1); //Freeze 25 | } 26 | } 27 | 28 | void loop() { 29 | if (inclinometer.available()) { //Get next block of data from sensor 30 | Serial.print("X Tilt: "); 31 | Serial.print(inclinometer.getCalculatedAngleX()); 32 | Serial.print("\t"); 33 | Serial.print("Y Tilt: "); 34 | Serial.print(inclinometer.getCalculatedAngleY()); 35 | Serial.print("\t"); 36 | Serial.print("Z Tilt: "); 37 | Serial.println(inclinometer.getCalculatedAngleZ()); 38 | delay(250); //Allow a little time to see the output 39 | } else inclinometer.reset(); 40 | } 41 | -------------------------------------------------------------------------------- /examples/Example3_BasicAccelerometerReading/Example3_BasicAccelerometerReading.ino: -------------------------------------------------------------------------------- 1 | /* Read Accelerometer data from Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example3_BasicAccelerometerReading 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | //Default SPI chip/slave select pin is D10 11 | 12 | // Need the following define for SAMD processors 13 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 14 | #define Serial SERIAL_PORT_USBVIRTUAL 15 | #endif 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | delay(2000); //SAMD boards may need a long time to init SerialUSB 20 | Serial.println("Reading basic Accelerometer values from SCL3300 Inclinometer"); 21 | 22 | if (inclinometer.begin() == false) { 23 | Serial.println("Murata SCL3300 inclinometer not connected."); 24 | while(1); //Freeze 25 | } 26 | } 27 | 28 | void loop() { 29 | if (inclinometer.available()) { //Get next block of data from sensor 30 | Serial.print("X Accelerometer: "); 31 | Serial.print(inclinometer.getCalculatedAccelerometerX()); 32 | Serial.print("\t"); 33 | Serial.print("Y Accelerometer: "); 34 | Serial.print(inclinometer.getCalculatedAccelerometerY()); 35 | Serial.print("\t"); 36 | Serial.print("Z Accelerometer: "); 37 | Serial.println(inclinometer.getCalculatedAccelerometerZ()); 38 | delay(250); //Allow a little time to see the output 39 | } else inclinometer.reset(); 40 | } 41 | -------------------------------------------------------------------------------- /examples/Example4_BasicTemperatureReading/Example4_BasicTemperatureReading.ino: -------------------------------------------------------------------------------- 1 | /* Read Temperature Sensor from Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example4_BasicTemperatureReading 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | //Default SPI chip/slave select pin is D10 11 | 12 | // Need the following define for SAMD processors 13 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 14 | #define Serial SERIAL_PORT_USBVIRTUAL 15 | #endif 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | delay(2000); //SAMD boards may need a long time to init SerialUSB 20 | Serial.println("Reading basic Temperature values from SCL3300 Inclinometer"); 21 | 22 | if (inclinometer.begin() == false) { 23 | Serial.println("Murata SCL3300 inclinometer not connected."); 24 | while(1); //Freeze 25 | } 26 | } 27 | 28 | void loop() { 29 | if (inclinometer.available()) { //Get next block of data from sensor 30 | Serial.print("Celsius Temperature: "); 31 | Serial.print(inclinometer.getCalculatedTemperatureCelsius()); 32 | Serial.print("\t"); 33 | Serial.print("Farenheit Temperature: "); 34 | Serial.println(inclinometer.getCalculatedTemperatureFarenheit()); 35 | delay(250); //Allow a little time to see the output 36 | } else inclinometer.reset(); 37 | } 38 | -------------------------------------------------------------------------------- /examples/Example5_RawDataReading/Example5_RawDataReading.ino: -------------------------------------------------------------------------------- 1 | /* Read Raw sensor data from Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example5_RawDataReading 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | //Default SPI chip/slave select pin is D10 11 | 12 | // Need the following define for SAMD processors 13 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 14 | #define Serial SERIAL_PORT_USBVIRTUAL 15 | #endif 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | delay(2000); //SAMD boards may need a long time to init SerialUSB 20 | Serial.println("Reading Raw register values from SCL3300 Inclinometer"); 21 | 22 | if (inclinometer.begin() == false) { 23 | Serial.println("Murata SCL3300 inclinometer not connected."); 24 | while(1); //Freeze 25 | } 26 | } 27 | 28 | void loop() { 29 | if (inclinometer.isConnected()) Serial.println("Inclinometer is still alive..."); 30 | else Serial.println("Inclinometer error detected..."); 31 | 32 | if (inclinometer.available()) { //Get next block of data from sensor 33 | Serial.print("Raw X Tilt: "); 34 | Serial.print(inclinometer.sclData.AngX); 35 | Serial.print("\t"); 36 | Serial.print("Y Tilt: "); 37 | Serial.print(inclinometer.sclData.AngY); 38 | Serial.print("\t"); 39 | Serial.print("Z Tilt: "); 40 | Serial.println(inclinometer.sclData.AngZ); 41 | Serial.print("Raw X Accel: "); 42 | Serial.print(inclinometer.sclData.AccX); 43 | Serial.print("\t"); 44 | Serial.print("Y Accel: "); 45 | Serial.print(inclinometer.sclData.AccY); 46 | Serial.print("\t"); 47 | Serial.print("Z Accel: "); 48 | Serial.println(inclinometer.sclData.AccZ); 49 | Serial.print("SCL3300 STO register: "); 50 | Serial.print((inclinometer.sclData.STO >> 8) & 0xff, HEX); 51 | Serial.print("\t"); 52 | Serial.print("WHOAMI register: "); 53 | Serial.println(inclinometer.sclData.WHOAMI, HEX); 54 | Serial.print("Raw Temperature: "); 55 | Serial.println(inclinometer.sclData.TEMP); 56 | Serial.print("Serial Number Register: "); 57 | Serial.print(inclinometer.getSerialNumber()); 58 | Serial.print("B33"); 59 | Serial.print("\t"); 60 | Serial.print("SL3300 Status Summary Register: "); 61 | Serial.println(inclinometer.sclData.StatusSum, HEX); 62 | delay(1000); 63 | } else inclinometer.reset(); 64 | } 65 | -------------------------------------------------------------------------------- /examples/Example6_FastReadMode/Example6_FastReadMode.ino: -------------------------------------------------------------------------------- 1 | /* Fast Read Sensor Mode for Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example6_FastReadMode 4 | * Warning: Using Fast Read Mode in the library works by keeping the 5 | * SPI connection continuously open. This may or may not affect 6 | * the behavior of other hardware interactions, depending on the 7 | * sketch design. Fast Read Mode is considered an advanced use case, 8 | * and not recommended for the beginner. 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | SCL3300 inclinometer; 15 | //Default SPI chip/slave select pin is D10 16 | 17 | // Need the following define for SAMD processors 18 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 19 | #define Serial SERIAL_PORT_USBVIRTUAL 20 | #endif 21 | 22 | int16_t AngX, AngY, AngZ, AccX, AccY, AccZ, STO, TEMP; 23 | uint16_t StatusSum, WHOAMI; 24 | long int n = 0; 25 | long int startmillis = 0; 26 | 27 | void setup() { 28 | Serial.begin(9600); 29 | delay(2000); //SAMD boards may need a long time to init SerialUSB 30 | Serial.println("Reading Raw register values from SCL3300 Inclinometer"); 31 | Serial.println("We use FastReadMode in 1 second bursts."); 32 | if (inclinometer.begin() == false) { 33 | Serial.println("Murata SCL3300 inclinometer not connected."); 34 | while(1); //Freeze 35 | } 36 | } 37 | 38 | void loop() { 39 | n = 0; 40 | inclinometer.setFastReadMode(); 41 | startmillis = millis(); 42 | while (millis() - startmillis < 1000) { 43 | if (inclinometer.available()) { //Get next block of data from sensor 44 | n++; 45 | // Read raw binary data 46 | AngX = inclinometer.sclData.AngX; 47 | AngY = inclinometer.sclData.AngY; 48 | AngZ = inclinometer.sclData.AngZ; 49 | AccX = inclinometer.sclData.AccX; 50 | AccY = inclinometer.sclData.AccY; 51 | AccZ = inclinometer.sclData.AccZ; 52 | STO = inclinometer.sclData.STO; 53 | WHOAMI = inclinometer.sclData.WHOAMI; 54 | TEMP = inclinometer.sclData.TEMP; 55 | StatusSum = inclinometer.sclData.StatusSum; 56 | } else inclinometer.reset(); 57 | } 58 | inclinometer.stopFastReadMode(); 59 | Serial.print("Iterations per second: "); 60 | Serial.println(n); 61 | } -------------------------------------------------------------------------------- /examples/Example7_FastReadModeContinuous/Example7_FastReadModeContinuous.ino: -------------------------------------------------------------------------------- 1 | /* Fast Read Sensor Mode for Murata SCL3300 Inclinometer 2 | * Version 3.2.0 - September 3, 2021 3 | * Example7_FastReadModeContinuous 4 | * Warning: Using Fast Read Mode in the library works by keeping the 5 | * SPI connection continuously open. This may or may not affect 6 | * the behavior of other hardware interactions, depending on the 7 | * sketch design. Fast Read Mode is considered an advanced use case, 8 | * and not recommended for the beginner. 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | SCL3300 inclinometer; 15 | //Default SPI chip/slave select pin is D10 16 | 17 | // Need the following define for SAMD processors 18 | #if defined (ARDUINO_ARCH_SAMD) 19 | #define Serial SerialUSB 20 | #endif 21 | 22 | int16_t AngX, AngY, AngZ, AccX, AccY, AccZ, STO, TEMP; 23 | uint16_t StatusSum, WHOAMI; 24 | long int n = 0; 25 | long int startmillis = 0; 26 | 27 | void setup() { 28 | Serial.begin(9600); 29 | delay(2000); //SAMD boards may need a long time to init SerialUSB 30 | Serial.println("Reading Raw register values from SCL3300 Inclinometer"); 31 | Serial.println("We use FastReadMode continuously."); 32 | if (inclinometer.begin() == false) { 33 | Serial.println("Murata SCL3300 inclinometer not connected."); 34 | while(1); //Freeze 35 | } 36 | inclinometer.setFastReadMode(); 37 | } 38 | 39 | void loop() { 40 | startmillis = millis(); 41 | n = 0; 42 | while (millis() - startmillis < 1000) { 43 | if (inclinometer.available()) { //Get next block of data from sensor 44 | n++; 45 | // Read raw binary data 46 | AngX = inclinometer.sclData.AngX; 47 | AngY = inclinometer.sclData.AngY; 48 | AngZ = inclinometer.sclData.AngZ; 49 | AccX = inclinometer.sclData.AccX; 50 | AccY = inclinometer.sclData.AccY; 51 | AccZ = inclinometer.sclData.AccZ; 52 | STO = inclinometer.sclData.STO; 53 | WHOAMI = inclinometer.sclData.WHOAMI; 54 | TEMP = inclinometer.sclData.TEMP; 55 | StatusSum = inclinometer.sclData.StatusSum; 56 | } else inclinometer.reset(); 57 | } 58 | Serial.print("Iterations per second: "); 59 | Serial.println(n); 60 | } -------------------------------------------------------------------------------- /examples/Example8_TwoSensors/Example8_TwoSensors.ino: -------------------------------------------------------------------------------- 1 | /* Read Tilt angles from Two Murata SCL3300 Inclinometers 2 | * Version 3.2.0 - September 3, 2021 3 | * Example8_TwoSensors 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometerA, inclinometerB; 10 | //First SPI chip (A) select pin is D10 11 | //Second SPI chip (B) select pin is D9 12 | 13 | // Need the following define for SAMD processors 14 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 15 | #define Serial SERIAL_PORT_USBVIRTUAL 16 | #endif 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | delay(2000); //SAMD boards may need a long time to init SerialUSB 21 | Serial.println("Reading basic Tilt Level Offset values from two SCL3300 Inclinometers"); 22 | 23 | if (inclinometerA.begin(10) == false) { 24 | Serial.println("Murata SCL3300 inclinometer A not connected."); 25 | while(1); //Freeze 26 | } 27 | if (inclinometerB.begin(9) == false) { 28 | Serial.println("Murata SCL3300 inclinometer B not connected."); 29 | while(1); //Freeze 30 | } 31 | } 32 | 33 | void loop() { 34 | if (inclinometerA.available()) { //Get next block of data from sensor 35 | Serial.print("Dev A: X Tilt: "); 36 | Serial.print(inclinometerA.getTiltLevelOffsetAngleX()); 37 | Serial.print("\t"); 38 | Serial.print("Y Tilt: "); 39 | Serial.print(inclinometerA.getTiltLevelOffsetAngleY()); 40 | Serial.print("\t"); 41 | Serial.print("Z Tilt: "); 42 | Serial.println(inclinometerA.getTiltLevelOffsetAngleZ()); 43 | } else inclinometerA.reset(); 44 | 45 | if (inclinometerB.available()) { //Get next block of data from sensor 46 | Serial.print("Dev B: X Tilt: "); 47 | Serial.print(inclinometerB.getTiltLevelOffsetAngleX()); 48 | Serial.print("\t"); 49 | Serial.print("Y Tilt: "); 50 | Serial.print(inclinometerB.getTiltLevelOffsetAngleY()); 51 | Serial.print("\t"); 52 | Serial.print("Z Tilt: "); 53 | Serial.println(inclinometerB.getTiltLevelOffsetAngleZ()); 54 | } else inclinometerB.reset(); 55 | delay(100); //Allow a little time to see the output 56 | } 57 | -------------------------------------------------------------------------------- /examples/Example9_AlternateSPI/Example9_AlternateSPI.ino: -------------------------------------------------------------------------------- 1 | /* Alternate SPI interface used to Read Tilt angles from Murata SCL3300 Inclinometer 2 | * Version 3.3.0 - September 13, 2021 3 | * Example9_AlternateSPI 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | SCL3300 inclinometer; 10 | 11 | // Need the following define for SAMD processors 12 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 13 | #define Serial SERIAL_PORT_USBVIRTUAL 14 | #endif 15 | 16 | void setup() { 17 | Serial.begin(9600); 18 | delay(2000); //SAMD boards may need a long time to init SerialUSB 19 | Serial.println("Define a specific SPI interface for the SCL3300 Inclinometer"); 20 | 21 | // Change the begin() parameters here, as needed, to reference the SPI 22 | // interface being used for the SCL3300 inclinometer. 23 | // The default Arduino interface is "SPI", and is shown here 24 | if (inclinometer.begin(SPI, 10) == false) { 25 | Serial.println("Murata SCL3300 inclinometer not connected."); 26 | while(1); //Freeze 27 | } else 28 | Serial.println("Murata SCL3300 inclinometer is connected."); 29 | } 30 | 31 | void loop() { 32 | if (inclinometer.isConnected()) { 33 | Serial.println("Inclinometer is still alive..."); 34 | } else { 35 | Serial.println("Inclinometer error detected..."); 36 | delay(1000); 37 | } 38 | if (inclinometer.available()) { //Get next block of data from sensor 39 | Serial.print("Raw X Tilt: "); 40 | Serial.print(inclinometer.sclData.AngX); 41 | Serial.print("\t"); 42 | Serial.print("Y Tilt: "); 43 | Serial.print(inclinometer.sclData.AngY); 44 | Serial.print("\t"); 45 | Serial.print("Z Tilt: "); 46 | Serial.println(inclinometer.sclData.AngZ); 47 | Serial.print("Raw X Accel: "); 48 | Serial.print(inclinometer.sclData.AccX); 49 | Serial.print("\t"); 50 | Serial.print("Y Accel: "); 51 | Serial.print(inclinometer.sclData.AccY); 52 | Serial.print("\t"); 53 | Serial.print("Z Accel: "); 54 | Serial.println(inclinometer.sclData.AccZ); 55 | Serial.print("SCL3300 STO register: "); 56 | Serial.print((inclinometer.sclData.STO >> 8) & 0xff, HEX); 57 | Serial.print("\t"); 58 | Serial.print("WHOAMI register: "); 59 | Serial.println(inclinometer.sclData.WHOAMI, HEX); 60 | Serial.print("Raw Temperature: "); 61 | Serial.println(inclinometer.sclData.TEMP); 62 | Serial.print("Serial Number Register: "); 63 | Serial.print(inclinometer.getSerialNumber()); 64 | Serial.print("B33"); 65 | Serial.print("\t"); 66 | Serial.print("SL3300 Status Summary Register: "); 67 | Serial.println(inclinometer.sclData.StatusSum, HEX); 68 | delay(1000); 69 | } else inclinometer.reset(); 70 | } 71 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ######################################################## 2 | # Syntax Coloring Map for SCL3300 Inclinometer Library # 3 | ######################################################## 4 | 5 | ####################################### 6 | # Class 7 | ####################################### 8 | 9 | SCL3300 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | reset KEYWORD2 17 | setMode KEYWORD2 18 | isConnected KEYWORD2 19 | available KEYWORD2 20 | setFastReadMode KEYWORD2 21 | stopFastReadMode KEYWORD2 22 | getCalculatedAngleX KEYWORD2 23 | getCalculatedAngleY KEYWORD2 24 | getCalculatedAngleZ KEYWORD2 25 | getTiltLevelOffsetAngleX KEYWORD2 26 | getTiltLevelOffsetAngleY KEYWORD2 27 | getTiltLevelOffsetAngleZ KEYWORD2 28 | getCalculatedAccelerometerX KEYWORD2 29 | getCalculatedAccelerometerY KEYWORD2 30 | getCalculatedAccelerometerZ KEYWORD2 31 | ReadDataBlock KEYWORD2 32 | getErrFlag1 KEYWORD2 33 | getErrFlag2 KEYWORD2 34 | getSerialNumber KEYWORD2 35 | getCalculatedTemperatureCelsius KEYWORD2 36 | getCalculatedTemperatureFarenheit KEYWORD2 37 | angle KEYWORD2 38 | acceleration KEYWORD2 39 | powerDownMode KEYWORD2 40 | WakeUp KEYWORD2 41 | 42 | 43 | ####################################### 44 | # Instances (KEYWORD2) 45 | ####################################### 46 | 47 | ####################################### 48 | # Constants (LITERAL1) 49 | ####################################### 50 | 51 | SPI_MODE LITERAL1 52 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SCL3300 2 | version=3.3.1 3 | author=David Armstrong 4 | maintainer=David Armstrong 5 | sentence=A library for SPI communication with the Murata SCL3300 Inclinometer sensor. 6 | paragraph=This sensor is a 3.3 volt device used to accurately measure tilt angles in three axes simultaneously. 7 | category=Sensors 8 | url=https://github.com/DavidArmstrong/SCL3300 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/SCL3300.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SCL3300.cpp 3 | SCL3300 Arduino Driver 4 | David Armstrong 5 | Version 3.3.0 - September 13, 2021 6 | https://github.com/DavidArmstrong/SCL3300 7 | 8 | Resources: 9 | Uses SPI.h for SPI operation 10 | 11 | Development environment specifics: 12 | Arduino IDE 1.8.15 13 | 14 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 15 | Please review the LICENSE.md file included with this example. 16 | Distributed as-is; no warranty is given. 17 | 18 | ******************************************************************************/ 19 | 20 | // include this library's description file 21 | #include "SCL3300.h" 22 | 23 | // Public Methods ////////////////////////////////////////////////////////// 24 | // Set the sensor mode to the number provided as modeNum. 25 | boolean SCL3300::setMode(int modeNum) { 26 | // Set Sensor mode - If not called, the default is mode 4, as set in header file 27 | // Only allowed values are: 1,2,3,4 28 | if (modeNum > 0 && modeNum < 5) { 29 | scl3300_mode = modeNum; 30 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 31 | transfer(modeCMD[scl3300_mode]); //Set mode on hardware 32 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 33 | if (crcerr || statuserr) { 34 | reset(); //Reset chip to fix the error state 35 | return false; //Let the caller know something went wrong 36 | } else return true; // Valid value, and chip was set to that mode 37 | } else 38 | return false; // Invalid value 39 | } 40 | 41 | // Current Version of begin() to initialize the library and the SCL3300 42 | boolean SCL3300::begin(void) { 43 | //This is the updated Version 3 begin function 44 | // Determine if we need to set up to use the default SPI interface, or some other one 45 | if (_spiPort == nullptr) _spiPort = &SPI; 46 | 47 | //Wait the required 1 ms before initializing the SCL3300 inclinomenter 48 | unsigned long startmillis = millis(); 49 | while (millis() - startmillis < 1) ; 50 | 51 | initSPI(); // Initialize SPI Library 52 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 53 | //Write SW Reset command 54 | transfer(SwtchBnk0); 55 | transfer(SWreset); 56 | startmillis = millis(); 57 | while (millis() - startmillis < 1) ; 58 | //Set measurement mode 59 | transfer(modeCMD[scl3300_mode]); //Set mode on hardware 60 | //We're good, so Enable angle outputs 61 | transfer(EnaAngOut); 62 | //The first response after reset is undefined and shall be discarded 63 | //wait 5 ms to stablize 64 | startmillis = millis(); 65 | while (millis() - startmillis < 100) ; 66 | 67 | //Read Status to clear the status summary 68 | transfer(RdStatSum); 69 | transfer(RdStatSum); //Again, due to off-response protocol used 70 | transfer(RdStatSum); //And now we can get the real status 71 | 72 | //Read the WHOAMI register 73 | transfer(RdWHOAMI); 74 | //And again 75 | transfer(RdWHOAMI); 76 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 77 | //We now wait until the end of begin() to report if an error occurred 78 | if (crcerr || statuserr) return false; 79 | // Once everything is initialized, return a known expected value 80 | // The WHOAMI command should give an 8 bit value of 0xc1 81 | return (SCL3300_DATA == 0xc1); //Let the caller know if this worked 82 | } 83 | 84 | // Set up the SPI communication with the SCL3300 with provided Chip Select pin number, and provided SPI port 85 | boolean SCL3300::begin(SPIClass &spiPort, uint8_t csPin) { 86 | scl3300_csPin = csPin; 87 | _spiPort = &spiPort; //Grab the port the user wants us to use 88 | return begin(); 89 | } // begin 90 | 91 | // Set up the SPI communication with the SCL3300 with provided Chip Select pin number 92 | boolean SCL3300::begin(uint8_t csPin) { 93 | scl3300_csPin = csPin; 94 | _spiPort = &SPI; // With this call, we do the default SPI interface 95 | return begin(); 96 | } // begin 97 | 98 | //Check to validate that the sensor is still reachable and ready to provide data 99 | boolean SCL3300::isConnected() { 100 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 101 | transfer(SwtchBnk0); 102 | //Read the WHOAMI register 103 | transfer(RdWHOAMI); 104 | //And again 105 | transfer(RdWHOAMI); 106 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 107 | if (crcerr || statuserr) return false; 108 | // Once everything is initialized, return a known expected value 109 | // The WHOAMI command should give an 8 bit value of 0xc1 110 | return (SCL3300_DATA == 0xc1); //Let the caller know if this worked 111 | } 112 | 113 | //Read all the sensor data together to keep it consistent 114 | //This is required according to the datasheet 115 | boolean SCL3300::available(void) { 116 | //Version 3 of this function 117 | boolean errorflag = false; 118 | //Read all Sensor Data, as per Datasheet requirements 119 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 120 | transfer(SwtchBnk0); 121 | transfer(RdAccX); 122 | if (crcerr || statuserr) errorflag = true; 123 | transfer(RdAccY); 124 | if (crcerr || statuserr) errorflag = true; 125 | sclData.AccX = SCL3300_DATA; 126 | transfer(RdAccZ); 127 | if (crcerr || statuserr) errorflag = true; 128 | sclData.AccY = SCL3300_DATA; 129 | transfer(RdSTO); 130 | if (crcerr || statuserr) errorflag = true; 131 | sclData.AccZ = SCL3300_DATA; 132 | transfer(RdTemp); 133 | if (crcerr || statuserr) errorflag = true; 134 | sclData.STO = SCL3300_DATA; 135 | transfer(RdAngX); 136 | if (crcerr || statuserr) errorflag = true; 137 | sclData.TEMP = SCL3300_DATA; 138 | transfer(RdAngY); 139 | if (crcerr || statuserr) errorflag = true; 140 | sclData.AngX = SCL3300_DATA; 141 | transfer(RdAngZ); 142 | if (crcerr || statuserr) errorflag = true; 143 | sclData.AngY = SCL3300_DATA; 144 | transfer(RdStatSum); 145 | if (crcerr || statuserr) errorflag = true; 146 | sclData.AngZ = SCL3300_DATA; 147 | transfer(RdWHOAMI); 148 | if (crcerr || statuserr) errorflag = true; 149 | sclData.StatusSum = SCL3300_DATA; 150 | transfer(RdWHOAMI); 151 | if (crcerr || statuserr) errorflag = true; 152 | sclData.WHOAMI = SCL3300_DATA; 153 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 154 | if (errorflag) return false; //Inform caller that something went wrong 155 | // The WHOAMI command should give an 8 bit value of 0xc1 156 | return (SCL3300_DATA == 0xc1); //Let the caller know this worked 157 | } 158 | 159 | /* Set SCL3300 library into Fast Read Mode 160 | * Warning: Using Fast Read Mode in the library works by keeping the 161 | * SPI connection continuously open. This may or may not affect 162 | * the behavior of other hardware interactions, depending on the 163 | * sketch design. Fast Read Mode is considered an advanced use case, 164 | * and not recommended for the beginner. 165 | */ 166 | void SCL3300::setFastReadMode() { 167 | setFastRead = true; 168 | beginTransmission(); //Set up this SPI port/bus 169 | begin(); //Re-init chip 170 | } 171 | 172 | /* Stop Fast Read Mode 173 | * Warning: Using Fast Read Mode in the library works by keeping the 174 | * SPI connection continuously open. This may or may not affect 175 | * the behavior of other hardware interactions, depending on the 176 | * sketch design. Fast Read Mode is considered an advanced use case, 177 | * and not recommended for the beginner. 178 | */ 179 | void SCL3300::stopFastReadMode() { 180 | setFastRead = false; 181 | endTransmission(); //Close connection to SPI port/bus 182 | begin(); //Re-init chip 183 | } 184 | 185 | //Return the calculated X axis tilt angle in degrees 186 | double SCL3300::getCalculatedAngleX() { 187 | double tempX = angle(sclData.AngX); 188 | if (tempX < 0.) tempX += 360.; 189 | return tempX; 190 | } 191 | 192 | //Return the calculated Y axis tilt angle in degrees 193 | double SCL3300::getCalculatedAngleY() { 194 | double tempY = angle(sclData.AngY); 195 | if (tempY < 0.) tempY += 360.; 196 | return tempY; 197 | } 198 | 199 | //Return the calculated Z axis tilt angle in degrees 200 | double SCL3300::getCalculatedAngleZ() { 201 | double tempZ = angle(sclData.AngZ); 202 | if (tempZ < 0.) tempZ += 360.; 203 | return tempZ; 204 | } 205 | 206 | //Return the calculated X axis offset tilt angle in degrees 207 | double SCL3300::getTiltLevelOffsetAngleX() { 208 | return angle(sclData.AngX); 209 | } 210 | 211 | //Return the calculated Y axis offset tilt angle in degrees 212 | double SCL3300::getTiltLevelOffsetAngleY() { 213 | return angle(sclData.AngY); 214 | } 215 | 216 | //Return the calculated Z axis offset tilt angle in degrees 217 | double SCL3300::getTiltLevelOffsetAngleZ() { 218 | return angle(sclData.AngZ); 219 | } 220 | 221 | //Return the calculated X axis accelerometer value in units of 'g' 222 | double SCL3300::getCalculatedAccelerometerX(void) { 223 | return acceleration(sclData.AccX); 224 | } 225 | 226 | //Return the calculated Y axis accelerometer value in units of 'g' 227 | double SCL3300::getCalculatedAccelerometerY(void) { 228 | return acceleration(sclData.AccY); 229 | } 230 | 231 | //Return the calculated Z axis accelerometer value in units of 'g' 232 | double SCL3300::getCalculatedAccelerometerZ(void) { 233 | return acceleration(sclData.AccZ); 234 | } 235 | 236 | //Return value of Error Flag 1 register 237 | uint16_t SCL3300::getErrFlag1(void) { 238 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 239 | transfer(SwtchBnk0); 240 | transfer(RdErrFlg1); 241 | transfer(RdErrFlg1); 242 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 243 | //Since we are fetching the Error Flag 1 value, we want to return what we got 244 | //to the caller, regardless of whether or not there was an error 245 | //if (crcerr || statuserr) return ((uint16_t)(SCL3300_CMD) & 0xff); //check CRC and RS bits 246 | return SCL3300_DATA; 247 | } 248 | 249 | //Return value of Error Flag 2 register 250 | uint16_t SCL3300::getErrFlag2(void) { 251 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 252 | transfer(SwtchBnk0); 253 | transfer(RdErrFlg2); 254 | transfer(RdErrFlg2); 255 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 256 | //Since we are fetching the Error Flag 2 value, we want to return what we got 257 | //to the caller, regardless of whether or not there was an error 258 | //if (crcerr || statuserr) return ((uint16_t)(SCL3300_CMD) & 0xff); //check CRC and RS bits 259 | return SCL3300_DATA; 260 | } 261 | 262 | // Read the sensor Serial Number as created by the manufacturer 263 | unsigned long SCL3300::getSerialNumber(void) { 264 | //Return Device Serial number 265 | boolean errorflag = false; 266 | unsigned long serialNum = 0; 267 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 268 | transfer(SwtchBnk1); 269 | if (crcerr || statuserr) errorflag = true; 270 | transfer(RdSer1); 271 | if (crcerr || statuserr) errorflag = true; 272 | transfer(RdSer2); 273 | serialNum = SCL3300_DATA; 274 | if (crcerr || statuserr) errorflag = true; 275 | transfer(SwtchBnk0); 276 | serialNum = ((unsigned long)SCL3300_DATA << 16) | serialNum; 277 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 278 | //We wait until now to return an error code 279 | //In this case we send a 0 since a real serial number will never be 0 280 | if (crcerr || statuserr || errorflag) return 0; 281 | return serialNum; 282 | } 283 | 284 | // Place the sensor in a Powered Down mode to save power 285 | uint16_t SCL3300::powerDownMode(void) { 286 | //Software power down of sensor 287 | if (!setFastRead) beginTransmission(); //Set up this SPI port/bus 288 | transfer(SwtchBnk0); 289 | transfer(SetPwrDwn); 290 | endTransmission(); //Let go of SPI port/bus 291 | //Since an error is non-zero, we will return 0 if there was no error 292 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits 293 | return 0; 294 | } 295 | 296 | // Revive the sensor from a power down mode so we can start getting data again 297 | uint16_t SCL3300::WakeMeUp(void) { 298 | //Software Wake Up of sensor 299 | beginTransmission(); //Set up this SPI port/bus 300 | transfer(WakeUp); 301 | if (!setFastRead) endTransmission(); //Let go of SPI port/bus 302 | //Since an error is non-zero, we will return 0 if there was no error 303 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits 304 | return 0; 305 | } 306 | 307 | // Hardware reset of the sensor electronics 308 | uint16_t SCL3300::reset(void) { 309 | //Software reset of sensor 310 | //beginTransmission(); //Set up this SPI port/bus 311 | //transfer(SwtchBnk0); 312 | //transfer(SWreset); 313 | //endTransmission(); //Let go of SPI port/bus 314 | //we have to call begin() to set up the SCL3300 to the same state as before it was reset 315 | begin(); //Re-init chip 316 | //Since an error is non-zero, we will return 0 if there was no error 317 | if (crcerr || statuserr) return (uint16_t)(SCL3300_CMD & 0xff); //check CRC and RS bits 318 | return 0; 319 | } 320 | 321 | // Routine to get temperature in degrees Celsius 322 | double SCL3300::getCalculatedTemperatureCelsius(void) { 323 | // Return calculated temperature in degrees C 324 | double Temperature = -273. + (sclData.TEMP / 18.9); 325 | return Temperature; 326 | } 327 | 328 | // Routine to get temperature in degrees Farenheit 329 | double SCL3300::getCalculatedTemperatureFarenheit(void) { 330 | // Return calculated temperature in degrees F 331 | double Temperature = -273. + (sclData.TEMP / 18.9); 332 | Temperature = (Temperature * 9./5.) + 32.; 333 | return Temperature; 334 | } 335 | 336 | //Convert raw angle value to degrees tilt 337 | double SCL3300::angle(int16_t SCL3300_ANG) { //two's complement value expected 338 | // Return Angle in degrees 339 | double Angle = (SCL3300_ANG / 16384.) * 90.; // 16384 = 2^14 340 | return Angle; 341 | } 342 | 343 | //Convert raw accelerometer value to g's of acceleration 344 | double SCL3300::acceleration(int16_t SCL3300_ACC) { //two's complement value expected 345 | // Return acceleration in g 346 | if (scl3300_mode == 1) return (double)SCL3300_ACC / 6000.; 347 | if (scl3300_mode == 2) return (double)SCL3300_ACC / 3000.; 348 | if (scl3300_mode == 3) return (double)SCL3300_ACC / 12000.; 349 | if (scl3300_mode == 4) return (double)SCL3300_ACC / 12000.; 350 | return (double)SCL3300_ACC / 12000.; //Default should never be reached 351 | } 352 | 353 | //private functions for serial transmission 354 | // Begin SPI bus transmission to the device 355 | void SCL3300::beginTransmission() { 356 | _spiPort->beginTransaction(spiSettings); 357 | } //beginTransmission 358 | 359 | // End SPI bus transmission to the device 360 | void SCL3300::endTransmission() { 361 | // take the chip/slave select high to de-select: 362 | digitalWrite(scl3300_csPin, HIGH); 363 | _spiPort->endTransaction(); 364 | unsigned long startmillis = millis(); 365 | while (millis() - startmillis < 1) ; //wait a bit 366 | } //endTransmission 367 | 368 | //Initialize the Arduino SPI library for the SCL3300 hardware 369 | void SCL3300::initSPI() { 370 | //Initialize the Arduino SPI library for the SCL3300 hardware 371 | _spiPort->begin(); 372 | // Maximum SPI frequency is 2 MHz - 4 MHz to achieve the best performance 373 | // initialize the chip select pin: 374 | pinMode(scl3300_csPin, OUTPUT); 375 | digitalWrite(scl3300_csPin, HIGH); 376 | // Data is read and written MSb first. 377 | // Data is captured on rising edge of clock (CPHA = 0) 378 | // Data is propagated on the falling edge (MISO line) of the SCK. (CPOL = 0) 379 | } 380 | 381 | // The following is taken directly from the Murata SCL3300 datasheet 382 | // Calculate CRC for 24 MSB's of the 32 bit dword 383 | // (8 LSB's are the CRC field and are not included in CRC calculation) 384 | uint8_t SCL3300::CalculateCRC(uint32_t Data) 385 | { 386 | uint8_t BitIndex; 387 | uint8_t BitValue; 388 | uint8_t SCL3300_CRC; 389 | 390 | SCL3300_CRC = 0xFF; 391 | for (BitIndex = 31; BitIndex > 7; BitIndex--) { 392 | BitValue = (uint8_t)((Data >> BitIndex) & 0x01); 393 | SCL3300_CRC = CRC8(BitValue, SCL3300_CRC); 394 | } 395 | SCL3300_CRC = (uint8_t)~SCL3300_CRC; 396 | return SCL3300_CRC; 397 | } 398 | uint8_t SCL3300::CRC8(uint8_t BitValue, uint8_t SCL3300_CRC) 399 | { 400 | uint8_t Temp; 401 | Temp = (uint8_t)(SCL3300_CRC & 0x80); 402 | if (BitValue == 0x01) { 403 | Temp ^= 0x80; 404 | } 405 | SCL3300_CRC <<= 1; 406 | if (Temp > 0) { 407 | SCL3300_CRC ^= 0x1D; 408 | } 409 | return SCL3300_CRC; 410 | } 411 | 412 | // Routine to transfer a 32-bit integer to the SCL3300, and return the 32-bit data read 413 | unsigned long SCL3300::transfer(unsigned long value) { 414 | FourByte dataorig; 415 | unsigned long startmicros; 416 | 417 | dataorig.bit32 = value; //Allow 32 bit value to be sent 8 bits at a time 418 | #ifdef debug_scl3300 419 | Serial_SCL.print(dataorig.bit32, HEX); 420 | Serial_SCL.print(" "); 421 | for (int j = 3; j >= 0; j--) { 422 | Serial_SCL.print(dataorig.bit8[j], HEX); 423 | Serial_SCL.print(" "); 424 | } 425 | #endif 426 | //Must allow at least 10 uSec between SPI transfers 427 | //The datasheet shows the CS line must be high during this time 428 | if (!setFastRead) startmicros = micros(); 429 | //while ((micros() - startmicros < 10) && (micros() > 10)) ; 430 | if (!setFastRead) while ((micros() - startmicros < 10)) ; 431 | 432 | digitalWrite(scl3300_csPin, LOW); //Now chip select can be enabled for the full 32 bit xfer 433 | SCL3300_DATA = 0; 434 | for (int i = 3; i >= 0; i--) { //Xfers are done MSB first 435 | dataorig.bit8[i] = _spiPort->transfer(dataorig.bit8[i]); 436 | } 437 | SCL3300_DATA = dataorig.bit8[1] + (dataorig.bit8[2] << 8); 438 | SCL3300_CRC = dataorig.bit8[0]; 439 | SCL3300_CMD = dataorig.bit8[3]; 440 | digitalWrite(scl3300_csPin, HIGH); //And we are done 441 | #ifdef debug_scl3300 442 | for (int i = 3; i >= 0; i--) { 443 | Serial_SCL.print(" "); 444 | Serial_SCL.print(dataorig.bit8[i], HEX); 445 | } 446 | Serial_SCL.print(" "); 447 | #endif 448 | if (SCL3300_CRC == CalculateCRC(dataorig.bit32)) 449 | crcerr = false; 450 | else 451 | crcerr = true; 452 | //check RS bits 453 | if ((SCL3300_CMD & 0x03) == 0x01) 454 | statuserr = false; 455 | else 456 | statuserr = true; 457 | #ifdef debug_scl3300 458 | Serial_SCL.print((SCL3300_CMD & 0x03)); 459 | Serial_SCL.print(" "); 460 | Serial_SCL.print(SCL3300_DATA, HEX); 461 | Serial_SCL.print(" "); 462 | Serial_SCL.print(SCL3300_CRC, HEX); 463 | Serial_SCL.print(" "); 464 | Serial_SCL.print(CalculateCRC(dataorig.bit32), HEX); 465 | Serial_SCL.print(" "); 466 | Serial_SCL.println(crcerr); 467 | #endif 468 | return dataorig.bit32; 469 | } 470 | -------------------------------------------------------------------------------- /src/SCL3300.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SCL3300.h 3 | SCL3300 Arduino Library Header File 4 | David Armstrong 5 | Version 3.2.0 - September 3, 2021 6 | https://github.com/DavidArmstrong/SCL3300 7 | 8 | Resources: 9 | Uses SPI.h for SPI operation 10 | 11 | Development environment specifics: 12 | Arduino IDE 1.8.9, 1.8.11, 1.8.12, 1.8.13, 1.8.15 13 | 14 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 15 | Please review the LICENSE.md file included with this example. 16 | Distributed as-is; no warranty is given. 17 | 18 | This file prototypes the SCL3300 class, as implemented in SCL3300.cpp 19 | 20 | ******************************************************************************/ 21 | 22 | // ensure this library description is only included once 23 | #ifndef __SCL3300_h 24 | #define __SCL3300_h 25 | 26 | // Uncomment the following line for debugging output 27 | //#define debug_scl3300 28 | 29 | // Need the following define for SAMD processors 30 | #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) 31 | #define Serial_SCL SERIAL_PORT_USBVIRTUAL 32 | #else 33 | #define Serial_SCL Serial 34 | #endif 35 | 36 | #include 37 | 38 | #if defined(ARDUINO) && ARDUINO >= 100 39 | #include "Arduino.h" 40 | #else 41 | #include "WProgram.h" 42 | #endif 43 | 44 | #include // SPI library is used for...SPI. 45 | 46 | #ifndef SCL3300_SPI_CLOCK 47 | #ifdef ARDUINO_ARCH_ESP32 48 | #define SCL3300_SPI_CLOCK 4000000 49 | #else 50 | #define SCL3300_SPI_CLOCK 4000000 51 | #endif 52 | #endif 53 | 54 | #ifndef SCL3300_SPI_MODE 55 | #define SCL3300_SPI_MODE SPI_MODE0 56 | #endif 57 | 58 | //Define allowed commands to SCL3300 inclinometer 59 | #define RdAccX 0x040000f7 60 | #define RdAccY 0x080000fd 61 | #define RdAccZ 0x0c0000fb 62 | #define RdSTO 0x100000e9 63 | #define EnaAngOut 0xb0001f6f 64 | #define RdAngX 0x240000c7 65 | #define RdAngY 0x280000cd 66 | #define RdAngZ 0x2c0000cb 67 | #define RdTemp 0x140000ef 68 | #define RdStatSum 0x180000e5 69 | #define RdErrFlg1 0x1c0000e3 70 | #define RdErrFlg2 0x200000c1 71 | #define RdCMD 0x340000df 72 | #define ChgMode1 0xb400001f 73 | #define ChgMode2 0xb4000102 74 | #define ChgMode3 0xb4000225 75 | #define ChgMode4 0xb4000338 76 | #define SetPwrDwn 0xb400046b 77 | #define WakeUp 0xb400001f 78 | #define SWreset 0xb4002098 79 | #define RdWHOAMI 0x40000091 80 | #define RdSer1 0x640000a7 81 | #define RdSer2 0x680000AD 82 | #define RdCurBank 0x7c0000b3 83 | #define SwtchBnk0 0xfc000073 84 | #define SwtchBnk1 0xfc00016e 85 | 86 | // Structure to hold raw sensor data 87 | // We need to populate all this every time we read a set of data 88 | struct SCL3300data { 89 | public: 90 | int16_t AccX; 91 | int16_t AccY; 92 | int16_t AccZ; 93 | int16_t STO; 94 | int16_t TEMP; 95 | int16_t AngX; 96 | int16_t AngY; 97 | int16_t AngZ; 98 | uint16_t StatusSum; 99 | uint16_t WHOAMI; 100 | }; 101 | 102 | // SCL3300 library interface description 103 | class SCL3300 { 104 | // user-accessible "public" interface 105 | public: 106 | SPISettings spiSettings{SCL3300_SPI_CLOCK, MSBFIRST, SCL3300_SPI_MODE}; 107 | 108 | SCL3300data sclData; 109 | boolean setMode(int mode); 110 | boolean begin(void); 111 | boolean begin(uint8_t csPin); 112 | boolean begin(SPIClass &spiPort, uint8_t csPin); 113 | //Functions to retrieve sensor data 114 | boolean isConnected(); 115 | boolean available(void); 116 | void setFastReadMode(); 117 | void stopFastReadMode(); 118 | double getCalculatedAngleX(void); 119 | double getCalculatedAngleY(void); 120 | double getCalculatedAngleZ(void); 121 | double getTiltLevelOffsetAngleX(void); 122 | double getTiltLevelOffsetAngleY(void); 123 | double getTiltLevelOffsetAngleZ(void); 124 | double getCalculatedAccelerometerX(void); 125 | double getCalculatedAccelerometerY(void); 126 | double getCalculatedAccelerometerZ(void); 127 | uint16_t getErrFlag1(void); 128 | uint16_t getErrFlag2(void); 129 | unsigned long getSerialNumber(void); 130 | double getCalculatedTemperatureCelsius(void); 131 | double getCalculatedTemperatureFarenheit(void); 132 | double angle(int16_t SCL3300_ANG); //two's complement value expected 133 | double acceleration(int16_t SCL3300_ACC); 134 | bool crcerr, statuserr; 135 | uint16_t powerDownMode(void); 136 | uint16_t WakeMeUp(void); 137 | uint16_t reset(void); 138 | 139 | // library-accessible "private" interface 140 | private: 141 | SPIClass *_spiPort = NULL; //The generic connection to user's chosen spi hardware 142 | 143 | uint8_t scl3300_csPin = 10; // Default SPI chip select pin 144 | uint8_t scl3300_mode = 4; // Default inclinometer mode 145 | uint8_t SCL3300_CMD, SCL3300_CRC; 146 | uint16_t SCL3300_DATA; 147 | double Temperature, X_angle, Y_angle, Z_angle; 148 | bool setFastRead = false; 149 | 150 | void initSPI(); 151 | void beginTransmission(); 152 | void endTransmission(); 153 | uint8_t CalculateCRC(uint32_t Data); 154 | uint8_t CRC8(uint8_t BitValue, uint8_t SCL3300_CRC); 155 | unsigned long transfer(unsigned long value); 156 | 157 | union FourByte { 158 | unsigned long bit32; 159 | unsigned int bit16[2]; 160 | unsigned char bit8[4]; 161 | }; 162 | unsigned long modeCMD[5] = { 0, ChgMode1, ChgMode2, ChgMode3, ChgMode4 }; 163 | }; 164 | #endif 165 | --------------------------------------------------------------------------------