ESP32 用クイックリファレンス

ESP32 board

Espressif ESP32 Development Board (画像出所: Adafruit)

以下は、ESP32 ベースのボードのためのクイックリファレンスです。このボードを初めて使う場合は、まず次のマイクロコントローラの概要を確認することを勧めます。

MicroPython のインストール

チュートリアルの章: ESP32 での MicroPython の始め方 を参照してください。そこにはトラブルシューティングについても記載されています。

ボードの一般的な制御

MicroPython REPL は、ボーレート 115200 の UART0 (GPIO1 = TX、GPIO3 = RX)で利用できます。タブ補完は、オブジェクトにどのようなメソッドがあるかを調べるのに便利です。貼り付けモード(ctrl-E)は、大きめの Pythonコードを REPL に貼り付けるのに便利です。

machine モジュール:

import machine

machine.freq()          # CPU の現在の周波数を取得
machine.freq(240000000) # CPU の周波数を 240 MHz に設定

esp モジュール:

import esp

esp.osdebug(None)       # ベンダ O/S デバッグメッセージをオフにする
esp.osdebug(0)          # ベンダ O/S デバッグメッセージを UART(0) にリダイレクト

# フラッシュストレージを操作するための低レベルのメソッド
esp.flash_size()
esp.flash_user_start()
esp.flash_erase(sector_no)
esp.flash_write(byte_offset, buffer)
esp.flash_read(byte_offset, buffer)

esp32 モジュール:

import esp32

esp32.hall_sensor()     # 内部ホールセンサーを読む
esp32.raw_temperature() # MCUの内部温度を華氏で読む
esp32.ULP()             # 超低消費電力コプロセッサへのアクセス

ESP32 の温度センサは、動作中に IC が暖かくなるため、通常は周囲温度より高くなります。この影響は、スリープから起床した直後に温度センサーを読むことによって最小限に抑えられます。

ネットワーキング

network モジュール:

import network

wlan = network.WLAN(network.STA_IF) # ステーションインタフェースを作成
wlan.active(True)       # インタフェースをアクティブ化
wlan.scan()             # アクセスポイントをスキャン
wlan.isconnected()      # ステーションが AP に繋がったかをチェック
wlan.connect('essid', 'password') # AP に接続
wlan.config('mac')      # インタフェースの MAC アドレスを取得
wlan.ifconfig()         # インタフェースの IP/netmask/gw/DNS アドレスを取得

ap = network.WLAN(network.AP_IF) # アクセスポイントインタフェースを作成
ap.config(essid='ESP-AP') # アクセスポイントの ESSID を設定
ap.config(max_clients=10) # ネットワークに接続できるクライアント数を設定
ap.active(True)         # インタフェースをアクティブ化

ローカルの WiFi ネットワークに接続するには、次の関数を流用してください:

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect('essid', 'password')
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

ネットワークが確立されると socket モジュールを使って、通常どおり TCP/UDP ソケットを作成して使用できます。HTTP リクエストするには urequests モジュールを使うと便利です。

wlan.connect() を呼んだ後、認証に失敗した場合やAPが範囲内にない場合でも、デバイスはデフォルトで 永遠 に接続を再試行します。 この状態で wlan.status() は、接続が成功するかインターフェースが無効になるまで、 network.STAT_CONNECTING を返します。これは wlan.config(reconnects=n) を呼び出すことで変更できます。n は再接続の回数です(0 は再試行しないことを意味し、-1 は永遠に再接続を試みるデフォルトの動作になります)。

遅延とタイミング

time モジュールを使います:

import time

time.sleep(1)           # 1秒間、一時停止する
time.sleep_ms(500)      # 500ミリ秒間、一時停止する
time.sleep_us(10)       # 10マイクロ秒間、一時停止する
start = time.ticks_ms() # ミリ秒カウンター値を取得
delta = time.ticks_diff(time.ticks_ms(), start) # 時差を計算

タイマー

ESP32 には4つのハードウェアタイマーがあります。 machine.Timer クラスに 0 から 3 までのタイマーIDを指定して使います。

from machine import Timer

tim0 = Timer(0)
tim0.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(0))

tim1 = Timer(1)
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))

period の単位はミリ秒です。

仮想タイマーは、このポートではサポートしていません。

ピンと GPIO

