はじめに...
第6回は、生成したコードを make してバイナリファイルを作成し、それを対象ハードウェアボードへ書き込んで、L チカを試みます。第5回で作成したモデル blink を引き続き使用します。
生成コードのビルド
前回、モデル コンフィギュレーション パラメータ設定において、[コード生成] ペイン ⇨ [ビルドプロセス] カテゴリの [コード生成のみ] パラメータにチェックを付けて、コードを生成するに止めましたが、実は既にこの段階でビルドを行える状況にありました。
これを確認します。
cd('z:\qiita\model');
open_system('blink');
set_param('blink','GenCodeOnly','off');
save_system('blink');
rmdir('blink_mytarget_ert','s');
rmdir('slprj','s');
slbuild('blink')
[コード生成のみ] パラメータのチェックを外してモデルを保存し、model フォルダ下のビルドフォルダ 「blink_mytarget_ert」と「slprj」を削除したのちにビルドします。
次は表示されたビルドメッセージの例です。
...
### Creating blink.hex
c:/ArduinoIDE/arduino-1.8.19/hardware/tools/avr/bin/avr-objcopy -O ihex -R .eeprom blink.elf blink.hex
### Created blink.hex ###
### Project size
text data bss dec hex filename
1050 4 15 1069 42d blink.elf
### Created blink.hex successfully (or it was already up to date)
### ビルド プロセスが正常に完了: blink
...
バイナリファイル blink.hex は、ビルドフォルダ blink_mytarget_ert 下に作られます。
mytarget_after_make.m
after_make フックポイントで呼び出す、バイナリファイル書き込み処理を記述した関数 m ファイルです。ファイル名は任意で、Target フォルダ (mytarget¥mytarget) へ置きます。
まずは mytarget_after_make() の全体構成です。
function mytarget_after_make(modelName)
{ボードパラメータ設定}
{書き込み確認}
{対象ハードウェア探索}
{書き込み実行}
{ボードをリセット}
end
function comport = searchTargetBoard()
...
end
function resetArduino(comport,baudrate)
...
end
ボードパラメータ設定
mcu = 'atmega328p';
baudrate = 115200;
protocol = 'arduino';
modelName = char(modelName);
対象ハードウェアのボードパラメータを設定します。これらの値は Arduino IDE で用意されている boards.txt ファイルからの転記です。
1.8.19 の場合、boards.txt ファイルのパスは arduino-1.8.19\hardware\arduino\avr\boards.txt です。
modelName は、ファイル下方で角括弧の文字連結を行うため、文字ベクトルへ変換しています。
書き込み確認
if ~ strcmp(get_param(modelName,'DownloadToArduino'),'on')
fprintf('DownloadToArduino が OFF です。\n');
return;
end
get_param() でコンフィギュレーションパラメータ設定 [Download To Arduino] の値を取得し、チェックが付いていなければ、メッセージを表示して処理を終えます。
対象ハードウェア探索
comport = searchTargetBoard();
if isempty(comport)
warning('RTW:mytarget:noBoardSpecification', ...
['Arduino Uno が見つかりません。' newline, ...
'##### 書き込みを中止します。']);
return;
end
fprintf('\n次の Arduino Uno が見つかりました。\n');
fprintf("COMポート: %s\n", comport);
[Download To Arduino] にチェックが付いていれば、searchComPort() で対象ハードウェアを探します。searchComPort() は後述します。
対象ハードウェアが見つかれば、COMポート番号を表す「COM4」のような文字列が、そうでなければ空文字が comport に入ります。
comport が空文字の場合、メッセージを出力して処理を中止します。
書き込み実行
hexDir = RTW.GetBuildDir(bdroot).BuildDirectory;
hexFile = strrep(fullfile(hexDir, [modelName '.hex']),'\','/');
バイナリファイル (blink.hex) のパスを設定します。
avrPath = 'c:\ArduinoIDE\arduino-1.8.19\hardware\tools\avr';
avrdude = fullfile(avrPath,'bin','avrdude.exe');
avrdudeConf = strrep(fullfile(avrPath,'etc','avrdude.conf'),'\','/');
avrdude ユーティリティと、avrdude.conf ファイルのパスを設定します。
cmd = sprintf( ...
'%s -C%s -v -p%s -c%s -P%s -b%u -D -Uflash:w:%s:i', ...
avrdude, avrdudeConf, mcu, protocol, comport, baudrate, hexFile);
fprintf("\n%s\n", cmd);
status = system(cmd,'-echo');
if (status ~= 0)
error('RTW:mytarget:downloadFailed', '書き込みに失敗しました。シリアル接続を確認してください。');
end
コマンドプロンプトへ渡すコマンド文字列を作成します。
MATLAB コマンドウィンドウで avrdude の出力メッセージを表示するよう「-echo」オプションを付けて実行します。
ボードをリセット
resetArduino(comport,baudrate);
対象ハードウェアをリセットします。resetArduino() は後述します。
searchTargetBoard()
まずは処理の全体です。
function comport = searchTargetBoard()
board = 'uno';
if ispc
cmd = 'chcp 437&pnputil /enum-devices /connected /class Ports';
[~,str] = system(cmd);
patt = 'Device Description: *Arduino ([0-9A-Za-z ]+?) \(COM(\d+)\)';
deviceInfo = regexpi(str,patt,'tokens');
comport = '';
for ii = 1:numel(deviceInfo)
if strcmpi(deviceInfo{ii}{1,1},board)
comport = deviceInfo{ii}{1,2};
break;
end
end
end
end
COM ポート情報の取得
cmd = 'chcp 437&pnputil /enum-devices /connected /class Ports';
[~,str] = system(cmd);
USB 接続済み COM ポートの情報を PnPUtil コマンドで取得します。
「/enum-devices」は Windows 10 バージョン 1607以降で利用できるオプションです。
str には次のような値が入ります。
Instance ID: USB\VID_2341&PID_0043\...
Device Description: Arduino Uno (COM5)
Class Name: Ports
Class GUID: {4d36e978-... }
Manufacturer Name: Arduino LLC (www.arduino.cc)
Status: Started
Driver Name: oem92.inf
Instance ID: USB\VID_2A03&PID_0042\...
Device Description: Arduino Mega 2560 (COM4)
Class Name: Ports
Class GUID: {4d36e978-... }
Manufacturer Name: Arduino Srl (www.arduino.org)
Status: Started
Driver Name: oem225.inf
(※) str はコマンドウィンドウ上でこのように表示されますが、実体は1行 n 列の文字ベクトルです。次に述べる deviceInfo が cell 「行」配列となるのはこのためです。
ボード名とポート番号のペアを作る
patt = 'Device Description: *Arduino ([0-9A-Za-z ]+?) \((COM\d+)\)';
deviceInfo = regexpi(str,patt,'tokens');
「Device Description:」に続く「Arduino」を除いたボード名とポート番号をペアにして deviceInfo へセットします。
deviceInfo は cell 配列で、上の例では次となります。
>> deviceInfo
deviceInfo =
1×2 の cell 配列
{1×2 cell} {1×2 cell}
>> deviceInfo{1}
ans =
1×2 の cell 配列
{'Uno'} {'COM5'}
>> deviceInfo{2}
ans =
1×2 の cell 配列
{'Mega 2560'} {'COM4'}
ボード名と一致するポート番号を取得
comport = '';
for ii = 1:numel(deviceInfo)
if strcmpi(deviceInfo{ii}{1,1},board)
comport = deviceInfo{ii}{1,2};
break;
end
end
ボード名が「uno」と一致する COM ポート番号を comport へ設定します。
resetArduino()
function resetArduino(port, baudrate)
s = serialport(port,baudrate);
pause(0.25);
delete(s);
clear s;
end
ソフトウェアリセットです。詳細は「Arduino UNO Rev3 with Long Pins」の「Automatic (Software) Reset」をご覧ください。
mytarget_make_rtw_hook.m
作成した mytarget_after_make() を、after_make フックポイントで呼び出すように mytarget_make_rtw_hook.mを編集します。
function mytarget_make_rtw_hook( ... )
...
switch hookMethod
...
case 'after_tlc'
mytarget_after_make(modelName);
case 'exit'
...
end % case
end % function
...
L チカ
対象ハードウェア (Arduino Uno Rev3) をPCとつなぎ、モデル コンフィギュレーションパラメータ設定の以下を確認して、ビルドします。
- [コード生成] ペイン
[ビルドプロセス] カテゴリの [コード生成のみ]:チェックなし
- [コード生成] ⇨ [My Target HW options] ペイン
[Download to board]:チェックあり
次はこちらで表示された、after_make フック処理ビルドメッセージの抜粋です。
次の Arduino Uno が見つかりました。
COMポート: COM5
"c:\ArduinoIDE\arduino-1.8.19\hardware\tools\avr\bin\avrdude.exe" -Cc:/ArduinoIDE/arduino-1.8.19/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -carduino -PCOM5 -b115200 -D -Uflash:w:Z:/qiita/model/blink_mytarget_ert/blink.hex:i
avrdude.exe: Version 6.3-20190619
...
Writing | ################################################## | 100% 0.21s
avrdude.exe: 1054 bytes of flash written
avrdude.exe: verifying flash memory against Z:/qiita/model/blink_mytarget_ert/blink.hex:
avrdude.exe: load data flash data from input file Z:/qiita/model/blink_mytarget_ert/blink.hex:
avrdude.exe: input file Z:/qiita/model/blink_mytarget_ert/blink.hex contains 1054 bytes
avrdude.exe: reading on-chip flash data:
Reading | ################################################## | 100% 0.15s
avrdude.exe: verifying ...
avrdude.exe: 1054 bytes of flash verified
avrdude.exe done. Thank you.
書き込みに成功すれば、このようなメッセージが表示されて、LED が点滅します。
本 blink モデルでは、Repeating Sequence Stair ブロックパラメータの [サンプル時間] を「-1」としているため、モデル コンフィギュレーションパラメータ [ソルバー] ペイン [固定ステップ サイズ (基本サンプル時間)] で指定した値が点滅時間になります。
終わりに...
以上で本連載を終了します。最後までお読みくださり、ありがとうございました。
対象ハードウェアを固定したり、ボード固有のパラメータをファイル内に直書きしたりして、保守性や柔軟性を欠いたものではありますが、ひとます、カスタムラピッドプロトタイピング環境の完成です。
いつものように登場したファイル (今回登場したファイルは薄黄色) とその格納先フォルダを示して、連載の締めくくりとします。

