Arduino core for the ESP32 リファレンス
●GPIOマトリクス機能
「(物理的な)ピン」「IO MUX(マルチプレクサ)」「GPIO マトリックス」という3つの回路があります。
GPIOピンは再割り当てすることが可能です。基本的に内蔵ペリフェラルのほぼ全てが変更できます。
ただし、以下の制約があります。
・GPIO 0,2 回路的にブートモードの設定に利用
・GPIO 1,3 シリアル通信(UART U0RXD、U0TXD)に利用するため注意
・GPIO 6~11 ESP-WROOM-32モジュール内部では既にFLASHメモリと接続されている
・GPIO 12 内蔵LDOの電圧設定に利用
・GPIO 15 U0TXDピンのデバッグログの設定に利用されることがある
・GPIO 34~39 入力のみ
Ethernet, SDIO, SPI, JTAG, UARTなどの高速信号は、パフォーマンス低下を回避するためにGPIOマトリクスを介さないで接続可能なものがあり、その場合は出力ピンが固定される。
●pinMode()一覧
ピンによって起動時に設定されているモードが違うので、使用するピンは初期化してから使うようにしたほうが安全です。
モード 入力接続 INPUT 入力(LOW=0、HIGH=1) INPUT_PULLUP 入力(3.3Vに抵抗経由で接続) INPUT_PULLDOWN 入力(GNDに抵抗経由で接続) ANALOG 入力(0~4095) OUTPUT 出力(LOW:0V、HIGH:3.3V) OUTPUT_OPEN_DRAIN 出力(LOWのときにはGND接続で変わらないが、HIGHのときには3.3Vを出力するのではなく、なにも接続されていないハイインピーダンス状態になります。) pinMode(4, OUTPUT); // GPIO_4番pinを出力設定
●デジタル入力 digitalRead()
25%の0.825Vより低い電圧の場合LOWになり、75%の2.475Vより高いとHIGHになります。
●デジタル出力 digitalWrite()
LOWの場合には0V、HIGHの場合には3.3Vの電圧を出力します。
LOWの場合には内部でGNDに接続するイメージになり、外部電源からGPIOに接続してLOWすることで、HIGHよりも多くの電流を流すことが可能です。
使用できるGPIOピンは、0~33
digitalWrite(4, HIGH); // GPIO_4番pinをHIGH
digitalWrite(4, LOW); // GPIO_4番pinをLOW
●PWM出力 ledcWrite()
パルス幅変調出力です。電流を周期的にON/OFFすることで出力量を制御します。ArduinoのanalogWrite()と同様の振る舞いをします。
チャンネルが0~15まであり、各チャンネル毎に周波数と分解能を設定して複数ピンへの割り当てが可能。
LEDCには Note / Tone 関係の関数が含まれています。ledcWriteNote() / ledcWriteTone() にて音を鳴らすことができます。
また、通信用のクロックとしても使用できます。
使用できるGPIOピンは、0~33
ledcSetup(0, 12000, 8); // チャンネル設定(channel, Hz, bit)8bitの場合は0~256の範囲で出力できる
ledcAttachPin(4, 0); // GPIO_4番pinをPWMの0チャンネルに設定
ledcWrite(0, 128); // 128/256で 50%の出力
●アナログ出力 dacWrite()
アナログ電圧が直接ピンから出力される。主にスピーカーを鳴らす場合に利用することが多い
出力値は、0~255 ※256ではない
ESP32は2chの8bit DACを内蔵しており、出力ピンはGPIO25,26ピンの位置に固定されています。
使用できるGPIOピンは、25、26
dacWrite(25, 128); // GPIO_25番pinを128/255で 50%の出力
●アナログ入力(ADC) analogRead()
アナログ入力として0~4095の値が返ってきます。
入力範囲はanalogReadResolution()にて解像度設定でより荒い値に変更することができます。
0は0V、4095は3.3Vに対応していますが、精度はそれほど高くないので注意して利用してください。
ADCに接続されているGPIOでのみアナログ入力が可能です。GPIO32以降であればどんな状況でも利用可能です。無線を利用しない場合にはADC2に接続されている端子でも利用が可能です。
ESP32には逐次比較型(SAR)ADCモジュールが2つ内蔵されています。分解能は9~12bitで、デフォルトは12bitです。
ADC1 には、GPIO32~39に相当するピンと、後述するホールセンサが接続されています。
ADC2 には、それ以外のピンと、deep sleep機能用の入力などが接続されています。
Wi-Fi使用時には ADC2が使えません。つまり、実質 A4 (IO32) ~ A7 (IO35) の 4 本しか使えません。
また、ADCの入力には減衰器を設定することができます。実のところ、ESP32のADCモジュールは0~1 Vの間でAD変換を行っています。
このモジュールに例えば11db(約1/3.6倍)の減衰器を設定することで、0~3.6 Vの間のAD変換ができるようになります。
デフォルトでは11dBの減衰が設定され、12bitでの最大値は3.6 Vを示しています。
また、現在AD変換の結果は少し誤差があるとのことです(?公式スレッド参照)。
他にも議論が見受けられ(?例1,?例2)、状況によって値が変わる可能性がある点に注意したほうが良いでしょう。
このADCの補正に関しては色々議論が進んでいるようです。参考情報として、電源電圧3.31 VでA0ピン(GPIO36)に1.667 Vを入力した時のADCの値は、
1950程度でした。値が4095の時3.50 Vになる計算です。この値も何度かのアップデートで変わっている可能性があります。
setupのブロックでanalogSetAttenuation()関数を呼ぶことで減衰率の設定ができます。
例えば減衰無し(入力電圧範囲 0~1 V)であれば、analogSetAttenuation(ADC_0db);と設定します。詳しくは?このあたりを参照ください。
また、ADC2回路を利用するピンは、今のところWiFi機能と並行して利用できず、常に値が4095になります(?参照)。
将来的に修正するようですが、注意してください。
ADCに使えるピンを以下の表に示します。
GPIO ADC WiFi使用時 0 ADC2_CH1 不可 2 ADC2_CH2 不可 4 ADC2_CH0 不可 12 ADC2_CH5 不可 13 ADC2_CH4 不可 14 ADC2_CH6 不可 15 ADC2_CH3 不可 25 ADC2_CH8 不可 26 ADC2_CH9 不可 27 ADC2_CH7 不可 32 ADC1_CH4 33 ADC1_CH5 34 ADC1_CH6 35 ADC1_CH7 36 ADC1_CH0 37 ADC1_CH1 38 ADC1_CH2 39 ADC1_CH3Serial.println(analogRead(4)); // GPIO_4番pinからアナログ入力
●Serial (UART)
Serialオブジェクトは、Serial、Serial1、Serial2として定義されており宣言なしに利用可能です。
3系統のハードウエアシリアルを利用可能です。※UART0は、USBポートで使用。
UART0 UART1 UART2 IO1 IO10 IO17 TXD IO3 IO9 IO16 RXD IO22 IO11 IO7 RTS IO19 IO6 IO8 CTSUART1を使用する場合は、制約上IO6~IO11が使用できないためピンを変更する必要があります。
HardwareSerial mySerial1(1); //UART1 (RX=9, TX=10)
HardwareSerial mySerial2(2); //UART2 (RX=16, TX=17)
void setup() {
mySerial1.begin(115200, SERIAL_8N1, 32, 33); //ピンを変更 (RX=32, TX=33)
mySerial2.begin(115200);
while(!mySerial1); //ポートを開くまでの待ち
Arduinoから機能拡張されている点は下記になります。
.begin() UARTを設定します。Serial1.begin(115200, SERIAL_8N1, 32, 33);
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1,
bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
.readStringUntil() 指定した文字を受信するまで読み込みます。Serial.readStringUntil('\r')
●I2C(Inter-Integrated Circuit)通信
半二重シリアル通信方式です。モーターや温度、湿度センサーなど多くの対応デバイスがあり、それら利用する場合にこの端子を利用します。
I2C0、I2C1の2系統があり、デフォルトでは以下のピンが設定されています。
・I2C0 GPIO 定数 21 SDA 22 SCL ・I2C1 未定義ArduinoIDEでは、Wire.begin() は引数を持っており、任意のピンに変更ができます。
void begin(int sda=-1, int scl=-1, uint32_t frequency=100000);
●SPI(Serial Peripheral Interface)通信
同期式全二重シリアル通信で、I2Cより高速にデータ通信を行うことができ、主にEEPROMやSDカード、各種素子などの扱うデータ容量が大きいところで利用されています。
また、内蔵FLASHとの接続にも利用されているため、IO6~IO11を使ったSPIは利用不可です。
VSPI、HSPIの2系統があり、デフォルトでは以下のピンが設定されています。
GPIO VSPI SPI 18 VSPICLK SCK 19 VSPIQ MISO 23 VSPID MOSI 5 VSPICS0 SS 21 VSPIHD 22 VSPIWP GPIO HSPI SPI 14 HSPICLK SCK 12 HSPIQ MISO 13 HSPID MOSI 15 HSPICS0 SS 4 HSPIHD 2 HSPIWPArduinoIDEでは、SPIClass.begin() は引数を持っており、任意のピンに変更ができます。
void begin(int8_t sck=SCK, int8_t miso=MISO, int8_t mosi=MOSI, int8_t ss=-1);
●Bluetooth
Bluetoothを使用するには、様々なライブラリが提供されており簡単に通信をすることが可能です。
◆BluetoothSerialライブラリ
シリアル通信をBluetooth通信に置き換える仕組みで、通常のUART通信と同じように記述できます。
ホスト側では、ESP32とペアリングをすると仮想シリアルポートが作成されます。
●WiFi
様々なライブラリを使うことで多くの機能を実現できます。スケッチ例にあるサンプルで確認できます。
WiFi.begin(ssid, password); //特定のAPへ接続 wifiMulti.run(); //複数のAPを指定できる WiFiScan(); //アクセスポイントをスキャンする WiFi.disconnect(true); // WiFi切断 true:Wi-Fi機能OFF false:APへ接続しない WiFi.mode(WIFI_OFF);
●ホールセンサ(磁気センサー) hallRead()
ESP32に内蔵されている磁力センサーです。ESP32に磁石を近づけると値が小さくなるセンサーです。
ホールセンサの出力は、内蔵LNAに接続されている、つまりGPIO36,37(SENSOR_VP,SENSOR_VN)につながっているため、
他の回路とは基本的に排他利用となっています。
●タッチ入力 touchRead()
静電容量を利用したタッチセンサーです。ピンに一瞬電荷をチャージして、直後にピンの電荷を確認することでタッチの確認をしています。
タッチセンサーとADCは別の回路のため、無線を利用している場合でもADC2に接続されているピンを利用することができます。
タッチセンサとして使える入力を以下に示します。
GPIO 定数 4 T0 0 T1 ←注意 2 T2 ←注意 15 T3 ←注意 13 T4 12 T5 14 T6 27 T7 33 T8 ←注意 32 T9 ←注意例によってGPIO0,2はブート設定で使われることがあったり、GPIO15はデバッグログの設定ピンだったり、
●内部温度センサー temperatureRead()
ESP32の内部温度のセンサーです。外気温ではなく内部温度のため高負荷でESP32を利用した場合には上昇していきます。
●動作クロックの変更
setup()で int ret = setCpuFrequencyMhz(240); //240,160,80,40,20,10が使用可
●Deep Sleepモード
ESP32の動作モードは、アクティブモード、モデムスリープモード、ライトスリープモード、ディープスリープモード、ハイバネーションモード、休止モードがあり
ArduinoIDEで簡単に扱えて効果が大きい停止モードがDeep Sleepになります。
Deep Sleepからもとの状態に戻す(ウェイクアップ)させるには次の方法があります。
・タイマーによるウェイクアップ esp_deep_sleep(time); //直ちにDeep Sleepに移行しマイクロ秒後にウェイクアップ esp_sleep_enable_timer_wakeup(time); //スリープ時間をマイクロ秒単位で指定 esp_deep_sleep_start(); //Deep Sleepへ移行し上記で設定した時間後にウェイクアップ ・外部ウェイクアップ ext0とext1の2種類があります。 esp_sleep_enable_etx0_wakeup(GPIO_NUM_x, level) //指定のGPIOピンが 0:Lowでウェイクアップ、1:Highでウェイクアップ esp_sleep_enable_etx1_wakeup(bitmask, mode) //複数のRTC GPIOを使用してウェイクアップ ・タッチピンを使ったウェイクアップ ・ULPコプロセッサを使ったウェイクアップ
●タスク処理
複数の処理を同時に起動して効率的に処理を行います。
・スレッド処理
同じCPUコア内にて時間で切り替えをしながら実行するタスクのことです。
・マルチコア処理
別のCPUコアで実行する処理となり完全な並列処理をします。
メモリやIO関連では同時アクセスしないよう排他制御を考慮する必要があります。
TaskHandle_t task1Handle; //タスクハンドルの宣言
void task1(void *pvParameters) { //引数はvoidのポインターを指定
while (1) { //通常は終了しないようループさせる
Serial.print(".");
delay(1); //ループ中に同じ優先度のタスクを実行するにはディレイを入れる
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); //通知が来るまで待機する場合
}
vTaskDelete(NULL); //タスクハンドルを使用しないで自分自身を削除する場合
}
void setup(){
xTaskCreateUniversal(
task1, //作成するタスク関数
"task1", //表示用タスク名。あまり意味がなく一覧を取得時に表示される
8192, //スタックメモリ量。基準値8192
NULL, //タスクへ渡す起動パラメータ。不要な場合はNULLを指定する
1, //優先度 0:低 24:高 loop()関数内は優先度1
&task1Handle, //タスクハンドル。起動後に変数を利用してタスクを制御する場合に指定し、不要な場合はNULLを指定する
APP_CPU_NUM //実行するコア。他にPRO_CPU_NUM
);
}
void loop(){
}
vTaskDelete(task1Handle); //タスクを削除
vTaskSuspend(task1Handle); //タスクを一時停止
vTaskResume(task1Handle); //タスクを再開
xTaskNotifyGive(task1Handle); //タスクに通知を送る
//タスクに通知を送る。sendDataは32bitの値で、eSetValueWithOverwriteは上書きする
xTaskNotify(rxTaskHandle, sendData, eSetValueWithOverwrite);
●キュー(Queue)
タスク間で複数のデータを安全にやり取りするための仕組みです。
データはFIFO(先入れ先出し)で格納されます。
QueueHandle_t myQueue; //キューハンドルの宣言
// 受信側のタスク関数
void rxTask(void *pvParameters) {
int receivedData = 0;
while (1) {
//キューからデータを受信(キューハンドル, 変数のアドレス, 待ち時間ms) portMAX_DELAY:受信するまで待機
if (xQueueReceive(myQueue, &receivedData, portMAX_DELAY) == pdPASS) {
Serial.println(receivedData);
}
}
}
void setup() {
myQueue = xQueueCreate(5, sizeof(int)); //キューの作成(キューに貯められる数, 要素サイズ)
if (myQueue == NULL) Serial.println("キューの作成に失敗しました");
xTaskCreateUniversal(rxTask, "ReceiverTask", 4096, NULL, 1, NULL, APP_CPU_NUM); //タスクの作成
}
void loop() {
static int counter = 0;
counter++;
//キューへデータを送信(キューハンドル, 変数のアドレス, キューが満杯のときの空き待ち時間ms)
if (xQueueSend(myQueue, &counter, 0) == pdPASS) {
Serial.println(counter);
} else {
Serial.println("キューが満杯で送信失敗");
}
delay(2000);
}
●ウォッチドッグ
定期的に生存確認を行ってシステムがハングアップしていないかを監視する仕組みです。
無限ループなどにはまっている場合に自動的にリブートします。
監視時間はウォッチドッグタイマ(WDT)と呼ばれ、ESP32では3秒間応答がないとリブートがかかります。
・初期値
Core 0(PRO_CPU)WDT有効
Core 1(APP_CPU)WDT無効 ※通常の処理はCore1です。
・ウォッチドッグタイマのリセット方法
delay()を入れることでWDTはリセットされます。
●ULPコプロセッサ
低消費電力用にもう一つプロセッサを載せており、これをULPコプロセッサと呼びます。
ただ、ArduinoIDEから利用する分には制約があり、プログラミングもアセンブラで行う必要があります。
●SPIFFS(SPI Flash File System)によるファイル操作
ESP32-DevKitC(ESP-WROOM-32)には4MByteのフラッシュメモリが内蔵されていてSPIで接続されています。
このフラッシュメモリをファイルシステムとしてストレージのように利用する事ができます。
SPIFFSは数MByteまで利用できますので、ファイルなどの比較的大きなデータでも保存できます。
一度書き込んだファイルはスケッチを書き換えても消えません。
また、EEPROMも同じフラッシュメモリに保存されます。
SPIFFS は便利ですが、秒単位でログを取るような用途には向いていません (フラッシュメモリなので書き換え回数に上限があります)。
設定値など小さなデータはEEPROMを利用する方がよいでしょう。サイズは4KB。
アップロードツールにて、Arudino IDEからファイルを書き込みすることができます。ただし、Arudino IDE 2.x.xは未対応。
●タイマー
ESP-WROOM-32には、64ビットタイマーモジュールが2個あり、それぞれのタイマーモジュールは2個のタイマーを持っています。
このため、合計4個のタイマーを利用することができます。
ボード 2.0.xと3.x.xで記述方法が変わったので注意します。
●GPIO割り込み(ISR)
ハードウエア割り込みは基本的に優先度が高いため、他のソフトウェア割り込みより優先して動きます。
attachInterrupt(GPIO_PIN, fnc, FALLING); 値 define トリガー条件 0x00 DISABLED 無効 0x01 RISING LOWからHIGHに変化 0x02 FALLING HIGHからLOWに変化 0x03 CHANGE 信号レベルが変化 0x04 ONLOW LOWのときに常に発生 0x05 ONHIGH HIGHのときに常に発生
●リセット
ESP.reset(); //ハードリセット(いくつかのレジスタは古い状態のままになる)
ESP.restart(); //再起動(上記よりもクリーンな起動ができる)
●リブートを繰り返し動作しない場合の対処
フラッシュメモリを消去し再度スケッチを書き込みすることで復帰する場合があります。
症状はシリアルモニターで115200bpsに設定した後、ESP32を起動しブートログにて確認をする。
書き込みツールを使用して、下記のコマンドを実行する。
esptool.exe --chip esp32 --port COM1 --baud 921600 erase_flash
●ビルトイン BASIC
ESP32-WROOM-32 にはビルトイン BASIC が仕込まれています。
ビルトインBASICを起動するには、GPIO12を10kΩ抵抗でプルアップします。
1.GPIO12 と 3V3 を10kΩ抵抗で繋ぐ。
2.USBでPCと接続し、シリアルモニタを115200 bpsで開く。
3.以下のようなメッセージが繰り返し出る ので Enter を入力するとBASIC が起動する。。
(GPIO15をプルダウンしている場合には”OK”のみが繰り返し表示される)
ets Jun 8 2016 00:22:57 rst:0x10 (RTCWDT_RTC_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0x00 clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 cmd len -1 Falling back to built-in command interpreter. OK >