diff --git a/Documentation/KX132/KX132-1211-Technical-Reference-Manual-Rev-1.0.pdf b/Documentation/KX132/KX132-1211-Technical-Reference-Manual-Rev-1.0.pdf deleted file mode 100644 index 40f7b63..0000000 Binary files a/Documentation/KX132/KX132-1211-Technical-Reference-Manual-Rev-1.0.pdf and /dev/null differ diff --git a/Documentation/KX132/kx132-1211-technical-reference-manual.pdf b/Documentation/KX132/kx132-1211-technical-reference-manual.pdf new file mode 100644 index 0000000..2c366f6 Binary files /dev/null and b/Documentation/KX132/kx132-1211-technical-reference-manual.pdf differ diff --git a/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-1.0.pdf b/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-1.0.pdf deleted file mode 100644 index 96db2d1..0000000 Binary files a/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-1.0.pdf and /dev/null differ diff --git a/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-4.0.pdf b/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-4.0.pdf new file mode 100644 index 0000000..12fccef Binary files /dev/null and b/Documentation/KX134/KX134-1211-Technical-Reference-Manual-Rev-4.0.pdf differ diff --git a/examples/Ex1_BasicReadings/Ex1_BasicReadings.ino b/examples/Ex1_BasicReadings/Ex1_BasicReadings.ino deleted file mode 100644 index 968892f..0000000 --- a/examples/Ex1_BasicReadings/Ex1_BasicReadings.ino +++ /dev/null @@ -1,72 +0,0 @@ -/********************************************************* -Author: Elias Santistevan @ SparkFun Electronics -Date: 5/2021 -Library repository can be found here: -https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library - -Basic example for reading back accelerometer values using I2C. - -This code is released under the [MIT License](http://opensource.org/licenses/MIT). - -Please review the LICENSE.md file included with this example. If you have any questions -or concerns with licensing, please contact techsupport@sparkfun.com. - -Distributed as-is; no warranty is given. -*******************************************************/ - -#include -#include "SparkFun_Qwiic_KX13X.h" - -QwiicKX132 kxAccel; -//QwiicKX134 kxAccel; // Uncomment this if using the KX134 - check your board - //if unsure. -outputData myData; // This will hold the accelerometer's output. - -void setup() { - - - while(!Serial){ - delay(50); - } - - Serial.begin(115200); - Serial.println("Welcome."); - - Wire.begin(); - if( !kxAccel.begin() ){ - Serial.println("Could not communicate with the the KX13X. Freezing."); - while(1); - } - else - Serial.println("Ready."); - - - - if( !kxAccel.initialize(DEFAULT_SETTINGS)){ // Loading default settings. - Serial.println("Could not initialize the chip."); - while(1); - } - else - Serial.println("Initialized..."); - - // kxAccel.setRange(KX132_RANGE16G); - // kxAccel.setRange(KX134_RANGE32G); // For a larger range uncomment - -} - -void loop() { - - myData = kxAccel.getAccelData(); - Serial.print("X: "); - Serial.print(myData.xData, 4); - Serial.print("g "); - Serial.print(" Y: "); - Serial.print(myData.yData, 4); - Serial.print("g "); - Serial.print(" Z: "); - Serial.print(myData.zData, 4); - Serial.println("g "); - - delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz - -} diff --git a/examples/Ex2_Interrupts/Ex2_Interrupts.ino b/examples/Ex2_Interrupts/Ex2_Interrupts.ino deleted file mode 100644 index 7502bfc..0000000 --- a/examples/Ex2_Interrupts/Ex2_Interrupts.ino +++ /dev/null @@ -1,79 +0,0 @@ -/********************************************************* -Author: Elias Santistevan @ SparkFun Electronics -Date: 5/2021 -Library repository can be found here: -https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library - -This example demonstrates the use of hardware interrupts for synchronizing -acceleromter data using I2C. - -This code is released under the [MIT License](http://opensource.org/licenses/MIT). - -Please review the LICENSE.md file included with this example. If you have any questions -or concerns with licensing, please contact techsupport@sparkfun.com. - -Distributed as-is; no warranty is given. -*******************************************************/ -#include -#include "SparkFun_Qwiic_KX13X.h" - -QwiicKX132 kxAccel; -//QwiicKX134 kxAccel; // Uncomment this if using the KX134 - check your board - //if unsure. - -outputData myData; // This will hold the accelerometer's output. -int dataReadyPin = 3; - -void setup() { - - pinMode(dataReadyPin, INPUT); - - while(!Serial){ - delay(50); - } - - Serial.begin(115200); - Serial.println("Welcome."); - - Wire.begin(); - if( !kxAccel.begin() ){ - Serial.println("Could not communicate with the the KX13X. Freezing."); - while(1); - } - else - Serial.println("Ready."); - - - - if( !kxAccel.initialize(INT_SETTINGS)){ // Load preset interrupt settings. - Serial.println("Could not initialize the chip. Freezing."); - while(1); - } - else - Serial.println("Initialized..."); - - // kxAccel.setRange(KX132_RANGE16G); - // kxAccel.setRange(KX134_RANGE32G); // For a larger range uncomment -} - -void loop() { - - if( digitalRead(dataReadyPin) == HIGH ){ // Wait for new data to be ready. - - myData = kxAccel.getAccelData(); - Serial.print("X: "); - Serial.print(myData.xData, 4); - Serial.print("g "); - Serial.print(" Y: "); - Serial.print(myData.yData, 4); - Serial.print("g "); - Serial.print(" Z: "); - Serial.print(myData.zData, 4); - Serial.println("g "); - - //kxAccel.clearInterrupt();// Because the data is being read in "burst" - //mode, meaning that all the acceleration data is being read at once, we don't - //need to clear the interrupt. - } - delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz -} diff --git a/examples/Ex3_SoftwareInterrupts/Ex3_SoftwareInterrupts.ino b/examples/Ex3_SoftwareInterrupts/Ex3_SoftwareInterrupts.ino deleted file mode 100644 index 04f6d8a..0000000 --- a/examples/Ex3_SoftwareInterrupts/Ex3_SoftwareInterrupts.ino +++ /dev/null @@ -1,76 +0,0 @@ -/********************************************************* -Author: Elias Santistevan @ SparkFun Electronics -Date: 5/2021 -Library repository can be found here: -https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library - -This example demonstrates the use of software interrupts for synchronizing -acceleromter data using I2C. - -This code is released under the [MIT License](http://opensource.org/licenses/MIT). - -Please review the LICENSE.md file included with this example. If you have any questions -or concerns with licensing, please contact techsupport@sparkfun.com. - -Distributed as-is; no warranty is given. -*******************************************************/ -#include -#include "SparkFun_Qwiic_KX13X.h" - -QwiicKX132 kxAccel; -//QwiicKX134 kxAccel; // Uncomment this if using the KX134 - check your board - //if unsure. -outputData myData; // This will hold the accelerometer's output. - -void setup() { - - while(!Serial){ - delay(50); - } - - Serial.begin(115200); - Serial.println("Welcome."); - - Wire.begin(); - if( !kxAccel.begin() ){ - Serial.println("Could not communicate with the the KX13X. Freezing."); - while(1); - } - else - Serial.println("Ready."); - - - - if( !kxAccel.initialize(SOFT_INT_SETTINGS)){ //Load preset software interrupt settings. - Serial.println("Could not initialize the chip. Freezing."); - while(1); - } - else - Serial.println("Initialized..."); - - // kxAccel.setRange(KX132_RANGE16G); - // kxAccel.setRange(KX134_RANGE32G); // For a larger range uncomment -} - -void loop() { - - - if( kxAccel.dataTrigger() ) { - Serial.println("Data Ready."); - // Interrupt is cleared on reading registers. - myData = kxAccel.getAccelData(); - Serial.print("X: "); - Serial.print(myData.xData, 4); - Serial.print("g "); - Serial.print(" Y: "); - Serial.print(myData.yData, 4); - Serial.print("g "); - Serial.print(" Z: "); - Serial.print(myData.zData, 4); - Serial.println("g "); - } - - - - delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz -} diff --git a/examples/Ex4_Buffer/Ex4_Buffer.ino b/examples/Ex4_Buffer/Ex4_Buffer.ino deleted file mode 100644 index b0ab240..0000000 --- a/examples/Ex4_Buffer/Ex4_Buffer.ino +++ /dev/null @@ -1,76 +0,0 @@ -/********************************************************* -Author: Elias Santistevan @ SparkFun Electronics -Date: 5/2021 -Library repository can be found here: -https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library - -This example routes the accelerometer data to the buffer and then reads it when -its full. - -This code is released under the [MIT License](http://opensource.org/licenses/MIT). - -Please review the LICENSE.md file included with this example. If you have any questions -or concerns with licensing, please contact techsupport@sparkfun.com. - -Distributed as-is; no warranty is given. -*******************************************************/ -#include -#include "SparkFun_Qwiic_KX13X.h" - -QwiicKX132 kxAccel; -//QwiicKX134 kxAccel; // Uncomment this if using the KX134 - check your board - //if unsure. -outputData myData; // This will hold the accelerometer's output. -int dataReadyPin = D1; - -void setup() { - - pinMode(dataReadyPin, INPUT); - - while(!Serial){ - delay(50); - } - - Serial.begin(115200); - Serial.println("Welcome."); - - Wire.begin(); - if( !kxAccel.begin() ){ - Serial.println("Could not communicate with the the KX13X. Freezing."); - while(1); - } - else - Serial.println("Ready."); - - if( !kxAccel.initialize(BUFFER_SETTINGS)){ //Load preset buffer settings. - Serial.println("Could not initialize the chip. Freezing."); - while(1); - } - else - Serial.println("Initialized..."); - - // kxAccel.setRange(KX132_RANGE16G); - // kxAccel.setRange(KX134_RANGE32G); // For a larger range uncomment - -} - -void loop() { - - - if( digitalRead(dataReadyPin) == HIGH ){ - - myData = kxAccel.getAccelData(); - Serial.print("X: "); - Serial.print(myData.xData, 4); - Serial.print("g "); - Serial.print(" Y: "); - Serial.print(myData.yData, 4); - Serial.print("g "); - Serial.print(" Z: "); - Serial.print(myData.zData, 4); - Serial.println("g "); - - } - - delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz -} diff --git a/examples/Ex5_BasicReadings_Spi/Ex5_BasicReadings_Spi.ino b/examples/Ex5_BasicReadings_Spi/Ex5_BasicReadings_Spi.ino deleted file mode 100644 index 718208b..0000000 --- a/examples/Ex5_BasicReadings_Spi/Ex5_BasicReadings_Spi.ino +++ /dev/null @@ -1,71 +0,0 @@ -/********************************************************* -Author: Elias Santistevan @ SparkFun Electronics -Date: 5/2021 -Library repository can be found here: -https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library - -This example routes the accelerometer data to the buffer and then reads it when -its full. - -This code is released under the [MIT License](http://opensource.org/licenses/MIT). - -Please review the LICENSE.md file included with this example. If you have any questions -or concerns with licensing, please contact techsupport@sparkfun.com. - -Distributed as-is; no warranty is given. -*******************************************************/ -#include -#include "SparkFun_Qwiic_KX13X.h" - -QwiicKX132 kxAccel; -//QwiicKX134 kxAccel; // Uncomment this if using the KX134 - check your board - //if unsure. -outputData myData; // This will hold the accelerometer's output. -int kxChipSelect = D1; - -void setup() { - - pinMode(kxChipSelect, OUTPUT); - digitalWrite(kxChipSelect, HIGH); - - Serial.begin(115200); - Serial.println("Welcome."); - - while(!Serial) - delay(50); - - SPI.begin(); - - if( !kxAccel.beginSPI(kxChipSelect) ){ - Serial.println("Could not communicate with the the KX13X. Freezing."); - while(1); - } - else - Serial.println("Ready."); - - if( !kxAccel.initialize(DEFAULT_SETTINGS)){ //Load preset buffer settings. - Serial.println("Could not initialize the chip. Freezing."); - while(1); - } - else - Serial.println("Initialized..."); - - //kxAccel.setRange(KX132_RANGE16G); - //kxAccel.setRange(KX134_RANGE32G); // For a larger range uncomment - -} - -void loop() -{ - - myData = kxAccel.getAccelData(); - Serial.print("X: "); - Serial.print(myData.xData, 4); - Serial.print(" Y: "); - Serial.print(myData.yData, 4); - Serial.print(" Z: "); - Serial.print(myData.zData, 4); - Serial.println(); - - delay(20); -} diff --git a/examples/example1_basic_readings/example1_basic_readings.ino b/examples/example1_basic_readings/example1_basic_readings.ino new file mode 100644 index 0000000..5606620 --- /dev/null +++ b/examples/example1_basic_readings/example1_basic_readings.ino @@ -0,0 +1,86 @@ +/* + example1-BasicReadings + + This example shows the basic settings and functions for retrieving accelerometer + data. + Please refer to the header file for more possible settings, found here: + ..\SparkFun_KX13X_Arduino_Library\src\sfe_kx13x_defs.h + + Written by Elias Santistevan @ SparkFun Electronics, October 2022 + + Product: + + https://www.sparkfun.com/products/17871 + + Repository: + + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library + + SparkFun code, firmware, and software is released under the MIT + License (http://opensource.org/licenses/MIT). +*/ + +#include +#include "SparkFun_KX13X.h" + +SparkFun_KX132 kxAccel; +// SparkFun_KX134 kxAccel; // For the KX134, uncomment this and comment line above + +outputData myData; // Struct for the accelerometer's data + +void setup() +{ + + Wire.begin(); + + Serial.begin(115200); + Serial.println("Welcome."); + + // Wait for the Serial monitor to be opened. + while(!Serial) + delay(50); + + + if( !kxAccel.begin() ) + { + Serial.println("Could not communicate with the the KX13X. Freezing."); + while(1); + } + + Serial.println("Ready."); + + if( kxAccel.softwareReset() ) + Serial.println("Reset."); + + // Many settings for KX13X can only be + // applied when the accelerometer is powered down. + // However there are many that can be changed "on-the-fly" + // check datasheet for more info, or the comments in the + // "...regs.h" file which specify which can be changed when. + kxAccel.enableAccel(false); + + kxAccel.setRange(0x18); // 16g Range + kxAccel.enableDataEngine(); // Enables the bit that indicates data is ready. + // kxAccel.setOutputDataRate(); // Default is 50Hz + kxAccel.enableAccel(); + + +} + +void loop() +{ + // Check if data is ready. + if( kxAccel.dataReady() ) + { + kxAccel.getAccelData(&myData); + Serial.print("X: "); + Serial.print(myData.xData, 4); + Serial.print(" Y: "); + Serial.print(myData.yData, 4); + Serial.print(" Z: "); + Serial.print(myData.zData, 4); + Serial.println(); + } + delay(20); // Delay should be 1/ODR (Output Data Rate), default is 1/50ODR + +} diff --git a/examples/example2_interrupts/example2_interrupts.ino b/examples/example2_interrupts/example2_interrupts.ino new file mode 100644 index 0000000..ccc17cc --- /dev/null +++ b/examples/example2_interrupts/example2_interrupts.ino @@ -0,0 +1,107 @@ +/* + example2-Interrupts + + This example shows how to route the data ready bit to either physical interrupt pin one and pin two. + + Please refer to the header file for more possible settings, found here: + ..\SparkFun_KX13X_Arduino_Library\src\sfe_kx13x_defs.h + + Written by Elias Santistevan @ SparkFun Electronics, October 2022 + + Product: + + https://www.sparkfun.com/products/17871 + + Repository: + + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library + + SparkFun code, firmware, and software is released under the MIT + License (http://opensource.org/licenses/MIT). +*/ + +#include +#include +#include "SparkFun_KX13X.h" + +SparkFun_KX132 kxAccel; +// SparkFun_KX134 kxAccel; // For the KX134, uncomment this and comment line above + +outputData myData; // Struct for the accelerometer's data +byte dataReadyPin = 2; // Change to fit your project. + +void setup() +{ + + Wire.begin(); + + Serial.begin(115200); + Serial.println("Welcome."); + + // Wait for the Serial monitor to be opened. + while(!Serial) + delay(50); + + + if( !kxAccel.begin() ) + { + Serial.println("Could not communicate with the the KX13X. Freezing."); + while(1); + } + + Serial.println("Ready."); + + // Reset the chip so that old settings don't apply to new setups. + if( kxAccel.softwareReset() ) + Serial.println("Reset."); + + // Many settings for KX13X can only be + // applied when the accelerometer is powered down. + // However there are many that can be changed "on-the-fly" + // check datasheet for more info, or the comments in the + // "...regs.h" file which specify which can be changed when. + kxAccel.enableAccel(false); + + kxAccel.enableDataEngine(); // Enables the bit that indicates data is ready. + kxAccel.enablePhysInterrupt(); // Enables interrupt pin 1 + kxAccel.routeHardwareInterrupt(0x10); // Routes the data ready bit to pin 1 + + // Routing Data Ready pin to interrupt pin 2. + //kxAccel.enablePhysInterrupt(true, 2); // Enables interrupt pin 2 + //kxAccel.routeHardwareInterrupt(0x10, 2); // Routes the data ready bit to pin 2 + + // This will change the interrupt behavior to latch instead of pulse + // In this case you'll need to release directly with clearInterrupt();. + //kxAccel.setLatchControl(); + + //kxAccel.setPinMode(); // Change interrupt to active HIGH + //kxAccel.setPulseWidth(); // Change the length of a pulsed (non latched) interrupt + + kxAccel.setRange(0x18); // 16g Range + //kxAccel.setOutputDataRate(); // Default is 400Hz + kxAccel.enableAccel(); + + +} + +void loop() +{ + + if( digitalRead(dataReadyPin) == HIGH ) // Check for data ready pin + { + kxAccel.getAccelData(&myData); + Serial.print("X: "); + Serial.print(myData.xData, 4); + Serial.print(" Y: "); + Serial.print(myData.yData, 4); + Serial.print(" Z: "); + Serial.print(myData.zData, 4); + Serial.println(); + + // If interrupt behavior has been changed to latch, use the + // following function to clear it after reading data. + //kxAccel.clearInterrupt(); + } + + delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz +} diff --git a/examples/example3_buffer/example3_buffer.ino b/examples/example3_buffer/example3_buffer.ino new file mode 100644 index 0000000..06dbf91 --- /dev/null +++ b/examples/example3_buffer/example3_buffer.ino @@ -0,0 +1,108 @@ +/* + example3-Buffer + + This example shows both how to setup the buffer but also how to route the buffer's + interrupt to a physical interrupt pin. + + Please refer to the header file for more possible settings, found here: + ..\SparkFun_KX13X_Arduino_Library\src\sfe_kx13x_defs.h + + Written by Elias Santistevan @ SparkFun Electronics, October 2022 + + Product: + + https://www.sparkfun.com/products/17871 + + Repository: + + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library + + SparkFun code, firmware, and software is released under the MIT + License (http://opensource.org/licenses/MIT). +*/ + +#include +#include "SparkFun_Qwiic_KX13X.h" + +SparkFun_KX132 kxAccel; +// SparkFun_KX134 kxAccel; // For the KX134, uncomment this and comment line above + +outputData myData; // Struct for the accelerometer's data +byte dataReadyPin = 2; // Change to fit your project. + +void setup() +{ + + Wire.begin(); + + Serial.begin(115200); + Serial.println("Welcome."); + + // Wait for the Serial monitor to be opened. + while(!Serial) + delay(50); + + + if( !kxAccel.begin() ) + { + Serial.println("Could not communicate with the the KX13X. Freezing."); + while(1); + } + + Serial.println("Ready."); + + // Reset the chip so that old settings don't apply to new setups. + if( kxAccel.softwareReset() ) + Serial.println("Reset."); + + // Many settings for KX13X can only be + // applied when the accelerometer is powered down. + // However there are many that can be changed "on-the-fly" + // check datasheet for more info, or the comments in the + // "...regs.h" file which specify which can be changed when. + kxAccel.enableAccel(false); + + kxAccel.enableBufferInt(); // Enables the Buffer interrupt + kxAccel.enablePhysInterrupt(); // Enables interrupt pin 1 + kxAccel.routeHardwareInterrupt(0x40); // Routes the data ready bit to pin 1 + + kxAccel.enableSampleBuffer(); // Enable buffer. + kxAccel.setBufferOperationMode(0x00); // Enable the buffer to be FIFO. + + // Additional Buffer Settings + + //uint8_t numSamples = 140; + //kxAccel.setBufferThreshold(numSamples); // Set the number of sample that can be stored in the buffer + + //kxAccel.setBufferResolution(); // Change sample resolution to 16 bit, 8 bit by default. + // This will change how many samples can be held in buffer. + + //kxAccel.clearBuffer(); // Clear the buffer + //kxAccel.getSampleLevel(); // Get the number of samples in the buffer. This number + // Changes depending on the resolution, see datasheet for more info. + + kxAccel.setRange(0x18); // 16g Range + //kxAccel.setOutputDataRate(); // Default is 50Hz + kxAccel.enableAccel(); + + +} + +void loop() +{ + + if( digitalRead(dataReadyPin) == HIGH ) // Check for data ready pin + { + kxAccel.getAccelData(&myData); + Serial.print("X: "); + Serial.print(myData.xData, 4); + Serial.print(" Y: "); + Serial.print(myData.yData, 4); + Serial.print(" Z: "); + Serial.print(myData.zData, 4); + Serial.println(); + + } + + delay(20); // Delay should be 1/ODR (Output Data Rate), default is 50Hz +} diff --git a/examples/example4_tap/example4_tap.ino b/examples/example4_tap/example4_tap.ino new file mode 100644 index 0000000..de0d7b5 --- /dev/null +++ b/examples/example4_tap/example4_tap.ino @@ -0,0 +1,87 @@ +/* + example6-tap + + This example shows the how to enable the tap interrupts. + + Please refer to the header file for more possible settings, found here: + ..\SparkFun_KX13X_Arduino_Library\src\sfe_kx13x_defs.h + + Written by Elias Santistevan @ SparkFun Electronics, October 2022 + + Product: + + https://www.sparkfun.com/products/17871 + + Repository: + + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library + + SparkFun code, firmware, and software is released under the MIT + License (http://opensource.org/licenses/MIT). +*/ + +#include +#include "SparkFun_KX13X.h" + +SparkFun_KX132 kxAccel; +// SparkFun_KX134 kxAccel; // For the KX134, uncomment this and comment line above + +byte direction = 0; + +void setup() +{ + + Wire.begin(); + + Serial.begin(115200); + Serial.println("Welcome."); + + // Wait for the Serial monitor to be opened. + while(!Serial) + delay(50); + + + if( !kxAccel.begin() ) + { + Serial.println("Could not communicate with the the KX13X. Freezing."); + while(1); + } + + Serial.println("Ready."); + + // Reset the chip so that old settings don't apply to new setups. + if( kxAccel.softwareReset() ) + Serial.println("Reset."); + + // Many settings for KX13X can only be + // applied when the accelerometer is powered down. + // However there are many that can be changed "on-the-fly" + // check datasheet for more info, or the comments in the + // "...regs.h" file which specify which can be changed when. + kxAccel.enableAccel(false); + + kxAccel.setRange(0x18); // 16g Range + kxAccel.enableTapEngine(); // Enable tap Engine + kxAccel.enableDirecTapInterupt(); // This enables checking the direction of the interrupt + //kxAccel.setTapDataRate(uint8_t rate); // Default is 400Hz + kxAccel.enableAccel(); + + +} + +void loop() +{ + // Check if tap was detected + if( kxAccel.tapDetected() ) + { + Serial.print("Tap Detected: "); + Serial.println(kxAccel.getDirection(), HEX); + kxAccel.clearInterrupt(); + } + + if( kxAccel.unknownTap() || kxAccel.doubleTapDetected() ) // These all share the same bit space + kxAccel.clearInterrupt(); + + delay(25); // Delay should be 1/ODR (Output Data Rate), default tap ODR is 400Hz + +} diff --git a/examples/example5_spi/example5_spi.ino b/examples/example5_spi/example5_spi.ino new file mode 100644 index 0000000..66a4eed --- /dev/null +++ b/examples/example5_spi/example5_spi.ino @@ -0,0 +1,92 @@ +/* + example5-BasicReadings-SPI + + This example shows the basic settings and functions for retrieving accelerometer + data using SPI. + Please refer to the header file for more possible settings, found here: + ..\SparkFun_KX13X_Arduino_Library\src\sfe_kx13x_defs.h + + Written by Elias Santistevan @ SparkFun Electronics, October 2022 + + Product: + + https://www.sparkfun.com/products/17871 + + Repository: + + https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library + + SparkFun code, firmware, and software is released under the MIT + License (http://opensource.org/licenses/MIT). +*/ + +#include +#include "SparkFun_KX13X.h" + +SparkFun_KX132_SPI kxAccel; +// SparkFun_KX134_SPI kxAccel; // For the KX134, uncomment this and comment line above + +outputData myData; // Struct for the accelerometer's data +byte chipSelect = 1; // Change to fit your project. + +void setup() +{ + + // Get the chip select pin ready. + pinMode(chipSelect, OUTPUT); + digitalWrite(chipSelect, HIGH); + + SPI.begin(); + + Serial.begin(115200); + Serial.println("Welcome."); + + // Wait for the Serial monitor to be opened. + while(!Serial) + delay(50); + + + if( !kxAccel.begin(chipSelect) ) + { + Serial.println("Could not communicate with the the KX13X. Freezing."); + while(1); + } + + Serial.println("Ready."); + + // Reset the chip so that old settings don't apply to new setups. + if( kxAccel.softwareReset() ) + Serial.println("Reset."); + + // Many settings for KX13X can only be + // applied when the accelerometer is powered down. + // However there are many that can be changed "on-the-fly" + // check datasheet for more info, or the comments in the + // "...regs.h" file which specify which can be changed when. + kxAccel.enableAccel(false); + + kxAccel.setRange(0x18); // 16g Range + kxAccel.enableDataEngine(); // Enables the bit that indicates data is ready. + // kxAccel.setOutputDataRate(); // Default is 50Hz + kxAccel.enableAccel(); + + +} + +void loop() +{ + // Check if data is ready. + if( kxAccel.dataReady() ) + { + kxAccel.getAccelData(&myData); + Serial.print("X: "); + Serial.print(myData.xData, 4); + Serial.print(" Y: "); + Serial.print(myData.yData, 4); + Serial.print(" Z: "); + Serial.print(myData.zData, 4); + Serial.println(); + } + delay(20); // Delay should be 1/ODR (Output Data Rate), default is 1/50ODR + +} diff --git a/library.properties b/library.properties index b0367fe..e444c4d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun KX13X Arduino Library -version=1.0.8 +version=2.0.0 author=SparkFun Electronics maintainer=Elias Santistevan @ SparkFun Electronics sentence=Communicates and configures the SparkFun KX132/KX134 Accelerometer. diff --git a/src/SparkFun_KX13X.h b/src/SparkFun_KX13X.h new file mode 100644 index 0000000..adaed18 --- /dev/null +++ b/src/SparkFun_KX13X.h @@ -0,0 +1,246 @@ +#pragma once +#include "SparkFun_Qwiic_KX13X.h" +#include +#include + +class SparkFun_KX132 : public QwDevKX132 +{ + + public: + + SparkFun_KX132() {}; + + /////////////////////////////////////////////////////////////////////// + // begin() + // + // This method is called to initialize the ISM330DHCX library and connect to + // the ISM330DHCX device. This method must be called before calling any other method + // that interacts with the device. + // + // This method follows the standard startup pattern in SparkFun Arduino + // libraries. + // + // Parameter Description + // --------- ---------------------------- + // wirePort optional. The Wire port. If not provided, the default port is used + // address optional. I2C Address. If not provided, the default address is used. + // retval true on success, false on startup failure + // + // This methond is overridden, implementing two versions. + // + // Version 1: + // User skips passing in an I2C object which then defaults to Wire. + bool begin(uint8_t deviceAddress = KX13X_ADDRESS_HIGH) + { + // Setup I2C object and pass into the superclass + setCommunicationBus(_i2cBus, deviceAddress); + + // Initialize the I2C buss class i.e. setup default Wire port + _i2cBus.init(); + + // Initialize the system - return results + return this->QwDevKX132::init(); + } + + //Version 2: + // User passes in an I2C object and an address (optional). + bool begin(TwoWire &wirePort, uint8_t deviceAddress = KX13X_ADDRESS_HIGH) + { + // Setup I2C object and pass into the superclass + setCommunicationBus(_i2cBus, deviceAddress); + + // Give the I2C port provided by the user to the I2C bus class. + _i2cBus.init(wirePort, true); + + // Initialize the system - return results + return this->QwDevKX132::init(); + } + + private: + + //I2C bus class + QwI2C _i2cBus; + +}; + +class SparkFun_KX132_SPI : public QwDevKX132 +{ + public: + + SparkFun_KX132_SPI() {}; + + /////////////////////////////////////////////////////////////////////// + // begin() + // + // This method is called to initialize the ISM330DHCX library and connect to + // the ISM330DHCX device. This method must be called before calling any other method + // that interacts with the device. + // + // This method follows the standard startup pattern in SparkFun Arduino + // libraries. + // + // Parameter Description + // --------- ---------------------------- + // spiPort optional. The SPI port. If not provided, the default port is used + // SPISettings optional. SPI "transaction" settings are need for every data transfer. + // Default used if not provided. + // Chip Select mandatory. The chip select pin ("CS") can't be guessed, so must be provided. + // retval true on success, false on startup failure + // + // This methond is overridden, implementing two versions. + // + // Version 1: + // User skips passing in an SPI object which then defaults to SPI. + + bool begin(uint8_t cs) + { + // Setup a SPI object and pass into the superclass + setCommunicationBus(_spiBus); + + // Initialize the SPI bus class with the chip select pin, SPI port defaults to SPI, + // and SPI settings are set to class defaults. + _spiBus.init(cs, true); + + // Initialize the system - return results + return this->QwDevKX132::init(); + } + + bool begin(SPIClass &spiPort, SPISettings kxSettings, uint8_t cs) + { + // Setup a SPI object and pass into the superclass + setCommunicationBus(_spiBus); + + // Initialize the SPI bus class with provided SPI port, SPI setttings, and chip select pin. + _spiBus.init(spiPort, kxSettings, cs, true); + + // Initialize the system - return results + return this->QwDevKX132::init(); + } + + private: + + // SPI bus class + SfeSPI _spiBus; + +}; + +class SparkFun_KX134 : public QwDevKX134 +{ + + public: + + SparkFun_KX134() {}; + + /////////////////////////////////////////////////////////////////////// + // begin() + // + // This method is called to initialize the ISM330DHCX library and connect to + // the ISM330DHCX device. This method must be called before calling any other method + // that interacts with the device. + // + // This method follows the standard startup pattern in SparkFun Arduino + // libraries. + // + // Parameter Description + // --------- ---------------------------- + // wirePort optional. The Wire port. If not provided, the default port is used + // address optional. I2C Address. If not provided, the default address is used. + // retval true on success, false on startup failure + // + // This methond is overridden, implementing two versions. + // + // Version 1: + // User skips passing in an I2C object which then defaults to Wire. + bool begin(uint8_t deviceAddress = KX13X_ADDRESS_HIGH) + { + // Setup I2C object and pass into the superclass + setCommunicationBus(_i2cBus, deviceAddress); + + // Initialize the I2C buss class i.e. setup default Wire port + _i2cBus.init(); + + // Initialize the system - return results + return this->QwDevKX134::init(); + } + + //Version 2: + // User passes in an I2C object and an address (optional). + bool begin(TwoWire &wirePort, uint8_t deviceAddress = KX13X_ADDRESS_HIGH) + { + // Setup I2C object and pass into the superclass + setCommunicationBus(_i2cBus, deviceAddress); + + // Give the I2C port provided by the user to the I2C bus class. + _i2cBus.init(wirePort, true); + + // Initialize the system - return results + return this->QwDevKX134::init(); + } + + private: + + //I2C bus class + QwI2C _i2cBus; + +}; + +class SparkFun_KX134_SPI : public QwDevKX134 +{ + public: + + SparkFun_KX134_SPI() {}; + + /////////////////////////////////////////////////////////////////////// + // begin() + // + // This method is called to initialize the ISM330DHCX library and connect to + // the ISM330DHCX device. This method must be called before calling any other method + // that interacts with the device. + // + // This method follows the standard startup pattern in SparkFun Arduino + // libraries. + // + // Parameter Description + // --------- ---------------------------- + // spiPort optional. The SPI port. If not provided, the default port is used + // SPISettings optional. SPI "transaction" settings are need for every data transfer. + // Default used if not provided. + // Chip Select mandatory. The chip select pin ("CS") can't be guessed, so must be provided. + // retval true on success, false on startup failure + // + // This methond is overridden, implementing two versions. + // + // Version 1: + // User skips passing in an SPI object which then defaults to SPI. + + bool begin(uint8_t cs) + { + // Setup a SPI object and pass into the superclass + setCommunicationBus(_spiBus); + + // Initialize the SPI bus class with the chip select pin, SPI port defaults to SPI, + // and SPI settings are set to class defaults. + _spiBus.init(cs, true); + + // Initialize the system - return results + return this->QwDevKX134::init(); + } + + bool begin(SPIClass &spiPort, SPISettings kxSettings, uint8_t cs) + { + // Setup a SPI object and pass into the superclass + setCommunicationBus(_spiBus); + + // Initialize the SPI bus class with provided SPI port, SPI setttings, and chip select pin. + _spiBus.init(spiPort, kxSettings, cs, true); + + // Initialize the system - return results + return this->QwDevKX134::init(); + } + + private: + + // SPI bus class + SfeSPI _spiBus; + +}; diff --git a/src/SparkFun_KX13X_regs.h b/src/SparkFun_KX13X_regs.h new file mode 100644 index 0000000..2a5388c --- /dev/null +++ b/src/SparkFun_KX13X_regs.h @@ -0,0 +1,778 @@ + +#define SFE_KX13X_MAN_ID 0x00// Retuns "KION" in ASCII + // +typedef struct +{ + uint8_t man_id : 8; +} sfe_kx13x_man_id_t; + +#define SFE_KX13X_PART_ID 0x01// Retuns "KION" in ASCII +typedef struct +{ + uint8_t part_id : 8; +} sfe_kx13x_part_id_t; + +#define SFE_KX13X_XADP_L 0x02 +typedef struct +{ + uint8_t xadp_l : 8; +} sfe_kx13x_xadp_l_t; + +#define SFE_KX13X_XADP_H 0x03 +typedef struct +{ + uint8_t xadp_h : 8; +} sfe_kx13x_xadp_h_t; + +#define SFE_KX13X_YADP_L 0x04 +typedef struct +{ + uint8_t yadp_l : 8; +} sfe_kx13x_yadp_l_t; + +#define SFE_KX13X_YADP_H 0x05 +typedef struct +{ + uint8_t yadp_l : 8; +} sfe_kx13x_yadp_h_t; + +#define SFE_KX13X_ZADP_L 0x06 +typedef struct +{ + uint8_t yadp_l : 8; +} sfe_kx13x_zadp_l_t; + +#define SFE_KX13X_ZADP_H 0x07 +typedef struct +{ + uint8_t zadp_h : 8; +} sfe_kx13x_zadp_h_t; + +#define SFE_KX13X_XOUT_L 0x08 +typedef struct +{ + uint8_t xout_l : 8; +} sfe_kx13x_xout_l_t; + +#define SFE_KX13X_XOUT_H 0x09 +typedef struct +{ + uint8_t xout_h : 8; +} sfe_kx13x_xout_h_t; + +#define SFE_KX13X_YOUT_L 0x0A +typedef struct +{ + uint8_t yout_l : 8; +} sfe_kx13x_yout_l_t; + +#define SFE_KX13X_YOUT_H 0x0B +typedef struct +{ + uint8_t yout_h : 8; +} sfe_kx13x_yout_h_t; + +#define SFE_KX13X_ZOUT_L 0x0C +typedef struct +{ + uint8_t zout_l : 8; +} sfe_kx13x_zout_l_t; + +#define SFE_KX13X_ZOUT_H 0x0D --------------^^-------------------------- +typedef struct +{ + uint8_t zout_h : 8; +} sfe_kx13x_zout_h_t; + +#define SFE_KX13X_COTR 0x12 +// Command Test Response +// Verifies the proper integrated circuit intergrity +typedef struct +{ + uint8_t dc_str : 8; //Default 0b01010101 : 0x55 +} sfe_kx13x_cotr_t; + +#define SFE_KX13X_WHO_AM_I 0x13 +//Identifies the accelerometer being used: 0x3D - KX132 and 0x46 - KX135 +typedef struct +{ + uint8_t wai : 8; +} sfe_kx13x_wai_t; + +#define SFE_KXI3X_TSCP 0x14 +//Current Tilt Position Register reports current position data +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t reserved_two : 1; + uint8_t left_state : 1; //X- + uint8_t right_state : 1; //X+ + uint8_t down_state : 1; //Y- + uint8_t up_state : 1; //Y+ + uint8_t face_down_state : 1; //Z- + uint8_t face_up_down_state : 1; //Z+ +} sfe_kx13x_tscp_t; + +#define SFE_KX13X_TSPP 0x15 +//Previous Tilt Position Register reports previous position data +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t reserved_two : 1; + uint8_t left_state : 1; //X- + uint8_t right_state : 1; //X+ + uint8_t down_state : 1; //Y- + uint8_t up_state : 1; //Y+ + uint8_t face_down_state : 1; //Z- + uint8_t face_up_down_state : 1; //Z+ +} sfe_kx13x_tspp_t; + +#define SFE_KX13X_INS1 0x16 +// Reports Tap and Double Tap interrupts according to the bit. Bit +// is cleared when the interrupt latch release register (INT_REL) is read. +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t reserved_two : 1; + uint8_t tap_left : 1; //X- + uint8_t tap_right : 1; //X+ + uint8_t tap_down : 1; //Y- + uint8_t tap_up : 1; //Y+ + uint8_t tap_face_down : 1; //Z- + uint8_t tap_face_up : 1; //Z+ +} sfe_kx13x_ins1_t; + +#define SFE_KX13X_INS2 0x17 +// Reports which function caused an interrupt +typedef struct +{ + uint8_t ffs : 1; // Free fall + uint8_t bfi : 1; // Buffer full + uint8_t wmi : 1; // Watermark + uint8_t drdy : 1; // Data Ready + uint8_t tdts : 2; // Tap/Double Tap + uint8_t reserved : 1; + uint8_t tps : 1; // Tilt Position +} sfe_kx13x_ins2_t; + +#define SFE_KX13X_INS3 0x18 +// Reports which axis and direction of detected motion triggered the wakeup interrupt +typedef struct +{ + uint8_t wufs : 1; + uint8_t bts : 1; + uint8_t xnwu : 1; //X- + uint8_t xpwu : 1; //X+ + uint8_t ynwu : 1; //Y- + uint8_t ypwu : 1; //Y+ + uint8_t znwu : 1; //Z- + uint8_t zpwu : 1; //Z+ +} sfe_kx13x_ins3_t; + +#define SFE_KX13X_STATUS_REG 0x19 +// Reports the combined status of the interrupts and the wake/back to sleep state +typedef struct +{ + uint8_t reserved_one : 3; + uint8_t combined_int : 1; + uint8_t reserved_two : 3; + uint8_t wake : 1; +} sfe_kx13x_status_reg_t; + +#define SFE_KX13X_INT_REL 0x1A +// Interrupt latch release: when an interrupt is flipped read this status to clear +// interrupt. +typedef struct +{ + uint8_t latch_release : 8; +} sfe_kx13x_int_rel_t; + +#define SFE_KX13X_CNTL1 0x1B +// Read/write control register that controls the "main feature" set. +// To change these values PC1 (bit 8) must be set to zero (stand-by mode). +typedef struct +{ + uint8_t pc1 : 1; + uint8_t res : 1; + uint8_t drdye : 1; + uint8_t gsel : 2; + uint8_t tdte : 1; + uint8_t reserved_one : 1; + uint8_t tpe : 1; +} sfe_kx13x_cntl1_t; + +#define SFE_KX13X_CNTL2 0x1C +// Read/Write control register that controls tilt position state enabling +// Default value: 0b00111111 +typedef struct +{ + uint8_t srst : 1; //Software reset + uint8_t cotc : 1; //Command Test Control bit + // The following bits control when an interrupt is generated + // for tilt: 1 = enabled + uint8_t lem : 1; // Left state (X-) + uint8_t rim : 2; // Right state (X+) + uint8_t dom : 1; // Down state (Y-) + uint8_t upm : 1; // Up state (Y+) + uint8_t fdm : 1; // Face-Down state (Z-) + uint8_t fum : 1; // Face-Up state (Z+) +} sfe_kx13x_cntl2_t; + +#define SFE_KX13X_CNTL3 0x1D +// Read/Write control register that provides control of the Output Data Rate (ODR) +// for tilt, tap, wake-up registers. +typedef struct +{ + uint8_t opt : 2; // ODR tilt position + uint8_t otdt : 3; // ODR tap/double-tap + uint8_t owuf : 3; // ORR wake-up +} sfe_kx13x_cntl3_t; + +#define SFE_KX13X_CNTL4 0x1E +// Read/write control register that provides more feature set control. +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t c_mode : 1; + uint8_t th_mode : 1; + uint8_t wufe : 1; + uint8_t btse : 1; + uint8_t pr_mode : 1; + uint8_t obts : 3; +} sfe_kx13x_cntl4_t; + +#define SFE_KX13X_CNTL5 0x1F +// Read/Write control register that providers more feature set control. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t reserved_one : 3; + uint8_t adpe : 1; + uint8_t reserved_two : 2; + uint8_t man_wake : 1; + uint8_t man_sleep : 1; +} sfe_kx13x_cntl5_t; + +#define SFE_KX13X_CNTL6 0x20 +// Read/Write control register that providers more feature set control. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t i2c_ale : 1; + uint8_t reserved_one : 5; + uint8_t i2c_alc : 2; +} sfe_kx13x_cntl6_t; + +#define SFE_KX13X_ODCNTL 0x21 +// Control registers that contorls acceleration outputs. +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t lpro : 1; // 0 - Filter ODR/9 : 1 - Filter ODR/2 + uint8_t fstup : 1; + uint8_t reserved_two : 1; + uint8_t osa : 4; +} sfe_kx13x_odcntl_t; + +#define SFE_KX13X_INC1 0x22 +// Controls settings for physical interrupt pin +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t pw1 : 2; + uint8_t ien1 : 1; // Enable/disable physical interrupt pin + uint8_t iea1 : 1; // Interrupt active level control, 0 - LOW : 1 - HIGH + uint8_t iel1 : 1; // Interrupt lactch control, 0 - latched : 1 - pulsed + uint8_t reserved_one : 1; + uint8_t stpol : 1; + uint8_t spi3e : 1; +} sfe_kx13x_inc1_t; + +#define SFE_KX13X_INC2 0x23 +// Defines behavior for Wake-Up Function and Back To Sleep +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t aoi : 1; + uint8_t xnwue : 1; //X- + uint8_t xpwue : 1; //X+ + uint8_t ynwue : 1; //Y- + uint8_t ypwue : 1; //Y+ + uint8_t znwue : 1; //Z- + uint8_t zpwue : 1; //Z+ +} sfe_kx13x_inc2_t; + +#define SFE_KX13X_INC3 0x24 +// Defines which axes can cause a tap based interrupt +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t undefined : 1; + uint8_t tmen : 1; // Alternate masking scheme + uint8_t tlem : 1; //X- + uint8_t trim : 1; //X+ + uint8_t tdom : 1; //Y- + uint8_t tpum : 1; //Y+ + uint8_t tfdm : 1; //Z- + uint8_t tfum : 1; //Z+ +} sfe_kx13x_inc3_t; + +#define SFE_KX13X_INC4 0x25 +// Controls which function triggers INT1 +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t ffi1 : 1; + uint8_t bfi1 : 1; + uint8_t wmi1 : 1; + uint8_t drdyi1 : 1; + uint8_t btsi1 : 1; + uint8_t tdti1 : 1; + uint8_t wufi1 : 1; + uint8_t tpi1 : 1; +} sfe_kx13x_inc4_t; + +#define SFE_KX13X_INC5 0x26 +// Controls the settings for the physical interrupt pin INT2. +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t pw2 : 2; + uint8_t ien2 : 1; + uint8_t iea2 : 1; + uint8_t iel2 : 1; + uint8_t reserved_one : 1; + uint8_t aclr2 : 1; + uint8_t aclr1 : 1; +} sfe_kx13x_inc5_t; + +#define SFE_KX13X_INC6 0x27 +// Controls which function triggers INT2 +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t ffi2 : 1; + uint8_t bfi2 : 1; + uint8_t wmi2 : 1; + uint8_t drdyi2 : 1; + uint8_t btsi2 : 1; + uint8_t tdti2 : 1; + uint8_t wufi2 : 1; + uint8_t tpi2 : 1; +} sfe_kx13x_inc6_t; + +#define SFE_KX13X_TILT_TIMER 0x29 +// Initial Count Registers for the tilt position state time (0 to 255 counts) +// Count is calculated as 1/ODR +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t tsc : 8; +} sfe_kx13x_tilt_timer_t; + +#define SFE_KX13X_TDTRC 0x2A +// Double tap report control +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t undefined : 6; + uint8_t dtre : 1; + uint8_t stre : 1; +} sfe_kx13x_tdtrc_t; + +#define SFE_KX13X_TDTC 0x2B +// Double tap time counter - see datashet for more specifics. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t tdtc : 8; +} sfe_kx13x_tdtc_t; + +#define SFE_KX13X_TTH 0x2C +// Double tap "jerk high" threshold to determine if a tap is detected. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t tth : 8; +} sfe_kx13x_tth_t; + +#define SFE_KX13X_TTL 0x2D +// Double tap "jerk low" threshold to determine if a tap is detected. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t ttl : 8; +} sfe_kx13x_ttl_t; + +#define SFE_KX13X_FTD 0x2E +// This register contains counter information for any single tap event. +// These settings can be changed on the fly - no need to put IC in stand-by. +// Check datasheet for conversion information. +typedef struct +{ + uint8_t ftdh : 5; //Default high limit is .05 seconds + uint8_t ftdl : 3; //Default low limits is .05 seconds +} sfe_kx13x_ftd_t; + +#define SFE_KX13X_STD 0x2F +// This register contains counter information for any double tap event. +// These settings can be changed on the fly - no need to put IC in stand-by. +// Check datasheet for conversion information. +typedef struct +{ + uint8_t std: 8; +} sfe_kx13x_std_t; + +#define SFE_KX13X_TLT 0x30 +// This register contains counter information for a tap event. +// These settings can be changed on the fly - no need to put IC in stand-by. +// Check datasheet for conversion information. +typedef struct +{ + uint8_t tlt : 8; +} sfe_kx13x_tlt_t; + +#define SFE_KX13X_TWS 0x31 +// This register contains counter information for of single and double taps. +// These settings can be changed on the fly - no need to put IC in stand-by. +// Check datasheet for conversion information. +typedef struct +{ + uint8_t tws : 8; +} sfe_kx13x_tws_t; + +#define SFE_KX13X_FFTH 0x32 +// This register configures the threshold for free fall detection. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t ffth : 8; +} sfe_kx13x_ffth_t; + +#define SFE_KX13X_FFC 0x33 +// This register configures the counter for free fall detection. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t ffc : 8; +} sfe_kx13x_ffc_t; + +#define SFE_KX13X_FFCNTL 0x34 +// This register configures the "main control" of the free fall engine i.e. +// engine enable, free fall latch, debouce, etc. +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t ffie : 1; + uint8_t ulmode : 1; + uint8_t ffdc : 2; + uint8_t dcrm : 1; + uint8_t offl : 3; +} sfe_kx13x_ffcntl_t; + +#define SFE_KX13X_TILT_ANGLE_LL 0x37 +// This register sets the low-level threshold for tilt angle detection. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t ll : 8; +} sfe_kx13x_ll_t; + +#define SFE_KX13X_TILT_ANGLE_HL 0x38 +// This register sets the high-level threshold for tilt angle detection. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t hl : 8; +} sfe_kx13x_hl_t; + +#define SFE_KX13X_HYST_SET 0x39 +// This register sets hysteresis that is placed in between the Screen Rotation states. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t reserved : 2; + uint8_t hyst : 6; +} sfe_kx13x_hyst_t; + +#define SFE_KX13X_LP_CNTL1 0x3A +// This register sets the Averging Filter Contrl which determines both - +// the number of internal aceleration samples to be averaged in low power mode +// and the number of internal acceleration samples to be averaged for digital engines +// operation: tap, double tap. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t reserved_one : 1; + uint8_t avc : 3; + uint8_t reserved_two : 4; +} sfe_kx13x_lp_cntl1_t; + +#define SFE_KX13X_LP_CNTL2 0x3B +// This register controls the advanced low power settings which can reduce +// the power consumption even more than low power and stand-by modes. +// To change these settings make sure IC is in "stand-by" mode: PC1 bit in CNTL1. +typedef struct +{ + uint8_t reserved : 7; + uint8_t lpstpsel : 1; +} sfe_kx13x_lpcntl2_t; + +#define SFE_KX13X_WUFTH 0x49 +// This register sets seven of the ten bits for the wake up threshold. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t wufth : 8; +} sfe_kx13x_wufth_t; + +#define SFE_KX13X_BTSWUFTH 0x4A +// This register contains final three of the ten bits of the back to sleep the threshold and +// the final three of ten bits of the wakup threshold. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t undefined_one : 1; + uint8_t btsth : 3; + uint8_t undefined_two : 1; + uint8_t wufth : 3; +} sfe_kx13x_btswufth_t; + +#define SFE_KX13X_BTSTH 0x4B +// This register sets seven of the ten bits for the back to sleep threshold. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t btsth : 8; +} sfe_kx13x_btsth_t; + +#define SFE_KX13X_BTSC 0x4C +// This register debounce counter register for the Back-To-Sleep engine. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t btsc : 8; +} sfe_kx13x_btsc_t; + +#define SFE_KX13X_WUFC 0x4D +// This register debounce counter register for the Wake-Up Function engine. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t wufc : 8; +} sfe_kx13x_wufc_t; + +#define SFE_KX13X_SELF_TEST 0x5D +// The self test enable register. +// Check datasheet for more information. +typedef struct +{ + uint8_t self_test : 8; +} sfe_kx13x_self_test_t; + +#define SFE_KX13X_BUF_CNTL1 0x5E +// This register controls the buffer sample threshold. +// The total samples set in this register is dependent on the "BRES" bits in +// BUF_CNTL2. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t smp_th : 8; +} sfe_kx13x_buf_cntl1_t; + +#define SFE_KX13X_BUF_CNTL2 0x5F +// This register controls the buffer sample operation. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t bufe : 1; // Activation of sample buffer + uint8_t bres : 1; // Resolution - 8 or 16 bit samples + uint8_t bfie : 1; // Full interrupt enable bit + uint8_t undefined : 3; + uint8_t bm : 2; //FIFO, Stream, Trigger +} sfe_kx13x_buf_cntl2_t; + +#define SFE_KX13X_BUF_STATUS_1 0x60 +// The buffer status registers (buff status one and two) report the number of +// data bytes in the sample buffer. +// The smp_lev word is 10 bits, you can find the remaining three bits in buf_status2. +typedef struct +{ + uint8_t smp_lev : 8; +} sfe_kx13x_buf_status1_t; + +#define SFE_KX13X_BUF_STATUS_2 0x61 +// The buffer status registers (buf_status_1/2) report the number of +// data bytes in the sample buffer. +// The smp_lev word is 10 bits, you can find the remaining first seven bits in +// buf_status1. +typedef struct +{ + uint8_t buf_trig : 1; + uint8_t undefined : 5; + uint8_t smp_lev : 2; +} sfe_kx13x_buf_status2_t; + +#define SFE_KX13X_BUF_CLEAR 0x62 +// This register clears the sample level bits found in the previous buf_status_1/2 +// register. This can be done by writing anything to this register. +// These settings can be changed on the fly - no need to put IC in stand-by. +typedef struct +{ + uint8_t buf_clear : 8; +} sfe_kx13x_buf_clear_t; + +#define SFE_KX13X_BUF_READ 0x63 +// Buffer Output Register, data is in 2's copmlement format +typedef struct +{ + uint8_t buf_read : 8; +} sfe_kx13x_buf_read_t; + +#define SFE_KX13X_ADP_CNTL1 0x64 +// This register sets the ODR of the Advanced Data Path and number of samples +// used to calculate RMS output. +typedef struct +{ + uint8_t reserved : 1; + uint8_t rms_avc : 3; + uint8_t oadp : 3; +} sfe_kx13x_adp_cntl1_t; + +#define SFE_KX13X_ADP_CNTL2 0x65 +// This register controls route of data path, wake-up/back-to-sleep, +// filter bypass amongst others. +typedef struct +{ + uint8_t adp_buf_sel : 1; + uint8_t adp_wb_isel : 1; + uint8_t rms_wb_osel : 1; + uint8_t adp_flt2_byp : 1; + uint8_t adp_flt1_byp : 1; + uint8_t undefined : 1; + uint8_t adp_rms_osel : 1; + uint8_t adp_f2_hp : 1; +} sfe_kx13x_adp_cntl2_t; + +#define SFE_KX13X_ADP_CNTL3 0x66 +// Sets ADP filter-1 coefficient (1/A) +typedef struct +{ + uint8_t adp_f1_1a : 8; +} sfe_kx13x_adp_cntl3_t; + +#define SFE_KX13X_ADP_CNTL4 0x67 +// Sets the ADP filter-1 coefficient (B/A) +// Bits [7:0] +typedef struct +{ + uint8_t adp_f1_ba : 8; +} sfe_kx13x_adp_cntl4_t; + +#define SFE_KX13X_ADP_CNTL5 0x68 +// Sets the ADP filter-1 coefficient (B/A) +// Bits [15:8] +typedef struct +{ + uint8_t adp_f1_ba : 8; +} sfe_kx13x_adp_cntl5_t; + +#define SFE_KX13X_ADP_CNTL6 0x69 +// Sets the ADP filter-1 coefficient (B/A) +// Bits [22:16] +typedef struct +{ + uint8_t undefined : 1; + uint8_t adp_f1_ba : 7; +} sfe_kx13x_adp_cntl6_t; + +#define SFE_KX13X_ADP_CNTL7 0x6A +// Sets the ADP filter-1 coefficient (C/A) +// Bits [7:0] +typedef struct +{ + uint8_t adp_f1_ca : 8; +} sfe_kx13x_adp_cntl7_t; + +#define SFE_KX13X_ADP_CNTL8 0x6B +// Sets the ADP filter-1 coefficient (C/A) +// Bits [15:8] +typedef struct +{ + uint8_t adp_f1_ca : 8; +} sfe_kx13x_adp_cntl8_t; + +#define SFE_KX13X_ADP_CNTL9 0x6C +// Sets the ADP filter-1 coefficient (C/A) +// Bits [22:16] +typedef struct +{ + uint8_t undefined : 1; + uint8_t adp_f1_ca : 7; +} sfe_kx13x_adp_cntl9_t; + +#define SFE_KX13X_ADP_CNTL10 0x6D +// Sets the ADP filter-1 input scale shift +typedef struct +{ + uint8_t undefined : 3; + uint8_t adp_f1_ish : 5; +} sfe_kx13x_adp_cntl10_t; + +#define SFE_KX13X_ADP_CNTL11 0x6E +// Sets the ADP filter-2 coefficient (1/A) +typedef struct +{ + uint8_t adp_f2_osh : 1; + uint8_t adp_f2_1a : 7; +} sfe_kx13x_adp_cntl11_t; + +#define SFE_KX13X_ADP_CNTL12 0x6F +// Sets the ADP filter-2 coefficient (B/A) +// Bits [7:0] +typedef struct +{ + uint8_t adp_f2_ba : 1; +} sfe_kx13x_adp_cntl12_t; + +#define SFE_KX13X_ADP_CNTL13 0x70 +// Sets the ADP filter-2 coefficient (B/A) +// Bits [14:8] +typedef struct +{ + uint8_t undefined : 1; + uint8_t adp_f2_ba : 1; +} sfe_kx13x_adp_cntl13_t; + +//---------------------------------- Set to Zero by Manufacturer vv ---- +#define SFE_KX13X_ADP_CNTL14 0x71 // ------------------------------- +#define SFE_KX13X_ADP_CNTL15 0x72 // ------------------------------- +#define SFE_KX13X_ADP_CNTL16 0x73 // ------------------------------- +#define SFE_KX13X_ADP_CNTL17 0x74 // ------------------------------- +//---------------------------------- Set to Zero by Manufacturer ^^ ---- + +#define SFE_KX13X_ADP_CNTL18 0x75 +// Sets the ADP filter-2 input scale shift +typedef struct +{ + uint8_t undefined : 3; + uint8_t adp_f1_ish : 5; +} sfe_kx13x_adp_cntl18_t; + +#define SFE_KX13X_ADP_CNTL19 0x76 +// Sets the ADP filter-2 output scale shift +typedef struct +{ + uint8_t undefined : 3; + uint8_t adp_f1_osh : 5; +} sfe_kx13x_adp_cntl19_t; + +typedef struct +{ + uint8_t SFE_KX13X_SUCCESS = 0x00; + uint8_t SFE_KX13X_GENERAL_ERROR = 0x01; + uint8_t SFE_KX13X_I2C_ERROR = 0x03; +} sfe_error_code_t; + diff --git a/src/SparkFun_Qwiic_KX13X.cpp b/src/SparkFun_Qwiic_KX13X.cpp index e589d69..bd4d8d2 100644 --- a/src/SparkFun_Qwiic_KX13X.cpp +++ b/src/SparkFun_Qwiic_KX13X.cpp @@ -17,168 +17,288 @@ Distributed as-is; no warranty is given. #include "SparkFun_Qwiic_KX13X.h" -QwiicKX13xCore::QwiicKX13xCore() { } //Constructor -uint8_t QwiicKX13xCore::beginCore(uint8_t deviceAddress, TwoWire &i2cPort) +uint8_t QwDevKX13X::getUniqueID() { - _deviceAddress = deviceAddress; //If provided, store the I2C address from user - _i2cPort = &i2cPort; - uint8_t partID; - KX13X_STATUS_t status = readRegister(&partID, KX13X_WHO_AM_I); - if( status != KX13X_SUCCESS ) - return status; - else - return partID; -} - -uint8_t QwiicKX13xCore::beginSPICore(uint8_t CSPin, uint32_t spiPortSpeed, SPIClass &spiPort) -{ - uint8_t partID; - - _i2cPort = NULL; - _spiPort = &spiPort; - _cs = CSPin; + uint8_t tempVal; + int retVal = readRegisterRegion(SFE_KX13X_WHO_AM_I, &tempVal, 1); + Serial.println(tempVal); - if( _spiPortSpeed > 10000000 ) - _spiPortSpeed = 10000000; + if( retVal != 0 ) + return 0; - _spiPortSpeed = spiPortSpeed; - - - // CPOL and CPHA are demonstrated on pg 25 of Specification Data sheet - // CPOL = 0, CPHA = 0 SPI_MODE0 -#ifdef ESP32 - kxSPISettings = SPISettings(spiPortSpeed, SPI_MSBFIRST, SPI_MODE0); -#else - kxSPISettings = SPISettings(spiPortSpeed, MSBFIRST, SPI_MODE0); -#endif - - KX13X_STATUS_t status = readRegister(&partID, KX13X_WHO_AM_I); + return tempVal; +} - if( status != KX13X_SUCCESS ) - return status; +//////////////////////////////////////////////////////////////////////////////////// +// setCommunicationBus() +// +// Method to set the bus object that is used to communicate with the device +// +// Parameter Description +// --------- ----------------------------- +// theBus The communication bus object +// i2cAddress I2C address for the 6DoF + +void QwDevKX13X::setCommunicationBus(QwIDeviceBus &theBus, uint8_t i2cAddress) +{ + _sfeBus = &theBus; + _i2cAddress = i2cAddress; +} - return partID; +//////////////////////////////////////////////////////////////////////////////////// +// setCommunicationBus() +// +// Overloaded option for setting the data bus (theBus) object to a SPI bus object. +// +// Parameter Description +// --------- ----------------------------- +// theBus The communication bus object +// + +void QwDevKX13X::setCommunicationBus(QwIDeviceBus &theBus) +{ + _sfeBus = &theBus; } // This function sets various register with regards to these pre-determined // settings. These settings are set according to "AN092 Getting Started" guide and can easily // have additional presets added. -bool QwiicKX13xCore::initialize(uint8_t settings) +bool QwDevKX13X::initialize(uint8_t settings) { - KX13X_STATUS_t returnError = KX13X_GENERAL_ERROR; - if( !accelControl(false) ){ + int retVal; + + if( !enableAccel(true) ) return false; - } + if( settings == DEFAULT_SETTINGS ) - returnError = writeRegister(KX13X_CNTL1, 0x00, DEFAULT_SETTINGS, 0); - if( settings == INT_SETTINGS ){ - setInterruptPin(true, 1); - routeHardwareInterrupt(HI_DATA_READY); - returnError = writeRegister(KX13X_CNTL1, 0x00, INT_SETTINGS, 0); - } - if( settings == SOFT_INT_SETTINGS ){ - returnError = writeRegister(KX13X_CNTL1, 0x00, INT_SETTINGS, 0); + retVal = writeRegisterByte(SFE_KX13X_CNTL1, DEFAULT_SETTINGS); + + if( settings == INT_SETTINGS ) + { + enablePhysInterrupt(); + routeHardwareInterrupt(0x10); + retVal = writeRegisterByte(SFE_KX13X_CNTL1, INT_SETTINGS); } - if( settings == BUFFER_SETTINGS ){ - setInterruptPin(true, 1); - routeHardwareInterrupt(HI_BUFFER_FULL); - enableBuffer(true, true); - setBufferOperation(BUFFER_MODE_FIFO, BUFFER_16BIT_SAMPLES); - returnError = writeRegister(KX13X_CNTL1, 0x00, INT_SETTINGS, 0); + + if( settings == BUFFER_SETTINGS ) + { + enablePhysInterrupt(); + routeHardwareInterrupt(0x40);//Buffer full interrupt + enableSampleBuffer(); //Enable buffer + setBufferOperationMode(0x00); //FIFO + retVal = writeRegisterByte(SFE_KX13X_CNTL1, INT_SETTINGS); } - if( returnError == KX13X_SUCCESS ) - return true; - else + if( retVal != 0 ) return false; + + return true; } -// Address: 0x1B, bit[7]: default value is: 0x00 -// This function sets the accelerometer into stand-by mode or -// an active mode depending on the given argument. -bool QwiicKX13xCore::accelControl(bool standby){ +bool QwDevKX13X::softwareReset() +{ - if( standby != true && standby != false ) - return false; - - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_CNTL1, 0x7F, standby, 7); - if( returnError == KX13X_SUCCESS ) + uint8_t reset = 0x80; + int retVal; + + retVal = writeRegisterByte(SFE_KX13X_CNTL2, reset); + + if( retVal != 0 ) return true; - else + + return false; + +} + +bool QwDevKX13X::enableAccel(bool enable) +{ + + uint8_t tempVal; + int retVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = (tempVal | (enable << 7)); + + retVal = writeRegisterByte(SFE_KX13X_CNTL1, tempVal); + + if( retVal != 0 ) return false; + + return true; } // Address: 0x1B, bit[7]: default value is: 0x00 // This function reads whether the accelerometer is in stand by or an active // mode. -uint8_t QwiicKX13xCore::readAccelState(){ +uint8_t QwDevKX13X::getOperatingMode(){ + + uint8_t tempVal; + int retVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return 2; // Not a possible value for the PC1 bit. - uint8_t tempRegVal; - readRegister(&tempRegVal, KX13X_CNTL1); - return (tempRegVal & 0x80) >> 7; + return (tempVal >> 7); } // Address: 0x1B, bit[1:0]: default value is: 0x00 (2g) // This function sets the acceleration range of the accelerometer outputs. // Possible KX132 arguments: 0x00 (2g), 0x01 (4g), 0x02 (8g), 0x03 (16g) // Possible KX134 arguments: 0x00 (8g), 0x01 (16g), 0x02 (32g), 0x03 (64g) -bool QwiicKX13xCore::setRange(uint8_t range){ +// KX13X needs to be set into standby mode to change this value +bool QwDevKX13X::setRange(uint8_t range) +{ + + int retVal; - if( range > 3) + if( range > 3 ) return false; - uint8_t accelState = readAccelState(); - accelControl(false); + retVal = writeRegisterByte(SFE_KX13X_CNTL1, range); - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_CNTL1, 0xE7, range, 3); - if( returnError == KX13X_SUCCESS ){ - accelControl(accelState); - return true; - } - else + if( retVal != 0 ) return false; + + return true; } +bool QwDevKX13X::enableDataEngine(bool enable) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (enable << 5); + + retVal = writeRegisterByte(SFE_KX13X_CNTL1, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::enableTapEngine(bool enable) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (enable << 2); + + retVal = writeRegisterByte(SFE_KX13X_CNTL1, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::enableTiltEngine(bool enable) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | enable; + + retVal = writeRegisterByte(SFE_KX13X_CNTL1, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} //Address: 0x21, bits[3:0] - default value is 0x06 (50Hz) //Sets the refresh rate of the accelerometer's data. // 0.781 * (2 * (n)) derived from pg. 26 of Techincal Reference Manual -bool QwiicKX13xCore::setOutputDataRate(uint8_t rate){ +bool QwDevKX13X::setOutputDataRate(uint8_t rate) +{ if( rate > 15 ) return false; - uint8_t accelState = readAccelState(); // Put it back where we found it. - accelControl(false); // Can't adjust without putting to sleep + uint8_t tempVal; + int retVal; - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_ODCNTL, 0xF0, rate, 0); - if( returnError == KX13X_SUCCESS ){ - accelControl(accelState); - return true; - } - else + retVal = readRegisterRegion(SFE_KX13X_CNTL1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | rate; + + retVal = writeRegisterByte(SFE_KX13X_ODCNTL, tempVal); + + if( retVal != 0 ) return false; + + return true; } +bool QwDevKX13X::setTapDataRate(uint8_t rate) +{ + + if( rate > 7 ) + return false; + + uint8_t tempVal; + int retVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL3, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (rate << 3); + + retVal = writeRegisterByte(SFE_KX13X_CNTL3, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} // Address:0x21 , bit[3:0]: default value is: 0x06 (50Hz) // Gets the accelerometer's output data rate. -float QwiicKX13xCore::readOutputDataRate(){ - - uint8_t tempRegVal; - readRegister(&tempRegVal, KX13X_ODCNTL); - tempRegVal &= 0x0F; - tempRegVal = (float)tempRegVal; - return (0.78 * (pow(2,tempRegVal))); +float QwDevKX13X::getOutputDataRate() +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_ODCNTL, &tempVal, 1); + + if( retVal != 0 ) + return 0.0; + tempVal = tempVal & 0x0F; + + return (0.78 * ( pow(2,(float)tempVal))); } @@ -186,93 +306,364 @@ float QwiicKX13xCore::readOutputDataRate(){ // This register controls the various interrupt settings, all of which can be // set here. Note: trying to set just one will set the others to their default // state. -bool QwiicKX13xCore::setInterruptPin(bool enable, uint8_t polarity, uint8_t pulseWidth, bool latchControl){ +// Thish configures all of the bits related to the interrupt pin. +bool QwDevKX13X::configureInterruptPin(uint8_t pinVal){ - if( enable != true && enable != false ) - return false; - else if( polarity != 1 && polarity != 0 ) - return false; - else if( pulseWidth != 1 && pulseWidth != 0 ) - return false; + int retVal; - uint8_t accelState = readAccelState(); // Put it back where we found it. - accelControl(false); // Can't adjust without putting to sleep + retVal = writeRegisterByte(SFE_KX13X_INC1, pinVal); - uint8_t combinedArguments = ((pulseWidth << 6) | (enable << 5) | (polarity << 4) | (latchControl << 3)); - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_INC1, 0x07, combinedArguments, 0); - if( returnError == KX13X_SUCCESS ){ - accelControl(accelState); - return true; - } - else + if( retVal != 0 ) return false; + + return true; +} + +bool QwDevKX13X::enablePhysInterrupt(bool enable, uint8_t pin) +{ + int retVal; + uint8_t tempVal; + + if( pin == 1 ) + { + retVal = readRegisterRegion(SFE_KX13X_INC1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (enable << 5); + + writeRegisterByte(SFE_KX13X_INC1, tempVal); + + } + + if( pin == 2 ) + { + retVal = readRegisterRegion(SFE_KX13X_INC5, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (enable << 5); + + writeRegisterByte(SFE_KX13X_INC5, tempVal); + + } + + return true; +} + +bool QwDevKX13X::setPinMode(bool activeLow) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INC1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (activeLow << 5); + + retVal = writeRegisterByte(SFE_KX13X_INC1, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::setLatchControl(bool latch) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INC1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (latch << 3); + + retVal = writeRegisterByte(SFE_KX13X_INC1, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::setPulseWidth(uint8_t width) +{ + int retVal; + uint8_t tempVal; + + if( width > 4 ) + return false; + + retVal = readRegisterRegion(SFE_KX13X_INC1, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (width << 6); + + retVal = writeRegisterByte(SFE_KX13X_INC1, tempVal); + + if( retVal != 0 ) + return false; + + return true; } // Address: 0x25, bits[7:0]: default value is 0: disabled // Enables anyone of the various interrupt settings to be routed to hardware // interrupt pin one or pin two. -bool QwiicKX13xCore::routeHardwareInterrupt(uint8_t rdr, uint8_t pin){ +bool QwDevKX13X::routeHardwareInterrupt(uint8_t rdr, uint8_t pin) +{ - if( rdr > 128 ) - return false; - if( pin != 1 && pin != 2) - return false; - - uint8_t accelState = readAccelState(); // Put it back where we found it. - accelControl(false); // Can't adjust without putting to sleep + int retVal; - KX13X_STATUS_t returnError; + if( pin > 2 ) + return false; - if( pin == 1 ){ - returnError = writeRegister(KX13X_INC4, 0x00, rdr, 0); - if( returnError == KX13X_SUCCESS ){ - accelControl(accelState); - return true; - } - else - returnError = writeRegister(KX13X_INC6, 0x00, rdr, 0); - if( returnError == KX13X_SUCCESS ){ - accelControl(accelState); - return true; - } + if( pin == 1 ) + { + retVal = writeRegisterByte(SFE_KX13X_INC4, rdr); + + if( retVal != 0 ) + return false; + } + + if( pin == 2 ) + { + retVal = writeRegisterByte(SFE_KX13X_INC6, rdr); + + if( retVal != 0 ) + return false; + } - return false; + return true; } // Address: 0x1A , bit[7:0]: default value is: 0x00 // This function reads the interrupt latch release register, thus clearing any // interrupts. -bool QwiicKX13xCore::clearInterrupt(){ +bool QwDevKX13X::clearInterrupt() +{ - uint8_t tempRegVal; - KX13X_STATUS_t returnError; - returnError = readRegister(&tempRegVal, KX13X_INT_REL); - if( returnError == KX13X_SUCCESS ) - return true; - else - return false; + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INT_REL, &tempVal, 1); + + if( retVal != 0 ) + return false; + + return true; } -// Address: 0x17 , bit[4]: default value is: 0 -// This function triggers collection of data by the KX13X. -bool QwiicKX13xCore::dataTrigger(){ +bool QwDevKX13X::enableDirecTapInterupt(bool enable) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_TDTRC, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | enable; + + retVal = writeRegisterByte(SFE_KX13X_TDTRC, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::enableDoubleTapInterupt(bool enable) +{ + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_TDTRC, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | (enable << 1); + + retVal = writeRegisterByte(SFE_KX13X_TDTRC, tempVal); + + if( retVal != 0 ) + return false; + + return true; +} + +bool QwDevKX13X::dataReady() +{ - uint8_t tempRegVal; - KX13X_STATUS_t returnError; - returnError = readRegister(&tempRegVal, KX13X_INS2); - if( returnError == KX13X_SUCCESS ){ - if( tempRegVal & 0x10 ) - return true; - else - return false; - } - else - return false; + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + if( tempVal & 0x10 ) + return true; + + return false; +} +bool QwDevKX13X::freeFall() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + if( tempVal & 0x80 ) + return true; + + return false; +} + +bool QwDevKX13X::bufferFull() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + if( tempVal & 0x40 ) + return true; + + return false; +} + +bool QwDevKX13X::waterMarkReached() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + if( tempVal & 0x10 ) + return true; + + return false; +} + +bool QwDevKX13X::tapDetected() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + + tempVal = tempVal & 0x0C; // Three states of interest: single tap detected + // undefined, and no tap. + + if( tempVal == 0x04 ) // True if tap - not undefined or no tap. + return true; + + return false; +} + +int8_t QwDevKX13X::getDirection() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS1, &tempVal, 1); + + if( retVal != 0 ) + return retVal; + + return tempVal; +} + +bool QwDevKX13X::unknownTap() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal & 0x0C; // Three states of interest: single tap detected + // undefined, and no tap. + + if( tempVal == 0x0C ) // True if undefined + return true; + + return false; +} + +bool QwDevKX13X::doubleTapDetected() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal & 0x0C; // Two states of interest: single tap detected + // and undefined. + + if( tempVal == 0x08 ) // True if tap - not undefined. + return true; + + return false; +} + +bool QwDevKX13X::tiltChange() +{ + + int retVal; + uint8_t tempVal; + + retVal = readRegisterRegion(SFE_KX13X_INS2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + if( tempVal == 0x01 ) + return true; + + return false; } // Address: 0x5E , bit[7:0]: default value is: unknown @@ -280,28 +671,32 @@ bool QwiicKX13xCore::dataTrigger(){ // buffer. Each sample is one full word of X,Y,Z data and the minimum that this // can be set to is two. The maximum is dependent on the resolution: 8 or 16bit, // set in the BUF_CNTL2 (0x5F) register (see "setBufferOperation" below). -bool QwiicKX13xCore::setBufferThreshold(uint8_t threshold){ +bool QwDevKX13X::setBufferThreshold(uint8_t threshold) +{ + + int retVal; + uint8_t tempVal; + uint8_t resolution; if( threshold < 2 || threshold > 171 ) return false; - - uint8_t tempRegVal; - uint8_t resolution; - KX13X_STATUS_t returnError; - returnError = readRegister(&tempRegVal, KX13X_BUF_CNTL2); - resolution = (tempRegVal & 0x40) >> 6; - if( returnError != KX13X_SUCCESS ) + retVal = readRegisterRegion(SFE_KX13X_BUF_CNTL2, &tempVal, 1); + + if( retVal != 0 ) return false; + resolution = (tempVal & 0x40) >> 6; // Isolate it, move it + if( threshold > 86 && resolution == 1 ) // 1 = 16bit resolution, max samples: 86 threshold = 86; - returnError = writeRegister(KX13X_BUF_CNTL1, 0x00, threshold, 0); - if( returnError == KX13X_SUCCESS ) + retVal = writeRegisterByte(SFE_KX13X_BUF_CNTL1, threshold); + + if( retVal != 0 ) return true; - else - return false; + + return false; } @@ -309,249 +704,207 @@ bool QwiicKX13xCore::setBufferThreshold(uint8_t threshold){ // This functions sets the resolution and operation mode of the buffer. This does not include // the threshold - see "setBufferThreshold". This is a "On-the-fly" register, accel does not need // to be powered own to adjust settings. -bool QwiicKX13xCore::setBufferOperation(uint8_t operationMode, uint8_t resolution){ +bool QwDevKX13X::setBufferOperationMode(uint8_t operationMode) +{ + + int retVal; + uint8_t tempVal; - if( resolution > 1 ) - return false; if( operationMode > 2 ) return false; + retVal = readRegisterRegion(SFE_KX13X_BUF_CNTL2, &tempVal, 1); - uint8_t combinedSettings = (resolution << 6) | operationMode; - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_BUF_CNTL2, 0xBC, combinedSettings, 0); - if( returnError == KX13X_SUCCESS ) + if( retVal != 0 ) return true; - else - return false; -} -// Address: 0x5F, bit[7] and bit[5]: default values is: 0x00 -// This functions enables the buffer and also whether the buffer triggers an -// interrupt when full. This is a "On-the-fly" register, accel does not need -// to be powered down to adjust settings. -bool QwiicKX13xCore::enableBuffer(bool enable, bool enableInterrupt){ + tempVal = tempVal | operationMode; - if( ( enable != true && enable != false) && (enableInterrupt != true && enableInterrupt != false) ) - return false; + retVal = writeRegisterByte(SFE_KX13X_BUF_CNTL2, tempVal); - uint8_t combinedSettings = (enable << 7) | (enableInterrupt << 5); - KX13X_STATUS_t returnError; - returnError = writeRegister(KX13X_BUF_CNTL2, 0x5F, combinedSettings, 0); - if( returnError == KX13X_SUCCESS ) - return true; - else + if( retVal != 0 ) return false; + + return true; } -// Address: 0x1C, bit[6]: default value is: 0x00 -//Tests functionality of the integrated circuit by setting the command test -//control bit, then checks the results in the COTR register (0x12): 0xAA is a -//successful read, 0x55 is the default state. -bool QwiicKX13xCore::runCommandTest() +bool QwDevKX13X::setBufferResolution(bool sixteenBit ) { - - uint8_t tempRegVal; - KX13X_STATUS_t returnError; + int retVal; + uint8_t tempVal; - returnError = writeRegister(KX13X_CNTL2, 0xBF, 1, 6); - if( returnError != KX13X_SUCCESS ) - return false; + retVal = readRegisterRegion(SFE_KX13X_BUF_CNTL2, &tempVal, 1); - returnError = readRegister(&tempRegVal, KX13X_COTR); - if( returnError == KX13X_SUCCESS && tempRegVal == COTR_POS_STATE) - return true; - else - return false; + if( retVal != 0 ) + return false; + + tempVal = tempVal | ((uint8_t)sixteenBit << 6); + + retVal = writeRegisterByte(SFE_KX13X_BUF_CNTL2, tempVal); + + if( retVal != 0 ) + return false; + + return true; } -// Address:0x08 - 0x0D or 0x63 , bit[7:0] -// Reads acceleration data from either the buffer or the output registers -// depending on if the user specified buffer usage. -bool QwiicKX13xCore::getRawAccelData(rawOutputData *rawAccelData){ - - uint8_t tempRegVal; - KX13X_STATUS_t returnError; - uint8_t tempRegData[TOTAL_ACCEL_DATA_16BIT] {}; +bool QwDevKX13X::enableBufferInt(bool enable) +{ + int retVal; + uint8_t tempVal; - returnError = readRegister(&tempRegVal, KX13X_INC4); - if( returnError != KX13X_SUCCESS ) - return false; + retVal = readRegisterRegion(SFE_KX13X_BUF_CNTL2, &tempVal, 1); - if( tempRegVal & 0x40 ){ // If Buffer interrupt is enabled, then we'll read accelerometer data from buffer register. - returnError = readMultipleRegisters(KX13X_BUF_READ, tempRegData, TOTAL_ACCEL_DATA_16BIT); - } - else - returnError = readMultipleRegisters(KX13X_XOUT_L, tempRegData, TOTAL_ACCEL_DATA_16BIT); + if( retVal != 0 ) + return false; + tempVal = tempVal | (enable << 5); + retVal = writeRegisterByte(SFE_KX13X_BUF_CNTL2, tempVal); - if( returnError == KX13X_SUCCESS ) { - rawAccelData->xData = tempRegData[XLSB]; - rawAccelData->xData |= (static_cast(tempRegData[XMSB]) << 8); - rawAccelData->yData = tempRegData[YLSB]; - rawAccelData->yData |= (static_cast(tempRegData[YMSB]) << 8); - rawAccelData->zData = tempRegData[ZLSB]; - rawAccelData->zData |= (static_cast(tempRegData[ZMSB]) << 8); - return true; - } + if( retVal != 0 ) + return false; - return false; + return true; } - -// Reads a single register using the selected bus. -KX13X_STATUS_t QwiicKX13xCore::readRegister(uint8_t *dataPointer, uint8_t reg) +bool QwDevKX13X::enableSampleBuffer(bool enable) { + int retVal; + uint8_t tempVal; - if( _i2cPort == NULL ) { + retVal = readRegisterRegion(SFE_KX13X_BUF_CNTL2, &tempVal, 1); - _spiPort->beginTransaction(kxSPISettings); - digitalWrite(_cs, LOW); + if( retVal != 0 ) + return false; - reg = (reg | SPI_READ); - _spiPort->transfer(reg); + tempVal = tempVal | ((uint8_t)enable << 7); - *dataPointer = _spiPort->transfer(0x00); + retVal = writeRegisterByte(SFE_KX13X_BUF_CNTL2, tempVal); - digitalWrite(_cs, HIGH); - _spiPort->endTransaction(); + if( retVal != 0 ) + return false; - return KX13X_SUCCESS; - } + return true; +} +uint16_t QwDevKX13X::getSampleLevel() +{ + int retVal; + uint8_t tempVal[2] = {0}; + uint16_t numSamples; - uint8_t i2cResult; + retVal = readRegisterRegion(SFE_KX13X_BUF_STATUS_1, tempVal, 2); - _i2cPort->beginTransmission(_deviceAddress); - _i2cPort->write(reg); - i2cResult = _i2cPort->endTransmission(false); - - if( i2cResult != 0 ) - return KX13X_I2C_ERROR; //Error: Sensor did not ack - // - _i2cPort->requestFrom(static_cast(_deviceAddress), static_cast(1)); //returns number of bytes - // - *dataPointer = _i2cPort->read(); - return KX13X_SUCCESS; - + if( retVal != 0 ) + return 0; + + numSamples = tempVal[0]; + numSamples = numSamples | ((tempVal[1] & 0x03) << 8); + + return numSamples; } -//Sends a request to read a number of registers -KX13X_STATUS_t QwiicKX13xCore::readMultipleRegisters(uint8_t reg, uint8_t dataBuffer[], uint16_t numBytes) +bool QwDevKX13X::clearBuffer() { - - if( _i2cPort == NULL ) { - _spiPort->beginTransaction(kxSPISettings); - digitalWrite(_cs, LOW); - reg = (reg | SPI_READ); - _spiPort->transfer(reg); - dataBuffer[0] = _spiPort->transfer(0x00); //first byte on transfer of address and read bit - for(size_t i = 1; i < numBytes; i++) { - dataBuffer[i] = _spiPort->transfer(0x00); //Assuming this will initiate auto-increment behavior - } - digitalWrite(_cs, HIGH); - _spiPort->endTransaction(); - return KX13X_SUCCESS; - } - else { - - if( numBytes > MAX_BUFFER_LENGTH ){ - KX13X_STATUS_t returnError; - returnError = overBufLenI2CRead(reg, dataBuffer, numBytes); - return returnError; - } - - uint8_t i2cResult; - _i2cPort->beginTransmission(_deviceAddress); - _i2cPort->write(reg); - i2cResult = _i2cPort->endTransmission(false); - if( i2cResult != 0 ) - return KX13X_I2C_ERROR; //Error: Sensor did not ack - - i2cResult = _i2cPort->requestFrom(_deviceAddress, uint8_t(numBytes), uint8_t(true)); - if( i2cResult == 0 ) - return KX13X_I2C_ERROR; - for(size_t i = 0; i < numBytes; i++) { - dataBuffer[i] = _i2cPort->read(); - } - return KX13X_SUCCESS; - } + int retVal; + uint8_t clear = 1; + + retVal = writeRegisterByte(SFE_KX13X_BUF_CLEAR, clear); + + if( retVal != 0 ) + return false; + + return true; } +// Address: 0x1C, bit[6]: default value is: 0x00 +//Tests functionality of the integrated circuit by setting the command test +//control bit, then checks the results in the COTR register (0x12): 0xAA is a +//successful read, 0x55 is the default state. +bool QwDevKX13X::runCommandTest() +{ + + uint8_t tempVal; + int retVal; -// This function is used when more than 32 bytes (TwoWire maximum buffer -// length) of data are requested. -KX13X_STATUS_t QwiicKX13xCore::overBufLenI2CRead(uint8_t reg, uint8_t dataBuffer[], int16_t numBytes) -{ - uint8_t resizedRead; - uint8_t i2cResult; - size_t arrayPlaceHolder = 0; - - _i2cPort->beginTransmission(_deviceAddress); - _i2cPort->write(reg); - i2cResult = _i2cPort->endTransmission(false); - if( i2cResult != 0 ) - return KX13X_I2C_ERROR; //Error: Sensor did not ack - - while(numBytes > 0) - { - if( numBytes > MAX_BUFFER_LENGTH ) - resizedRead = MAX_BUFFER_LENGTH; - else - resizedRead = numBytes; - - i2cResult = _i2cPort->requestFrom(_deviceAddress, resizedRead, uint8_t(false)); //false = repeated start - if( i2cResult == 0 ) - return KX13X_I2C_ERROR; - for(size_t i = 0; i < resizedRead; i++) { - dataBuffer[arrayPlaceHolder] = _i2cPort->read(); - arrayPlaceHolder++; - } - numBytes = numBytes - MAX_BUFFER_LENGTH; // end condition - } - return KX13X_SUCCESS; + retVal = readRegisterRegion(SFE_KX13X_CNTL2, &tempVal, 1); + + if( retVal != 0 ) + return false; + + tempVal = tempVal | 0x40; + + // Going to assume that communication is working at this point. + writeRegisterByte(SFE_KX13X_CNTL2, tempVal); + + readRegisterRegion(SFE_KX13X_COTR, &tempVal, 1); + + if( tempVal != 0xAA ) + return false; + + readRegisterRegion(SFE_KX13X_CNTL2, &tempVal, 1); + + if( tempVal != 0 ) + return false; + + readRegisterRegion(SFE_KX13X_COTR, &tempVal, 1); + + if( tempVal != 0x55 ) + return false; + + return true; } -// Writes the given value to the given register, using the provided mask and -// bit position. -KX13X_STATUS_t QwiicKX13xCore::writeRegister(uint8_t reg, uint8_t mask, uint8_t data, uint8_t bitPos) -{ +// Address:0x08 - 0x0D or 0x63 , bit[7:0] +// Reads acceleration data from either the buffer or the output registers +// depending on if the user specified buffer usage. +bool QwDevKX13X::getRawAccelData(rawOutputData *rawAccelData){ - uint8_t tempRegVal; - KX13X_STATUS_t returnError; + + int retVal; + uint8_t tempVal; + uint8_t tempRegData[6] = {0}; - returnError = readRegister(&tempRegVal, reg); - if( returnError != KX13X_SUCCESS ) - return KX13X_I2C_ERROR; - tempRegVal &= mask; - tempRegVal |= (data << bitPos); + // Check if buffer is enabled + retVal = readRegisterRegion(SFE_KX13X_INC4, &tempVal, 1); - if( _i2cPort == NULL ) { - - _spiPort->beginTransaction(kxSPISettings); - digitalWrite(_cs, LOW); - _spiPort->transfer(reg | SPI_WRITE); - _spiPort->transfer(tempRegVal); - digitalWrite(_cs, HIGH); - _spiPort->endTransaction(); - return KX13X_SUCCESS; - } + if( retVal != 0 ) + return false; - else { - _i2cPort->beginTransmission(_deviceAddress); - _i2cPort->write(reg); // Move to register - _i2cPort->write(tempRegVal); + if( tempVal & 0x40 )// If Buffer is enabled, read there. + retVal = readRegisterRegion(SFE_KX13X_BUF_READ, tempRegData, 6); + else + retVal = readRegisterRegion(SFE_KX13X_XOUT_L, tempRegData, 6); - uint8_t i2cResult = _i2cPort->endTransmission(); - if( i2cResult != 0 ) - return KX13X_I2C_ERROR; - else - return KX13X_SUCCESS; - } + if( retVal != 0 ) + return false; + rawAccelData->xData = tempRegData[XLSB]; + rawAccelData->xData |= (uint16_t)((tempRegData[XMSB]) << 8); + rawAccelData->yData = tempRegData[YLSB]; + rawAccelData->yData |= (uint16_t)((tempRegData[YMSB]) << 8); + rawAccelData->zData = tempRegData[ZLSB]; + rawAccelData->zData |= ((uint16_t)(tempRegData[ZMSB]) << 8); + + return true; +} + + +int QwDevKX13X::readRegisterRegion(uint8_t reg, uint8_t *data, uint16_t len) +{ + return (int)_sfeBus->readRegisterRegion(_i2cAddress, reg, data, len); +} + +int QwDevKX13X::writeRegisterRegion(uint8_t reg, uint8_t *data, uint16_t len) +{ + return (int)_sfeBus->writeRegisterRegion(_i2cAddress, reg, data, len); } +int QwDevKX13X::writeRegisterByte(uint8_t reg, uint8_t value) +{ + return (int)_sfeBus->writeRegisterByte(_i2cAddress, reg, value); +} //***************************************** KX132 ****************************************** @@ -559,60 +912,49 @@ KX13X_STATUS_t QwiicKX13xCore::writeRegister(uint8_t reg, uint8_t mask, uint8_t //****************************************************************************************** //****************************************************************************************** -// Constructor -QwiicKX132::QwiicKX132() { } // Uses the beginCore function to check that the part ID from the "who am I" // register matches the correct value. Uses I2C for data transfer. -bool QwiicKX132::begin(uint8_t kxAddress, TwoWire &i2cPort){ +bool QwDevKX132::init(void) +{ + if( !_sfeBus->ping(_i2cAddress) ) + return false; - if( kxAddress != KX13X_DEFAULT_ADDRESS && kxAddress != KX13X_ALT_ADDRESS ) - return false; + if( getUniqueID() != KX132_WHO_AM_I ) + return false; - uint8_t partID = beginCore(kxAddress, i2cPort); - if( partID == KX132_WHO_AM_I ) - return true; - else - return false; - + return true; } -// Uses the beginCore function to check that the part ID from the "who am I" -// register matches the correct value. Uses SPI for data transfer. -bool QwiicKX132::beginSPI(uint8_t csPin, uint32_t spiPortSpeed, SPIClass &spiPort){ +// Grabs raw accel data and passes it to the following function to be +// converted. +bool QwDevKX132::getAccelData(outputData *userData){ + + bool retVal; - uint8_t partID; + retVal = getRawAccelData(&rawAccelData); - partID = beginSPICore(csPin, spiPortSpeed, spiPort); - - if( partID == KX132_WHO_AM_I ) - return true; + if( !retVal ) + return false; - return false; -} + retVal = convAccelData(userData, &rawAccelData); -// Grabs raw accel data and passes it to the following function to be -// converted. -outputData QwiicKX132::getAccelData(){ - - if( getRawAccelData(&rawAccelData) && - convAccelData(&userAccel, &rawAccelData) ) - return userAccel; + if( !retVal ) + return false; - userAccel.xData = 0xFF; - userAccel.yData = 0xFF; - userAccel.zData = 0xFF; - return userAccel; + return true; } // Converts acceleration data according to the set range value. -bool QwiicKX132::convAccelData(outputData *userAccel, rawOutputData *rawAccelData){ +bool QwDevKX132::convAccelData(outputData *userAccel, rawOutputData *rawAccelData){ uint8_t regVal; uint8_t range; - KX13X_STATUS_t returnError; - returnError = readRegister(®Val, KX13X_CNTL1); - if( returnError != KX13X_SUCCESS ) + int retVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, ®Val, 1); + + if( retVal != 0 ) return false; range = (regVal & 0x18) >> 3; @@ -639,6 +981,8 @@ bool QwiicKX132::convAccelData(outputData *userAccel, rawOutputData *rawAccelDat userAccel->yData = (float)rawAccelData->yData * convRange16G; userAccel->zData = (float)rawAccelData->zData * convRange16G; break; + default: + return false; } return true; @@ -650,61 +994,51 @@ bool QwiicKX132::convAccelData(outputData *userAccel, rawOutputData *rawAccelDat //****************************************************************************************** //Constructor -QwiicKX134::QwiicKX134() { } -// Uses the beginCore function to check that the part ID from the "who am I" -// register matches the correct value. Uses I2C for data transfer. -bool QwiicKX134::begin(uint8_t kxAddress, TwoWire &i2cPort){ - if( kxAddress != KX13X_DEFAULT_ADDRESS && kxAddress != KX13X_ALT_ADDRESS ) - return false; - - uint8_t partID = beginCore(kxAddress, i2cPort); - if( partID == KX134_WHO_AM_I ) - return true; - else - return false; -} +bool QwDevKX134::init(void) +{ + if( !_sfeBus->ping(_i2cAddress) ) + return false; + if( getUniqueID() != KX134_WHO_AM_I ) + return false; -// Uses the beginCore function to check that the part ID from the "who am I" -// register matches the correct value. Uses SPI for data transfer. -bool QwiicKX134::beginSPI(uint8_t csPin, uint32_t spiPortSpeed, SPIClass &spiPort){ + return true; +} - uint8_t partID; - partID = beginSPICore(csPin, spiPortSpeed, spiPort); +bool QwDevKX134::getAccelData(outputData *userData) +{ + + bool retVal; - if( partID == KX134_WHO_AM_I ) - return true; + retVal = getRawAccelData(&rawAccelData); - return false; -} + if( !retVal ) + return false; -// Grabs raw accel data and passes it to the following function to be -// converted. -outputData QwiicKX134::getAccelData(){ + retVal = convAccelData(userData, &rawAccelData); - if( getRawAccelData(&rawAccelData) && - convAccelData(&userAccel, &rawAccelData) ) - return userAccel; + if( !retVal ) + return false; - userAccel.xData = 0xFF; - userAccel.yData = 0xFF; - userAccel.zData = 0xFF; - return userAccel; + return true; } -// Converts acceleration data according to the set range value. -bool QwiicKX134::convAccelData(outputData *userAccel, rawOutputData *rawAccelData){ +bool QwDevKX134::convAccelData(outputData *userAccel, rawOutputData *rawAccelData) +{ uint8_t regVal; uint8_t range; - KX13X_STATUS_t returnError; - returnError = readRegister(®Val, KX13X_CNTL1); - if( returnError != KX13X_SUCCESS ) + int retVal; + + retVal = readRegisterRegion(SFE_KX13X_CNTL1, ®Val, 1); + + if( retVal != 0 ) return false; range = (regVal & 0x18) >> 3; + switch( range ) { case KX134_RANGE8G: @@ -727,6 +1061,8 @@ bool QwiicKX134::convAccelData(outputData *userAccel, rawOutputData *rawAccelDat userAccel->yData = (float)rawAccelData->yData * convRange64G; userAccel->zData = (float)rawAccelData->zData * convRange64G; break; + default: + return false; } diff --git a/src/SparkFun_Qwiic_KX13X.h b/src/SparkFun_Qwiic_KX13X.h index ee05468..3be1894 100644 --- a/src/SparkFun_Qwiic_KX13X.h +++ b/src/SparkFun_Qwiic_KX13X.h @@ -9,27 +9,30 @@ local, and you've found our code helpful, please buy us a round! Distributed as-is; no warranty is given. ******************************************************************************/ -#ifndef __SparkFun_Qwiic_KX13X_H__ -#define __SparkFun_Qwiic_KX13X_H__ - - -#if (ARDUINO >= 100) -#include "Arduino.h" -#else -#include "WProgram.h" -#endif +#pragma once #include #include +#include "SparkFun_KX13X_regs.h" +#include "sfe_bus.h" -#define KX13X_DEFAULT_ADDRESS 0x1F -#define KX13X_ALT_ADDRESS 0x1E +#define KX13X_ADDRESS_HIGH 0x1F +#define KX13X_ADDRESS_LOW 0x1E #define KX132_WHO_AM_I 0x3D #define KX134_WHO_AM_I 0x46 -#define TOTAL_ACCEL_DATA_16BIT 6 + +#define KX132_RANGE2G 0x00 +#define KX132_RANGE4G 0x01 +#define KX132_RANGE8G 0x02 +#define KX132_RANGE16G 0x03 + +#define KX134_RANGE8G 0x00 +#define KX134_RANGE16G 0x01 +#define KX134_RANGE32G 0x02 +#define KX134_RANGE64G 0x03 + #define TOTAL_ACCEL_DATA_8BIT 3 -#define MAX_BUFFER_LENGTH 32 #define XLSB 0 #define XMSB 1 @@ -39,7 +42,6 @@ Distributed as-is; no warranty is given. #define ZMSB 5 #define SPI_READ 0x80 // OR'ed at most sig BIT with register address -#define SPI_WRITE 0x00 // OR'ed at most sig BIT with register address #define DEFAULT_SETTINGS 0xC0 #define INT_SETTINGS 0xE0 @@ -47,9 +49,6 @@ Distributed as-is; no warranty is given. #define BUFFER_SETTINGS 0xE2 #define TILT_SETTINGS 0xE3 -#define COTR_DEF_STATE 0x55 -#define COTR_POS_STATE 0xAA - #define BUFFER_16BIT_SAMPLES 0x01 #define BUFFER_8BIT_SAMPLES 0x00 #define BUFFER_MODE_FIFO 0x00 @@ -68,217 +67,159 @@ struct rawOutputData { int16_t zData; }; -//Accelerometer Data -enum KX13X_REGISTERS { - - KX13X_MAN_ID = 0x00,// Retuns "KION" in ASCII - KX13X_PART_ID,// Who am I + Silicon specific ID - KX13X_XADP_L,// ------- X, Y, and Z - High and Low bytes ----- - KX13X_XADP_H, - KX13X_YADP_L, - KX13X_YADP_H, - KX13X_ZADP_L, - KX13X_ZADP_H, - KX13X_XOUT_L, - KX13X_XOUT_H, - KX13X_YOUT_L, - KX13X_YOUT_H, - KX13X_ZOUT_L, - KX13X_ZOUT_H, // --------------^^-------------------------- - // 0x0E - 0x11 Reserved - KX13X_COTR = 0x12,// Command Test Register - KX13X_WHO_AM_I, // Who am I: 0x3D-KX132, 0x46-KX134 - KXI3X_TSCP,// -------Tilt Register---------------------- - KX13X_TSPP,// -----------^^----------------------------- - KX13X_INS1, // -------Interrupt Registers --------------- - KX13X_INS2, - KX13X_INS3, - KX13X_STATUS_REG, - KX13X_INT_REL, // ------------^^---------------------------- - KX13X_CNTL1,// --------Control Registers----------------- - KX13X_CNTL2, - KX13X_CNTL3, - KX13X_CNTL4, - KX13X_CNTL5, - KX13X_CNTL6,// -------------^^--------------------------- - KX13X_ODCNTL, - KX13X_INC1,//Controls settings for INT1 - KX13X_INC2,//Defines behavior for Wake-Up Function and Back To Sleep - KX13X_INC3,//Defines which axes can cause a tap based interrupt - KX13X_INC4,//Controls which function triggers INT1 - KX13X_INC5, - KX13X_INC6,//Controls which function triggers INT2 - // 0x28 Reserved - KX13X_TILT_TIMER = 0x29, - KX13X_TDTRC, // Tap Control Regs ----- - KX13X_TDTC, - KX13X_TTH, - KX13X_TTL, - KX13X_FTD, - KX13X_STD, - KX13X_TLT, - KX13X_TWS, - KX13X_FFTH, - KX13X_FFC, - KX13X_FFCNTL, - // 0x35 - 0x36 Reserved - KX13X_TILT_ANGLE_LL = 0x37, - KX13X_TILT_ANGLE_HL, - KX13X_HYST_SET, - KX13X_LP_CNTL1, - KX13X_LP_CNTL2, - // 0x3C - 0x48 Reserved - KX13X_WUFTH = 0x49, - KX13X_BTSWUFTH, - KX13X_BTSTH, - KX13X_BTSC, - KX13X_WUFC, - // 0x4E - 0x5C Reserved - KX13X_SELF_TEST = 0x5D, - KX13X_BUF_CNTL1, - KX13X_BUF_CNTL2, - KX13X_BUF_STATUS_1, - KX13X_BUF_STATUS_2, - KX13X_BUF_CLEAR, - KX13X_BUF_READ, - KX13X_ADP_CNTL1, - KX13X_ADP_CNTL2, - KX13X_ADP_CNTL3, - KX13X_ADP_CNTL4, - KX13X_ADP_CNTL5, - KX13X_ADP_CNTL6, - KX13X_ADP_CNTL7, - KX13X_ADP_CNTL8, - KX13X_ADP_CNTL9, - KX13X_ADP_CNTL10, - KX13X_ADP_CNTL11, - KX13X_ADP_CNTL12, - KX13X_ADP_CNTL13, - KX13X_ADP_CNTL14, - KX13X_ADP_CNTL15, - KX13X_ADP_CNTL16, - KX13X_ADP_CNTL17, - KX13X_ADP_CNTL18, - KX13X_ADP_CNTL19 - //Reserved 0x77 - 0x7F -}; - -typedef enum { - - KX13X_SUCCESS = 0x00, - KX13X_GENERAL_ERROR, - KX13X_I2C_ERROR, - -} KX13X_STATUS_t; - -enum HARDWARE_INTERRUPT { - - HI_TILT_POSITION = 0x01, - HI_WAKE_UP = 0x02, - HI_TAP_DOUBLE_TAP = 0x04, - HI_BACK_TO_SLEEP = 0x08, - HI_DATA_READY = 0x10, - HI_WATERMARK = 0x20, - HI_BUFFER_FULL = 0x40, - HI_FREEFALL = 0x80 -}; - - -class QwiicKX13xCore +class QwDevKX13X { - public: + public: - QwiicKX13xCore(); + QwDevKX13X() : _i2cAddress{0}, _cs{0} {}; + + ////////////////////////////////////////////////////////////////////////////////// + // writeRegisterRegion() + // + // + // Parameter Description + // --------- ----------------------------- + // reg register to read from + // data Array to store data in + // length Size of data in bytes (8 bits): 2 bytes = length of two + // retval -1 = error, 0 = success + int writeRegisterRegion(uint8_t reg, uint8_t *data, uint16_t length); + + ////////////////////////////////////////////////////////////////////////////////// + // writeRegisterByte() + // + // + // Parameter Description + // --------- ----------------------------- + // reg register to read from + // data Array to store data in + // retval -1 = error, 0 = success + // + int writeRegisterByte(uint8_t reg, uint8_t data); + + ////////////////////////////////////////////////////////////////////////////////// + // readRegisterRegion() + // + // + // Parameter Description + // --------- ----------------------------- + // reg register to read from + // data Array to store data in + // length Length of the data to read + // retval -1 = error, 0 = success + + int readRegisterRegion(uint8_t reg, uint8_t *data, uint16_t length); + + ////////////////////////////////////////////////////////////////////////////////// + // setCommunicationBus() + // + // Called to set the Communication Bus object to use + // + // Parameter Description + // --------- ----------------------------- + // theBus The Bus object to use + // idBus The bus ID for the target device. + // + + void setCommunicationBus(QwIDeviceBus &theBus, uint8_t i2cAddress); + void setCommunicationBus(QwIDeviceBus &theBus); + + uint8_t getUniqueID(); - uint8_t beginCore(uint8_t, TwoWire &wirePort); - uint8_t beginSPICore(uint8_t, uint32_t, SPIClass &spiPort); bool initialize(uint8_t settings = DEFAULT_SETTINGS); - bool runCommandTest(); - bool accelControl(bool); - uint8_t readAccelState(); + + // General Settings + bool enableAccel(bool enable = true); + uint8_t getOperatingMode(); bool setRange(uint8_t); - bool setOutputDataRate(uint8_t); - float readOutputDataRate(); bool setInterruptPin(bool enable, uint8_t polarity = 0, uint8_t pulseWidth = 0, bool latchControl = false); + bool enableDataEngine(bool enable = true); + bool enableTapEngine(bool enable = true); + bool enableTiltEngine(bool enable = true); + bool setOutputDataRate(uint8_t); + float getOutputDataRate(); bool routeHardwareInterrupt(uint8_t, uint8_t pin = 1); + bool dataReady(); + bool runCommandTest(); + uint8_t readAccelState(); + bool getRawAccelData(rawOutputData*); + bool softwareReset(); + bool setTapDataRate(uint8_t rate); + + // Interrupt Settings + bool configureInterruptPin(uint8_t pinVal); + bool enablePhysInterrupt(bool enable = true, uint8_t pin = 1); + bool enableDirecTapInterupt(bool enable = true); + bool enableDoubleTapInterupt(bool enable = true); + bool setPinMode(bool activeLow = true); + bool setLatchControl(bool latch = true); + bool setPulseWidth(uint8_t width); + float readOutputDataRate(); bool clearInterrupt(); - bool dataTrigger(); + bool tapDetected(); + int8_t getDirection(); + bool unknownTap(); + bool waterMarkReached(); + bool bufferFull(); + bool freeFall(); + bool doubleTapDetected(); + bool tiltChange(); + + // Buffer Setttings bool setBufferThreshold(uint8_t); - bool setBufferOperation(uint8_t, uint8_t); - bool enableBuffer(bool, bool); + bool setBufferOperationMode(uint8_t operationMode); + bool setBufferResolution(bool sixteenBit = true); + bool enableBufferInt(bool enable = true); + bool enableSampleBuffer(bool enable = true); + uint16_t getSampleLevel(); + bool clearBuffer(); - bool getRawAccelData(rawOutputData*); - - KX13X_STATUS_t readRegister(uint8_t*, uint8_t); - KX13X_STATUS_t writeRegister(uint8_t, uint8_t, uint8_t, uint8_t); - KX13X_STATUS_t readMultipleRegisters(uint8_t, uint8_t dataBuffer[] , uint16_t); - KX13X_STATUS_t overBufLenI2CRead(uint8_t, uint8_t dataBuffer[] , int16_t); - // CPOL and CPHA are demonstrated on pg 25 of Specification Data sheet - // CPOL = 0, CPHA = 0 SPI_MODE0 - SPISettings kxSPISettings; rawOutputData rawAccelData; - outputData userAccel; - - private: - TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware - SPIClass *_spiPort; //The generic connection to user's chosen SPI hardware + protected: - uint8_t _deviceAddress; - uint32_t _spiPortSpeed; // max port speed is 10MHz + QwIDeviceBus *_sfeBus; //The generic connection to user's chosen SPI hardware + uint8_t _i2cAddress; uint8_t _cs; - - }; - -class QwiicKX132 : public QwiicKX13xCore + +class QwDevKX132 : public QwDevKX13X { public: - QwiicKX132(); - bool begin(uint8_t kxAddress = KX13X_DEFAULT_ADDRESS, TwoWire &i2cPort = Wire); - bool beginSPI(uint8_t, uint32_t spiPortSpeed = 2000000, SPIClass &spiPort = SPI); - outputData getAccelData(); - bool convAccelData(outputData*, rawOutputData*); - - private: + QwDevKX132() {}; - const double convRange2G = .00006103518784142582; - const double convRange4G = .0001220703756828516; - const double convRange8G = .0002441407513657033; - const double convRange16G = .0004882811975463118; + bool init(void); + bool getAccelData(outputData *userData); + bool convAccelData(outputData *userAccel, rawOutputData *rawAccelData); -#define KX132_RANGE2G 0x00 -#define KX132_RANGE4G 0x01 -#define KX132_RANGE8G 0x02 -#define KX132_RANGE16G 0x03 + //KX132 conversion values - all 16 bit resolution + const double convRange2G = .00006; + const double convRange4G = .00012; + const double convRange8G = .00024; + const double convRange16G = .00048; + private: }; -class QwiicKX134 : public QwiicKX13xCore +class QwDevKX134 : public QwDevKX13X { - public: + public: - QwiicKX134(); - bool begin(uint8_t kxAddress = KX13X_DEFAULT_ADDRESS, TwoWire &i2cPort = Wire); - bool beginSPI(uint8_t, uint32_t spiPortSpeed = 10000000, SPIClass &spiPort = SPI); - outputData getAccelData(); - bool convAccelData(outputData*, rawOutputData*); + QwDevKX134() {}; - private: + bool init(void); + bool getAccelData(outputData *userData); + bool convAccelData(outputData *userAccel, rawOutputData *rawAccelData); - const double convRange8G = .000244140751365703299; - const double convRange16G = .000488281197546311838; - const double convRange32G = .000976523950926236762; - const double convRange64G = .001953125095370342112; + //KX134 conversion values - all 16 bit resolution + const double convRange8G = .00024; + const double convRange16G = .00049; + const double convRange32G = .00098; + const double convRange64G = .00195; -#define KX134_RANGE8G 0x00 -#define KX134_RANGE16G 0x01 -#define KX134_RANGE32G 0x02 -#define KX134_RANGE64G 0x03 + private: }; - -#endif /* QWIIC_KX13X */ diff --git a/src/sfe_bus.cpp b/src/sfe_bus.cpp new file mode 100644 index 0000000..f205aef --- /dev/null +++ b/src/sfe_bus.cpp @@ -0,0 +1,365 @@ +// sfe_bus.cpp +// +// This is a library written for SparkFun Qwiic KX132 and KX134 boards +// +// SparkFun sells these bpards at its website: www.sparkfun.com +// +// Do you like this library? Help support SparkFun. Buy a board! +// +//SparkFun Triple Axis Accelerometer - KX132/KX134 (Qwiic) +// * KX132 - https://www.sparkfun.com/products/17871 +// * KX134 - https://www.sparkfun.com/products/17589 +// +// Written by Kirk Benell @ SparkFun Electronics +// Modified by Elias Santistevan @ SparkFun Electronics, September 2022 +// +// Repository: +// https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library +// +// +// SparkFun code, firmware, and software is released under the MIT +// License(http://opensource.org/licenses/MIT). +// +// SPDX-License-Identifier: MIT +// +// The MIT License (MIT) +// +// Copyright (c) 2022 SparkFun Electronics +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: The +// above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED +// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// The following classes specify the behavior for communicating +// over the respective data buses: Inter-Integrated Circuit (I2C) +// and Serial Peripheral Interface (SPI). + +#include "sfe_bus.h" +#include + +#define kMaxTransferBuffer 32 +#define SPI_READ 0x80 + +// What we use for transfer chunk size +const static uint16_t kChunkSize = kMaxTransferBuffer; + +////////////////////////////////////////////////////////////////////////////////////////////////// +// Constructor +// + + +QwI2C::QwI2C(void) : _i2cPort{nullptr} +{ +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// I2C init() +// +// Methods to init/setup this device. The caller can provide a Wire Port, or this class +// will use the default + +bool QwI2C::init(TwoWire &wirePort, bool bInit) +{ + + // if we don't have a wire port already + if( !_i2cPort ) + { + _i2cPort = &wirePort; + + if( bInit ) + _i2cPort->begin(); + } + + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// I2C init() +// +// Methods to init/setup this device. The caller can provide a Wire Port, or this class +// will use the default +bool QwI2C::init() +{ + if( !_i2cPort ) + return init(Wire); + else + return false; +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// ping() +// +// Is a device connected? +bool QwI2C::ping(uint8_t i2c_address) +{ + + if( !_i2cPort ) + return false; + + _i2cPort->beginTransmission(i2c_address); + return _i2cPort->endTransmission() == 0; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterByte() +// +// Write a byte to a register + +bool QwI2C::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite) +{ + + if (!_i2cPort) + return false; + + _i2cPort->beginTransmission(i2c_address); + _i2cPort->write(offset); + _i2cPort->write(dataToWrite); + return _i2cPort->endTransmission() == 0; +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterRegion() +// +// Write a block of data to a device. + +int QwI2C::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length) +{ + + _i2cPort->beginTransmission(i2c_address); + _i2cPort->write(offset); + _i2cPort->write(data, (int)length); + + return _i2cPort->endTransmission() ? -1 : 0; // -1 = error, 0 = success +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// readRegisterRegion() +// +// Reads a block of data from an i2c register on the devices. +// +// For large buffers, the data is chuncked over KMaxI2CBufferLength at a time +// +// +int QwI2C::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) +{ + uint8_t nChunk; + uint16_t nReturned; + + if (!_i2cPort) + return -1; + + int i; // counter in loop + bool bFirstInter = true; // Flag for first iteration - used to send register + + while (numBytes > 0) + { + _i2cPort->beginTransmission(addr); + + if (bFirstInter) + { + _i2cPort->write(reg); + bFirstInter = false; + } + + if (_i2cPort->endTransmission() != 0) + return -1; // error with the end transmission + + // We're chunking in data - keeping the max chunk to kMaxI2CBufferLength + nChunk = numBytes > kChunkSize ? kChunkSize : numBytes; + + nReturned = _i2cPort->requestFrom((int)addr, (int)nChunk, (int)true); + + // No data returned, no dice + if (nReturned == 0) + return -1; // error + + // Copy the retrieved data chunk to the current index in the data segment + for (i = 0; i < nReturned; i++){ + *data++ = _i2cPort->read(); + } + + // Decrement the amount of data recieved from the overall data request amount + numBytes = numBytes - nReturned; + + } // end while + + return 0; // Success +} + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// Constructor +// + +SfeSPI::SfeSPI(void) : _spiPort{nullptr} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// SPI init() +// +// Methods to init/setup this device. The caller can provide a SPI Port, or this class +// will use the default + + +bool SfeSPI::init(SPIClass &spiPort, SPISettings& kxSettings, uint8_t cs, bool bInit) +{ + + // if we don't have a SPI port already + if( !_spiPort ) + { + _spiPort = &spiPort; + + if( bInit ) + _spiPort->begin(); + } + + + // SPI settings are needed for every transaction + _sfeSPISettings = kxSettings; + + // The chip select pin can vary from platform to platform and project to project + // and so it must be given by the user. + if( !cs ) + return false; + + _cs = cs; + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// SPI init() +// +// Methods to init/setup this device. The caller can provide a SPI Port, or this class +// will use the default +bool SfeSPI::init(uint8_t cs, bool bInit) +{ + + //If the transaction settings are not provided by the user they are built here. + SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0); + + //In addition of the port is not provided by the user, it defaults to SPI here. + return init(SPI, spiSettings, cs, bInit); + +} + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// ping() +// +// Is a device connected? The SPI ping is not relevant but is defined here to keep consistency with +// I2C class i.e. provided for the interface. +// + + +bool SfeSPI::ping(uint8_t i2c_address) +{ + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterByte() +// +// Write a byte to a register + +bool SfeSPI::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite) +{ + + if( !_spiPort ) + return false; + + // Apply settings + _spiPort->beginTransaction(_sfeSPISettings); + // Signal communication start + digitalWrite(_cs, LOW); + + _spiPort->transfer(offset); + _spiPort->transfer(dataToWrite); + + // End communcation + digitalWrite(_cs, HIGH); + _spiPort->endTransaction(); + + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// writeRegisterRegion() +// +// Write a block of data to a device. + +int SfeSPI::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length) +{ + + int i; + + // Apply settings + _spiPort->beginTransaction(_sfeSPISettings); + // Signal communication start + digitalWrite(_cs, LOW); + _spiPort->transfer(offset); + + for(i = 0; i < length; i++) + { + _spiPort->transfer(*data++); + } + + // End communication + digitalWrite(_cs, HIGH); + _spiPort->endTransaction(); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////// +// readRegisterRegion() +// +// Reads a block of data from the register on the device. +// +// +// + + +int SfeSPI::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes) +{ + if (!_spiPort) + return -1; + + int i; // counter in loop + + // Apply settings + _spiPort->beginTransaction(_sfeSPISettings); + // Signal communication start + digitalWrite(_cs, LOW); + // A leading "1" must be added to transfer with register to indicate a "read" + reg = (reg | SPI_READ); + _spiPort->transfer(reg); + + for(i = 0; i < numBytes; i++) + { + *data++ = _spiPort->transfer(0x00); + } + + // End transaction + digitalWrite(_cs, HIGH); + _spiPort->endTransaction(); + return 0; + +} diff --git a/src/sfe_bus.h b/src/sfe_bus.h new file mode 100644 index 0000000..0d2a976 --- /dev/null +++ b/src/sfe_bus.h @@ -0,0 +1,125 @@ +// sfe_bus.h +// +// This is a library written for SparkFun Qwiic KX132 and KX134 boards +// +// SparkFun sells these bpards at its website: www.sparkfun.com +// +// Do you like this library? Help support SparkFun. Buy a board! +// +//SparkFun Triple Axis Accelerometer - KX132/KX134 (Qwiic) +// * KX132 - https://www.sparkfun.com/products/17871 +// * KX134 - https://www.sparkfun.com/products/17589 +// +// Written by Kirk Benell @ SparkFun Electronics +// Modified by Elias Santistevan @ SparkFun Electronics, September 2022 +// +// Repository: +// https://github.com/sparkfun/SparkFun_KX13X_Arduino_Library +// +// +// +// SparkFun code, firmware, and software is released under the MIT +// License(http://opensource.org/licenses/MIT). +// +// SPDX-License-Identifier: MIT +// +// The MIT License (MIT) +// +// Copyright (c) 2022 SparkFun Electronics +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: The +// above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED +// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// The following classes specify the behavior for communicating +// over the respective data buses: Inter-Integrated Circuit (I2C) +// and Serial Peripheral Interface (SPI). For ease of implementation +// an abstract interface (QwIDeviceBus) is used. + +#pragma once + + +#include +#include + + +// The following abstract class is used an interface for upstream implementation. +class QwIDeviceBus +{ + public: + + virtual bool ping(uint8_t address) = 0; + + virtual bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data) = 0; + + virtual int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t* data, uint16_t length) = 0; + + virtual int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t numBytes) = 0; + +}; + +// The QwI2C device defines behavior for I2C implementation based around the TwoWire class (Wire). +// This is Arduino specific. +class QwI2C : public QwIDeviceBus +{ + public: + + QwI2C(void); + + bool init(); + + bool init(TwoWire& wirePort, bool bInit=false); + + bool ping(uint8_t address); + + bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data); + + int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t* data, uint16_t length); + + int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t numBytes); + + private: + + TwoWire* _i2cPort; +}; + +// The SfeSPI class defines behavior for SPI implementation based around the SPIClass class (SPI). +// This is Arduino specific. +// Paramaters like "address" are kept although irrelevant to SPI due to the use of the abstract class +// as interface, QwIDeviceBus. +class SfeSPI : public QwIDeviceBus +{ + public: + + SfeSPI(void); + + bool init(uint8_t cs, bool bInit=false); + + bool init(SPIClass& spiPort, SPISettings& kxSettings, uint8_t cs, bool bInit=false); + + bool ping(uint8_t address); + + bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data); + + int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t* data, uint16_t length); + + int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t numBytes); + + private: + + SPIClass* _spiPort; + // Settings are used for every transaction. + SPISettings _sfeSPISettings; + uint8_t _cs; +}; +