machine.Pin クラスを使います:

from machine import Pin

p0 = Pin(0, Pin.OUT)    # GPIO 0 の出力ピンを作成
p0.on()                 # ピンを "on" (high) レベルに設定
p0.off()                # ピンを "off" (low) レベルに設定
p0.value(1)             # ピンを on/high に設定

p2 = Pin(2, Pin.IN)     # GPIO 2 の入力ピンを作成
print(p2.value())       # 値 0 または 1 を取得

p4 = Pin(4, Pin.IN, Pin.PULL_UP) # 内部プルアップ抵抗を有効化
p5 = Pin(5, Pin.OUT, value=1) # 作成時にピンを high に設定

使用可能なピンは、ESP32 チップの実際の GPIO ピン番号に対応する 0-19, 21-23, 25-27, 32-39 です。これらは ESP32 チップの実際の GPIO ピン番号に対応しています。多くのエンドユーザーボードでは、独自のアドホックピン番号(D0、D1、... など)が使われています。ボードの論理ピンと物理的なチップピンとのマッピングについては、ボードのマニュアルを参照してください。

注記:

  • ピン 1 と 3 は、それぞれ REPL UART の TX と RX
  • ピン 6, 7, 8, 11, 16, 17 は内蔵フラッシュの接続に使っているので、他の目的で使うのは推奨しません
  • ピン 34-39 は入力専用で、内部プルアップ抵抗もありません
  • 一部のピンのプル値は、ディープスリープ中の消費電力を減らすために Pin.PULL_HOLD に設定できます。

ピンを反転させるのに使える、高レベルの抽象化インタフェース machine.Signal があります。 負論理(active-low)の LED でも on()value(1) で点灯できるので便利です。

UART (シリアルバス)

machine.UART を参照

from machine import UART

uart1 = UART(1, baudrate=9600, tx=33, rx=32)
uart1.write('hello')  # 5バイト書き出す
uart1.read(5)         # 5バイトまで読み込む

ESP32 には3つのハードウェア UART があります: UART0, UART1, UART2 です。それぞれにデフォルトの GPIO が割り当てられていますが、ESP32 の種類やボードによっては、これらのピンが内蔵フラッシュ、オンボードの PSRAM、ペリフェラルと競合しているかもしれません。

GPIO マトリクスを使えば、どの GPIO もハードウェア UART に使えますので、競合を回避するには、コンストラクト時に tx と rx ピンを指定するだけです。デフォルトのピンは以下の通りです。

UART0 UART1 UART2
tx 1 10 17
rx 3 9 16

PWM (パルス幅変調)

PWM はすべての出力対応ピンで有効にできます。基本周波数は 1Hz から 40MHz の範囲ですが、トレードオフがあります。ベース周波数が高くなると、デューティ分解能は低下します詳細については LED制御 を参照してください。今のところ、デューティ比は 0-1023 の範囲内でなければなりません。

machine.PWM クラスを使います:

from machine import Pin, PWM

pwm0 = PWM(Pin(0))      # ピンから PWM オブジェクトを作成
pwm0.freq()             # 現在の周波数を取得
pwm0.freq(1000)         # 周波数を設定
pwm0.duty()             # 現在のデューティ比を取得
pwm0.duty(200)          # デューティ比を設定
pwm0.deinit()           # PWM を無効化

pwm2 = PWM(Pin(2), freq=20000, duty=512) # 作成と設定を一度に実行

ADC (アナログ/デジタル変換)

ESP32 で ADC 機能はピン 32-39 で利用できます。デフォルト設定を使用する場合、ADC ピンの入力電圧は 0.0V-1.0V である必要があります(1.0V を超える値は 4095 となります)。この電圧範囲を広げるには attenuation (減衰率)を適用する必要があります。

machine.ADC クラスを使います:

from machine import ADC

adc = ADC(Pin(32))          # ADC ピンの ADC オブジェクトを作成
adc.read()                  # 0.0v - 1.0v 範囲を 0-4095 の値で読込み

adc.atten(ADC.ATTN_11DB)    # 11dBの入力減衰率を設定(電圧範囲はおよそ 0.0v - 3.6v)
adc.width(ADC.WIDTH_9BIT)   # 9ビットの戻り値を設定(戻り値の範囲 0-511)
adc.read()                  # 新しく設定された減衰率と戻り値幅を使って値を読込み

