firmware/src/motion/QMA6100PSensor.cpp
Thomas Göttgens adf1bc4b0e
fix tracker build (#5151)
fix tracker 1000 build
2024-10-26 14:40:10 +02:00

183 lines
5.1 KiB
C++

#include "QMA6100PSensor.h"
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_QMA6100P)
// Flag when an interrupt has been detected
volatile static bool QMA6100P_IRQ = false;
// Interrupt service routine
void QMA6100PSetInterrupt()
{
QMA6100P_IRQ = true;
}
QMA6100PSensor::QMA6100PSensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) {}
bool QMA6100PSensor::init()
{
// Initialise the sensor
sensor = QMA6100PSingleton::GetInstance();
if (!sensor->init(device))
return false;
// Enable simple Wake on Motion
return sensor->setWakeOnMotion();
}
#ifdef QMA_6100P_INT_PIN
int32_t QMA6100PSensor::runOnce()
{
// Wake on motion using hardware interrupts - this is the most efficient way to check for motion
if (QMA6100P_IRQ) {
QMA6100P_IRQ = false;
wakeScreen();
}
return MOTION_SENSOR_CHECK_INTERVAL_MS;
}
#else
int32_t QMA6100PSensor::runOnce()
{
// Wake on motion using polling - this is not as efficient as using hardware interrupt pin (see above)
uint8_t tempVal;
if (!sensor->readRegisterRegion(SFE_QMA6100P_INT_ST0, &tempVal, 1)) {
LOG_DEBUG("QMA6100PSensor::isWakeOnMotion failed to read interrupts");
return MOTION_SENSOR_CHECK_INTERVAL_MS;
}
if ((tempVal & 7) != 0) {
// Wake up!
wakeScreen();
}
return MOTION_SENSOR_CHECK_INTERVAL_MS;
}
#endif
// ----------------------------------------------------------------------
// QMA6100PSingleton
// ----------------------------------------------------------------------
// Get a singleton wrapper for an Sparkfun QMA_6100P_I2C
QMA6100PSingleton *QMA6100PSingleton::GetInstance()
{
if (pinstance == nullptr) {
pinstance = new QMA6100PSingleton();
}
return pinstance;
}
QMA6100PSingleton::QMA6100PSingleton() {}
QMA6100PSingleton::~QMA6100PSingleton() {}
QMA6100PSingleton *QMA6100PSingleton::pinstance{nullptr};
// Initialise the QMA6100P Sensor
bool QMA6100PSingleton::init(ScanI2C::FoundDevice device)
{
// startup
#ifdef Wire1
bool status = begin(device.address.address, device.address.port == ScanI2C::I2CPort::WIRE1 ? &Wire1 : &Wire);
#else
// check chip id
bool status = begin(device.address.address, &Wire);
#endif
if (status != true) {
LOG_WARN("QMA6100PSensor::init begin failed\n");
return false;
}
delay(20);
// SW reset to make sure the device starts in a known state
if (softwareReset() != true) {
LOG_WARN("QMA6100PSensor::init reset failed\n");
return false;
}
delay(20);
// Set range
if (!setRange(QMA_6100P_MPU_ACCEL_SCALE)) {
LOG_WARN("QMA6100PSensor::init range failed");
return false;
}
// set active mode
if (!enableAccel()) {
LOG_WARN("ERROR :QMA6100PSensor::active mode set failed");
}
// set calibrateoffsets
if (!calibrateOffsets()) {
LOG_WARN("ERROR :QMA6100PSensor:: calibration failed");
}
#ifdef QMA_6100P_INT_PIN
// Active low & Open Drain
uint8_t tempVal;
if (!readRegisterRegion(SFE_QMA6100P_INTPINT_CONF, &tempVal, 1)) {
LOG_WARN("QMA6100PSensor::init failed to read interrupt pin config");
return false;
}
tempVal |= 0b00000010; // Active low & Open Drain
if (!writeRegisterByte(SFE_QMA6100P_INTPINT_CONF, tempVal)) {
LOG_WARN("QMA6100PSensor::init failed to write interrupt pin config");
return false;
}
// Latch until cleared, all reads clear the latch
if (!readRegisterRegion(SFE_QMA6100P_INT_CFG, &tempVal, 1)) {
LOG_WARN("QMA6100PSensor::init failed to read interrupt config");
return false;
}
tempVal |= 0b10000001; // Latch until cleared, INT_RD_CLR1
if (!writeRegisterByte(SFE_QMA6100P_INT_CFG, tempVal)) {
LOG_WARN("QMA6100PSensor::init failed to write interrupt config");
return false;
}
// Set up an interrupt pin with an internal pullup for active low
pinMode(QMA_6100P_INT_PIN, INPUT_PULLUP);
// Set up an interrupt service routine
attachInterrupt(QMA_6100P_INT_PIN, QMA6100PSetInterrupt, FALLING);
#endif
return true;
}
bool QMA6100PSingleton::setWakeOnMotion()
{
// Enable 'Any Motion' interrupt
if (!writeRegisterByte(SFE_QMA6100P_INT_EN2, 0b00000111)) {
LOG_WARN("QMA6100PSingleton::setWakeOnMotion failed to write interrupt enable");
return false;
}
// Set 'Significant Motion' interrupt map to INT1
uint8_t tempVal;
if (!readRegisterRegion(SFE_QMA6100P_INT_MAP1, &tempVal, 1)) {
LOG_WARN("QMA6100PSingleton::setWakeOnMotion failed to read interrupt map");
return false;
}
sfe_qma6100p_int_map1_bitfield_t int_map1;
int_map1.all = tempVal;
int_map1.bits.int1_any_mot = 1; // any motion interrupt to INT1
tempVal = int_map1.all;
if (!writeRegisterByte(SFE_QMA6100P_INT_MAP1, tempVal)) {
LOG_WARN("QMA6100PSingleton::setWakeOnMotion failed to write interrupt map");
return false;
}
// Clear any current interrupts
QMA6100P_IRQ = false;
return true;
}
#endif