[qmc5883l] Use GPIO interrupt when DRDY pin is configured (#15876)

This commit is contained in:
Jonathan Swoboda
2026-04-21 07:47:16 -04:00
committed by GitHub
parent 26a656af29
commit cb56f9a9bf
2 changed files with 35 additions and 6 deletions

View File

@@ -24,6 +24,8 @@ static const uint8_t QMC5883L_REGISTER_CONTROL_1 = 0x09;
static const uint8_t QMC5883L_REGISTER_CONTROL_2 = 0x0A;
static const uint8_t QMC5883L_REGISTER_PERIOD = 0x0B;
void IRAM_ATTR QMC5883LComponent::gpio_intr(QMC5883LComponent *arg) { arg->enable_loop_soon_any_context(); }
void QMC5883LComponent::setup() {
// Soft Reset
if (!this->write_byte(QMC5883L_REGISTER_CONTROL_2, 1 << 7)) {
@@ -35,6 +37,12 @@ void QMC5883LComponent::setup() {
if (this->drdy_pin_) {
this->drdy_pin_->setup();
if (this->drdy_pin_->is_internal()) {
static_cast<InternalGPIOPin *>(this->drdy_pin_)
->attach_interrupt(&QMC5883LComponent::gpio_intr, this, gpio::INTERRUPT_RISING_EDGE);
this->drdy_use_isr_ = true;
this->stop_poller();
}
}
uint8_t control_1 = 0;
@@ -65,8 +73,8 @@ void QMC5883LComponent::setup() {
return;
}
if (this->get_update_interval() < App.get_loop_interval()) {
high_freq_.start();
if (!this->drdy_use_isr_ && this->get_update_interval() < App.get_loop_interval()) {
this->high_freq_.start();
}
}
@@ -84,16 +92,32 @@ void QMC5883LComponent::dump_config() {
LOG_SENSOR(" ", "Heading", this->heading_sensor_);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_PIN(" DRDY Pin: ", this->drdy_pin_);
if (this->drdy_pin_ != nullptr) {
ESP_LOGCONFIG(TAG, " DRDY mode: %s",
this->drdy_use_isr_ ? LOG_STR_LITERAL("interrupt") : LOG_STR_LITERAL("polling"));
}
}
void QMC5883LComponent::update() {
i2c::ErrorCode err;
uint8_t status = false;
// If DRDY pin is configured and the data is not ready return.
// If DRDY is on an external expander we keep the polling path and early-return
// if data is not ready yet. Internal DRDY pins take the ISR path via loop().
if (this->drdy_pin_ && !this->drdy_pin_->digital_read()) {
return;
}
this->read_sensor_();
}
void QMC5883LComponent::loop() {
this->disable_loop();
if (!this->drdy_use_isr_ || !this->drdy_pin_->digital_read()) {
return;
}
this->read_sensor_();
}
void QMC5883LComponent::read_sensor_() {
i2c::ErrorCode err;
uint8_t status = false;
// Status byte gets cleared when data is read, so we have to read this first.
// If status and two axes are desired, it's possible to save one byte of traffic by enabling

View File

@@ -32,6 +32,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
void setup() override;
void dump_config() override;
void update() override;
void loop() override;
void set_drdy_pin(GPIOPin *pin) { drdy_pin_ = pin; }
void set_datarate(QMC5883LDatarate datarate) { datarate_ = datarate; }
@@ -44,6 +45,9 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
protected:
static void IRAM_ATTR gpio_intr(QMC5883LComponent *arg);
void read_sensor_();
QMC5883LDatarate datarate_{QMC5883L_DATARATE_10_HZ};
QMC5883LRange range_{QMC5883L_RANGE_200_UT};
QMC5883LOversampling oversampling_{QMC5883L_SAMPLING_512};
@@ -53,6 +57,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *heading_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr};
GPIOPin *drdy_pin_{nullptr};
bool drdy_use_isr_{false};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,