ESP32 用クイックリファレンス
Espressif ESP32 Development Board (画像出所: Adafruit)
以下は、ESP32 ベースのボードのためのクイックリファレンスです。このボードを初めて使う場合は、まず次のマイクロコントローラの概要を確認してみてください。
ESP32 にはいくつかの種類があります。MicroPython では ESP32, ESP32C3, ESP32C6, ESP32S2, ESP32S3 をサポートしていますが、それらの間には機能の違いがいくつかあることに注意してください。
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.raw_temperature() # MCUの内部温度を華氏で読む
esp32.ULP() # 超低消費電力コプロセッサへのアクセス。ESP32C3/C6 では使えません
ESP32 の温度センサは、動作中に IC が暖かくなるため、通常は周囲温度より高くなります。この影響は、スリープから起床した直後に温度センサーを読むことによって最小限に抑えられます。
ESP32C3, ESP32C6, ESP32S2, ESP32S3 には内部温度センサーもあります。これは ESP32 とは少し異なる方法で実装されており、温度を摂氏で返します。
esp32.mcu_temperature() # MCU の内部温度を摂氏で読み込む
ネットワーキング
WLAN
network モジュールの network.WLAN クラス:
import network
wlan = network.WLAN() # ステーションインタフェースを作成(デフォルト。アクセスポイントインタフェースについては後述)
wlan.active(True) # インタフェースをアクティブ化
wlan.scan() # アクセスポイントをスキャン
wlan.isconnected() # ステーションが AP に繋がったかをチェック
wlan.connect('ssid', 'key') # AP に接続
wlan.config('mac') # インタフェースの MAC アドレスを取得
wlan.ipconfig('addr4') # インタフェースの IPv4 アドレスを取得
ap = network.WLAN(network.WLAN.IF_AP) # アクセスポイントインタフェースを作成
ap.config(ssid='ESP-AP') # アクセスポイントの SSID を設定
ap.config(max_clients=10) # ネットワークに接続できるクライアント数を設定
ap.active(True) # インタフェースをアクティブ化
ローカルの WiFi ネットワークに接続するには、次の関数を流用してください:
def do_connect():
import machine, network
wlan = network.WLAN()
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('ssid', 'key')
while not wlan.isconnected():
machine.idle()
print('network config:', wlan.ipconfig('addr4'))
ネットワークが確立されると socket モジュールを使って、通常どおり TCP/UDP ソケットを作成して使用できます。HTTP リクエストするには requests モジュールを使うと便利です。
wlan.connect() を呼んだ後、認証に失敗した場合やAPが範囲内にない場合でも、デバイスはデフォルトで 永遠 に接続を再試行します。 この状態で wlan.status() は、接続が成功するかインターフェースが無効になるまで、 network.STAT_CONNECTING を返します。これは wlan.config(reconnects=n) を呼び出すことで変更できます。n は再接続の回数です(0 は再試行しないことを意味し、-1 は永遠に再接続を試みるデフォルトの動作になります)。
LAN
内蔵 MAC (オリジナル ESP32
オリジナルの ESP32 SoC には内蔵の Ethernet MAC があります。この MAC を使うには、外部の Ethernet PHY をチップの EMAC ピンに接続する必要があります。EMAC ピンの大部分は固定されているため、詳細については ESP32 のデータシートを参照してください。
PHY が接続されている場合、内蔵 Ethernet MAC は network.LAN のコンストラクタで設定できます。
import network
lan = network.LAN(mdc=PIN_MDC, ...) # ピンとモードを設定
lan.active(True) # インタフェースをアクティブ化
lan.ipconfig('addr4') # インタフェースの IPv4 アドレスを取得
コンストラクタの必須キーワード引数は次のとおりです:
mdcとmdio- MDC と MDIO ピンを指定するmachine.Pinオブジェクト(または整数値)。phy_type- PHY デバイス種別を指定。サポートしているデバイスはPHY_GENERIC,PHY_LAN8710,PHY_LAN8720,PHY_IP101,PHY_RTL8201,PHY_DP83848,PHY_KSZ8041,PHY_KSZ8081。これらの値はすべてnetworkモジュールに定義されている定数。phy_addr- PHY デバイスのアドレス番号。0x00 から 0x1f までの範囲の整数値。一般的によく使われるのは0と1。
インタフェースを設定するには、上記のすべてのキーワード引数を指定する必要があります。
オプションのキーワード引数は次のとおりです:
reset- PHY のリセットピンを指定するmachine.Pinオブジェクト(または 整数値)。power- PHY デバイスの電源を切り換えるピンを指定するmachine.Pinオブジェクト(または 整数値)。ref_clk- EMACref_clk信号で使うピンを指定するmachine.Pinオブジェクト(または 整数値)。指定しない場合は、ボードのデフォルト値が適用されます(たいていは GPIO 0 ですが、Ethernet を搭載した一部のボードでは異なる可能性があります)。ref_clk_mode- ESP32 の EMACref_clkピンを入力または出力として設定します。適切な値はmachine.Pin.INまたはmachine.Pin.OUTです。指定しない場合は、ボードのデフォルト値が適用されます(たいていは入力ですが、Ethernet を搭載した一部のボードでは異なる可能性があります)。
次のコードは、いくつかの人気のあるESP32ボードの LAN インタフェースで動作する設定です:
# Olimex ESP32-GATEWAY: Pin(5) で電源制御
# Olimex ESP32 PoE と ESP32-PoE ISO: Pin(12) で電源制御
lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5),
phy_type=network.PHY_LAN8720, phy_addr=0,
ref_clk=machine.Pin(17), ref_clk_mode=machine.Pin.OUT)
# Wireless-Tag WT32-ETH01 の場合
lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18),
phy_type=network.PHY_LAN8720, phy_addr=1, power=None)
# Wireless-Tag WT32-ETH01 v1.4 の場合
lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18),
phy_type=network.PHY_LAN8720, phy_addr=1,
power=machine.Pin(16))
# Espressif ESP32-Ethernet-Kit_A_V1.2 の場合
lan = network.LAN(id=0, mdc=Pin(23), mdio=Pin(18), power=Pin(5),
phy_type=network.PHY_IP101, phy_addr=1)
SPI Ethernet インタフェース
すべての ESP32 SoC は、外部の SPI Ethernet インタフェースチップをサポートしています。これらの Ethernet インターフェースは、Ethernet RMII インターフェースではなく、SPI バスを介して接続されます。
注釈
唯一の例外は ESP32 d2wd バリアントですが、この機能はコードサイズを節約するために無効化されています。
SPI Ethernet は、 network.LAN コンストラクタを使いますが、異なるキーワード引数のセットが必要です。
import machine, network
spi = machine.SPI(1, sck=SCK_PIN, mosi=MOSI_PIN, miso=MISO_PIN)
lan = network.LAN(spi=spi, cs=CS_PIN, ...) # Set the pin and mode configuration
lan.active(True) # activate the interface
lan.ipconfig('addr4') # get the interface's IPv4 addresses
コンストラクタの必須キーワード引数は次のとおりです:
spi- この接続用に設定するmachine.SPIオブジェクト。なお、SPI オブジェクトで設定されたクロック速度は無視され、SPI Ethernet のクロック速度はコンパイル時に設定されます。cs- インタフェースに接続する CS ピンを指定するmachine.Pinオブジェクト(または 整数値)。int- インタフェースに接続する INT ピンを指定するmachine.Pinオブジェクト(または 整数値)。phy_type- SPI Ethernet インタフェースの種別を指定。サポートしているデバイスはPHY_KSZ8851SNL,PHY_DM9051,PHY_W5500。これらの値はすべてnetworkモジュールに定義されている定数。phy_addr- PHY デバイスのアドレス番号。0x00 から 0x1f までの範囲の整数値。SPI Ethernet デバイスで一般的によく使われるのは0。
インタフェースを設定するには、上記のすべてのキーワード引数を指定する必要があります。
コンストラクタのオプションキーワード引数は次のとおりです:
reset- SPI Ethernet インタフェースのリセットピンを指定するmachine.Pinオブジェクト(または 整数値)。power- SPI Ethernet インタフェースの電源を切り換えるピンを指定するmachine.Pinオブジェクト(または 整数値)。
次のコードは、WIZNet W5500 チップを ESP32-S3 開発ボードのピンに接続する設定例です。
import machine, network
from machine import Pin, SPI
spi = SPI(1, sck=Pin(12), mosi=Pin(13), miso=Pin(14))
lan = network.LAN(spi=spi, phy_type=network.PHY_W5500, phy_addr=0,
cs=Pin(10), int=Pin(11))
注釈
WIZnet W5500 Ethernet は、他のいくつかの MicroPython ポートでもサポートしていますが、 異なるソフトウェアインターフェース を使います。
遅延とタイミング
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ポートには、ESP32のデバイスタイプに応じて、1、2、4個のハードウェアタイマーがあります。ESP32C2 にはタイマーが1個、ESP32C4、ESP32C6、ESP32H4 にはタイマーが2個、その他のESP32デバイスでは 4 個のタイマーが搭載されています。 machine.Timer クラスを使う際は、タイマーIDとして0 (1個の場合)、0と1 (2個の場合)、0~3 (4個の場合)を指定して使います。
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 の単位はミリ秒です。UART.IRQ_RXIDLE を指定する場合、タイマー0は IRQ_RXIDLE メカニズムのために必要となるため、他の用途には使わないでください。
このポートではタイマーコールバックがソフト割り込みとしてスケジュールされます。ハードコールバックは実装されていません。 hard=True を指定すると ValueError が発生します。
仮想タイマーは、このポートではサポートしていません。
ピンと 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 に設定p6 = Pin(6, Pin.OUT, drive=Pin.DRIVE_3) # 最大電流値を設定
使用可能なピンは、ESP32 チップの実際の GPIO ピン番号に対応する 0-19, 21-23, 25-27, 32-39 です。これらは ESP32 チップの実際の GPIO ピン番号に対応しています。多くのエンドユーザーボードでは、独自のアドホックピン番号(D0、D1、... など)が使われています。ボードの論理ピンと物理的なチップピンとのマッピングについては、ボードのマニュアルを参照してください。
4つのドライブ電流値(drive strength)がサポートされています。これは Pin() コンストラクタまたは Pin.init() メソッドの drive キーワード引数で設定できます。4つのドライブ電流値は、それぞれ異なる安全最大ソース/シンク電流とおおよその内部ドライバー抵抗を持ちます。
Pin.DRIVE_0: 5mA / 130 Ω
Pin.DRIVE_1: 10mA / 60 Ω
Pin.DRIVE_2: 20mA / 30 Ω (設定しない場合のデフォルトのドライブ電流値)
Pin.DRIVE_3: 40mA / 15 Ω
Pin() と Pin.init() の hold= キーワード引数は、ESP32の「パッドホールド」(pad hold)機能を有効にします。 True に設定すると、ピンの構成(入力/出力の方向、プル抵抗、出力値)が保持され、それ以降の変更は適用されません(出力レベルの変更を含む)。 hold=False に設定すると、未変更のピン設定変更が直ちに適用され、ピンが解放されます。ピンがすでにホールドされている状態で hold=True に設定すると、設定変更を適用し、その直後にホールドが再適用されます。
注記:
ピン 1 と 3 は、それぞれ REPL UART の TX と RX
ピン 6, 7, 8, 11, 16, 17 は内蔵フラッシュの接続に使っているので、他の目的で使うのは推奨しません
ピン 34-39 は入力専用で、内部プルアップ抵抗もありません
スリープ時のピンの挙動については ディープスリープモード を参照してください。
ピンを反転させるのに使える、高レベルの抽象化インタフェース 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 に使えます。例外はピン 34-39 で、これらは入力専用なので rx にしか使えません。競合を回避するには、コンストラクト時に tx と rx ピンを指定するだけです。デフォルトのピンは以下の通りです。
UART0 |
UART1 |
UART2 |
|
|---|---|---|---|
tx |
1 |
10 |
17 |
rx |
3 |
9 |
16 |
SPIRAM を搭載した ESP32 では、SPIRAM のピンとの競合を避けるため、UART1 のデフォルトピンは tx=5 と rx=4 に設定しています。
PWM (パルス幅変調)
PWM はすべての出力対応ピンで有効にできます。基本周波数は 1Hz から 40MHz の範囲ですが、トレードオフがあります。ベース周波数が高くなると、デューティ分解能は低下します詳細については LED制御 を参照してください。
machine.PWM クラスを使います:
from machine import Pin, PWM, lightsleep
pwm0 = PWM(Pin(0), freq=5000, duty_u16=32768) # ピンから PWM オブジェクトを作成
freq = pwm0.freq() # 現在の周波数を取得
pwm0.freq(1000) # 1Hz から 40MHz の範囲で PWM 周波数を設定
duty = pwm0.duty() # 現在のデューティ比(0-1023 の範囲)を取得(デフォルト 512、50%)
pwm0.duty(256) # 0 から 1023 の範囲でデューティ比(duty/1023)を設定(この場合は 25%)
duty_u16 = pwm0.duty_u16() # 現在のデューティ比(0-65535 の範囲)を取得
pwm0.duty_u16(65536*3//4) # 0 から 65535 の範囲でデューティ比(duty_u16/65525)を設定(この場合は 75%)
duty_ns = pwm0.duty_ns() # 現在のパルス幅を ns 単位で取得
pwm0.duty_ns(250_000) # ナノ秒でパルス幅を 0 から 1_000_000_000/freq の範囲で設定(この場合は 25%)
pwm0.deinit() # このピンの PWM を無効化
pwm2 = PWM(Pin(2), freq=20000, duty=512) # 作成と設定を一度に実行
print(pwm2) # PWM 設定を表示
pwm2.deinit() # このピンの PWM を無効化
pwm0 = PWM(Pin(0), duty_u16=16384) # 25% の時間、出力を高レベルにする。
pwm2 = PWM(Pin(2), duty_u16=16384, invert=1) # 25% の時間、出力を低レベルにする。
pwm4 = PWM(Pin(4), lightsleep=True) # ライトスリープモードの間でも PWM を許可
lightsleep(10*1000) # ライトスリープの10秒間、pwm0, pwm2 はオフになり、pwm4 はそのまま
# ライトスリープの10秒後、pwm0, pwm2, pwm4 はオンになる
ESP チップによってハードウェアのペリフェラルは異なります:
ハードウェア仕様 |
ESP32 |
ESP32-S2, ESP32-S3, ESP32-P4 |
ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-H2 |
グループ(スピードモード)数 |
2 |
1 |
1 |
グループ毎のタイマー数 |
4 |
4 |
4 |
グループ毎のチャンネル数 |
8 |
8 |
6 |
Different PWM frequencies = (groups * timers) |
8 |
4 |
4 |
Total PWM channels (Pins, duties) = (groups * channels) |
16 |
8 |
6 |
ライトスリープ中は、ESP32 の PWM は低速モードでしか動作できないため、利用可能なタイマーは4つ、チャネルは8つに制限されます。
ESP32 では最大16個のPWMチャンネル(ピン)を使えますが、利用できるPWM周波数は8種類のみで、残りの8チャンネルは同じ周波数でなければなりません。一方,同じ周波数であれば,16の独立したPWMデューティ比が可能です。
さらなる例は パルス幅変調 チュートリアルを参照。
DAC (デジタル/アナログ変換)
ESP32 において DAC 機能はピン 25 と 26 で利用できます。ESP32S2 において DAC 機能はピン 17 と 18 で利用できます。
DAC の使用例:
from machine import DAC, Pin
dac = DAC(Pin(25)) # 指定のピンで作動する DAC オブジェクトを作成
dac.write(128) # 0から255までの生アナログ値について、現状を 50% に設定
ADC (アナログ/デジタル変換)
ESP32 で ADC 機能はピン 32-39 (ADC ブロック1)とピン 0, 2, 4, 12-15, 25-27 (ADC ブロック2)で利用できます。
machine.ADC クラスを使います:
from machine import ADC
adc = ADC(pin) # 指定のピンについて ADC オブジェクトを作成
val = adc.read_u16() # 生のアナログ値を 0-65535 の範囲で読込み
val = adc.read_uv() # アナログ値をマイクロボルト単位で読込み
ADC ブロック2は WiFi でも使っているため、WiFi がアクティブなときにブロック2ピンからアナログ値を読み込もうとすると例外が発生します。
内部 ADC の基準電圧は通常 1.1V ですが、パッケージによって若干の違いがあります。ADC は基準電圧の近くでは線形性が悪く(特に高減衰の場合)、100mV 程度の最小測定電圧があり、これ以下の電圧は 0 として読まれます。電圧を正確に読むには read_uv() メソッド(下記参照)を使うことが推奨されます。
ESP32 固有の ADC クラスのメソッドリファレンス:
- class ADC(pin, *, atten)
指定したピンの ADC オブジェクトを返します。ESP32 は異なるタイミングの ADC サンプリングをサポートしていないため、
sample_nsキーワード引数はサポートしていません。基準電圧以上の電圧を読み取るには、キーワード引数
attenで入力減衰率を適用します。有効な値(およびおおよその線形測定範囲)は以下のとおりです:ADC.ATTN_0DB: 減衰率を適用しません(100mV - 950mV)ADC.ATTN_2_5DB: 2.5dB の減衰率(100mV - 1250mV)ADC.ATTN_6DB: 6dB の減衰率(150mV - 1750mV)ADC.ATTN_11DB: 11dB の減衰率(150mV - 2450mV)
警告
入力ピンの絶対最大定格電圧は 3.6V であり、この境界線に近づくと IC に損傷を与える可能性があることに注意してください!
- ADC.read_uv()
このメソッドは、ADC の既知の特性と、製造時に設定されたパッケージごとの eFuse 値を使って、校正された入力電圧(減衰前)をマイクロボルト単位で返します。返される値はミリボルトの分解能しかありません(つまり、常に 1000 マイクロボルトの倍数です)。
キャリブレーションは、ADC のリニアレンジにおいてのみ有効です。特に、グランドに接続された入力は、0 マイクロボルトを超える値として読み取られます。しかし、線形範囲内では、
read_u16()を使って結果を定数でスケーリングするよりも、より正確で一貫した結果が得られるでしょう。
ESP32 ポートは machine.ADC API もサポートします:
- class ADCBlock(id, *, bits)
指定した
id(1 または 2) の ADC ブロックオブジェクトを返し、指定した分解能(ESP32 シリーズによって 9 から 12 ビット)に初期化します。分解能を指定しない場合はサポートされている最高の分解能になります。
- ADCBlock.connect(pin)
- ADCBlock.connect(channel)
- ADCBlock.connect(channel, pin)
指定した ADC ピンまたはチャンネル番号に対応する
ADCオブジェクトを返します。GPIO への ADC チャンネルの任意の接続はサポートされていないため、このブロックに接続されていないピンを指定したり、チャンネルとピンが不一致の場合は例外が発生します。
Legacy methods:
- ADC.read()
このメソッドは ADC ブロックの分解能(デフォルトの12ビット分解能では0〜4095)にしががった範囲の生の ADC 値を返します。
- ADC.atten(atten)
ADC.init(atten=atten)と同等です。
- ADC.width(bits)
ADC.block().init(bits=bits)と同等です。
低い解像度に切り替えられるチップは普通のノーマルな ESP32 だけです。C2 と S3 は 12 ビットに固定されており、S2 は 13 ビットに固定されています。
互換性のために ADC オブジェクトはチップごとに対応する ADC 解像度を示す定数をチップ毎に用意しています。
- ESP32:
ADC.WIDTH_9BIT= 9ADC.WIDTH_10BIT= 10ADC.WIDTH_11BIT= 11ADC.WIDTH_12BIT= 12
- ESP32 C3 & S3:
ADC.WIDTH_12BIT= 12
- ESP32 S2:
ADC.WIDTH_13BIT= 13
- ADC.deinit()
ADC ドライバを解除します。
パルスカウンター (ピンのパルス/エッジをカウント)
ESP32 にはハードウェア構成によって最大8個のパルスカウンターペリフェラルがあり、ID は 0~7 です。これらは任意の入力ピンで立ち上がりエッジや立ち下がりエッジをカウントするよう設定できます。
これには esp32.PCNT を使います:
from machine import Pin
from esp32 import PCNT
counter = PCNT(0, pin=Pin(2), rising=PCNT.INCREMENT) # カウンターを作成
counter.start() # カウンターを開始
count = counter.value() # カウンターを -32768..32767 の範囲で読込み
counter.value(0) # カウンターをリセット
count = counter.value(0) # 読込みとリセット
PCNT ハードウェアは、1つのユニットで複数ピンの監視をサポートし、直交デコード(quadrature decoding)やアップ/ダウン信号カウンタを実装できます。
一般的なパルスカウント用途をよりシンプルに抽象化したものについては machine.Counter クラスと machine.Encoder クラスを参照してください:
from machine import Pin, Counter
counter = Counter(0, Pin(2)) # カウンターの作成と開始
count = counter.value() # カウント値を任意精度の符号付き整数として読み取り
encoder = Encoder(0, Pin(12), Pin(14)) # エンコーダーの作成とカウント開始
count = encoder.value() # カウント値を任意精度の符号付き整数として読み取り
これらの Counter() および Encoder() オブジェクトに渡される id は PCNT の id でなければならないことに注意してください。
ソフトウェア 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, 0, 1, 12, 48, 0)) # 指定の日時を設定
# 2017/8/23 1:12:48
# 曜日の値は無視される
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()を引数なしで呼び出すと、デバイスは無期限にスリープしますソフトウェアリセットによってリセットの原因が変わることはありません
一部の ESP32 ピン(0、2、4、12-15、25-27、32-39)はディープスリープ中に RTC に接続され、 esp32 モジュールの wake_on_ 関数でデバイスを起動するのに使えます。出力可能な RTC ピン(34-39 を除くすべて)は、ディープスリープに入るときにもプルアップまたはプルダウン抵抗の構成を保持します。
ディープスリープ中にプル抵抗が積極的に必要とされず、電流リークの原因となる可能性がある場合(例えば、プルアップ抵抗がスイッチを介してグランドに接続されている場合)、ディープスリープモードに入る前に電力を節約するためにそれらを無効にする必要があります。
from machine import Pin, deepsleep
# ブート時は入力 RTC ピンをプルアップ付きに設定
pin = Pin(2, Pin.IN, Pin.PULL_UP)
# プルアップを無効にして10秒間スリープさせる
pin.init(pull=None)
machine.deepsleep(10000)
Pin.init() の hold=True 引数でパッドホールドを有効にすると、出力設定された RTC ピンもディープスリープ時にその出力方向とレベルを保持するようになります。
RTC 以外の GPIO ピンは、ディープスリープに入るとデフォルトで接続が解除されます。ピンのパッドホールドを有効にし、ディープスリープ中に GPIO パッドホールドを有効にすると、出力レベルを含む RTC 以外のピンの設定を保持できます。
from machine import Pin, deepsleep
import esp32
opin = Pin(19, Pin.OUT, value=1, hold=True) # hold output level
ipin = Pin(21, Pin.IN, Pin.PULL_UP, hold=True) # hold pull-up
# RTC 以外の GPIO のディープスリープ時のパッドホールドを有効にする
esp32.gpio_deep_sleep_hold(True)
# 10秒スリープさせる
deepsleep(10000)
スリープからの復帰時には、パッドホールドを含むピンコンフィギュレーションが保持されます。パッドホールドの詳細については、上記の ピンと GPIO を参照してください。
SD カード
machine.SDCard を参照:
import machine, os, vfs
# オリジナルの ESP32 では、スロット2がピン sck=18, cs=5, miso=19, mosi=23 を使用
sd = machine.SDCard(slot=2)
vfs.mount(sd, '/sd') # マウント
os.listdir('/sd') # ディレクトリ内容の一覧
vfs.umount('/sd') # 取出し
RMT
RMT は ESP32 固有であり、12.5ns の分解能で正確なデジタルパルスを生成できます。詳細については esp32.RMT を参照してください。使い方は次のとおりです。
import esp32
from machine import Pin
r = esp32.RMT(pin=Pin(18), resolution_hz=10000000)
r # RMT(pin=18, source_freq=80000000, resolution_hz=10000000)
# チャンネルの分解能は resolution_hz が元になる。10000000 であれば 100ns
r.write_pulses((1, 20, 2, 40), 0) # 0 を 100ns, 1 を 2000ns, 0 を 200ns, 1 を 4000ns 送信
ESP32-C2 ファミリには RMT ペリフェラルが搭載されていないため、このクラスは ESP32-C2 の SoC では使えません。
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 ドライバー
neopixel と apa106 モジュールを使います:
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 はより一般的な 800kHz のユニットを制御するように設定されています。NeoPixel オブジェクトを作成する際に timing=0 を渡すことで、他のデバイス(よくあるのは 400kHz)を制御するために代替のタイミングを使えます。
NeoPixel の低レベル駆動については machine.bitstream を参照してください。この低レベルドライバは、デフォルトで RMT チャンネルを使います。
APA102 (DotStar)はクロック端子が追加されているため、別のドライバーを使います。
静電容量タッチ
ESP32, ESP32-S2, ESP32-S3 では machine モジュールの TouchPad クラスを使った静電容量方式タッチをサポートします:
from machine import TouchPad, Pin
t = TouchPad(Pin(14))
t.read() # タッチすると小さい数値を返す
TouchPad.read はピンとボードのグランド接続間の静電容量に比例する値を返します。ESP32 では、ピン(または接続されたタッチパッド)に触れるとその値が小さくなり、ESP32-S2やESP32-S3では、ピンに触れるとその値が大きくなります。
いずれの場合でも、タッチによって返される値に大きな変化が生じます。ただし、返される値は 相対的 なもので、ボードや周囲の環境によって異なる場合があるため、キャリブレーション(基準値や移動平均との比較など)が必要になる場合があります。
マイコン |
タッチをサポートするピン |
ESP32 |
0, 2, 4, 12, 13, 14, 15, 27, 32, 33 |
ESP32-S2 |
1 から 14 の間 |
ESP32-S3 |
1 から 14 の間 |
他のピンに割り当てようとすると 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 フォーラムを参照してください。