とりあえず1PIN単位で動くものだけ調べてみました。
※(2019/08/30)ごめんなさい、嘘書いてありました。アナログのpinMode()設定が違っていたので入力値がおかしかったみたいです。
最新情報はM5StickC非公式日本語リファレンスを確認おねがいします。
PIN配置
GROVEのVOUTは5Vでした。しなしながらIO32とIO33のアナログ入力は3.3Vまでなので、アナログのGROVEセンサーとかをつなげると物によってはちゃんと動かない気がします。
PIN設定
PIN | IO | Map | Function |
IO26 | I/O | Extended IO port | GPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1 |
IO36(SENSOR_VP) | I | Extended IO port | GPIO36, ADC1_CH0, RTC_GPIO0 |
IO0 | I/O | Microphone
SCL Extended IO port | ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK |
IO32 | I/O | GROVE SDA | 32K_XP (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9 |
IO33 | I/O | GROVE SCL | 32K_XN (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8 |
外部からアクセスができる上記5PINが調査対象です。
調査結果
PIN | digitalRead() | analogRead() | touchRead() | dacWrite() | digitalWrite() | ledcWrite() |
IO26 | ○ | ○ | NG | ○ | ○ | ○ |
IO36 | ○ | ○ | NG | NG | NG | NG |
IO0 | ○ | NG | NG | NG | ○ | ○ |
IO32 | ○ | ○ | 33 | NG | ○ | ○ |
IO33 | ○ | ○ | 32 | NG | ○ | ○ |
IO26はADC2_CH9に繋がっているのに、Wi-fi使っていない場合でもアナログ入力できませんでした。上側にあるポートからはアナログ入力できなそうですね。
タッチセンサーがまた微妙で、ESP32のデータシートがおそらく間違っていて、内部的に逆に接続されている気がします。
調査方法
digitalRead() デジタル入力 0(1.65V未満) or 1(1.65V以上)
#include <M5StickC.h> int PIN = 32; void setup() { M5.begin(); pinMode( PIN, INPUT); } void loop() { Serial.printf("%04d\n", digitalRead(PIN) ); delay(500); }
上記コードのPIN変数を変えていって実験しました。digitalRead()はどのポートでも利用できます。
analogRead() アナログ入力 0(0V)-4095(3.3V)
#include <M5StickC.h> int PIN = 32; void setup() { M5.begin(); pinMode(PIN, ANALOG); } void loop() { Serial.printf("%04d\n", analogRead(PIN) ); delay(500); }
アナログ入力はIO0が正しく取得できません。内部的にプルアップされている関係で、0と4095のどちらかの数値になります。
touchRead() 静電容量取得 0に近いほうがタッチ
#include <M5StickC.h> int PIN = 32; boolean touched = false; int threshold = 16; void gotTouch() { touched = true; } void setup() { M5.begin(); pinMode( PIN, INPUT); touchAttachInterrupt(PIN, gotTouch, threshold); } void loop() { if (touched) { Serial.println("touch!"); touched = false; } Serial.printf("%4d\n", touchRead(PIN) ); delay(500); }
touchRead()は触ると数値が小さくなるので、触らないときの数字と、触って下がったときの数字の中間か、やや低い値をthresholdに設定してください。
タッチは初めて実験してみましたが、混乱しました。IO32とIO33の結果が逆でした。
コードを見ても、データシートも見ても問題ないはずだったので、他のESP32 Devボードで実験してみたら、やっぱり逆です。
たぶんデータシートが間違っていますね。
typedef struct { uint8_t reg; /*!< GPIO register offset from DR_REG_IO_MUX_BASE */ int8_t rtc; /*!< RTC GPIO number (-1 if not RTC GPIO pin) */ int8_t adc; /*!< ADC Channel number (-1 if not ADC pin) */ int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */ } esp32_gpioMux_t;
こんな構造体があって、ArduinoではGPIOを管理していました。
PIN | reg | rtc | adc | touch |
0 | 0x44 | 11 | 11 | 1 |
1 | 0x88 | -1 | -1 | -1 |
2 | 0x40 | 12 | 12 | 2 |
3 | 0x84 | -1 | -1 | -1 |
4 | 0x48 | 10 | 10 | 0 |
5 | 0x6c | -1 | -1 | -1 |
6 | 0x60 | -1 | -1 | -1 |
7 | 0x64 | -1 | -1 | -1 |
8 | 0x68 | -1 | -1 | -1 |
9 | 0x54 | -1 | -1 | -1 |
10 | 0x58 | -1 | -1 | -1 |
11 | 0x5c | -1 | -1 | -1 |
12 | 0x34 | 15 | 15 | 5 |
13 | 0x38 | 14 | 14 | 4 |
14 | 0x30 | 16 | 16 | 6 |
15 | 0x3c | 13 | 13 | 3 |
16 | 0x4c | -1 | -1 | -1 |
17 | 0x50 | -1 | -1 | -1 |
18 | 0x70 | -1 | -1 | -1 |
19 | 0x74 | -1 | -1 | -1 |
20 | 0x78 | -1 | -1 | -1 |
21 | 0x7c | -1 | -1 | -1 |
22 | 0x80 | -1 | -1 | -1 |
23 | 0x8c | -1 | -1 | -1 |
24 | 0 | -1 | -1 | -1 |
25 | 0x24 | 6 | 18 | -1 |
26 | 0x28 | 7 | 19 | -1 |
27 | 0x2c | 17 | 17 | 7 |
28 | 0 | -1 | -1 | -1 |
29 | 0 | -1 | -1 | -1 |
30 | 0 | -1 | -1 | -1 |
31 | 0 | -1 | -1 | -1 |
32 | 0x1c | 9 | 4 | 9 |
33 | 0x20 | 8 | 5 | 8 |
34 | 0x14 | 4 | 6 | -1 |
35 | 0x18 | 5 | 7 | -1 |
36 | 0x04 | 0 | 0 | -1 |
37 | 0x08 | 1 | 1 | -1 |
38 | 0x0c | 2 | 2 | -1 |
39 | 0x10 | 3 | 3 | -1 |
こんな感じのマトリクスで、内部レジスタのアドレスとか番号が並んでいます。
PIN | reg | rtc | adc | touch |
32 | 0x1c | 9 | 4 | 9 |
33 | 0x20 | 8 | 5 | 8 |
該当部分だけ抜きですと、RTCとTouchとかはPIN番号大きい方から割り当てていますが、ADCは逆です。Touchもデータシート上は上記の記述ですが、実際の実装はIO32がT8でIO33がT9になっていると思われます。
ここ以外のいろんな場所でも逆に定義されているので、ライブラリは修正されない気もします。
一応商品としてはありますので、使うときにはIO32を取得してください。
dacWrite() アナログ出力 0(0V)-255(3.3V)
#include <M5StickC.h> int PIN = 26; void setup() { M5.begin(); pinMode(PIN, OUTPUT); } void loop() { dacWrite(PIN, 0); delay(500); dacWrite(PIN, 128); delay(500); dacWrite(PIN, 255); delay(500); }
dacWrite()はIO26でしか使えません。(内部的にはIO25でも可能)
IO26からの出力にLEDと抵抗に接続してものをオシロスコープで測定した結果です。若干電圧低下していますが、概ね255で3.3V程度、128でその半分の電圧が出力されています。
digitalWrite() デジタル出力 LOW(0V) or HIGH(3.3V)
#include <M5StickC.h> int PIN = 32; void setup() { M5.begin(); pinMode(PIN, OUTPUT); } void loop() { digitalWrite(PIN, HIGH); delay(500); digitalWrite(PIN, LOW); delay(500); }
IO36はIOがInputのみなので、出力には使えませんが、それ以外のPINでは使えました。
ledcWrite() PWM出力
#include <M5StickC.h> int PIN = 32; int PWMCH = 0; void setup() { M5.begin(); pinMode(PIN, OUTPUT); ledcSetup(PWMCH, 12000, 8); ledcAttachPin(PIN, PWMCH); } void loop() { ledcWrite(PWMCH, 0); // 0%(0.0V) delay(500); ledcWrite(PWMCH, 128); // 50%(1.7V) delay(500); ledcWrite(PWMCH, 256); // 100%(3.3V) delay(500); }
PWMはdigitalWrite()で出力を定期的にON/OFFさせることで、擬似的なdacWrite()に似た動きになります。PWMは4PIN同時に利用することが可能で、細かい設定はledcSetup()で行っています。サンプルは周波数が 12KHz で分解能が8ビット(0-256)になっています。
8ビットの場合、256分割してそのうち何個を出力するかの指定なので、出力しないの0と全部出力するの256までの257段階で制御が可能です。
上記はキャプチャ用に周波数50Hzに落として実験しましたが、上記のように128(50%)を指定するとONとOFFが交互にきて、平均すると半分の電圧相当になります。
LEDの明るさ調整とかであればdacWrite()でなくて、PWM制御で十分明るさが変わります。
まとめ
GROVEの電源が5Vなんで、ちょっと注意が必要そうですね。あと本家だといろいろな拡張HATが開発されているようですので、楽しみです。
今後はI2Cとか2PIN以上必要な通信を調べていきたいと思います。
コメント
素晴らしいレポートありがとうございます