mirror of
https://github.com/apache/nuttx.git
synced 2026-10-03 12:18:06 +00:00
espressif/esp_irq.c: fix up_disable_irq()/up_enable_irq() for GPIO IRQs
esp_gpio_irq() registers per-pin GPIO interrupts through gpio_isr_handler_add(), never through esp_setup_irq(), so esp_get_handle() never finds them and up_disable_irq()/up_enable_irq() silently no-op for any GPIO-derived irq number. Fall back to esp_gpioirqdisable()/esp_gpioirqenable() (translating irq back to a pin via ESP_IRQ2PIN()) when the normal interrupt-matrix lookup misses. This surfaced through drivers/sensors/lsm6ds3trc_uorb.c: its ISR schedules a worker to drain the sensor's FIFO over I2C and disables its own IRQ until the worker re-enables it, so a level-triggered source (e.g. a PM GPIO wake source left in level mode) doesn't refire continuously and starve every task, HPWORK included, before the worker ever gets to run. That disable/enable only works now that up_disable_irq()/up_enable_irq() actually do something for GPIO irqs. Signed-off-by: Felipe Moura <moura.fmo@gmail.com> Assisted-by: Claude:claude-sonnet-5
This commit is contained in:
parent
074c8e3034
commit
3d267aab2a
2 changed files with 78 additions and 4 deletions
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "xtensa.h"
|
||||
|
||||
#include "esp_gpio.h"
|
||||
#include "esp_irq.h"
|
||||
|
||||
#include "esp_intr_alloc.h"
|
||||
|
|
@ -596,6 +597,21 @@ void up_enable_irq(int irq)
|
|||
|
||||
if (intr_handle == IRQ_UNMAPPED)
|
||||
{
|
||||
/* Not a real interrupt-matrix source -- esp_gpio_irq() registers
|
||||
* per-pin GPIO IRQs through gpio_isr_handler_add() instead, so
|
||||
* esp_get_handle() never finds them here. Try it as a GPIO pin.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ESPRESSIF_GPIO_IRQ
|
||||
int pin = ESP_IRQ2PIN(irq);
|
||||
|
||||
if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq)
|
||||
{
|
||||
esp_gpioirqenable(pin);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
irqwarn("IRQ %d not mapped to handle\n", irq);
|
||||
return;
|
||||
}
|
||||
|
|
@ -636,6 +652,17 @@ void up_disable_irq(int irq)
|
|||
intr_handle = esp_get_handle(this_cpu(), irq);
|
||||
if (intr_handle == IRQ_UNMAPPED)
|
||||
{
|
||||
/* See the matching comment in up_enable_irq(). */
|
||||
|
||||
#ifdef CONFIG_ESPRESSIF_GPIO_IRQ
|
||||
int pin = ESP_IRQ2PIN(irq);
|
||||
|
||||
if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq)
|
||||
{
|
||||
esp_gpioirqdisable(pin);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <nuttx/config.h>
|
||||
#include <nuttx/nuttx.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/debug.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
|
@ -202,6 +203,8 @@ struct lsm6ds3trc_dev_s
|
|||
bool interrupt_mode; /* True if using the INT pin instead of
|
||||
* kthread polling */
|
||||
enum lsm6ds3trc_int_e int_pin; /* Shared INT pin (interrupt mode only) */
|
||||
int irq; /* IRQ number for int_pin, saved by the
|
||||
* ISR so the worker can re-enable it */
|
||||
struct work_s work; /* Shared interrupt work queue
|
||||
* structure -- one burst read serves
|
||||
* both sub-sensors */
|
||||
|
|
@ -834,9 +837,8 @@ static int accel_thread(int argc, char **argv)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void lsm6ds3trc_fifo_worker(FAR void *arg)
|
||||
static void lsm6ds3trc_fifo_worker_body(FAR struct lsm6ds3trc_dev_s *dev)
|
||||
{
|
||||
FAR struct lsm6ds3trc_dev_s *dev = arg;
|
||||
uint8_t status[2];
|
||||
int16_t raw[FIFO_MAX_WORDS];
|
||||
int16_t raw_temp;
|
||||
|
|
@ -980,6 +982,24 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lsm6ds3trc_fifo_worker
|
||||
*
|
||||
* Description:
|
||||
* work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt()
|
||||
* disabled, after the FIFO has actually been drained -- see the comment
|
||||
* on lsm6ds3trc_interrupt() for why the order matters.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void lsm6ds3trc_fifo_worker(FAR void *arg)
|
||||
{
|
||||
FAR struct lsm6ds3trc_dev_s *dev = arg;
|
||||
|
||||
lsm6ds3trc_fifo_worker_body(dev);
|
||||
up_enable_irq(dev->irq);
|
||||
}
|
||||
|
||||
#else
|
||||
/****************************************************************************
|
||||
* Name: lsm6ds3trc_worker
|
||||
|
|
@ -993,9 +1013,8 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void lsm6ds3trc_worker(FAR void *arg)
|
||||
static void lsm6ds3trc_worker_body(FAR struct lsm6ds3trc_dev_s *dev)
|
||||
{
|
||||
FAR struct lsm6ds3trc_dev_s *dev = arg;
|
||||
int16_t raw[7]; /* temp, gx, gy, gz, ax, ay, az */
|
||||
struct sensor_gyro gyro_data;
|
||||
struct sensor_accel accel_data;
|
||||
|
|
@ -1043,6 +1062,24 @@ static void lsm6ds3trc_worker(FAR void *arg)
|
|||
sizeof(accel_data));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lsm6ds3trc_worker
|
||||
*
|
||||
* Description:
|
||||
* work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt()
|
||||
* disabled, after the measurement has actually been drained -- see the
|
||||
* comment on lsm6ds3trc_interrupt() for why the order matters.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void lsm6ds3trc_worker(FAR void *arg)
|
||||
{
|
||||
FAR struct lsm6ds3trc_dev_s *dev = arg;
|
||||
|
||||
lsm6ds3trc_worker_body(dev);
|
||||
up_enable_irq(dev->irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -1053,6 +1090,13 @@ static void lsm6ds3trc_worker(FAR void *arg)
|
|||
* became ready -- the I2C read cannot run in interrupt context, so it's
|
||||
* deferred to lsm6ds3trc_worker()/lsm6ds3trc_fifo_worker() on HPWORK.
|
||||
*
|
||||
* The IRQ is disabled here and only re-enabled once the worker has
|
||||
* drained the condition that raised it: if a PM wake source ever leaves
|
||||
* this pin level-triggered instead of edge-triggered (or the line is
|
||||
* simply slow to fall), leaving the IRQ enabled would re-fire it
|
||||
* continuously and starve every task, including the worker that would
|
||||
* otherwise clear it.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int lsm6ds3trc_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
|
|
@ -1064,6 +1108,9 @@ static int lsm6ds3trc_interrupt(int irq, FAR void *context, FAR void *arg)
|
|||
|
||||
DEBUGASSERT(arg != NULL);
|
||||
|
||||
dev->irq = irq;
|
||||
up_disable_irq(irq);
|
||||
|
||||
dev->timestamp = sensor_get_timestamp();
|
||||
|
||||
#ifdef CONFIG_SENSORS_LSM6DS3TRC_FIFO
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue