おもちゃラボ

Unityで遊びを作ってます

【Arduino】アセンブラ入門 その1

ArduinoはAVR(ATMega328)というマイコンの外側にIO用の電子回路をくっつけただけの構造なので、もちろんAVRの文法に従ってアセンブラでプログラムを書くことが出来ます。

このご時世アセンブラて!と思わないこともないですが、ディスプレイのドライバだったりネットワークのパケット処理だったり、結構速度を求められる場面では役に立つことがあります。

普通にC言語で書く場合と比べると10倍以上の速度の差が出ることもざらにあるので、覚えておいて損はないですよ〜

今回の記事の内容は次のとおりです。

まずは何もしないアセンブラを書いてみよう

アセンブラでプログラムを書く、といっても何もプログラムのすべてをアセンブラにする必要はありません。遅い所だけを狙って、その処理だけをアセンブラで書く。プログラムを高速化する時の鉄則ですね〜。

このように、プログラムの一部だけをアセンブラにすることをインラインアセンブラと呼びます。この記事では基本的にインラインアセンブラの書き方を紹介しています。

まずは、アセンブリ言語版ハローワールド(?)の何もしない命令を書いてみましょう。次のプログラムを書いてください。

void setup()
{
	asm( "nop \n" );
}

これだけ?と思ったかもしれませんね。はい、なんとコレだけです(笑)インラインでアセンブラを書くにはasmの()の中にアセンブラで文字列としてプログラムを書くだけです。

nopはNo Operationの略で「何もしない命令」です。実行しても何も起こりませんが、ちゃんとコンパイルも通ってプログラムも実行できている、ということが大切です。

変数?いやレジスタを使ってみよう

アセンブラのプログラムが思いのほか簡単にかけることがわかったところで、つぎは変数を使ってみましょう。といっても、アセンブラに変数という概念はなくて、ハードウエアとして実装されている「レジスタ」に値を入れたり、取り出したりして使うことになります。

次のプログラムを入力してみてください。実はかなりお行儀が悪いプログラムなのですが、それは次のお話・・・ということで(笑)

volatile byte a=0;

void setup() {
  Serial.begin(9600);
 
  asm (
    "ldi r23, 37  \n"
    "sts (a), r23 \n"
  );
 
  Serial.print("a = "); Serial.println(a);
}

ここでは37という数値を23番レジスタに格納し、それを変数aに代入しています。なんとなく、雰囲気で分かっちゃいますね(といって説明を省こうとする布石だったりする)。

Arduinoには次の3種類のメモリが用意されています。

  • EEPROM
  • SRAM
  • フラッシュメモリ

1つ目はEEPROM、電源を切ってもデータが消えないメモリです。2つ目がSRAMで、データや一時変数などの値が置かれるメモリになります。3つ目がフラッシュメモリ、これはArduinoで作ったプログラムを置く所ですね。

上で書いたレジスタはSRAMの一部として実装されています。Arduinoには32個のレジスタ(r0〜r31)があり、それぞれ8bitの値を格納することが出来ます。

f:id:nn_hokuson:20170911231349j:plain

上のプログラムではLDI命令(Load Immediate)を使っています。LDIは定数をレジスタに格納する命令です。ここでは37という定数を、23番レジスタに格納しています。LDI命令で指定できるレジスタはr16〜r31までなので注意してください。

アセンブラの2行目ではSTS命令(Store direct to data Space)を使っています。STS命令はレジスタの値をSRAMに置かれている変数に代入する命令です。ここでは23番レジスタに入っている値を変数aに代入しています。

まとめると、アセンブラを実行すると

  1. 37という値が23番レジスタに格納され
  2. 23番レジスタの値が変数aに代入されます

したがって、最後にシリアルコンソールに表示される値は37になります。

37

今回、変数aはグローバル変数として宣言しました。これは変数の値をSRAM内に置くためです。もしローカル変数としてsetup関数の中で宣言すると、SRAMには置かれない(stackに配置される)ため、STS命令でエラーが出てしまいます。

Clobber(クラバー)を使って安全にレジスタを使おう

先程のプログラムでは、37という値を格納するレジスタを「えいや」で23番レジスタと決めました。もし、運悪くこの23番レジスタが使われていた場合は、そこにあった数値は37で上書きされて消えてしまいます。

このようなレジスタのバッティングを防ぐため、Clobberという構文があります。Clobberで使用するレジスタを宣言しておくと、コンパイラに「このレジスタは使わないでね〜」と伝えることが出来ます。

クローバの書き方が少し特殊で次のようになります。

volatile byte a=0;

void setup() {
  Serial.begin(9600);
 
  asm (
    "ldi r23, 37  \n"
    "sts (a), r23 \n"
    :::"r23"
  );
 
  Serial.print("a = "); Serial.println(a);
}

コロン3つに続けて、使用するレジスタの名前を文字列として記述します。ここでは23番レジスタを使うので"r23"と書いています。

コロン3つってなんやねん、となりますよね?。私もなりました。このあたりで一般的なインラインアセンブラの書き方を紹介しておきます。インラインアセンブラは次の4つのパートから成り立っています。

asm (
  "プログラム"
  "プログラム"
  ・・・・・
  :"出力":"入力":"Clobber"
);

プログラムのパートはこれまで書いてきたアセンブラプログラムになります。「出力」と「入力」のパートは後ほど説明しますが、簡単に言うと「インラインアセンブラに入力する値のリストと出力する値を書く場所」になります(そのままだ・・・)。入出力のレジスタ宣言に続けて、最後にClobberを書きます。

上の例では出力と入力のパートに何も記述していないので「:::"r23"」という不思議な書き方になってしまっているのです。

不思議な書き方ですが、このように書くことで23番レジスタは自分のプログラムで使うと宣言し、安全にプログラムを実行することが出来ます。

2つの値をスワップしよう

最後に今回のまとめとして2つの値をスワップするプログラムを作ってみましょう。C言語で普通に書くと次のようなプログラムになります。

volatile byte a = 73;
volatile byte b = 41;
 
void setup() {
  Serial.begin(9600);
 
  byte tmp c;
  c = a;
  a = b;
  b = c;
     
  Serial.println(a);
  Serial.println(b);
}

一時変数cを使って値を入れ替えているだけです。なんというか、めっちゃオーソドックス、普通中の普通のプログラムですね。

実行すると次のように変数aと変数bの値が入れ替わって表示されます。

41
73

これをインラインアセンブラで書き換えてみましょう。

volatile byte a = 73;
volatile byte b = 41;
 
void setup() {
  Serial.begin(9600);
 
  asm (
    "lds r17, (a) \n"
    "lds r19, (b) \n"
    "sts (b), r17 \n"
    "sts (a), r19 \n"
    : : : "r17", "r19"
  );
 
  Serial.println(a);
  Serial.println(b);
}

このプログラムでは、まず変数の値をレジスタに格納するためにLDS命令を使っています。LDS命令はLoad Direct from data spaceの略で、SRAMに置かれたデータをレジスタに読み込みます。LDI命令(値をレジスタに読み込む)とは異なるので注意してください。

  • LDI命令:数値をレジスタに読み込む
  • LDS命令:変数の値をレジスタに読み込む

aと変数bの値を17番と19番のレジスタに格納してから,STS命令を使ってレジスタの値を変数に書き戻しています。

このプログラムでは17番レジスタと19番レジスタを使っているので、クローバには"r17"と"r19"を指定しています。このように複数のレジスタを使う場合には「,」で区切ってレジスタ番号を書きます。

まとめ

今回はインラインアセンブラの書き方やレジスタの役割、レジスタに値を格納する方法、クローバの意味などを説明しました。次回はインラインアセンブラへの入出力について説明していきます。

[asin:B00E1EA6XM:detail]

【Unity】iOSにアプリをインストールするときのエラー対処法

UnityでXcodeのプロジェクトを書き出して、いざiPhoneにインストールしようとすると、ビルドまではうまくいったのに転送の段階で次のようなエラーが出ることがあります。

Could not launch "アプリ名"
Verify the Developer App certificate for your account is trusted on your device.

f:id:nn_hokuson:20170906200436p:plain

これは、無料のApple Developper IDを使っている場合に出るエラーで、インストールしたアプリをiPhone側で認証する必要があります。

iPhone/iPadの端末から「設定アプリ」を起動し、「一般」→「デバイス管理」をタップして下さい(iOSのバージョンによっては「プロファイルとデバイス管理」になっている可能性があります)

f:id:nn_hokuson:20170906201152j:plain:w550

続いて、お使いのApple IDを選択し、「"Apple ID"を信頼」を選択します。最後に、アラートビューの「信頼」をタップして設定完了です。

f:id:nn_hokuson:20170906202141j:plain

詳しくはアップルのサイトでも解説されていますので、参考にしてみて下さい。

support.apple.com

【Unity2021対応】Androidビルドでエラーが出る場合の対処法

UnityでAndroidビルドした場合、さまざまなエラーに出くわすことになると思います。ここでは、Androidビルド時に出る各エラーについてその対処法をまとめています。

Unable to list target platformsのエラー

Unity側でAndroidSDKのパスは正しく設定されているのに次のようなエラーが出ることがあります。

Unable to list target platforms. Please make sure the android sdk path is correct. See the Console for more details. See the Console for details.

f:id:nn_hokuson:20180503102242p:plain:w400

これは、UnityがAndroid Studioのバージョンに対応できていない場合に出るエラーです。次の手順でAndroidの中のtoolsフォルダを更新するとビルドできるようになりました。

toolsフォルダを確認する

上のようなエラーが出た場合は、/Users/ユーザ名/Library/Android/sdkフォルダの中にあるのtoolsフォルダの中身を確認してみて下さい。

toolsフォルダにはFinderのメニューバーから「移動」→「フォルダへ移動」を選択し、「フォルダの場所を入力」の欄に上記のパスを入力して下さい。

f:id:nn_hokuson:20170905200204p:plain:w320

toolsフォルダの中身が左図のような状態にだとエラーが出るようです。右図のような場合にはエラーは出ません。
f:id:nn_hokuson:20170905201148j:plain:w480

toolsフォルダを更新する

下記のURLより少し古いtoolsフォルダをダウンロードし、現在のtoolsフォルダと置換してみて下さい(心配な方はバックアップを取っておいて下さい)

http://dl.google.com/android/repository/tools_r22.0.5-macosx.zip

再度AndroidでビルドすればUnityEditor.BuildPlayerWindow+BuildMethodExceptionのエラーは出ずに、正しくビルドできるようになるはずです。エラーが出てうまくいかない!という方は一度試してみて下さい!

それでもエラーが出る場合

Android SDK自体が古い可能性があります。Android Studioを普通にインストールしただけではAndroid SDKが更新されないことがあるようです。

その場合は「/Users/ユーザ名/Library/Android」フォルダ以下を全て消去した上で、Android Studioを起動すると、自動的にAndroid SDKの更新が始まります。

上記の手順で最新のAndroid SDKを入れた上で、再度toolsフォルダのみ更新してみて下さい。

Gradle build failedが出る

Unityのプロジェクトがあるパスに日本語が含まれていた場合、Gradle build failedのエラーが出ることがあります。プロジェクト名や、上位のフォルダ名などに日本語が含まれていないことを確認してください。

Gradle build failedが出る(Unity2019から)

Unity2019からはBuild Settingsの項目から「Build System」が削除されました。
したがって、Unity2019からは上記の方法では問題を修正できません。

Build Settingsに「Export Project」という項目があるため
これにチェックを入れてプロジェクトをAndroid Studio用にExportして下さい。

f:id:nn_hokuson:20191018212425p:plain:w300

ExportしたプロジェクトをAndroid Studioで読み込むと
Gradleをアップグレードしますか?という画面が出てくるので
OKを押して、Gradleをアップグレードします。

その後、Unityを再起動し、BUild Settingsの「Export Project」のチェックを外してから
普通にビルドすると、正しくビルドできます。

Gradle build failedが出る(Unity2018まで)

