2022年10月10日月曜日

STM32Arduinoで2番目のシリアルは未定義だが、定義すれば使える


背景

STM32とはST社が販売しているマイコンの1種です。
ピンの数と機能が多く用意されており、USARTとUARTの回路がそれぞれ4つずつ用意されています。

しかしながら、STM32マイコン向けのarduino環境ではUSBで通信するためのシリアルポート以外は定義されていません。
調べたところ有効なピンを利用して自分で定義すれば使えると分かりました。

備忘録を兼ねて動作確認用のコードと関連資料のリンクを記事に残します。

使った物

  • Nucleo-144 STM32F767ZI
    STM32F767ZIというマイコンを搭載した開発ボードです。
  • プログラムを書き込むPC + USBケーブル
    開発環境はPlatformIOを利用しました。
  • ピンソケット + はんだ + はんだごて
    Nucleo-144の両側の穴から信号線を引き出すためにピンソケットを取り付けました。
  • ジャンパワイヤ
    ピンソケットの信号線の接続に利用しました。


各シリアルとピンの関係

今回利用するマイコンSTM32F767ZIのデータシートを見ると、下記UARTとUSARTはそれぞれ下記のピンがRXとTXに割り当てられてしました。(表に間違いがあればコメントなどで指摘していただけると嬉しいです。)

USARTとUARTの違いは前者が同期モードでの通信を備えている回路であり、どちらもarduinoのシリアルポートとして使えます。
USARTの同期モードをstm32arduinoのシリアルポートで利用する方法は把握していません。

開発ボードのデータシートを見るとUSART3のPD9とPD8がstlinkに接続されていると分かりました。
さらに開発時のマイコンのライブラリであるstm32arduinoではそのPD9とPD8Serial3が定義された上でSerialに割り当てられています。

役割RXピンTXピン備考
USART1PB15PB14
USART2PA3,PD6PA2,PD5
USART3PD9,PC11,PB11PD8,PC10,PB10USB通信用に
SerialとSerial3として
PD9とPD8で定義済み
UART4PA1,PA11,PC11,PD0,PH14,PI9PA0,PA12,PC10,PD1,PH13
UART5PB5,PB8,PB12,PD2PB6,PB9,PB13,PC12
USART6PC7,PG9PC6,PG14
UART7PA8,PB3,PE7,PF6PA15,PB4,PE8,PF7
UART7PE0PE1

定義済みのSerial3以外を定義して同時に動かす

Serial1-8を同時に動かします。

下記の配線をした上で全てのシリアルポートを扱うプログラムを動かせました。
  • PB14(Serial1 TX)とPD6(Serial2 RX)を接続
  • PD5(Serial2 TX)とPA11(Serial4 RX)を接続
  • PA0(Serial4 TX)とPB5(Serial5 RX)を接続
  • PB6(Serial5 TX)とPG9(Serial6 RX)を接続
  • PG14(Serial6 TX)とPA8(Serial7 RX)を接続
  • PA15(Serial7 TX)とPE0(Serial8 RX)を接続
  • PE1(Serial8 TX)とPB15(Serial1 RX)を接続

配線するとこうなりました。
引き出されているピンは並びが不規則なので、開発ボードのデータシートの開発ボードのデータシートのTable21か22で必要なピンを検索して探すのが早いと思います。


全てのシリアルポートを扱うプログラムはこちらです。
print(出力)後にflushを呼ばないと送信順序が乱れる(値が保持されて出力が後回しになってしまうことがある)のに注意です。

#include <Arduino.h>

HardwareSerial Serial1(PB15, PB14);
HardwareSerial Serial2(PD6, PD5);
// HardwareSerial Serial3(PD9, PD8);
HardwareSerial Serial4(PA11, PA0);
HardwareSerial Serial5(PB5, PB6);
HardwareSerial Serial6(PG9, PG14);
HardwareSerial Serial7(PA8, PA15);
HardwareSerial Serial8(PE0, PE1);

void setup() {
Serial.begin(115200);
Serial1.begin(115200);
Serial2.begin(115200);
// Serial3.begin(115200);
Serial4.begin(115200);
Serial5.begin(115200);
Serial6.begin(115200);
Serial7.begin(115200);
Serial8.begin(115200);
}

