Fix T1000-E QMA6100P I2C probing (#10713)
* Fix T1000-E QMA6100P I2C probing * Refactored to make generic * address copilot comments * fix(i2c): address copilot comments on QMA6100P scanning and hardware init - ScanI2CTwoWire: gate bounded QMA6100P probing to addresses 0x12/0x13 only (Copilot comment: avoid blocking other I2C device detection on nRF52) Falls back to normal Wire probing for all other addresses, allowing BMM150 and other devices at overlapping addresses to be properly detected. - Nrf52Twim: suppress cppcheck redundantAssignment on ENABLE register write (intentional disable→configure→enable pattern for hardware safety; explicit disable ensures known state before configuration even if already disabled) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Nrf52Twim: gate on HAS_QMA6100P; suppress cppcheck redundantAssignment The TWIM helper is only used by the QMA6100P probing path (T1000-E, the sole board defining HAS_QMA6100P). It was gated only on ARCH_NRF52, so it compiled as dead code on every other nRF52 board and was analyzed by the rak4631 cppcheck job -- which failed on a redundantAssignment false positive. Gate the header and source on HAS_QMA6100P so the file is only built/analyzed where it is actually used. Also keep an inline suppression on the ENABLE re-assignment (a required volatile disable->reconfigure->enable sequence) for the case where the T1000-E build is run through cppcheck locally. Fixes the rak4631 cppcheck CI failure for PR #10713. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: nomdetom <nomdetom@protonmail.com> Co-authored-by: Tom <116762865+NomDeTom@users.noreply.github.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
Ben Meadors
nomdetom
Tom
parent
2fdb722e00
commit
0eaad08735
@@ -11,6 +11,25 @@
|
|||||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32)
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32)
|
||||||
#include "meshUtils.h" // vformat
|
#include "meshUtils.h" // vformat
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_QMA6100P) && (defined(ARCH_NRF52) || defined(NRF52_SERIES) || defined(NRF52))
|
||||||
|
#include "platform/nrf52/Nrf52Twim.h"
|
||||||
|
#include <QMA6100P.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool probeQMA6100P(uint8_t address)
|
||||||
|
{
|
||||||
|
uint8_t chipID = 0;
|
||||||
|
|
||||||
|
Nrf52Twim::restoreBus();
|
||||||
|
const bool readOk = Nrf52Twim::readRegister(address, SFE_QMA6100P_CHIP_ID, chipID);
|
||||||
|
const bool found = readOk && chipID == QMA6100P_CHIP_ID;
|
||||||
|
Nrf52Twim::restoreBus();
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
||||||
@@ -277,11 +296,36 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
// 0x7C-0x7F Reserved for future purposes
|
// 0x7C-0x7F Reserved for future purposes
|
||||||
|
|
||||||
for (addr.address = 8; addr.address < 120; addr.address++) {
|
for (addr.address = 8; addr.address < 120; addr.address++) {
|
||||||
|
#if defined(HAS_QMA6100P) && (defined(ARCH_NRF52) || defined(NRF52_SERIES) || defined(NRF52))
|
||||||
|
bool nrf52QmaFound = false;
|
||||||
|
#endif
|
||||||
if (asize != 0) {
|
if (asize != 0) {
|
||||||
if (!in_array(address, asize, (uint8_t)addr.address))
|
if (!in_array(address, asize, (uint8_t)addr.address))
|
||||||
continue;
|
continue;
|
||||||
LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address);
|
LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address);
|
||||||
}
|
}
|
||||||
|
// For QMA6100P candidates on nRF52, use bounded I2C probing; otherwise use normal Wire
|
||||||
|
#if defined(HAS_QMA6100P) && (defined(ARCH_NRF52) || defined(NRF52_SERIES) || defined(NRF52))
|
||||||
|
if (addr.address == QMA6100P_ADDRESS_LOW || addr.address == QMA6100P_ADDRESS_HIGH) {
|
||||||
|
nrf52QmaFound = probeQMA6100P(addr.address);
|
||||||
|
err = nrf52QmaFound ? 0 : 2;
|
||||||
|
} else {
|
||||||
|
i2cBus->beginTransmission(addr.address);
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
err = 2;
|
||||||
|
if ((addr.address >= 0x30 && addr.address <= 0x37) || (addr.address >= 0x50 && addr.address <= 0x5F)) {
|
||||||
|
if (i2cBus->read() != -1)
|
||||||
|
err = 0;
|
||||||
|
} else {
|
||||||
|
err = i2cBus->writeQuick((uint8_t)0);
|
||||||
|
}
|
||||||
|
if (err != 0)
|
||||||
|
err = 2;
|
||||||
|
#else
|
||||||
|
err = i2cBus->endTransmission();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
i2cBus->beginTransmission(addr.address);
|
i2cBus->beginTransmission(addr.address);
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
err = 2;
|
err = 2;
|
||||||
@@ -295,6 +339,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
err = 2;
|
err = 2;
|
||||||
#else
|
#else
|
||||||
err = i2cBus->endTransmission();
|
err = i2cBus->endTransmission();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
type = NONE;
|
type = NONE;
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
@@ -750,7 +795,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SCAN_SIMPLE_CASE(BMM150_ADDR, BMM150, "BMM150", (uint8_t)addr.address);
|
case BMM150_ADDR:
|
||||||
|
#if defined(HAS_QMA6100P) && (defined(ARCH_NRF52) || defined(NRF52_SERIES) || defined(NRF52))
|
||||||
|
if (nrf52QmaFound) {
|
||||||
|
logFoundDevice("QMA6100P", (uint8_t)addr.address);
|
||||||
|
type = QMA6100P;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
logFoundDevice("BMM150", (uint8_t)addr.address);
|
||||||
|
type = BMM150;
|
||||||
|
break;
|
||||||
#ifdef HAS_TPS65233
|
#ifdef HAS_TPS65233
|
||||||
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address);
|
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,9 +2,83 @@
|
|||||||
|
|
||||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_QMA6100P)
|
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_QMA6100P)
|
||||||
|
|
||||||
|
#ifdef ARCH_NRF52
|
||||||
|
#include "platform/nrf52/Nrf52Twim.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Flag when an interrupt has been detected
|
// Flag when an interrupt has been detected
|
||||||
volatile static bool QMA6100P_IRQ = false;
|
volatile static bool QMA6100P_IRQ = false;
|
||||||
|
|
||||||
|
#ifdef ARCH_NRF52
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool qma6100pUpdateRegister(uint8_t address, uint8_t reg, uint8_t (*mutate)(uint8_t))
|
||||||
|
{
|
||||||
|
uint8_t value = 0;
|
||||||
|
return Nrf52Twim::readRegister(address, reg, value) && Nrf52Twim::writeRegister(address, reg, mutate(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qma6100pSetRange(uint8_t value)
|
||||||
|
{
|
||||||
|
sfe_qma6100p_fsr_bitfield_t fsr;
|
||||||
|
fsr.all = value;
|
||||||
|
fsr.bits.range = QMA_6100P_MPU_ACCEL_SCALE;
|
||||||
|
return fsr.all;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qma6100pEnableAccel(uint8_t value)
|
||||||
|
{
|
||||||
|
sfe_qma6100p_pm_bitfield_t pm;
|
||||||
|
pm.all = value;
|
||||||
|
pm.bits.mode_bit = 1;
|
||||||
|
return pm.all;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qma6100pConfigureIntPin(uint8_t value)
|
||||||
|
{
|
||||||
|
return value | 0b00000010;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qma6100pConfigureIntLatch(uint8_t value)
|
||||||
|
{
|
||||||
|
return value | 0b10000001;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qma6100pMapAnyMotionToInt1(uint8_t value)
|
||||||
|
{
|
||||||
|
sfe_qma6100p_int_map1_bitfield_t intMap1;
|
||||||
|
intMap1.all = value;
|
||||||
|
intMap1.bits.int1_any_mot = 1;
|
||||||
|
return intMap1.all;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qma6100pInitBounded(uint8_t address)
|
||||||
|
{
|
||||||
|
// SFE_QMA6100P_SR: write 0xB6 to trigger soft-reset, then 0x00 to release
|
||||||
|
constexpr uint8_t QMA6100P_SOFT_RESET = 0xb6;
|
||||||
|
constexpr uint8_t QMA6100P_SOFT_RESET_RELEASE = 0x00;
|
||||||
|
// SFE_QMA6100P_INT_EN2: bits[2:0] = any-motion enable for Z, Y, X axes
|
||||||
|
constexpr uint8_t QMA6100P_INT_EN2_ANY_MOT_XYZ = 0b00000111;
|
||||||
|
|
||||||
|
uint8_t chipID = 0;
|
||||||
|
|
||||||
|
Nrf52Twim::restoreBus();
|
||||||
|
const bool ok = Nrf52Twim::readRegister(address, SFE_QMA6100P_CHIP_ID, chipID) && chipID == QMA6100P_CHIP_ID &&
|
||||||
|
Nrf52Twim::writeRegister(address, SFE_QMA6100P_SR, QMA6100P_SOFT_RESET) &&
|
||||||
|
Nrf52Twim::writeRegister(address, SFE_QMA6100P_SR, QMA6100P_SOFT_RESET_RELEASE) &&
|
||||||
|
qma6100pUpdateRegister(address, SFE_QMA6100P_FSR, qma6100pSetRange) &&
|
||||||
|
qma6100pUpdateRegister(address, SFE_QMA6100P_PM, qma6100pEnableAccel) &&
|
||||||
|
Nrf52Twim::writeRegister(address, SFE_QMA6100P_INT_EN2, QMA6100P_INT_EN2_ANY_MOT_XYZ) &&
|
||||||
|
qma6100pUpdateRegister(address, SFE_QMA6100P_INT_MAP1, qma6100pMapAnyMotionToInt1) &&
|
||||||
|
qma6100pUpdateRegister(address, SFE_QMA6100P_INTPINT_CONF, qma6100pConfigureIntPin) &&
|
||||||
|
qma6100pUpdateRegister(address, SFE_QMA6100P_INT_CFG, qma6100pConfigureIntLatch);
|
||||||
|
Nrf52Twim::restoreBus();
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
// Interrupt service routine
|
// Interrupt service routine
|
||||||
void QMA6100PSetInterrupt()
|
void QMA6100PSetInterrupt()
|
||||||
{
|
{
|
||||||
@@ -15,6 +89,20 @@ QMA6100PSensor::QMA6100PSensor(ScanI2C::FoundDevice foundDevice) : MotionSensor:
|
|||||||
|
|
||||||
bool QMA6100PSensor::init()
|
bool QMA6100PSensor::init()
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_NRF52
|
||||||
|
if (!qma6100pInitBounded(device.address.address)) {
|
||||||
|
LOG_WARN("QMA6100P init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QMA6100P_IRQ = false;
|
||||||
|
|
||||||
|
#ifdef QMA_6100P_INT_PIN
|
||||||
|
pinMode(QMA_6100P_INT_PIN, INPUT_PULLUP);
|
||||||
|
attachInterrupt(QMA_6100P_INT_PIN, QMA6100PSetInterrupt, FALLING);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
// Initialise the sensor
|
// Initialise the sensor
|
||||||
sensor = QMA6100PSingleton::GetInstance();
|
sensor = QMA6100PSingleton::GetInstance();
|
||||||
if (!sensor->init(device))
|
if (!sensor->init(device))
|
||||||
@@ -22,6 +110,7 @@ bool QMA6100PSensor::init()
|
|||||||
|
|
||||||
// Enable simple Wake on Motion
|
// Enable simple Wake on Motion
|
||||||
return sensor->setWakeOnMotion();
|
return sensor->setWakeOnMotion();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QMA_6100P_INT_PIN
|
#ifdef QMA_6100P_INT_PIN
|
||||||
@@ -40,6 +129,16 @@ int32_t QMA6100PSensor::runOnce()
|
|||||||
|
|
||||||
int32_t QMA6100PSensor::runOnce()
|
int32_t QMA6100PSensor::runOnce()
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_NRF52
|
||||||
|
// restoreBus() is intentionally omitted here: it tears down and re-initialises Wire,
|
||||||
|
// which would be destructive on every poll. The bus is stable after init(); a failed
|
||||||
|
// read is handled gracefully below.
|
||||||
|
uint8_t tempVal = 0;
|
||||||
|
if (!Nrf52Twim::readRegister(device.address.address, SFE_QMA6100P_INT_ST0, tempVal)) {
|
||||||
|
LOG_DEBUG("QMA6100PS isWakeOnMotion failed to read interrupts");
|
||||||
|
return MOTION_SENSOR_CHECK_INTERVAL_MS;
|
||||||
|
}
|
||||||
|
#else
|
||||||
// Wake on motion using polling - this is not as efficient as using hardware interrupt pin (see above)
|
// Wake on motion using polling - this is not as efficient as using hardware interrupt pin (see above)
|
||||||
|
|
||||||
uint8_t tempVal;
|
uint8_t tempVal;
|
||||||
@@ -47,6 +146,7 @@ int32_t QMA6100PSensor::runOnce()
|
|||||||
LOG_DEBUG("QMA6100PS isWakeOnMotion failed to read interrupts");
|
LOG_DEBUG("QMA6100PS isWakeOnMotion failed to read interrupts");
|
||||||
return MOTION_SENSOR_CHECK_INTERVAL_MS;
|
return MOTION_SENSOR_CHECK_INTERVAL_MS;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((tempVal & 7) != 0) {
|
if ((tempVal & 7) != 0) {
|
||||||
// Wake up!
|
// Wake up!
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#include "Nrf52Twim.h"
|
||||||
|
|
||||||
|
#if defined(ARCH_NRF52) && defined(HAS_QMA6100P)
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32_t i2cTimeoutUs = 5000;
|
||||||
|
|
||||||
|
void stopTwim(NRF_TWIM_Type *twim);
|
||||||
|
|
||||||
|
bool waitForEventOrError(volatile uint32_t &event, NRF_TWIM_Type *twim)
|
||||||
|
{
|
||||||
|
const uint32_t start = micros();
|
||||||
|
while (!event && !twim->EVENTS_ERROR) {
|
||||||
|
if ((uint32_t)(micros() - start) >= i2cTimeoutUs) {
|
||||||
|
stopTwim(twim);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event && !twim->EVENTS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void configureTwim(NRF_TWIM_Type *twim)
|
||||||
|
{
|
||||||
|
twim->ENABLE = TWIM_ENABLE_ENABLE_Disabled;
|
||||||
|
twim->PSEL.SCL = PIN_WIRE_SCL;
|
||||||
|
twim->PSEL.SDA = PIN_WIRE_SDA;
|
||||||
|
twim->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100;
|
||||||
|
// ENABLE is a volatile HW register: the peripheral must be disabled (above) before
|
||||||
|
// PSEL/FREQUENCY can be changed, then re-enabled here. Not a redundant store.
|
||||||
|
twim->ENABLE = TWIM_ENABLE_ENABLE_Enabled; // cppcheck-suppress redundantAssignment
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTwimEvents(NRF_TWIM_Type *twim)
|
||||||
|
{
|
||||||
|
twim->SHORTS = 0;
|
||||||
|
twim->EVENTS_STOPPED = 0;
|
||||||
|
twim->EVENTS_ERROR = 0;
|
||||||
|
twim->EVENTS_SUSPENDED = 0;
|
||||||
|
twim->EVENTS_RXSTARTED = 0;
|
||||||
|
twim->EVENTS_TXSTARTED = 0;
|
||||||
|
twim->EVENTS_LASTRX = 0;
|
||||||
|
twim->EVENTS_LASTTX = 0;
|
||||||
|
twim->ERRORSRC = TWIM_ERRORSRC_ANACK_Msk | TWIM_ERRORSRC_DNACK_Msk | TWIM_ERRORSRC_OVERRUN_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopTwim(NRF_TWIM_Type *twim)
|
||||||
|
{
|
||||||
|
twim->TASKS_STOP = 1;
|
||||||
|
const uint32_t start = micros();
|
||||||
|
while (!twim->EVENTS_STOPPED && (uint32_t)(micros() - start) < i2cTimeoutUs)
|
||||||
|
;
|
||||||
|
clearTwimEvents(twim);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitForStop(NRF_TWIM_Type *twim)
|
||||||
|
{
|
||||||
|
const uint32_t start = micros();
|
||||||
|
while (!twim->EVENTS_STOPPED && !twim->EVENTS_ERROR) {
|
||||||
|
if ((uint32_t)(micros() - start) >= i2cTimeoutUs) {
|
||||||
|
stopTwim(twim);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bool stopped = twim->EVENTS_STOPPED && !twim->EVENTS_ERROR;
|
||||||
|
if (!stopped)
|
||||||
|
stopTwim(twim);
|
||||||
|
else
|
||||||
|
clearTwimEvents(twim);
|
||||||
|
return stopped;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace Nrf52Twim
|
||||||
|
{
|
||||||
|
void restoreBus()
|
||||||
|
{
|
||||||
|
#if defined(TRACKER_T1000_E)
|
||||||
|
pinMode(PIN_3V3_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_3V3_EN, HIGH);
|
||||||
|
pinMode(PIN_3V3_ACC_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_3V3_ACC_EN, HIGH);
|
||||||
|
#ifdef T1000X_SENSOR_EN_PIN
|
||||||
|
pinMode(T1000X_SENSOR_EN_PIN, OUTPUT);
|
||||||
|
digitalWrite(T1000X_SENSOR_EN_PIN, HIGH);
|
||||||
|
#endif
|
||||||
|
delay(20);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Wire.end();
|
||||||
|
|
||||||
|
pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
|
||||||
|
pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 9 && digitalRead(PIN_WIRE_SDA) == LOW; i++) {
|
||||||
|
pinMode(PIN_WIRE_SCL, OUTPUT);
|
||||||
|
digitalWrite(PIN_WIRE_SCL, LOW);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
pinMode(PIN_WIRE_SDA, OUTPUT);
|
||||||
|
digitalWrite(PIN_WIRE_SDA, LOW);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
|
||||||
|
Wire.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readRegister(uint8_t address, uint8_t reg, uint8_t &value)
|
||||||
|
{
|
||||||
|
NRF_TWIM_Type *twim = NRF_TWIM0;
|
||||||
|
|
||||||
|
configureTwim(twim);
|
||||||
|
clearTwimEvents(twim);
|
||||||
|
twim->ADDRESS = address;
|
||||||
|
twim->TXD.PTR = (uint32_t)®
|
||||||
|
twim->TXD.MAXCNT = 1;
|
||||||
|
// LASTTX_SUSPEND shortcut: peripheral suspends automatically after the TX
|
||||||
|
// byte, so EVENTS_SUSPENDED is set before we even poll — no clearing race.
|
||||||
|
twim->SHORTS = TWIM_SHORTS_LASTTX_SUSPEND_Msk;
|
||||||
|
twim->TASKS_RESUME = 1;
|
||||||
|
twim->TASKS_STARTTX = 1;
|
||||||
|
|
||||||
|
if (!waitForEventOrError(twim->EVENTS_SUSPENDED, twim)) {
|
||||||
|
stopTwim(twim);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
twim->EVENTS_SUSPENDED = 0;
|
||||||
|
twim->EVENTS_LASTRX = 0;
|
||||||
|
twim->RXD.PTR = (uint32_t)&value;
|
||||||
|
twim->RXD.MAXCNT = 1;
|
||||||
|
twim->SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk;
|
||||||
|
twim->TASKS_RESUME = 1;
|
||||||
|
twim->TASKS_STARTRX = 1;
|
||||||
|
|
||||||
|
return waitForStop(twim) && twim->RXD.AMOUNT == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeRegister(uint8_t address, uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
NRF_TWIM_Type *twim = NRF_TWIM0;
|
||||||
|
uint8_t data[] = {reg, value};
|
||||||
|
|
||||||
|
configureTwim(twim);
|
||||||
|
clearTwimEvents(twim);
|
||||||
|
twim->ADDRESS = address;
|
||||||
|
twim->TXD.PTR = (uint32_t)data;
|
||||||
|
twim->TXD.MAXCNT = sizeof(data);
|
||||||
|
twim->SHORTS = TWIM_SHORTS_LASTTX_STOP_Msk;
|
||||||
|
twim->TASKS_RESUME = 1;
|
||||||
|
twim->TASKS_STARTTX = 1;
|
||||||
|
|
||||||
|
return waitForStop(twim);
|
||||||
|
}
|
||||||
|
} // namespace Nrf52Twim
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
// Only the QMA6100P probing path (T1000-E) uses this TWIM helper; gate it on
|
||||||
|
// HAS_QMA6100P so it isn't compiled/analyzed as dead code on other nRF52 boards.
|
||||||
|
#if defined(ARCH_NRF52) && defined(HAS_QMA6100P)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Nrf52Twim
|
||||||
|
{
|
||||||
|
void restoreBus();
|
||||||
|
bool readRegister(uint8_t address, uint8_t reg, uint8_t &value);
|
||||||
|
bool writeRegister(uint8_t address, uint8_t reg, uint8_t value);
|
||||||
|
} // namespace Nrf52Twim
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user