summaryrefslogtreecommitdiffstatshomepage
path: root/esp8266
diff options
context:
space:
mode:
authorPaul Sokolovsky <pfalcon@users.sourceforge.net>2015-12-21 23:04:11 +0200
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2016-03-11 09:13:31 +0700
commit97c262890058896b0acd735b54d66d9ea19c3a53 (patch)
treef6a0d9674231ad785a63710c792dfad5aed1f7ec /esp8266
parent9ae51257bd40b1f010c2abbfb0a38b6d44860ea8 (diff)
downloadmicropython-97c262890058896b0acd735b54d66d9ea19c3a53.tar.gz
micropython-97c262890058896b0acd735b54d66d9ea19c3a53.zip
esp8266: Add alternative event loop implementation.
This implementation provides the same interface and uses the same datastructures as used by BootROM, i.e. is a drop-in replacement for it. But it offers one advantage: it allows to run single iteration of event-pumping loop. Original BootROM function are renamed, prefixed with underscore. There's a switch which allows to use forward calls to them, for compatibility testing. The implementation also includes workarounds for hardware timer handler, and these workarounds may be SDK version specific.
Diffstat (limited to 'esp8266')
-rw-r--r--esp8266/eagle.rom.addr.v6.ld10
-rw-r--r--esp8266/ets_alt_task.c182
-rw-r--r--esp8266/ets_alt_task.h1
3 files changed, 188 insertions, 5 deletions
diff --git a/esp8266/eagle.rom.addr.v6.ld b/esp8266/eagle.rom.addr.v6.ld
index 19576cb73d..80e03922bb 100644
--- a/esp8266/eagle.rom.addr.v6.ld
+++ b/esp8266/eagle.rom.addr.v6.ld
@@ -132,12 +132,12 @@ PROVIDE ( ets_memcmp = 0x400018d4 );
PROVIDE ( ets_memcpy = 0x400018b4 );
PROVIDE ( ets_memmove = 0x400018c4 );
PROVIDE ( ets_memset = 0x400018a4 );
-PROVIDE ( ets_post = 0x40000e24 );
+PROVIDE ( _ets_post = 0x40000e24 );
PROVIDE ( ets_printf = 0x400024cc );
PROVIDE ( ets_putc = 0x40002be8 );
PROVIDE ( ets_rtc_int_register = 0x40002a40 );
-PROVIDE ( ets_run = 0x40000e04 );
-PROVIDE ( ets_set_idle_cb = 0x40000dc0 );
+PROVIDE ( _ets_run = 0x40000e04 );
+PROVIDE ( _ets_set_idle_cb = 0x40000dc0 );
PROVIDE ( ets_set_user_start = 0x40000fbc );
PROVIDE ( ets_str2macaddr = 0x40002af8 );
PROVIDE ( ets_strcmp = 0x40002aa8 );
@@ -146,12 +146,12 @@ PROVIDE ( ets_strlen = 0x40002ac8 );
PROVIDE ( ets_strncmp = 0x40002ab8 );
PROVIDE ( ets_strncpy = 0x40002a98 );
PROVIDE ( ets_strstr = 0x40002ad8 );
-PROVIDE ( ets_task = 0x40000dd0 );
+PROVIDE ( _ets_task = 0x40000dd0 );
PROVIDE ( ets_timer_arm = 0x40002cc4 );
PROVIDE ( ets_timer_disarm = 0x40002d40 );
PROVIDE ( ets_timer_done = 0x40002d80 );
PROVIDE ( ets_timer_handler_isr = 0x40002da8 );
-PROVIDE ( ets_timer_init = 0x40002e68 );
+PROVIDE ( _ets_timer_init = 0x40002e68 );
PROVIDE ( ets_timer_setfn = 0x40002c48 );
PROVIDE ( ets_uart_printf = 0x40002544 );
PROVIDE ( ets_update_cpu_frequency = 0x40002f04 );
diff --git a/esp8266/ets_alt_task.c b/esp8266/ets_alt_task.c
new file mode 100644
index 0000000000..9e56987432
--- /dev/null
+++ b/esp8266/ets_alt_task.c
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include "osapi.h"
+#include "os_type.h"
+#include "ets_sys.h"
+#include "etshal.h"
+
+// Use standard ets_task or alternative impl
+#define USE_ETS_TASK 0
+
+#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+struct task_entry {
+ os_event_t *queue;
+ os_task_t task;
+ uint8_t qlen;
+ uint8_t prio;
+ int8_t i_get;
+ int8_t i_put;
+};
+
+static void (*idle_cb)(void *);
+static void *idle_arg;
+
+#define FIRST_PRIO 0x14
+#define LAST_PRIO 0x20
+#define PRIO2ID(prio) ((prio) - FIRST_PRIO)
+
+volatile struct task_entry emu_tasks[PRIO2ID(LAST_PRIO) + 1];
+
+static inline int prio2id(uint8_t prio) {
+ int id = PRIO2ID(prio);
+ if (id < 0 || id >= MP_ARRAY_SIZE(emu_tasks)) {
+ printf("task prio out of range: %d\n", prio);
+ while (1);
+ }
+ return id;
+}
+
+void dump_task(int prio, volatile struct task_entry *t) {
+ printf("q for task %d: queue: %p, get ptr: %d, put ptr: %d, qlen: %d\n",
+ prio, t->queue, t->i_get, t->i_put, t->qlen);
+}
+
+void dump_tasks(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(emu_tasks); i++) {
+ if (emu_tasks[i].qlen) {
+ dump_task(i + FIRST_PRIO, &emu_tasks[i]);
+ }
+ }
+ printf("====\n");
+}
+
+bool ets_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen) {
+ static unsigned cnt;
+ printf("#%d ets_task(%p, %d, %p, %d)\n", cnt++, task, prio, queue, qlen);
+#if USE_ETS_TASK
+ return _ets_task(task, prio, queue, qlen);
+#else
+ int id = prio2id(prio);
+ emu_tasks[id].task = task;
+ emu_tasks[id].queue = queue;
+ emu_tasks[id].qlen = qlen;
+ emu_tasks[id].i_get = 0;
+ emu_tasks[id].i_put = 0;
+ return true;
+#endif
+}
+
+bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
+// static unsigned cnt; printf("#%d ets_post(%d, %x, %x)\n", cnt++, prio, sig, param);
+#if USE_ETS_TASK
+ return _ets_post(prio, sig, param);
+#else
+ ets_intr_lock();
+
+ const int id = prio2id(prio);
+ os_event_t *q = emu_tasks[id].queue;
+ if (emu_tasks[id].i_put == -1) {
+ // queue is full
+ printf("ets_post: task %d queue full\n", prio);
+ return false;
+ }
+ q = &q[emu_tasks[id].i_put++];
+ q->sig = sig;
+ q->par = param;
+ if (emu_tasks[id].i_put == emu_tasks[id].qlen) {
+ emu_tasks[id].i_put = 0;
+ }
+ if (emu_tasks[id].i_put == emu_tasks[id].i_get) {
+ // queue got full
+ emu_tasks[id].i_put = -1;
+ }
+ //printf("after ets_post: "); dump_task(prio, &emu_tasks[id]);
+ //dump_tasks();
+
+ ets_intr_unlock();
+
+ return true;
+#endif
+}
+
+bool ets_loop_iter(void) {
+ //static unsigned cnt;
+ bool progress = false;
+ for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
+ ets_intr_lock();
+ //printf("etc_loop_iter: "); dump_task(t - emu_tasks + FIRST_PRIO, t);
+ if (t->i_get != t->i_put) {
+ progress = true;
+ //printf("#%d Calling task %d(%p) (%x, %x)\n", cnt++,
+ // t - emu_tasks + FIRST_PRIO, t->task, t->queue[t->i_get].sig, t->queue[t->i_get].par);
+ //ets_intr_unlock();
+ t->task(&t->queue[t->i_get]);
+ //ets_intr_lock();
+ //printf("Done calling task %d\n", t - emu_tasks + FIRST_PRIO);
+ if (t->i_put == -1) {
+ t->i_put = t->i_get;
+ }
+ if (++t->i_get == t->qlen) {
+ t->i_get = 0;
+ }
+ }
+ ets_intr_unlock();
+ }
+ return progress;
+}
+
+#if SDK_BELOW_1_1_1
+void my_timer_isr(void *arg) {
+// uart0_write_char('+');
+ ets_post(0x1f, 0, 0);
+}
+
+// Timer init func is in ROM, and calls ets_task by relative addr directly in ROM
+// so, we have to re-init task using our handler
+void ets_timer_init() {
+ printf("ets_timer_init\n");
+// _ets_timer_init();
+ ets_isr_attach(10, my_timer_isr, NULL);
+ SET_PERI_REG_MASK(0x3FF00004, 4);
+ ETS_INTR_ENABLE(10);
+ ets_task((os_task_t)0x40002E3C, 0x1f, (os_event_t*)0x3FFFDDC0, 4);
+
+ WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0);
+ WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x28, 0x88);
+ WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0);
+ printf("Installed timer ISR\n");
+}
+#endif
+
+bool ets_run(void) {
+#if USE_ETS_TASK
+ #if SDK_BELOW_1_1_1
+ ets_isr_attach(10, my_timer_isr, NULL);
+ #endif
+ _ets_run();
+#else
+// ets_timer_init();
+ *(char*)0x3FFFC6FC = 0;
+ ets_intr_lock();
+ printf("ets_alt_task: ets_run\n");
+ dump_tasks();
+ ets_intr_unlock();
+ while (1) {
+ if (!ets_loop_iter()) {
+ //printf("idle\n");
+ ets_intr_lock();
+ if (idle_cb) {
+ idle_cb(idle_arg);
+ }
+ asm("waiti 0");
+ ets_intr_unlock();
+ }
+ }
+#endif
+}
+
+void ets_set_idle_cb(void (*handler)(void *), void *arg) {
+ //printf("ets_set_idle_cb(%p, %p)\n", handler, arg);
+ idle_cb = handler;
+ idle_arg = arg;
+}
diff --git a/esp8266/ets_alt_task.h b/esp8266/ets_alt_task.h
new file mode 100644
index 0000000000..c423995841
--- /dev/null
+++ b/esp8266/ets_alt_task.h
@@ -0,0 +1 @@
+bool ets_loop_iter(void);