void printInfo(Stream* serial, String label) {
serial->print("data from " + label);
serial->flush();
}

void receiveInfo(Stream* serial, String label) {
Serial.print(label + ": ");
while (serial->available()) {
Serial.print((char)serial->read());
}
Serial.println();
}

void loop() {
Serial.println("write");
printInfo(&Serial1, "1");
printInfo(&Serial2, "2");
// printInfo(&Serial3, "3");
printInfo(&Serial4, "4");
printInfo(&Serial5, "5");
printInfo(&Serial6, "6");
printInfo(&Serial7, "7");
printInfo(&Serial8, "8");
receiveInfo(&Serial1, "1");
receiveInfo(&Serial2, "2");
// receiveInfo(&Serial3, "3");
receiveInfo(&Serial4, "4");
receiveInfo(&Serial5, "5");
receiveInfo(&Serial6, "6");
receiveInfo(&Serial7, "7");
receiveInfo(&Serial8, "8");
Serial.println("at " + String(millis()));
delay(2000);
}

platformioの設定ファイルは今回利用する開発ボード nucleo_f767zi のプロジェクトとしました。
platformio.ini
[env:nucleo_f767zi]
board = nucleo_f767zi
platform = ststm32
framework = arduino
monitor_speed = 115200

書き込んで動かしてログを確認すると、期待通りに隣のシリアルポートから送信される情報を受け取れていました。
1: data from 8
2: data from 1
4: data from 2
5: data from 4
6: data from 5
7: data from 6
8: data from 7
at 6044


RXとTXはポート番号が合っていればどの組み合わせでも動く

UART7のピンを複数の組み合わせで試してみます。

UART7で使えるピンはこれらです。
RX: PA8,PB3,PE7,PF6
TX: PA15,PB4,PE8,PF7


まずRX PA8、TX PA15の動作を確認します。
繋ぐとこうなりました。


Serial2とやりとりするプログラムを試します。
#include <Arduino.h>

HardwareSerial Serial2(PD6, PD5);
HardwareSerial Serial7(PA8, PA15);

void setup() {
Serial.begin(115200);
Serial2.begin(115200);
Serial7.begin(115200);
}

void printInfo(Stream* serial, String label) {
serial->print("data from " + label);
serial->flush();
}

void receiveInfo(Stream* serial, String label) {
Serial.print(label + ": ");
while (serial->available()) {
Serial.print((char)serial->read());
}
Serial.println();
}

void loop() {
Serial.println("write");
printInfo(&Serial2, "2");
printInfo(&Serial7, "7");
receiveInfo(&Serial2, "2");
receiveInfo(&Serial7, "7");
Serial.println("at " + String(millis()));
delay(2000);
}

期待通りに動きました。
2: data from 7
7: data from 2
at 2003

他の組み合わせも試してみます。

RXだけ変更してRX PB3、TXPA15を試します。
プログラムはSerial7の定義が変わります。
HardwareSerial Serial7(PB3, PA15);

繋ぐとこうなりました。


write
2: data from 7
7: data from 2
at 10007

先ほどと同様に期待通り動きました。
他の組み合わせも試してみます。

RX PB3, TX PB4 -> 動作成功
RX PF6, TX PE8 -> 動作成功
RX PF6, TX PF7 -> 動作成功

全ての組み合わせを試してはいませんが、UART7のRXとTXの役割が割り当てられていれば、どのピンの組み合わせでも動きそうでした。

終わり

開発ボードのデータシートを見ただけではUSART2とUSART6とのピンしか分からず戸惑いましたが、マイコンSTM32F767ZIのデータシートを見ると残りのUSARTとUARTのピンの割当が分かり、stm32arduinoで期待通りに動くと分かりました。

参考

マイコンSTM32F767ZIの紹介ページ
マイコンSTM32F767ZIのデータシート(PDF)
開発ボード(STM32 Nucleo-144 boards (MB11)のデータシート(PDF)
stm32arduino

0 件のコメント :