M5StickCのIOについて調べてみた

とりあえず1PIN単位で動くものだけ調べてみました。

※(2019/08/30)ごめんなさい、嘘書いてありました。アナログのpinMode()設定が違っていたので入力値がおかしかったみたいです。

最新情報はM5StickC非公式日本語リファレンスを確認おねがいします。

PIN配置

GROVEのVOUTは5Vでした。しなしながらIO32とIO33のアナログ入力は3.3Vまでなので、アナログのGROVEセンサーとかをつなげると物によってはちゃんと動かない気がします。

PIN設定

PINIOMapFunction
IO26I/OExtended IO portGPIO26, DAC_2, ADC2_CH9, RTC_GPIO7, EMAC_RXD1
IO36(SENSOR_VP)IExtended IO portGPIO36, ADC1_CH0, RTC_GPIO0
IO0I/OMicrophone SCL
Extended IO port
ADC2_CH1, TOUCH1, RTC_GPIO11, CLK_OUT1, EMAC_TX_CLK
IO32I/OGROVE SDA32K_XP (32.768 kHz crystal oscillator input), ADC1_CH4, TOUCH9, RTC_GPIO9
IO33I/OGROVE SCL32K_XN (32.768 kHz crystal oscillator output), ADC1_CH5, TOUCH8, RTC_GPIO8

外部からアクセスができる上記5PINが調査対象です。

調査結果

PINdigitalRead()analogRead()touchRead()dacWrite()digitalWrite()ledcWrite()
IO26NG
IO36NGNGNGNG
IO0NGNGNG
IO3233NG
IO3332NG

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を管理していました。

PINregrtcadctouch
00x4411111
10x88-1-1-1
20x4012122
30x84-1-1-1
40x4810100
50x6c-1-1-1
60x60-1-1-1
70x64-1-1-1
80x68-1-1-1
90x54-1-1-1
100x58-1-1-1
110x5c-1-1-1
120x3415155
130x3814144
140x3016166
150x3c13133
160x4c-1-1-1
170x50-1-1-1
180x70-1-1-1
190x74-1-1-1
200x78-1-1-1
210x7c-1-1-1
220x80-1-1-1
230x8c-1-1-1
240-1-1-1
250x24618-1
260x28719-1
270x2c17177
280-1-1-1
290-1-1-1
300-1-1-1
310-1-1-1
320x1c949
330x20858
340x1446-1
350x1857-1
360x0400-1
370x0811-1
380x0c22-1
390x1033-1

こんな感じのマトリクスで、内部レジスタのアドレスとか番号が並んでいます。

PINregrtcadctouch
320x1c949
330x20858

該当部分だけ抜きですと、RTCとTouchとかはPIN番号大きい方から割り当てていますが、ADCは逆です。Touchもデータシート上は上記の記述ですが、実際の実装はIO32がT8でIO33がT9になっていると思われます。

ここ以外のいろんな場所でも逆に定義されているので、ライブラリは修正されない気もします。

GROVE – タッチセンサ

一応商品としてはありますので、使うときには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以上必要な通信を調べていきたいと思います。

コメント

  1. としちゃん より:

    素晴らしいレポートありがとうございます