ESP32 固有の ADC クラスのメソッドリファレンス:

ADC.atten(attenuation)

このメソッドは ADC の入力減衰率を設定できます。これにより、精度を犠牲にして、より広い入力電圧範囲が可能になります(同じビット数でより広い範囲を表すようになります)。attenuation には次のものを指定できます:

  • ADC.ATTN_0DB: 0dB の減衰率で、1.00v が最大入力電圧となります - これはデフォルト設定です
  • ADC.ATTN_2_5DB: 2.5dBの減衰率、約1.34v が最大入力電圧となります
  • ADC.ATTN_6DB: 6dBの減衰率、約2.00v が最大入力電圧となります
  • ADC.ATTN_11DB: 11dBの減衰率、約3.6v が最大入力電圧となります

警告

11dB の減衰率で最大 3.6v までの範囲が可能となりますが、入力ピンの絶対最大定格電圧は 3.6v なので、この境界に近づくとデバイスに損傷を与える可能性があります!

ADC.width(width)

このメソッドは ADC の読み取り中に利用して返すビット数を設定します。width には次のものが指定できます:

  • ADC.WIDTH_9BIT: 9 ビットデータ
  • ADC.WIDTH_10BIT: 10 ビットデータ
  • ADC.WIDTH_11BIT: 11 ビットデータ
  • ADC.WIDTH_12BIT: 12 ビットデータ - これはデフォルト設定です

ソフトウェア SPI バス

ソフトウェア SPI (ビットバンギング)はすべてのピンで動作し、 machine.SoftSPI クラスを介してアクセスします:

from machine import Pin, SoftSPI

# 与えたピンから SoftSPI バスを構築
# 極性 polarity は SCK のアイドル状態
# phase=0 は SCK の第1エッジでサンプルを意味、chase=1 は第2を意味
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))

spi.init(baudrate=200000) # ボーレートを設定

spi.read(10)            # MISO で 10 バイト読込み
spi.read(10, 0xff)      # 10 バイト読込み、その間 MOSI に 0xff を出力

buf = bytearray(50)     # バッファを作成
spi.readinto(buf)       # 与えたバッファに読込み(この場合は 50 バイト)
spi.readinto(buf, 0xff) # 与えたバッファに読込み、MOSI に 0xff を出力

spi.write(b'12345')     # MOSI に 5 バイト書込み

buf = bytearray(4)      # バッファを作成
spi.write_readinto(b'1234', buf) # MOSI に書き込み、MISO からバッファに読み込み
spi.write_readinto(buf, buf) # MOSI に buf を書き込み、MISO から buf に読み込み

警告

現在のところ、ソフトウェア SPI を初期化するときには sck, mosi, miso すべて を指定しなければなりません。

ハードウェア SPI バス

より高速な伝送速度を可能にする2つのハードウェア SPI チャネルがあります(最大80MHz)。SPI チャンネルには、必要となる I/O 方向をサポートし、他で使われていないものであればどの I/O ピンでも使えます(ピンと GPIO を参照)。しかし、デフォルトで SPI に設定されていないピンについては、GPIO マルチプレクサの追加層を通す必要があります。これは高速での信頼性に影響を与えます。次のデフォルト以外のピンで使用した場合、ハードウェア SPI チャネルは 40MHz に制限されます。

HSPI (id=1) VSPI (id=2)
sck 14 18
mosi 13 23
miso 12 19

ハードウェア SPI には machine.SPI クラスを使ってアクセスします。このクラスには先述のソフトウェア SPI と同じメソッドがあります:

from machine import Pin, SPI

hspi = SPI(1, 10000000)
hspi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
vspi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))

ソフトウェア I2C バス

ソフトウェア I2C (ビット・バンギングを使用)は、出力可能なすべてのピンで動作し、 machine.SoftI2C クラスを使ってアクセスします。

from machine import Pin, SoftI2C

i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)

i2c.scan()              # デバイスをスキャン

i2c.readfrom(0x3a, 4)   # アドレス 0x3a のデバイスから 4 バイト読み込み
i2c.writeto(0x3a, '12') # アドレス 0x3a のデバイスに '12' を書き込み

