LOLIN ESP32 OLED ボードの MicroPython で マルチスレッド とタイマー割り込み

---

清水＠ロボット部 (日本Androidの会 秋葉原支部)です。
ロボット部の勉強会で、説明とデモを予定しています。 日程は 2018/1/8 月、成人の日 で調整中です。

ロボット部 Googleグループ
https://groups.google.com/forum/?hl=ja#!forum/robot-android-group-japan-akb

---

WEMOS社 LOLIN32 ESP32 OLED ボード上で MicroPython のマルチスレッドとタイマー割り込みを動かして見ました。

- import _thread でマルチスレッドが使えます。
_thread は、Python 3.6.3 標準ライブラリの低水準のスレッド API です。 

- import machine、machine.Timer　でタイマー割り込みも動いているようです。

センサーで計測しながら、Webサーバで情報提供ができそうです。

# マルチスレッド プログラム

３つのスレッドが並列に走ります。順番にLockを獲得して時刻を出力します。

```python:main.py 
# Multiple threads & lock program 
# MicroPython on Lolin ESP32 OLED 128x64 16x6(0..50)

import _thread, time
Lock = _thread.allocate_lock()

global Start
def now(): return 'time {:0>4}'.format(time.time() - Start)
def heavyPrint(msg):
    with Lock:
        print('%s, %s' % (now(), msg))
        time.sleep(1)
    
def th_func(id, limit, delay):
    for i in range(limit):
        heavyPrint('%s Running thread %d, Count %d' % (now(), id, i))
        time.sleep(delay)

def go(multi, limit, delay):
    global Start; Start = time.time()
    for id in range(multi):
        _thread.start_new_thread(th_func, (id, limit, delay))

go(3,2,0)
```
---

マルチスレッド 実行結果
３つのスレッドが排他的にLockを獲得しています。
Lock待ちが観察できます。

```python:コンソール出力
time 0000, time 0000 Running thread 0, Count 0
time 0001, time 0000 Running thread 1, Count 0
time 0002, time 0000 Running thread 2, Count 0
time 0003, time 0001 Running thread 0, Count 1
time 0004, time 0002 Running thread 1, Count 1
time 0005, time 0003 Running thread 2, Count 1
```

# タイマー割り込み プログラム
２つのタイマーが割り込みを発生します。
中間にタイマー割り込み停止期間を設けています。

```python:main.py 
# 2 timers test program 
# MicroPython on Lolin ESP32 OLED 

import machine, time

timers = (machine.Timer(0), machine.Timer(1))  
counts = [0,0]

global Start 
def now():return 'time {:0>4}'.format(time.time() - Start)

def timePrint(msg): print('%s, %s' % (now(), msg))

def handl(timer):
    global counts
    i = timers.index(timer)
    timePrint("Timer %s, Count %s" % (i, counts[i]))
    counts[i] += 1

def go(delay):
    global Start; Start = time.time()
    timers[0].init(period=1000, mode=machine.Timer.PERIODIC, callback=handl)
    timers[1].init(period=2000, mode=machine.Timer.PERIODIC, callback=handl)

    time.sleep(delay)  

    state = machine.disable_irq()
    timePrint(" main IRQ disable ---")
    time.sleep(delay)
    machine.enable_irq(state)  
    timePrint(" main IRQ enable ---")

    time.sleep(delay)
    timers[0].deinit()
    timers[1].deinit()
    time.sleep(1)
    timePrint(" main stop ---")

go(3)
```
---
タイマー割り込み 実行結果
２つのタイマー割り込みが動いています。
途中に割り込み停止期間があります。

```python:コンソール出力
time 0001, Timer 0, Count 0
time 0002, Timer 1, Count 0
time 0002, Timer 0, Count 1
time 0003,  main IRQ disable ---
time 0003, Timer 0, Count 2
time 0006,  main IRQ enable ---
time 0006, Timer 0, Count 3
time 0006, Timer 0, Count 4
time 0006, Timer 1, Count 1
time 0006, Timer 1, Count 2
time 0007, Timer 0, Count 5
time 0008, Timer 1, Count 3
time 0008, Timer 0, Count 6
time 0009, Timer 0, Count 7
time 0010,  main stop ---
```

# 参考情報
Threading
https://docs.pycom.io/chapter/tutorials/all/threading.html

17.9. _thread — 低水準の スレッド API
[https://docs.python.jp/3/library/_thread.html](https://docs.python.jp/3/library/_thread.html)

ESP32 MicroPython: Timer interrupts
https://techtutorialsx.com/2017/10/07/esp32-micropython-timer-interrupts/

MicroPython on an ESP32 Board With Integrated SSD1306 OLED Display (WEMOS/Lolin)
https://www.instructables.com/id/MicroPython-on-an-ESP32-Board-With-Integrated-SSD1/

Micropython + ESP32のためのIDE「uPyCraft」を使ってみた
http://blog.boochow.com/article/453812032.html