mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-05 17:40:51 +00:00
T1000-E Peripherals (#5141)
* T1000-E Peripherals - enable intelligent charge controller signals - enable Accelerometer - enable internal I2C bus - provide Power to Accelerometer * POC Accelerometer Code (wakeScreen is moot for that device, just test if the driver works) * fix building without the sensor
This commit is contained in:
@@ -14,6 +14,9 @@
|
||||
#include "LSM6DS3Sensor.h"
|
||||
#include "MPU6050Sensor.h"
|
||||
#include "MotionSensor.h"
|
||||
#ifdef HAS_QMA6100P
|
||||
#include "QMA6100PSensor.h"
|
||||
#endif
|
||||
#include "STK8XXXSensor.h"
|
||||
|
||||
extern ScanI2C::DeviceAddress accelerometer_found;
|
||||
@@ -97,6 +100,11 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
case ScanI2C::DeviceType::ICM20948:
|
||||
sensor = new ICM20948Sensor(device);
|
||||
break;
|
||||
#ifdef HAS_QMA6100P
|
||||
case ScanI2C::DeviceType::QMA6100P:
|
||||
sensor = new QMA6100PSensor(device);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
disable();
|
||||
return;
|
||||
|
||||
183
src/motion/QMA6100PSensor.cpp
Normal file
183
src/motion/QMA6100PSensor.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "QMA6100PSensor.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && 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
|
||||
63
src/motion/QMA6100PSensor.h
Normal file
63
src/motion/QMA6100PSensor.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#ifndef _QMA_6100P_SENSOR_H_
|
||||
#define _QMA_6100P_SENSOR_H_
|
||||
|
||||
#include "MotionSensor.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && HAS_QMA6100P
|
||||
|
||||
#include <QMA6100P.h>
|
||||
|
||||
// Set the default accelerometer scale - gpm2, gpm4, gpm8, gpm16
|
||||
#ifndef QMA_6100P_MPU_ACCEL_SCALE
|
||||
#define QMA_6100P_MPU_ACCEL_SCALE SFE_QMA6100P_RANGE32G
|
||||
#endif
|
||||
|
||||
// The I2C address of the Accelerometer (if found) from main.cpp
|
||||
extern ScanI2C::DeviceAddress accelerometer_found;
|
||||
|
||||
// Singleton wrapper for the Sparkfun QMA_6100P_I2C class
|
||||
class QMA6100PSingleton : public QMA6100P
|
||||
{
|
||||
private:
|
||||
static QMA6100PSingleton *pinstance;
|
||||
|
||||
protected:
|
||||
QMA6100PSingleton();
|
||||
~QMA6100PSingleton();
|
||||
|
||||
public:
|
||||
// Create a singleton instance (not thread safe)
|
||||
static QMA6100PSingleton *GetInstance();
|
||||
|
||||
// Singletons should not be cloneable.
|
||||
QMA6100PSingleton(QMA6100PSingleton &other) = delete;
|
||||
|
||||
// Singletons should not be assignable.
|
||||
void operator=(const QMA6100PSingleton &) = delete;
|
||||
|
||||
// Initialise the motion sensor singleton for normal operation
|
||||
bool init(ScanI2C::FoundDevice device);
|
||||
|
||||
// Enable Wake on Motion interrupts (sensor must be initialised first)
|
||||
bool setWakeOnMotion();
|
||||
};
|
||||
|
||||
class QMA6100PSensor : public MotionSensor
|
||||
{
|
||||
private:
|
||||
QMA6100PSingleton *sensor = nullptr;
|
||||
|
||||
public:
|
||||
explicit QMA6100PSensor(ScanI2C::FoundDevice foundDevice);
|
||||
|
||||
// Initialise the motion sensor
|
||||
virtual bool init() override;
|
||||
|
||||
// Called each time our sensor gets a chance to run
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user