PR

M5stackで複数モジュールを付けるとUARTが競合する問題の解決法

組み込み機器

通信ができません…

こうした悩みを解決します。

立プロ

新卒でメーカーに入り、10年間組み込みの現場で設計を行う。
今は個人事業主として自作の組み込み機器開発や、エージェント様に紹介いただき業務委託を行っています。
C,C#,JavaScript, Vue, PHP, VBA, GAS, Kotlinなど、扱う言語が増えゆく日々。

立プロをフォローする

問題

M5stack basicにM5Stack用 3G 拡張ボード(SORACOM)M5Stack用GPSモジュール V2 [M003]を接続しました。

それでGPSモジュールの製品ぺージに下記の記載がされていることを確認しました。

本製品のような専用の拡張モジュールを縦に積み重ねていくことで機能を追加することができます。

この時は何も考えずに、積み重ねて機能追加できるなんて便利だなあと思ってましたが、いざ積み重ねるとどちらも動作しないのです。

そしてモジュールを1つだけ接続して動作させるのは、いずれも問題ないことを確認しました。

これは2つのモジュールが互いに影響してるんだな、と思い両者の仕様を見たところ…

それぞれUARTでESP32マイコンと通信してデータ送受信を行うもので、これが同じSerial2というUARTポートを使って競合していたのです。

Serial0に切り替えてみる

M5stack(厳密にはESP32マイコン)には、serial0, serial1, serial2の3つのUARTがあります。

UARTを使うにはHardwareSerial.cppから番号指定して、begin()で設定という流れですね。

//GPSモジュールのサンプルコード抜粋
HardwareSerial GPS_s(2); //この引数と、後述するbegin関数の_uart_nrが等しい
GPS_s.begin(9600); //9600bps

begin関数ではswitch文でピン設定を行っています。

//begin関数一部抜粋
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
{
    if (!uartIsDriverInstalled(_uart)) {
        switch (_uart_nr) {
            case UART_NUM_0:
                if (rxPin < 0 && txPin < 0) rxPin = SOC_RX0; /*3*/  txPin = SOC_TX0; /*1*/
            break;
#if SOC_UART_NUM > 1                   // may save some flash bytes...
            case UART_NUM_1:
               if (rxPin < 0 && txPin < 0) {
                    rxPin = RX1; /*9*/  txPin = TX1; /*10*/
//                    rxPin = 2;  txPin = 5;
                }
            break;
#endif
#if SOC_UART_NUM > 2                   // may save some flash bytes...
            case UART_NUM_2:
               if (rxPin < 0 && txPin < 0) rxPin = RX2; /*16*/  txPin = TX2; /*17*/
            break;
#endif
        }
    }
//後段の処理...
}

で、よくよくGPSモジュールのマニュアルを見ると必要に応じて自分で配線を切り替えてください、と書いてるんですね。
※M5stack Fireでは16,17番ピンがPSRAMに割り当てられていることの対策です。

モジュールの基板を見たら、たしかに16,17を使っていて、半田の間に切欠きがありました。

そしてありがたいことに別ピンを近接配置してくれており、RXDを1、TXDに3をつなげばSerial0が使えそう!

ってことで早速カッターで16,17の間を切って、1,3をつなげます。

余談ですが日置電機のテスタを使って導通確認しています。安心、安全、高速、高精度で私の好きなメーカーです。

ソフト側もSerial0を指定して、いざ書き込み…ができない!

なんと、Serial0はUSBと共通の端子になっていたようで書き込みができない仕様だったのです!

後になって気づいて未確認ではありますが、たぶんSerial0自体は使えます。

Serial0に初期設定されている1,3番ピンがUSBと共通になっているだけなので、Serial0のピン配置を例えば、2,5番ピンに設定して動かすことはできるはず。

これは困った…Serial1につなぐとしてもソフト側初期指定の9,10番ピンは出てないし、GPSモジュールは5,13番ピンにしかつなげない…

結局何にもつながってないと思われる2,5番ピンを使ってSerial1で設定することにしました。

Serial1を使う

2,5番ピンを使う選択をしたものの、配線を自分でつなぐ必要がありました。

HardwareSerial.cppのbegin関数、UART_NUM_1部分のTXD,RXDのピン配置を指定しなおして、書込み…がまたできない!!

そこでモジュールを切り離して本体だけにしたところ…書き込みができました。

よく分かりませんが、2,5番ピンもUSBに影響を与えるようです。全く独立してる気がするがなぜ…?

結局ソフト書き込む際は毎回モジュールを外してから書き込んでます…。

まとめ

とりあえず結論としては下記のとおりとなります。

  • Serial0、Serial1, Serial2いずれも使用可(のはず、Serial0は未確認)
  • Serial0初期設定の1,3番ピンはUSBと共通端子になっていて書き込みエラーとなる
    (1,3番ピンを指定しなければSerial0も使えるはず、ピン指定はHardwareSerial.cppにて)
  • 2,5番ピンは独立GPIOのはずだが書き込みエラーとなる、書込み後の動作は問題なし

コメント

タイトルとURLをコピーしました