Simulink&Nucleo-L432KCで7セグメントLEDを動かす

mbedが2026年7月にサービスを終了するとアナウンスがあってから半年、未だにNucleoの動作環境構築に悩んでいました。
CubeIDEで開発をしてもいいのですが、せっかく大学ライセンスでMATLAB/Simulinkが使えるならぱ、ライブラリもあるしそっちで構築してみようというのが始まり

今回は、SimulinkからNucleo-L432KCを用いて4桁7セグメントLEDを動かすことを目標にしています（+おまけでCAN受信も行います）
Simulink使わなければ楽に作れますが、敢えてのチャレンジです。

## 対象者
* マイコンをそれなりに触ってきた
* Simulinkで効率的にSTM32開発を行いたい
* MATLAB/Simulink触れたことがある

## 準備するもの
* [STM32 Nucleo Board STM32L432KC](https://www.st.com/ja/microcontrollers-microprocessors/stm32l432kc.html)
* MATLAB/Simulinkアドオン
[Embedded Coder Support Package for STMicroelectronics STM32 Processors](https://jp.mathworks.com/matlabcentral/fileexchange/43093-embedded-coder-support-package-for-stmicroelectronics-stm32-processors)
* PC接続用のUSB端子
* 電子工作用品一式（ブレットボード、安定化電源、ジャンパーワイヤー等）
* [74HC595](https://akizukidenshi.com/catalog/g/g114053/) 8bitシフトレジスタ
* 5641AS 4桁7セグメントLED（何かのスターターキットに入っていた商品、GND共通のカソードコモンタイプ）

### 動作環境
* Windows 11 Education 23H2
* MATLAB 2024a
* Simulink バージョン24.1


## 初期設定
アドオンである、Embedded Coder Support Package for STMicroelectronics STM32 Processors は日本語文献が少なく苦労します。それほど上級者向けまたは需要が無いということなのでしょうか...
mathworks社のヘルプページを以下に掲載します。

https://jp.mathworks.com/help/ecoder/stm32-spkg.html

### インストール手順
①インストール
MATLABホームのアドオンエクスプローラーからインストールが完了すると「アドオンの管理」に以下の写真のような行が追加されます。赤い四角で囲った設定マークをクリックして詳細設定を開始します。
![スクリーンショット 2025-02-03 115016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/ae590383-7c77-2731-b2cd-6cbf0c80ecb7.png)

②使用マイコン設定
設定画面では使用するマイコンにチェックマークを入れてください。今回はL432KCのため、「STM32L4xx Based MCU」にチェックを入れてください。将来的に他のマイコンを使用する場合はそれに合わせてください。後で追加することも可能です。
![スクリーンショット 2025-02-03 115613.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/04e81773-05f5-c955-69fd-4bb600704923.png)
次に必要なソフトをインストールします。
ウィンドウに表示されている Download リンクからOSに対応した製品をインストールしてください。その際、 **Versionに記載されたのと一致** させるようにしてください。後で認識しない原因となります。（My STアカウント必須）
![スクリーンショット 2025-02-03 120000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/397b3b68-c189-2eae-8001-7628c1f7c7c6.png)

2製品のインストールが終わったら、正しくインストールされているかのチェックです。基本的にインストール先をデフォルト設定している場合はパスできます。

最後にパッケージのインストールです。Install ボタンを押して気長にお待ちください。ウィンドウ内の**NOTE**にも書いていますが、STM32CubeMXのポップアップ画面が隠れて表示されていることもあります。許可を出さないとインストールが進まないため放置することは推奨しません。
![スクリーンショット 2025-02-03 120547.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/39959c06-bdc3-def0-0dc8-ec89ec5b9c51.png)

③チェック
* STM32CubeMXが起動できるか
* Simulinkのライブラリブラウザーを開いたときにアドオンが表示されているか

この2点を確認してください。インストール終了です！

## 配線
* 74HC595の説明はカットします。[この](https://iot.keicode.com/arduino/arduino-shift-register-sn74hc595.php)サイトは参考になりました
* 今回は作りたいものが3桁までのため3桁目までしか使いません。ドットも表示しません。将来的な機能追加のため

配線図は以下の通りです。ブレットボード上に展開してください。NucleoのPA4はそのままマイコンのA4ピンに接続されているわけではないので、[データシート](https://www.st.com/resource/en/user_manual/um1956-stm32-nucleo32-boards-mb1180-stmicroelectronics.pdf)のP29を参考にしてください。
![スクリーンショット 2025-02-04 105816.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/0c37ab47-0334-d4fe-e7af-1dc8a8ba498e.png)
![スクリーンショット 2025-02-05 092057.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/1884dfe5-68da-ace6-cc28-b1a1b691d7bf.png)
NMOSにプルダウン抵抗（G-S間抵抗）は？と私も思いましたが、GPIOの設定でプッシュプル型にしているため不要なのかもしれません。オープンドレインなら必要なはず。ゲート抵抗は抵抗値が高いとスイッチングに影響が出ますが今回は440Ωでもスイッチングの遅れは感じませんでした。
74HC595とLEDの間は適切な抵抗を入れてください。今回は440Ωを入れています。
これを見たらわかるようにSPI通信を使用してデータ転送を行います。

## モデル作成
必要な機能は
* 数値データを各桁に分解
* 各桁ごとにデータ送信
* 桁の切り替え

です。
これを見たらわかるように、順序が大事なプログラムですが、Simulinkで実行順序を正確に構築することは多少難しく感じています。そのため今回は[Stateflow](https://jp.mathworks.com/products/stateflow.html)を使用して順序を構築しました。優先順位機能を使ってもよいのですが、視覚的に分かりやすいので採用します。
Simulinkモデルは以下です。

![スクリーンショット 2025-02-04 115350.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/9238b910-efe4-7a91-3ca0-5fa32cba9270.png)

### 桁分解サブシステム
![スクリーンショット 2025-02-04 115507.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/4d1f5718-3e59-5bbe-5b04-0a0813dbe0b0.png)

数値データがdouble型で入ってくることを想定しています。直後にData Type Conversionブロックでuint16に変換しています。出力は3要素の配列です。

### 桁処理&送信 stateflow
1桁ずつ同じ処理を繰り返しています。4桁の場合はもうひとつ増やすだけ
モデル全体のステップ時間が0.001秒なので、`after(1,msec)`は指定するだけ無駄ですが念のため設定しました。
![スクリーンショット 2025-02-05 091426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/fcc0b933-6459-937e-40e6-a959228cbde9.png)

#### digittransferモデル
データを送信する場所です。
![スクリーンショット 2025-02-05 091555.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/b4d64836-4249-984f-34e2-6408f49359f2.png)
桁の数値から送信データを作るMatlab FunctionとSPI送信ブロックで構成されています。

SPI Controller Transferブロックの設定は
![スクリーンショット 2025-02-04 114803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/f90fbd22-292f-e33f-b91d-0d106b0ae1b4.png)
![スクリーンショット 2025-02-04 114812.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/533355a2-52e7-4645-8c58-cc69f71694e9.png)
このようにしました。CubeMXの設定と合わせてください。
Rxは不要なので無効化します。送信専用ブロックでもいけるのかな？

モデル内のmatlab functionは以下です。
```matlab
function output = fcn(u, data)

y = u(1);
output = data(y+1);
```
引数`u`には、桁分解サブシステムの出力が、引数`data`には`Numpatterndata`とあります。ベースワークスペースに定義され、中身はこのような配列になっています。送信する数字に対応しています。
![スクリーンショット 2025-02-04 115024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/cd2161bc-369a-52bb-7113-abd165e0fae7.png)

このfunctionの出力は`output`で1桁分の送信データが入っています。
注意点として、`y=u(1)`は3桁目であるからで、2桁目の場合は`y=u(2)`としてください。これは桁分解サブシステムのoutputが3要素であるからです。

#### Digiton/off モデル
桁を選択するために後ろのN-chMOSFET駆動信号を送信します。
Onの場合はConstantブロックで1を、Offは0を送信するだけです。
ポートの設定を適宜変更してください。
![スクリーンショット 2025-02-05 091215.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/097537e8-a4d2-ef70-9f5d-53b9fa335a4e.png)

## CubeMXの設定
ここからの設定に関しては[公式ヘルプ](https://jp.mathworks.com/help/ecoder/stmicroelectronicsstm32f4discovery/ug/Getting-started-stm32cubemx.html)にも基本的事項は掲載してありますので参考に。

設定が終わるとピンの設定はこうなります。

![スクリーンショット 2025-02-04 204957.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/4136dae4-7216-bcd4-a06a-094c748901d5.png)

`File -> New Project -> Board selector`でNUCLEO-L432KCを選択し、プロジェクトを作成します。
左欄`Connectivity->SPI1`をFull-Duplex Master で有効化します。SPI通信のボーレートはLED表示の安定性に関連してくるためPrescalerを調整して遅めに設定しても問題ありません。
digit1~3とSPI1_CSはGPIO_Outputです。
Simulinkのエクスターナルモードでテストを行うため、USARTのDMA設定もしておきます。初期設定がUSART2だったのでそちらを使用。1でもいいと思われる。
![スクリーンショット 2025-02-04 210614.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/cd19f083-17b2-610e-e2e0-b65021906165.png)


ピンの設定が終わったら、`Project Manager -> Project`に進み以下の設定を行います
* Do not generate the main() を有効化する

`Project Manager -> Advanced Settings`に進み以下の設定を行います
* 使用する機能をHALからLLに選択する
* Do Not Generate Function Calls のチェックを全て外す
* Visibility (Static)のチェックを全て外す

後程Simulinkのエクスターナルモード実行時にエラーが起きないように、MX_DMA_Initの順番は、MX_USART_UART_Initの前に並び変えておいてください。詳細は[ここ](https://jp.mathworks.com/matlabcentral/answers/2048172-why-am-i-receiving-an-xcp-timeout-error-when-starting-external-mode-on-an-stm32-board-using-the-emb)

![スクリーンショット 2025-02-04 205831.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/587c2d59-fec8-aa33-e6a5-4a5459316cc9.png)

これで準備はできました。Simulinkのコンパイル時にCubeMXの設定エラーは丁寧に表示してくれるため、迷宮入りすることはありません。Simulinkサンキュー

## さあ実行
単体で実行してもデータの元がないため、Simulinkのエクスターナルモードを使用して、PC上で値を変化させながらテストを行います
![スクリーンショット 2025-02-04 214743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/d53e081b-bbeb-ac6f-ce45-c3ffa8aa505d.png)
モデルではConstantブロックにknobを紐づけています。実行中にknobを動かすことでConstantブロックの値が変化し、送信される数値も変わる仕組みです。
ソルバーは固定ステップ0.001秒刻みに設定しました。

NucleoをPCにつなぎ、ハードウェア設定からCOMポートの設定を間違いなく行い、
![スクリーンショット 2025-02-04 214329.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/cd289ba7-f538-e62b-58e4-137cd17fb09b.png)
「監視と調整」ボタンから実行できます。
きれいに表示できましたでしょうか？？

私の環境ではSPI通信速度を30Mbpsに設定するとダイナミック表示が上手くできませんでした。そこで7.5Mbpsに落とすときれいに表示されました。ちらつく場合はそういった設定も必要かもしれません。

スタンドアロンで実行する際は右の「ビルド」ボタンからコンパイルを行うと.binファイルが出力されます。

## （おまけ）CAN通信もやってみる
データの入力元をほかのマイコンからのCANにしてみます。
CANの受信には、CAN Readブロックと CAN Unpack ブロックを使用します。
![スクリーンショット 2025-02-05 085549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/ac3c226b-ffbc-9061-4fa1-61ac27a1ed30.png)
CAN Readだけでも構成はできますが、後処理が複雑になるため、CANメッセージとして出力し、Unpackブロックで指定したdbcファイルを基に、信号ごとに抽出しています。
dbcファイルが用意できない場合はID、ビット数などをUnpackブロックに指定することも可能です。

CubeMXでのCAN設定には以下の記事を参考にしました。

https://qiita.com/sirayuri/items/b905330c8ad5358e7bdd

ボーレートを500kbpsにするため、Configurationは写真のように設定しました。割り込み設定は不要です。
![スクリーンショット 2025-02-05 090225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687134/5e2769cd-569b-e4dc-73b6-4016146fabb2.png)
CANトランシーバーは前述記事と同様にMCP2561で構成することができます。
CANの送信側は適当にご用意ください。

## まとめ
STM32 NucleoをSimulinkから動かし、7セグメントLEDを光らせる手順を紹介しました。
Simulinkの利点であるシミュレーションを活かして、MBDなどに役立ててもらえればと思います。

## 参考文献（再掲）
* STM32L432KC

https://www.st.com/ja/microcontrollers-microprocessors/stm32l432kc.html

* Embedded Coder Support Package for STMicroelectronics STM32 Processors

https://jp.mathworks.com/matlabcentral/fileexchange/43093-embedded-coder-support-package-for-stmicroelectronics-stm32-processors

* 74HC595 秋月電子

https://akizukidenshi.com/catalog/g/g114053/

* CANdb

https://www.vector.com/jp/ja/products/products-a-z/software/candb/#c151321

* CubeMXでのCAN設定

https://qiita.com/sirayuri/items/b905330c8ad5358e7bdd