Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esp8266: put pin interrupt handler in iRAM #5962

Merged
merged 4 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/library/machine.Pin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ Methods
- ``hard`` if true a hardware interrupt is used. This reduces the delay
between the pin change and the handler being called. Hard interrupt
handlers may not allocate memory; see :ref:`isr_rules`.
Not all ports support this argument.

This method returns a callback object.

Expand Down
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
5 changes: 5 additions & 0 deletions ports/esp8266/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@
#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL
#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL

#include "xtirq.h"
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)

// type definitions for the specific machine

#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p)))
Expand Down Expand Up @@ -192,5 +196,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))
4 changes: 4 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,10 @@ typedef double mp_float_t;
#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f
#endif

#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE
#define MICROPY_WRAP_MP_SCHED_SCHEDULE(f) f
#endif

/*****************************************************************************/
/* Miscellaneous settings */

Expand Down
2 changes: 1 addition & 1 deletion py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void mp_sched_unlock(void) {
MICROPY_END_ATOMIC_SECTION(atomic_state);
}

bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) {
bool MICROPY_WRAP_MP_SCHED_SCHEDULE(mp_sched_schedule)(mp_obj_t function, mp_obj_t arg) {
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
bool ret;
if (!mp_sched_full()) {
Expand Down