FPGAマガジン No.13のMAX10特集に掲載していただいた”第1章 MAX10+BLEモジュールでスマホ制御ラジコンを作る!”の関連リストおよび補足です.
記事では,Macnicaから販売されているOdyssey MAX10 FPGA Eval Kitを紹介しています.提供されているOdyssey IoT Solutionsを使って,”簡単な”FPGA+BLEなモバイルアプリケーションを”簡単”に開発できる環境です.FPGAに限らず組み込み関連では,ちょっとした簡単なことをしたいだけなのに準備が大変なことも多いのですが,この環境では手軽に試すことができます.
詳しくは,本文を参照いただければ嬉しいのですが,サンプルと補足はこちらをご覧ください.
“サンプルをベースに開発フローを修得”のサンプル
I2Cで読み出し可能なレジスタを追加してみるテストです.i2c_template(Odyssey Downloadsよりi2c_template.zipをダウンロード)をベースとして,I2C越しでPCと共有するレジスタファイルに相当する registerInterface.v を変更してみました.
変更箇所は次の通りです.
--- registerInterface.v.orig 2016-04-30 20:18:33.033223472 +0900
+++ registerInterface.v 2016-04-30 15:41:57.082962975 +0900
@@ -74,13 +74,20 @@ reg [7:0] reg_led;
reg [7:0] reg_switch;
reg [7:0] reg_button;
+reg [31:0] counter = 32'h0;
+
+always @(posedge clk) begin
+ counter <= counter + 1;
+end
+
// --- I2C Read
always @(posedge clk) begin
case (addr)
8'h00: dataOut <= reg_auto;
8'h01: dataOut <= reg_led;
8'h02: dataOut <= reg_switch;
- 8'h03: dataOut <= reg_button;
+ 8'h03: dataOut <= reg_button;
+ 8'h04: dataOut <= counter[24:17];
default: dataOut <= 8'h00;
endcase
end
変更後のファイルはregisterInterface.v.
“スマホ制御ラジコンを作ろう”のサンプル
タイトルのスマホ制御ラジコンのサンプルです.ADCを使って測距センサの値を読みたかったのでaudio_moitorのサンプル(Odyssey Downloadsよりaudio_monitor.zipをダウンロード)をベースに改変しました.I2C越しでモータ制御用のI/Oを制御できるようにするために,レジスタファイル(registerInterface.v)を変更し,またI/Oをトップまでのパスを作るために,i2cSlave.vとtop.vを変更しています.
変更箇所は次の通りです.
registerInterface.vの変更
--- registerInterface.v.orig 2016-04-30 20:39:35.552689510 +0900
+++ registerInterface.v 2016-04-30 18:06:05.578817848 +0900
@@ -70,7 +70,8 @@ module registerInterface (
reg14_microphone_upper_in,
reg15_microphone_lower_in,
reg16_microphone_max_upper_in,
- reg17_microphone_max_lower_in
+ reg17_microphone_max_lower_in,
+ motor_ctrl_out
);
input clk;
input [7:0] addr;
@@ -95,6 +96,7 @@ input [7:0] reg14_microphone_upper_in;
input [7:0] reg15_microphone_lower_in;
input [7:0] reg16_microphone_max_upper_in;
input [7:0] reg17_microphone_max_lower_in;
+output[7:0] motor_ctrl_out;
reg [7:0] dataOut;
reg [7:0] reg_auto;
@@ -115,6 +117,7 @@ reg [7:0] reg_microphone_upper;
reg [7:0] reg_microphone_lower;
reg [7:0] reg_microphone_max_upper;
reg [7:0] reg_microphone_max_lower;
+reg [7:0] reg_motor_ctrl_out;
// --- I2C Read
@@ -150,6 +153,7 @@ always @(posedge clk) begin
if (writeEn == 1'b1) begin
case (addr)
8'h01: reg_adc_cmd <= dataIn;
+ 8'h04: reg_motor_ctrl_out <= dataIn;
endcase
end
@@ -175,6 +179,7 @@ end
//assign reg1_led_out = reg_led;
assign reg1_adc_cmd_out = reg_adc_cmd;
+assign motor_ctrl_out = reg_motor_ctrl_out;
endmodule
i2cSlave.vの変更
--- i2cSlave.v.orig 2016-04-30 20:39:08.267414890 +0900
+++ i2cSlave.v 2016-04-30 18:49:11.212526054 +0900
@@ -67,7 +67,8 @@ module i2cSlave (
reg14_microphone_upper_in,
reg15_microphone_lower_in,
reg16_microphone_max_upper_in,
- reg17_microphone_max_lower_in
+ reg17_microphone_max_lower_in,
+ motor_ctrl_out
);
input clk;
@@ -92,6 +93,7 @@ input [7:0] reg14_microphone_upper_in;
input [7:0] reg15_microphone_lower_in;
input [7:0] reg16_microphone_max_upper_in;
input [7:0] reg17_microphone_max_lower_in;
+output [7:0] motor_ctrl_out;
// local wires and regs
reg sdaDeb;
@@ -212,7 +214,8 @@ registerInterface u_registerInterface(
.reg14_microphone_upper_in (reg14_microphone_upper_in),
.reg15_microphone_lower_in (reg15_microphone_lower_in),
.reg16_microphone_max_upper_in (reg16_microphone_max_upper_in),
- .reg17_microphone_max_lower_in (reg17_microphone_max_lower_in)
+ .reg17_microphone_max_lower_in (reg17_microphone_max_lower_in),
+ .motor_ctrl_out (motor_ctrl_out)
);
serialInterface u_serialInterface (
top.vの変更
--- top.v.orig 2016-04-30 20:39:44.097462345 +0900
+++ top.v 2016-04-30 19:08:25.875079454 +0900
@@ -112,7 +112,14 @@ module top (
//gpio
output [7:0] OUT_LED,
input [2:0] IN_SWITCH,
- input [1:0] IN_BUTTON_N
+ input [1:0] IN_BUTTON_N,
+
+ // motor ctrl
+ output motor0_fwd, // J4:4 - LVDS_OUT2_N - M11
+ output motor0_rev, // J4:6 - LVDS_OUT3_N - M13
+ output motor1_fwd, // J4:8 - LVDS_OUT0_N - N6
+ output motor1_rev // J4:10 - LVDS_OUT1_N - J8
+
);
@@ -162,6 +169,7 @@ module top (
wire [23:0] adc_ch4_volt_data;
wire [23:0] adc_ch5_volt_data;
+ wire [7:0] motor_ctrl;
//--------------------------
// PLL
@@ -241,9 +249,14 @@ i2cSlave i2c_inst(
.reg14_microphone_upper_in (reg_microphone_upper),
.reg15_microphone_lower_in (reg_microphone_lower),
.reg16_microphone_max_upper_in (reg_microphone_max_upper),
- .reg17_microphone_max_lower_in (reg_microphone_max_lower)
+ .reg17_microphone_max_lower_in (reg_microphone_max_lower),
+ .motor_ctrl_out(motor_ctrl)
);
+assign motor0_fwd = motor_ctrl[0];
+assign motor0_rev = motor_ctrl[1];
+assign motor1_fwd = motor_ctrl[2];
+assign motor1_rev = motor_ctrl[3];
//--------------------------
// ADC Commands
変更後のファイルは odyssey_car_sample.zip をダウンロードして展開してください.
追加したモータ制御用のポートの割当てはソースコードのコメント通りです.GUIで設定するか,qsfに以下を追加してください.
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to motor0_fwd
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to motor0_rev
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to motor1_fwd
set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to motor1_rev
とりあえず試してみたい方へ
FPGA用ビットストリームをスマホ・アプリをバインドしたGATTファイルはこちら.
- “サンプルをベースに開発フローを修得”のサンプル(My I2C Test) – GATT_2309.bin (md5: ce1c625bb74387187af33ec977290195)
- “スマホ制御ラジコンを作ろう”のサンプル(OdysseyCar) – GATT_2169.bin (md5: cc79aefa807071e2c77b3de5f55757e1)
それぞれボードのROMに書き込んで動作を確認できます.
非Windows環境で開発する場合
生成したMAX10キット用のバイナリはUSB越しのシリアル通信でボード上のROMに書き込むことができます.コマンドの入力(ASCII)とデータの転送(ファイルの生データをバイナリ形式で送る)が必要です.
Windowsであれば,記事で書いた通りTeraTermで簡単にできるのですが,LinuxやWindowsでは,シリアル通信に不慣れだとやや面倒です.
手軽な方法としては,minicomなどのターミナルソフトとcatを組み合わせる方法があります.
具体的には,2つのターミナルを用意し,
- minicomなどボードと通信するターミナルでコマンドをデータを書きこむところまで操作をすめる
- 別のターミナルで cat GATT_xxxx.bin > /dev/ttyACM0 などとしてデータを書き込む
- ボードと通信しているターミナルソフトで改行を入力
とすればOKです.
なお,minicomの場合はLFとCRを共にONにする(\C-a aと\C-a u)と表示が崩れません.