I have to make this sensor (LIS3DH) work on a ClearCore controller and I couldn’t use the Adafruit libraries so I went through the Adafruit libraries to understand them and write this. This does not need any other library except SPI. It has been tested on an Arduino Mega
I had to go through many many pages online and through the Adafruit code for a week to make this work. Hopefully, this helps others.
The writeToRegister and mask code seems to be a bit buggy but it works for what I need so I won’t be spending time on that.
#include <SPI.h>
//#define DEBUG_SERIAL Serial
//#define DEBUG_SERIAL_X_RESULT Serial
//#define DEBUG_SERIAL_AVERAGE Serial
// Used for hardware
#define LIS3DH_CS 53
//Registers to use
#define WHO_AM_I_WRITE 0xF
#define EMPTY_STRING 0xFF
#define CTRL_REG1 0x20
#define CTRL_REG4 0x23
//X-axis acceleration data. The value is expressed in two’s complement.
const uint8_t OUT_X_L = 0x28;
const uint8_t OUT_X_H = 0x29;
const uint8_t OUT_Y_L = 0x2A;
const uint8_t OUT_Y_H = 0x2B;
const uint8_t OUT_Z_L = 0x2C;
const uint8_t OUT_Z_H = 0x2D;
//Data
#define RANGE_2G 0b00
#define RANGE_2G_HIGH_REZ 0b001
#define RANGE_4G 0b01
#define RANGE_8G 0b10
#define RANGE_16G 0b11
#define RANGE_16G_HIGH_REZ 0b111
#define ENABLE_X_Y_Z 0x07
#define DATARATE_1_HZ 0b0001
#define DATARATE_100_HZ 0b0101
#define DATARATE_400_HZ 0b0111
#define ENABLE_HIGH_REZ 0b1
//Config
SPISettings *_spiSetting = new SPISettings(500000, MSBFIRST, SPI_MODE0);
boolean foundLIS3DH = false;
const int NORMALIZE_MIN_SCALE = -25;
const int NORMALIZE_MAX_SCALE = 25;
//this value will need to be changed if the range is changed from RANGE_2G to something else
const int NORMALIZE_MIN_VALUE = -16000;
const int NORMALIZE_MAX_VALUE = 16000;
void setup(void) {
Serial.begin(9600);
while (!Serial) delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("LIS3DH test!");
setupSPI();
setupLIS3DH();
}
void setupSPI() {
//Initializes SPI bus and sets CS pin high
pinMode(LIS3DH_CS, OUTPUT);
digitalWrite(LIS3DH_CS, HIGH);
//it is important to call begin
SPI.begin();
}
void setupLIS3DH() {
uint8_t result = readRegister(WHO_AM_I_WRITE);
if (result == 0) {
foundLIS3DH = false;
Serial.println("LIS3DH not found");
} else {
foundLIS3DH = true;
Serial.println("LIS3DH found");
enableXYZAxis();
changeRange();
changeDataRate();
displayDataRate();
}
}
void changeRange() {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****changeRange()******");
#endif
writeToRegister(CTRL_REG4, RANGE_2G_HIGH_REZ, 3);
//writeToRegister(CTRL_REG4, RANGE_16G, 4);
readRegister(CTRL_REG4);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****changeRange() end***");
#endif
}
void enableHighResolution() {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****enableHighResolution()******");
#endif
writeToRegister(CTRL_REG4, ENABLE_HIGH_REZ, 3);
readRegister(CTRL_REG4);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****enableHighResolution() end***");
#endif
}
int readAxisNormalized(uint8_t axisAdressLow, uint8_t axisAddressHigh) {
int newValue = readAxis(axisAdressLow, axisAddressHigh);
int normalizedValue = map(newValue, NORMALIZE_MIN_VALUE, NORMALIZE_MAX_VALUE, NORMALIZE_MIN_SCALE, NORMALIZE_MAX_SCALE);
return normalizedValue;
}
int16_t readAxis(uint8_t axisAdressLow, uint8_t axisAddressHigh) {
uint8_t resultLow = readRegister(axisAdressLow);
uint8_t resultHigh = readRegister(axisAddressHigh);
#ifdef DEBUG_SERIAL_X_RESULT
DEBUG_SERIAL_X_RESULT.print("resultLow = readRegister(axisAdressLow); ");
DEBUG_SERIAL_X_RESULT.println(resultLow);
DEBUG_SERIAL_X_RESULT.println(resultLow, BIN);
DEBUG_SERIAL_X_RESULT.print("resultHigh = readRegister(axisAddressHigh); ");
DEBUG_SERIAL_X_RESULT.println(resultHigh);
DEBUG_SERIAL_X_RESULT.println(resultHigh, BIN);
#endif
//combining the values as is done in void Adafruit_LIS3DH::read(void)
int16_t resultCombined = resultLow;
resultCombined |= ((uint16_t)resultHigh) << 8;
#ifdef DEBUG_SERIAL_X_RESULT
DEBUG_SERIAL_X_RESULT.print("resultCombined ");
DEBUG_SERIAL_X_RESULT.println(resultCombined);
#endif
return resultCombined;
}
void enableXYZAxis() {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****enableXYZAxis()******");
#endif
writeToRegister(CTRL_REG1, ENABLE_X_Y_Z, 0);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****enableXYZAxis() end***");
#endif
}
void changeDataRate() {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****changeDataRate()******");
#endif
writeToRegister(CTRL_REG1, DATARATE_100_HZ, 4);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****changeDataRate() end***");
#endif
}
void displayDataRate() {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****displayDataRate()******");
#endif
uint8_t result = readRegister(CTRL_REG1);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.println("*****displayDataRate() end***");
#endif
}
uint8_t readRegister(uint8_t readAddress) {
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("readRegister(0x");
DEBUG_SERIAL.print(readAddress, HEX);
DEBUG_SERIAL.println(")");
#endif
//Example: The register CTRL_REG4 has a HEX value of 0x23. 23 = 00100011 in binary.
//Adafruit did an OR with HEX 0x80. It sets the first bit to 1.
//This seems to be needed to make things work, but only on the read, not the write.
uint8_t eightBitReadAddress = readAddress | 0x80;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("eightBitReadAddress 0x");
DEBUG_SERIAL.println(eightBitReadAddress, HEX);
#endif
//write to the register and then read
uint8_t result = 0;
SPI.beginTransaction(*_spiSetting);
{
digitalWrite(LIS3DH_CS, LOW);
//set the register we are interested in
SPI.transfer(eightBitReadAddress);
result = SPI.transfer(EMPTY_STRING);
digitalWrite(LIS3DH_CS, HIGH);
}
SPI.endTransaction();
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("Result in binary from register ");
DEBUG_SERIAL.println(result, BIN);
DEBUG_SERIAL.print("Result in HEX from register ");
DEBUG_SERIAL.println(result, HEX);
#endif
return result;
}
void writeToRegister(uint8_t writeAddress, uint8_t valueToWrite, uint8_t shift) {
//get the current value in the register
uint8_t valueInRegister = readRegister(writeAddress);
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("writeToRegister(0x");
DEBUG_SERIAL.print(writeAddress, HEX);
DEBUG_SERIAL.print(", 0x");
DEBUG_SERIAL.print(valueToWrite, HEX);
DEBUG_SERIAL.println(")");
#endif
//from Adafruit bool Adafruit_BusIO_RegisterBits::write(uint32_t data)
//populate the register with the new value, only modify the bits that need to be changed
uint8_t mask = (1 << (valueToWrite)) - 1;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("mask ");
DEBUG_SERIAL.println(mask, BIN);
#endif
valueInRegister &= mask;
#ifdef DEBUG_SERIAL
DEBUG_SERIAL.print("valueInRegister &= mask ");
DEBUG_SERIAL.println(valueInRegister, BIN);
#endif
mask <<= shift;
valueInRegister &= ~mask; // remove the current data at that spot
valueInRegister |= valueToWrite << shift; // and add in the new data
//*****************************************************
//write to the register and then read
SPI.beginTransaction(*_spiSetting);
{
digitalWrite(LIS3DH_CS, LOW);
//set the register we are interested in
SPI.transfer(writeAddress);
//write the new value to the register
SPI.transfer(valueInRegister);
digitalWrite(LIS3DH_CS, HIGH);
}
SPI.endTransaction();
}
void loop() {
long resultX = readAxisNormalized(OUT_X_L, OUT_X_H);
long resultY = readAxisNormalized(OUT_Y_L, OUT_Y_H);
long resultZ = readAxisNormalized(OUT_Z_L, OUT_Z_H);
Serial.print("X:"); Serial.print(resultX); Serial.print(" Y: "); Serial.print(resultY); Serial.print(" Z: "); Serial.println(resultZ);
delay(100);
}