buf = bytearray(10)     # 10バイトのバッファを作成
i2c.writeto(0x3a, buf)  # 与えたバッファをペリフェラルに書き込み

ハードウェア I2C バス

2つのハードウェア I2C ペリフェラルがあり、識別子 0 と 1 がついています。利用可能な出力対応ピンはすべて SCL と SDA にできますが、デフォルトは以下のようになっています。

I2C(0) I2C(1)
scl 18 25
sda 19 26

ハードウェア I2C には machine.I2C クラスを使ってアクセスしますこのクラスには先述のソフトウェア I2C と同じメソッドがあります:

from machine import Pin, I2C

i2c = I2C(0)
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)

I2S バス

machine.I2S を参照。

from machine import I2S, Pin

i2s = I2S(0, sck=Pin(13), ws=Pin(14), sd=Pin(34), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object
i2s.write(buf)             # オーディオサンプルのバッファを I2S デバイスに書き出す

i2s = I2S(1, sck=Pin(33), ws=Pin(25), sd=Pin(32), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object
i2s.readinto(buf)          # I2S デバイスからのオーディオサンプルをバッファに読み込む

I2S クラスは現在、テクニカルプレビューとして利用できます。プレビュー期間中は、ユーザーからのフィードバックを歓迎します。このフィードバックに基づいて、I2S クラス API と実装が変更される可能性があります。

ESP32には id=0 と id=1 の2つの I2S バスがあります。

リアルタイムクロック (RTC)

machine.RTC を参照:

from machine import RTC

rtc = RTC()
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # 指定の日時を設定
rtc.datetime() # 日時を取得

WDT (ウォッチドッグタイマー)

machine.WDT を参照:

from machine import WDT

# WDT を有効化し、タイムアウトを 5s に設定(最低値は 1s)
wdt = WDT(timeout=5000)
wdt.feed()

ディープスリープモード

次のコードで、スリープ、起床、リセット原因のチェックが行えます:

import machine

# ディープスリープから起こされたかをチェック
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
    print('woke from a deep sleep')

# 10秒間のディープスリープに入る
machine.deepsleep(10000)

注記:

  • deepsleep() を引数なしで呼び出すと、デバイスは無期限にスリープします

  • ソフトウェアリセットによってリセットの原因が変わることはありません

  • 内部プルアップが有効であると、リーク電流が発生する可能性があります。消費電力をさらに減らすために、内部プルアップを無効にできます:

    p1 = Pin(4, Pin.IN, Pin.PULL_HOLD)
    

    ディープスリープ解除後には、次のようにしてピンを有効化する必要があります(この例では出力ピンに設定):

    p1 = Pin(4, Pin.OUT, None)
    

SD カード

machine.SDCard を参照:

import machine, uos

# スロット 2 はピン sck=18, cs=5, miso=19, mosi=23 を使用
sd = machine.SDCard(slot=2)
uos.mount(sd, "/sd")  # mount

uos.listdir('/sd')    # ディレクトリ内容の一覧

uos.umount('/sd')     # 取出し

RMT

RMT は ESP32 固有であり、12.5ns の分解能で正確なデジタルパルスを生成できます。詳細については esp32.RMT を参照してください。使い方は次のとおりです。

import esp32
from machine import Pin

r = esp32.RMT(0, pin=Pin(18), clock_div=8)
r   # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
# チャンネルの分解能は 100ns (1/(source_freq/clock_div)).
r.write_pulses((1, 20, 2, 40), start=0) # 0 を 100ns, 1 を 2000ns, 0 を 200ns, 1 を 4000ns 送信

OneWire ドライバー

OneWire ドライバーはソフトウェアで実装され、すべてのピンで動作します:

from machine import Pin
import onewire

ow = onewire.OneWire(Pin(12)) # GPIO 12 で OneWire バスを作成
ow.scan()               # バス上のデバイスリストをスキャン
ow.reset()              # バスをリセット
ow.readbyte()           # 1バイト読込み
ow.writebyte(0x12)      # バスに1バイト書込み
ow.write('123')         # バスに複数バイト書込み
ow.select_rom(b'12345678') # ROM コードで指定したデバイスを選択

DS18S20 と DS18B20 デバイス用の特定のドライバーがあります:

import time, ds18x20
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
    print(ds.read_temp(rom))

4.7k のプルアップ抵抗をデータラインに接続してください。convert_temp() メソッドは、温度をサンプリングするたびに呼び出す必要があることに注意してください。

NeoPixel/APA106 ドライバー

neopixelapa106 モジュールを使います:

from machine import Pin
from neopixel import NeoPixel

pin = Pin(0, Pin.OUT)   # NeoPixel 駆動のための GPIO 0 を出力に設定
np = NeoPixel(pin, 8)   # 8ピクセル用の NeoPixel ドライバーを GPIO 0 で作成
np[0] = (255, 255, 255) # 第1ピクセルを白に設定
np.write()              # 全ピクセルにデータ書込み
r, g, b = np[0]         # 第1ピクセルの色を取得

APA106 ドライバーは NeoPixel を継承していますが、内部的には異なる色順を使っています:

from apa106 import APA106
ap = APA106(pin, 8)
r, g, b = ap[0]

NeoPixel の低レベル駆動もあります:

import esp
esp.neopixel_write(pin, grb_buf, is800khz)

警告

デフォルトで NeoPixel は、より一般的な 800kHz のユニットを制御するように設定されています。 NeoPixel オブジェクト構築時に timing=0 を渡すことで、他の(よくあるのは 400kHz)デバイスを制御する代替のタイミングを使えます。

APA102 (DotStar)はクロック端子が追加されているため、別のドライバーを使います。

静電容量タッチ

machine モジュールの TouchPad クラスを使います:

from machine import TouchPad, Pin

t = TouchPad(Pin(14))
t.read()              # タッチすると小さい数値を返す

TouchPad.read は容量変化に関連した値を返します。ピンにタッチすると小さい数字(通常は数十の値)となり、タッチしていない場合は大きい数字(1000を超える)となるのが一般的です。ただし、これらの値は相対的なもので、ボードと周囲の構成によって変わる可能性があるため、ある程度の調整が必要となるでしょう。

ESP32 で使える静電容量タッチ対応ピンは 0, 2, 4, 12, 13 14, 15, 27, 32, 33 の10本です。この他のピンに割り当てようとすると ValueError になります。

TouchPad を使ってESP32をスリープから復帰させることもできます:

import machine
from machine import TouchPad, Pin
import esp32

t = TouchPad(Pin(14))
t.config(500)               # ピンが接触したと見なす敷居値を設定
esp32.wake_on_touch(True)
machine.lightsleep()        # タッチされる MCU をスリープさせる

タッチパッドの詳細については <https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/touch_pad.html>`_ を参照してください。

DHT ドライバー

DHT ドライバーはソフトウェアで実装され、すべてのピンで動作します:

import dht
import machine

d = dht.DHT11(machine.Pin(4))
d.measure()
d.temperature() # 例: 23 (°C)
d.humidity()    # 例: 41 (% RH)

d = dht.DHT22(machine.Pin(4))
d.measure()
d.temperature() # 例: 23.6 (°C)
d.humidity()    # 例: 41.3 (% RH)

WebREPL (Web ベースの対話プロンプト)

WebREPL (Web ブラウザ経由でアクセス可能な REPL)は、ESP32 ポートで使用可能な実験的な機能です。Web クライアントを https://github.com/micropython/webrepl (http://micropython.org/webrepl で入手可能なホストバージョン)からダウンロードしてきて、次のコマンドを実行して設定してください:

import webrepl_setup

画面の指示にしたがいます。再起動後、接続可能になります。起動時に自動起動を無効にした場合は、次のコマンドを使用してデーモンを実行することができます:

import webrepl
webrepl.start()

# もしくは指定のパスワードでスタート
webrepl.start(password='mypass')

WebREPL デーモンは STA または AP のいずれのアクティブインターフェースでも listen します。これにより、ルータ(STA インターフェイス)を介してでも、またはアクセスポイントに接続しているときでも直接 ESP32 に接続できます。

ターミナル/コマンドプロンプトでできることの他に、WebREPL にはファイル転送(アップロードとダウンロードの両方)の機能も用意しています。Webクライアントには、対応する機能のボタンがあります。また、上記のリポジトリのコマンドラインクライアント``webrepl_cli.py`` を使うこともできます。

ファイルを ESP32 ボードに転送するための、コミュニティでサポートされている他の代替方法については、MicroPython フォーラムを参照してください。