Unity2017.3.1以降を使っている場合、次のようなエラーが出ることがあります。

f:id:nn_hokuson:20180503133229p:plain:w350

CommandInvokationFailure: Gradle build failed.
/Library/Java/JavaVirtualMachines/jdk1.8.0_141.jdk/Contents/Home/bin/java -classpath "/Applications/Unity/PlaybackEngines/AndroidPlayer/Tools/gradle/lib/gradle-launcher-4.0.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx2048m" "assembleRelease"

Unity2017.3からはBuild SystemとしてGradleが標準になったのですが、これが原因でビルドに失敗することがあるようです。

ビルドシステムをもとに戻すためにはメニューバーからFile→Build Settingsを選択し、Build Systemの項目をInternalに設定して下さい。

f:id:nn_hokuson:20180503133358p:plain:w400

ビルド中にSelect Android SDK root Folderが出る

Select Android SDK root Folderが出た場合は、Macであれば「/Users/ユーザ名/Library/Android/sdk」、WIndowsであれば「C:\Users\ユーザ名\AppData\ Local\Android\sdk\」を選択してOKボタンを押して下さい。

Android SDK is outdatedというエラーが出る

インストールされているAndroid SDKのバージョンが、Unityで指定したSDKバージョンよりも低い場合に出るエラーです。とりあえず動かしたい場合は「Use Highest Installed」を選択すれば大丈夫です。

f:id:nn_hokuson:20180503102917p:plain:w450

実機転送する時にエラーが出る

Android携帯をPCに接続しているにも関わらず、「No Android Device Found!」や「Couldn't find Android device」など、Androidデバイスが見つかりません系のエラーが出ることがあります。

Make sure USB debugging has been enabled
Check your device, in most cases there should be a small icon in the status bar telling you if the USB connection is up.
If you are sure that device is attached then it might be USB driver problem, for details please check Android SDK Setup section in Unity manual.

f:id:nn_hokuson:20170314194612p:plain
f:id:nn_hokuson:20170314194618p:plain

Android開発者向けオプションをオンにする

開発者向けオプションをオンにするためには、「設定」 →「端末情報」を開き、「ビルド番号」 を 7 回タップして下さい。
「デベロッパになりました」という文章が出てきたら、設定画面に戻り端末情報の上に開発者向けオプションが表示されていることを確認してください。

開発者向けオプションをタップして

  • 開発者向けオプションがONになっていること
  • USBデバッグにチェックが入っていること

を確認して下さい。

f:id:nn_hokuson:20170314200239p:plain

ドライバを最新にする

お使いのAndroidデバイスの最新ドライバをインストールしてPCを再起動して下さい。

USB接続モードを確認する

Androidアプリをインストールするためには、メディア転送モード(MTP)ではなくファイル転送モード(MSC)である必要があります。
転送モードの変更は「設定」→「Xperia 接続設定(名前は機種により変わります)」→「USB接続設定」→「USB接続モード」で選択できます。

AndroidでPCからのアクセスを許可する

次のようなエラーがアプリ転送時に出る場合は、Androidのロック画面を解除してPCからのアクセスを許可して下さい。
f:id:nn_hokuson:20180503133021p:plain:w350

Unable to retrieve device properties. Please make sure the Android SDK is installed and is properly configured in the Editor.

USBデバッグが許可できない

アプリを転送する時に、端末側でBecause an app is obscuring a permission request と表示されて、USBデバッグが許可できないことがあります。

これは、画面上にオーバーレイして表示するアプリ(例えばスクリーンキャプチャなど)が起動していることが原因です。

該当のアプリを終了するか、設定→アプリ→画面左上の詳細設定ボタン(歯車など)→特別なアクセス→ほかのアプリに重ねて表示(フローティング表示するアプリ)をオフにして下さい。

その他の対策

これでも認識されない場合は、次の項目を試して下さい。

  • プロジェクトフォルダのパスに日本語が含まれていないか確かめる
  • USBポートを別のポートに差し替える
  • USBケーブルには通信用と充電用があるので、通信用ケーブルを使用する
  • PCを再起動する