Skip to content

Commit

Permalink
esp8266/machine_pin: Move pin_intr_handler to iRAM, de-support hard IRQ.
Browse files Browse the repository at this point in the history
GPIO interrupts can occur when the flash ROM cache is in use and so the
GPIO interrupt handler must be in iRAM.  This commit moves the handler to
iRAM, and also moves mp_sched_schedule to iRAM which is called by
pin_intr_handler.

As part of this fix the Pin class can no longer support hard=True in the
Pin.irq() method, because the VM and runtime are too big to put in iRAM.

Fixes micropython#5714.
  • Loading branch information
dpgeorge committed Apr 30, 2020
1 parent 544c308 commit 0bd58a5
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 19 deletions.
24 changes: 5 additions & 19 deletions ports/esp8266/machine_pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include "py/gc.h"
#include "py/mphal.h"
#include "extmod/virtpin.h"
#include "ets_alt_task.h"
#include "modmachine.h"

#define GET_TRIGGER(phys_port) \
Expand Down Expand Up @@ -87,40 +86,25 @@ STATIC uint8_t pin_mode[16 + 1];
// forward declaration
STATIC const pin_irq_obj_t pin_irq_obj[16];

// whether the irq is hard or soft
STATIC bool pin_irq_is_hard[16];

void pin_init0(void) {
ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_ATTACH(pin_intr_handler_iram, NULL);
// disable all interrupts
memset(&MP_STATE_PORT(pin_irq_handler)[0], 0, 16 * sizeof(mp_obj_t));
memset(pin_irq_is_hard, 0, sizeof(pin_irq_is_hard));
for (int p = 0; p < 16; ++p) {
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << p);
SET_TRIGGER(p, 0);
}
ETS_GPIO_INTR_ENABLE();
}

void pin_intr_handler(uint32_t status) {
void MP_FASTCODE(pin_intr_handler)(uint32_t status) {
status &= 0xffff;
for (int p = 0; status; ++p, status >>= 1) {
if (status & 1) {
mp_obj_t handler = MP_STATE_PORT(pin_irq_handler)[p];
if (handler != MP_OBJ_NULL) {
if (pin_irq_is_hard[p]) {
int orig_ets_loop_iter_disable = ets_loop_iter_disable;
ets_loop_iter_disable = 1;
mp_sched_lock();
gc_lock();
mp_call_function_1_protected(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
gc_unlock();
mp_sched_unlock();
ets_loop_iter_disable = orig_ets_loop_iter_disable;
} else {
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
}
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
}
}
}
Expand Down Expand Up @@ -390,6 +374,9 @@ STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
if (self->phys_port >= 16) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("pin does not have IRQ capabilities"));
}
if (args[ARG_hard].u_bool) {
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ not supported"));
}

if (n_args > 1 || kw_args->used != 0) {
// configure irq
Expand All @@ -401,7 +388,6 @@ STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
}
ETS_GPIO_INTR_DISABLE();
MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler;
pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool;
SET_TRIGGER(self->phys_port, trigger);
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port);
ETS_GPIO_INTR_ENABLE();
Expand Down
1 change: 1 addition & 0 deletions ports/esp8266/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,5 +192,6 @@ extern const struct _mp_obj_module_t mp_module_onewire;

#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n
#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) MP_FASTCODE(f)
#define MICROPY_WRAP_MP_SCHED_SCHEDULE(f) MP_FASTCODE(f)

#define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr))

0 comments on commit 0bd58a5

Please sign in to comment.