前回、M5StackとArduino Uno間でCANフレームの送受信ができるようになりました。しかしCANは「バス」です。1対1で通信できても物足りませぬ。そこで今回はST MicroelectronicsのSTM32マイコン搭載、Nucleo-F072RBをCANバスに接続してみます。でもね、PHYはMicrochip製MCP2562。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
(送信実験用のC++コード全文は末尾に)
Nucleo-F072RB、STM32搭載のマイコンボード
前回までは、CANインタフェースを持たないマイコンに外付けでCANインタフェースを取り付けておりました。しかし今回は違います。ST Microelectronics社製STM32F072RBT6マイコンには、CANインタフェース機能が搭載されているのであります。なお、このマイコンはSTM32シリーズの中ではちょっと古くて小さい感じだと思うのですが、しっかり量産中でした。
CANインタフェースを搭載ということでCANのプロトコルに関わる処理は「やってくれる」のです。しかし、物理層までは搭載されていません。デジタルな0/1で処理できるTXD/RXDのレベルまで。実際にNucleo-F072RBボードのどこに端子が出ているかを示すためにST社の図を1枚引用させていただきます。図の赤丸のところの端子を取り出して使わせてもらっています。
CANインタフェースは1チャネルのみですが、2か所に出ています。そのうちの右側を選んだのはタマタマです。
MCP2562 CANトランシーバ
さて実際に差動信号で動作しているCANバスに接続するためにはCANトランシーバ(PHY)が必要です。今回使用させていただきましたのは Microchip社製 MCP2562であります。2561と2562が兄弟チップのようですが、今回は2562を購入(秋月通商殿)。これは2562の特徴としてデジタルIO端子への電源が主電源端子と別になっていて便利なためです。なおArduino Uno用のCANインタフェースボードにもMicrochip社製の同系列のデバイス、MCP2551が搭載されていました。
Nucleo-F072RBとMCP2562の接続
接続そのものは簡単で、以下で一応動作いたしました。
実際に接続している様子を以下の写真に掲げました。CANバスに現れるフレームを解読するために例によってCAN解読モードのAnalog Discovery 2も接続しているのでCANのところの配線込み入っています。
とりあえずCANフレーム垂れ流しの送信実験
末尾に掲げたコードは、Arm Mbed OS上で動作する筈のCANのサンプルコードを「勝手改造」してしまったものです。オンラインのMbedコンパイラ環境上で、CANのサンプルプログラムをゲットし、無改造でそのまま走らせてみたのですが、ランタイムエラーが発生してしまいダメでした。そこで「不細工に」大幅改造してしまったものです。これであればCANフレームの垂れ流し動作、一応できています。Analog Discovery 2で解読するとこんな感じ。なお速度は125kHzといたしました。
しかしながら2点問題あり、です。1点目は、ペイロードを1バイト、値としては0~255の循環で載せているつもりなのですが、ペイロードは常に0になってしまっています。要追及。
もう1点は、Mbedオンライン・コンパイラのビルド結果です。Flashメモリはまだ余裕シャキシャキなのですが、RAMはいっぱいいっぱいでした。残り0.2kB。動いたことが僥倖という感じのギリギリ使用量です。もしかすると正式のサンプルプログラムが実行時エラーになってしまう原因かもしれないです。
ビルド構成など変えてどこまでRAMを少なくできるのか?末尾のコードを見ていただくと分かる通り、今現在も「ほとんど何もやってない」プログラムです。メモリ使用量がこのままではCANフレームの垂れ流し以上のコードは載せられない可能性大です。
まあ、もっとRAMに余裕のあるマイコン・ボード使うほうが良いとは思うのです。手元にあるもう一枚のNucleoボード、F401REは上位機種でまだRAMに余裕ありそうなのですが、残念なことにCANインタフェースが無い!
なかなか思ったようにはうまく行きませぬ。まあね、キツキツなところを押したり引いたりするのがマイコン、ですけれども。
鳥なき里のマイコン屋(124) M5StackとUno間、CANフレームのラウンドトリップ へ戻る
鳥なき里のマイコン屋(126) ラズパイPico、遅ればせながらビルド&デバッグ環境整える へ進む
Nucleo-F072RB用 CANフレーム送信実験用コード(Arm Mbed OS)
#include "mbed.h" DigitalOut led1(LED1); CAN can1(PA_11, PA_12, 125000); char counter = 0; int main() { printf("main()\n"); while (1) { can1.write(CANMessage(1337, &counter, 1)); counter++; printf("Message sent: %d\n", counter); led1 = !led1; ThisThread::sleep_for(1000); } }