2019.04.22

MITOUJTAG ProでDDR3メモリテストを追加し、テストスイートを作成

インターコネクトテスト、NORフラッシュテストに続き、DDR3メモリテストもパッケージ化しました。

DDR3メモリテストはこのブログでも何度か出てきているのであえて説明しませんが、バウンダリスキャンでFPGAの端子を操作して、DDR3メモリに読み書きするというものです。

ユーザ側のソースはとてもシンプルです。

printf("★FPGA1_DDR3のテストを行います\n");
int error_num = 0;
unsigned long dbus_error = 0;
unsigned long abus_error = 0;
DDR3Signals dsigs;
dsigs.ras = &U1_DDR3_RAS;
dsigs.cas = &U1_DDR3_CAS;
dsigs.wen = &U1_DDR3_WEN;
dsigs.cs = &U1_DDR3_CS;
dsigs.cke = &U1_DDR3_CKE;
dsigs.a = &U1_DDR3_ADDR;
dsigs.ba = &U1_DDR3_BA;
dsigs.d = &U1_DDR3_DQ;
dsigs.odt = &U1_DDR3_ODT;
dsigs.dm = &U1_DDR3_DM;
dsigs.ckp = &U1_DDR3_CLKP;
dsigs.ckn = &U1_DDR3_CLKN;
dsigs.dqsp = &U1_DDR3_DQSP;
dsigs.dqsn = &U1_DDR3_DQSN;
dsigs.reset = &U1_DDR3_RESET;
if(test_sdram(dsigs,abus_error,dbus_error))
{
printf("FPGA1_DDR3は正常です\n");
}
else
{
printf("FPGA1_DDR3に異常があります\n");
}
printf("\n");
j_bypass();

もちろん、呼び出した先の関数でMRSの設定やらRAS/CASの制御やDQSのタイミングなどはC++でぐちゃぐちゃと書かれていますが、ユーザが気にすることはありません。

ユーザがやることは、dsigsという構造体のメンバにRASやCAS、アドレス等を登録してtest_sdram関数を呼び出すだけです。

Ddr3

バス幅や構成は抽象化されているので、様々なボードに対して同じソースが使えます。

今回、3回に分けてJTAGスクリプトの機能を紹介してきました。

JTAGスクリプトを使うと、デスクトップで手軽にFPGAやCPUの端子をバウンダリスキャンで操作することができ、基板の検査を楽に行えます。

インターコネクトテスト、NORフラッシュテスト、DDR3メモリテストを行うための全ソースコードを下記のURLにアップロードしました。

MITOUJTAG ProのJTAGスクリプトのサンプル

MITOUJTAG Proをお使いのお客様はダウンロードしていただくことができます。どうぞ様々な基板の検査に応用し、設計、製造、検査の手間を効率化してみてください。

 

| | コメント (0)

2019.04.21

MITOUJTAG ProでNOR型フラッシュを扱うためのクラス

MITOUJTAG ProにはJTAGスクリプトとしてユーザプログラムを作り、組み込んで使う機能があります。

このJTAGスクリプト機能を使ってNOR型フラッシュのテストを行うプログラムを用意しました。

C++のクラス化です。

	printf("Flashメモリを読み出します\n");
BPIFlash *bpi = new BPIFlash(U1_FLASH_ADDR,
U1_FLASH_DATA,
U1_FLASH_CE,
U1_FLASH_WE,
U1_FLASH_OE);
// bpi->NarrowMode(); // NarrowModeにしない→16/8bitの選択は16bitを選ぶ
bpi->RegistOptionalByteSignal(U1_FLASH_BYTE); // オプション信号
bpi->RegistOptionalBusySignal(U1_FLASH_BUSY); // オプション信号
bpi->RegistOptionalResetSignal(U1_FLASH_RESET); // オプション信号
bpi->Dump(0,256); // メモリダンプの実行
delete bpi;
printf("\n");

BPIFlashクラスのコンストラクタを、アドレスやデータの信号線を引数として呼び出すと、検査用のオブジェクトを作ってくれます。

そして、RESETやBUSYなどのオプションの信号を登録した後で、Dump(アドレス,長さ)を呼び出すと、FlashROMの信号を操作してメモリの内容を読み出してダンプしてくれます。

下の図は、MAX10のBSDLファイルを書き込んだFlashROMを読み出したところです。

Bpi1

アクセスしているときの波形を示します。

OEとCEをLにしてアドレスをカウントアップさせるだけなので、単純ですね。

Norflash

このクラスは、データバスの幅は自動的に認識してくれますが、NarrowMode関数を呼び出すと、BYTE信号をLにしてA-1を操作するモードでアクセスするようになります。これは16bitのFlashROMを8bit幅でアクセスするというモードで、アドレスバスにA-1(マイナス1)というA0以下を意味する珍奇な信号がでてきます。

A-1は、通常はデータバスの最上位ビットに出てくるので、D15がトグルします。

Norflash2

読み出した結果はこのように同じ内容をバイト単位でアクセスしたものになります。

Bpi2

このほか、ビッグエンディアンにする機能もあります。

このソースのダウンロード方法は、次回の記事で公開します。

| | コメント (0)

2019.04.20

MITOUJTAG Proでインターコネクトテスト

MITOUJTAG Pro でインターコネクトテストを行えるようにしました。

インターコネクトテストというのは、複数のICの間の配線にオープン・ショートがないかを1本1本チェックするテストです。

ターゲットボードは、下の写真の「JTAGチャレンジ基板」。

Jcha

JTAGチャレンジ基板は、バウンダリスキャンの実習を目的としたボードで、データバスの一部をジャンパピンで切ったりショートしたりして、バウンダリスキャンの挙動を調べることができます。

このボードでは、Spartan-7とMAX10が16本のデータバスと2本のクロックでつながっています。

書いたスクリプトは以下のようなものです。

bool U1_to_U2_interconnect_test()
{
JSSignal u1_bus;
u1_bus << U1_FPGA_DBUS(15 downto 0);
u1_bus << U1_FPGA_CLK_p;
u1_bus << U1_FPGA_CLK_n;
JSSignal u2_bus;
u2_bus << U2_FPGA_DBUS(15 downto 0);
u2_bus << U2_FPGA_CLK_p;
u2_bus << U2_FPGA_CLK_n;
printf("U1とU2間の配線を検査します (U1出力)\n");
if(!interconnect_test(&u1_bus,&u2_bus))
{
printf("ERROR:U1とU2間の配線に異常があります\n\n");
return false;
}
printf("SUCCESS:U1とU2間の配線は正常です\n\n");
return true;
}

この、U1_FPGA_DBUSやU2_FPGA_CLK_pという名前のオブジェクトは、信号線に対応したもので、JTAG信号クラス(JSSignal)型のオブジェクトです。

JSSignal型の新しいオブジェクトを作り、<<で放り込んでいって、最後にinterconnect_testという関数に入れると、1本ずつ信号をHにするWalking 1や、一本ずつ信号をLにするWalking 0テストをしてくれるようになっています。

実際にやってみました。

MAX10とSpartan-7の間の信号を一本ずつ検査します。

下の波形がその実行中の波形で、緑の線が入力、赤の線が出力を表しています。

Interconnect_1

このように、通常は何事もなければ出力したものと同じ波形が入力デバイスで得られるはずです。

しかし、信号にショートやオープンがあった場合、下の波形のように異常な個所が出てきます。

Interconnect_3

これによって、D0とD4に異常が生じているということが判断できるというわけです。

このようなインターコネクトテストを行うためのC++のクラスと関数を用意したので、MITOUJTAG Proにユーザ機能として手軽に追加して実行できるという仕組みです。また、どのような順序であっても、どのような回数であっても、C++のプログラムを書き換えればよいので、自由にカスタマイズできます。

最後に、Spartan-7の場合、FPGAの設計時に入力としてコンフィギュレーションされてしまっている端子は、バウンダリスキャンを使っても出力にすることができません。

下の波形の左半分は、Spartan-7が起動しているときに、Spartan-7から出力した信号をMAX10で受け取ろうとしたものです。

Interconnect_4

Spartan-7(赤い線)は出力しているつもりなのに、MAX10(緑の線)からは何も受け取れていません。

バウンダリスキャンでインターコネクトテストを行う場合には、FPGAは未コンフィギュレーションの状態でやらないと、正しい結果が得られない場合があります。

このソースのダウンロード方法は、次々回の記事で公開します。

 

| | コメント (0)

2019.04.19

MITOUJTAGで長いチェーンを扱うとエラーが出る件と対策パッチ

あるお客様からのご指摘で、MITOUJTAGで長いJTAGチェーンを扱う場合に不具合が発見されたため、パッチを作成しました。

具体的には、MITOUJTAGはIR(命令レジスタ)の長さが100bit以上になるJTAGチェーンで、SAMPLEやEXTESTなどのバウンダリスキャンコマンドを発行した際に、不正な処理(多くはメモリ保護違反)が生じることがわかりました。

Mimic2

これは、ALTERA(INTEL)のFPGAではおよそ10個、XILINXではおよそ17個のFPGAを1つのJTAGにチェーン接続した場合に起こります。
この問題はJTAGデバイスが1~5個程度の通常の基板では起こりません。

パッチは下記のリンクからダウンロードできます。
長いJTAGチェーンでの不具合を対策するパッチ

※このパッチはMITOUJTAG BASIC 3.41用です。他のバージョンに適用した場合の動作は保証できません。次回の更新時にMITOUJTAG Pro,BASIC,Lightの各バージョンに取り込まれます。

 

さて、この問題を発見するために、JTAGMIMICという特別なデザインを作成して検証しました。JTAGMIMICはVivadoのデザインdえす。

Jtagmimic

MIMIC(ミミック)とは、真似する、擬態するという意味の言葉です。ドラクエでは宝箱に扮したモンスターでおなじみですね。

JTAGMIMIC(ジェイタグミミック)は、任意のJTAGデバイスをエミュレートするデザインをFPGAの中に作りこむ仕組みで、当社のSpartan-6ボードやArtix-7ボードで動作します。

今回は18個のFPGAを持つ仮想的なJTAGチェーンを、FPGAの中に作ることで検証しました。

 

Spartan-6ボード/Artix-7ボードとMITOUJTAGをご利用のお客様に無償で提供させていただきます。

詳しくは下記のURLをご覧ください。

http://www.tokudenkairo.co.jp/jtag/mimic.html

| | コメント (0)

2019.04.17

長いJTAGチェーンを仮想的に作る

ALTERA(INTEL)のArria10を10個つないだJTAGチェーンをMITOUJTAGでバウンダリスキャンして、12fpsくらいのレートで画面が更新できました。もうちょっといいPCだと22fpsくらい出ます。

Arria10

続きはこちら↓

» 続きを読む

| | コメント (0)

2019.04.11

LAN9514のEEPROMをLinuxから設定する方法

Micrichip社のLAN9514というICがあります。

USBのハブとホストに加え100BASEのUSB-LANを搭載しているICで、コネクタをつなぐだけで4ポートのUSBホストと100BASEのLANが実現できます。

Lan9514

RaspberryPiやZynqberryにも搭載されています。(RaspberryPiではEEPROMにMACアドレスを書いていないという話もあるので、この方法で変わるかどうかは試していない。ZynqberryはOK)

このICが作るLANのMACアドレスはEEPROMに設定されていなければ電源を投入するたび(リセットするたび)ランダムで決まります。

ランダムになってしまうと、例えばDHCPサーバが割り当てるIPアドレスがリブートのたびに変わるので、困る場合があります。例えば、Windowsでホスト名でファイル共有をするのに時間がかかるとか。

そこで、このICのMACアドレスをLinuxから設定することを試してみました。

LAN9514のEEPROMを設定するには、まずデバイスドライバを読んでみたところethtoolsという構造体があったので、ethtoolsとは何ぞやということで調べてみると、PHYの管理などができるそういうツールがあるようです。

これはZYNQのLinuxからサクッとapt-getでインストールできました。

zynqberry@zynqberry:~$ sudo apt-get install ethtool
[sudo] password for zynqberry:
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
bind9-host geoip-database libavahi-core7 libbind9-90 libdaemon0 libdns100
libgeoip1 libisc95 libisccc90 libisccfg90 liblwres90
これを削除するには 'apt-get autoremove' を利用してください。
以下のパッケージが新たにインストールされます:
ethtool
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。
84.5 kB のアーカイブを取得する必要があります。
この操作後に追加で 284 kB のディスク容量が消費されます。
取得:1 http://ports.ubuntu.com/ubuntu-ports/ trusty/main ethtool armhf 1:3.13-1 [84.5 kB]
84.5 kB を 1秒 で取得しました (74.3 kB/s)
以前に未選択のパッケージ ethtool を選択しています。
(データベースを読み込んでいます ... 現在 50239 個のファイルとディレクトリがイン ストールされています。)
Preparing to unpack .../ethtool_1%3a3.13-1_armhf.deb ...
Unpacking ethtool (1:3.13-1) ...
ethtool (1:3.13-1) を設定しています ...

起動してみます。一般ユーザでやる場合はsudoを付けてください。

zynqerry@zynqberry:~$ sudo ethtool -e eth0
Offset Values
------ ------
0x0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0110: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0120: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0140: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0150: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0160: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0170: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0190: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

初期状態では、中身は全部FFのようです。

ethtoolsを使ってEEPROMを書き込むには、ethtools -E eth0 の後ろにmagicやoffset、lengthを指定する必要があります。LAN9514のmagicは0x9500です。offsetはEEPROMの何番地から書き込むかで、これは0。lengthは140にします。

書き込むべきデータはLAN9514のデータシートに載っているので、それをコピペするなどしてテキスト化し、それをもとにバイナリファイルを作ります。Linuxで16進のテキストからバイナリ列を作るには、echoの後ろに-enを付けて、エスケープシーケンスを含んだ文字列を書けばよいようです。

echo -en "\xA5\x12\x34\x56\x78\x9A\xBC\x01\x04\x05\x09\x04\x0A\x1D\x00\x00\x00\x00\x00\x00\x00\x00\x12\x22\x12\x2B\x12\x34\x12\x3D\x00\x00\x24\x04\x14\x95\x00\x01\x9B\x18\x00\x02\x00\x00\x01\x00\x01\x00\x32\x00\x00\x00\x00\x00\x21\x43\x05\x01\x0A\x03\x53\x00\x4D\x00\x53\x00\x43\x00\x12\x01\x00\x02\xFF\x00\x01\x40\x24\x04\x00\xEC\x00\x01\x01\x00\x00\x01\x09\x02\x27\x00\x01\x01\x00\xE0\x01\x09\x04\x00\x00\x03\xFF\x00\xFF\x00\x12\x01\x00\x02\xFF\x00\xFF\x40\x24\x04\x00\xEC\x00\x01\x01\x00\x00\x01\x09\x02\x27\x00\x01\x01\x00\xE0\x01\x09\x04\x00\x00\x03\xFF\x00\xFF\x00" > eeprom.bin

これで140バイトの設定データが出来ました。

上の赤い部分がMACアドレスなので、必要に応じて書き換えてください。なお、最初の1バイトのbit1が'1'になっている(つまり0x02)MACアドレスはプライベートアドレスなので、自分の責任で自由に使うことができます。

ethtool -E eth0 magic 0x9500 offset 0 length 140 < eeprom.bin

これで書き込まれました。
確認してみましょう

zynqberry@zynqberry:~$ sudo ethtool -e eth0
Offset Values
------ ------
0x0000: a5 12 34 56 78 9a bc 01 04 05 09 04 0a 1d 00 00
0x0010: 00 00 00 00 00 00 12 22 12 2b 12 34 12 3d 00 00
0x0020: 24 04 14 95 00 01 9b 18 00 02 00 00 01 00 01 00
0x0030: 32 00 00 00 00 00 21 43 05 01 0a 03 53 00 4d 00
0x0040: 53 00 43 00 12 01 00 02 ff 00 01 40 24 04 00 ec
0x0050: 00 01 01 00 00 01 09 02 27 00 01 01 00 e0 01 09
0x0060: 04 00 00 03 ff 00 ff 00 12 01 00 02 ff 00 ff 40
0x0070: 24 04 00 ec 00 01 01 00 00 01 09 02 27 00 01 01
0x0080: 00 e0 01 09 04 00 00 03 ff 00 ff 00 ff ff ff ff
0x0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0100: a5 12 34 56 78 9a bc 01 04 05 09 04 0a 1d 00 00
0x0110: 00 00 00 00 00 00 12 22 12 2b 12 34 12 3d 00 00
0x0120: 24 04 14 95 00 01 9b 18 00 02 00 00 01 00 01 00
0x0130: 32 00 00 00 00 00 21 43 05 01 0a 03 53 00 4d 00
0x0140: 53 00 43 00 12 01 00 02 ff 00 01 40 24 04 00 ec
0x0150: 00 01 01 00 00 01 09 02 27 00 01 01 00 e0 01 09
0x0160: 04 00 00 03 ff 00 ff 00 12 01 00 02 ff 00 ff 40
0x0170: 24 04 00 ec 00 01 01 00 00 01 09 02 27 00 01 01
0x0180: 00 e0 01 09 04 00 00 03 ff 00 ff 00 ff ff ff ff
0x0190: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x01f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

ちゃんと書き込まれているのがわかります。

起動時のメッセージを見ると、今まではランダムになっていたのが、

[    2.669168] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[ 2.675982] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2.686405] smsc95xx v1.0.5
[ 2.784367] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-ci_hdrc.0-1.1, smsc95xx USB 2.0 Ethernet, fe:c0:42:d9:23:f9
[ 7.477999] EXT4-fs (mmcblk0p2): recovery complete
[ 7.485256] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 7.493315] VFS: Mounted root (ext4 filesystem) on device 179:2.

下のように設定したが使われているのがわかります。

[    2.663831] init: ureadahead main process (1120) terminated with status 5
[ 2.688673] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[ 2.695469] usb 1-1.1: New USB device strings: Mfr=1, Product=0, SerialNumber=0
[ 2.705719] usb 1-1.1: Manufacturer: SMSC
[ 2.718420] smsc95xx v1.0.5
[ 2.823765] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-ci_hdrc.0-1.1, smsc95xx USB 2.0 Ethernet, 12:34:56:78:9a:bc

ifconfigで見てみると、

eth0      Link encap:イーサネット  ハードウェアアドレス 12:34:56:78:9a:bc
inetアドレス:192.168.1.215 ブロードキャスト:192.168.1.255 マスク:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1
RXパケット:99 エラー:0 損失:14 オーバラン:0 フレーム:0
TXパケット:75 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:8532 (8.5 KB) TXバイト:9821 (9.8 KB)

lo Link encap:ローカルループバック
inetアドレス:127.0.0.1 マスク:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 メトリック:1
RXパケット:106 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:106 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1
RXバイト:5300 (5.3 KB) TXバイト:5300 (5.3 KB)

ちゃんと書き変わりました。

なお、ethtoolsでは、140バイトのデータを正しく書かないとLAN9514が起動しなくなってしまいます。その場合はEEPROMを物理的に外すなどの処置が必要になるので多少の危険を伴います。最初の7バイトだけを書き込んだら動かなくなったので、復旧に苦労しました。

 

もっと簡単な方法としては、

ifconfig eth0 down
ifconfig eth0 hw ether 02:01:02:03:04:05
ifconfig eth0 up

で設定してしまうことです。これを/etc/rc.localに書いておけば起動時に設定されます。

ZYNQの内蔵のGigabitEtherは、Linuxのドライバの問題によりこの方法ではMACアドレスを変更できませんが、LAN9514経由のUSB-LANであればifconfigでMACアドレスを変更できるので、より安全で手軽です。

ユーザがSDカードをどんなふうに書き換えても動くようにハード的に固定値を書き込んでおきたいという場合にはethtooslでEEPROMに書き込むのがよいでしょう。

 

| | コメント (0)

2019.04.07

ZYNQのLinuxでMPC79411というRTCを使う方法

Microchip社のリアルタイムクロックMPC79411をZYNQのLinuxから使うには、DeviceTreeに以下のように書きます。

i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
status = "okay";
clocks = <0x1 0x26>;
interrupt-parent = <0x4>;
interrupts = <0x0 0x19 0x4>;
reg = <0xe0004000 0x1000>;
#address-cells = <0x1>;
#size-cells = <0x0>;
clock-frequency = <0x61a80>;
rtc@6F {
compatible = "mcp7941x";
reg = <0x6f>;
};
};

この6FというのがI2Cのデバイスアドレスで、compatible="mpc7941x"と書くことで起動時に探されます。clock-frequency=<0x61a80>というのはI2Cのクロックを400kHzにするという意味です。ぴったり400kHzになります。

# dtc -I dts -O dtb devicetree.dts > /mnt/devicetree.dtb

でデバイスツリーを作り、rebootします。

MPC79411のドライバはDS1307用の汎用RTCドライバを用いているので、起動時にはDS1307のドライバで認識され、

[    1.304585] i2c /dev entries driver
[ 1.308235] cdns-i2c e0004000.i2c: 400 kHz mmio e0004000 irq 23
[ 1.315197] rtc-ds1307 0-006f: SET TIME!
[ 1.320404] rtc-ds1307 0-006f: rtc core: registered mcp7941x as rtc0
[ 1.326682] rtc-ds1307 0-006f: 64 bytes nvram
[ 1.331237] cdns-i2c e0005000.i2c: 400 kHz mmio e0005000 irq 24

と、起動時に認識されます。

MPC79411はアドレス0のbit7がSTARTビットといってカウントを開始するためのレジスタとなっていて、アドレス3のbit3がバッテリバックアップの有効化ビットなので、これらをONにしないと動きません。

そのため、必ずMPC7941Xを指定してDS1307ドライバを使う必要があります。

これで電源が落ちても時間を保持できます。

» 続きを読む

| | コメント (0)

2019.04.05

ZYNQでEMIO経由でI2Cを動かす方法

ZYNQのI2CをEMIO経由で出すデザインを作ったのですが、全く信号が出てこないので困っていました。

I2CをEMIO経由で出すとIIC_0とIIC_1という2つのバスが出てきて、この中にはSDAとSCLの信号がI,O,Tで3本ずつ通っています。

I2cdesign5

このIIC_0の信号を外に出すために、次のようなコードを書いていたのですが、

	i2c_iobuf_inst : IOBUF port map (
IO => sda1_io,
O => sda1_o,
I => sda1_i,
T => sda1_t
);
scl1_io <= scl1_i;
sda2_io <= sda2_i;
scl2_io <= scl2_i;
scl1_o <= '0';
sda2_o <= '0';
scl2_o <= '0';

信号が何も出てこないという結果となっていました。

I2Cがそもそも動いていないのか、初期化などに失敗しているのかと考えられました。

しかし、PLはそのままにしてPSだけ修正し、I2CをEMIOに通すようにしたら、なんと、I2Cの信号が出てくるようになったのです!

I2cdesign4

U-BOOTでi2c probeを実行し、その時のPLの中の波形をMITOUJTAGを使ってみてみると、ぴったり100kHzのクロックで出てきています。

I2cdesign6

波形を目で読んでみると、0x03,0x05,0x07,0x09・・・と奇数番地にアクセスしています。

しかし、EMIOデザインにするとこの波形も出てきません。

Vivadoのバグかと思ってVivado2018.3にアップデートしてみても変化なし。

もうわけがわからないので、徹底的にデバッグすることにしました。

まず、EMIOを通すデザインとMIO50,51から出すデザインの2つを作って、export hardwareを行い、ps7_init.tclの内容を比べてみると、

mask_write 0XF80007C8 0x00003FFF 0x00001300
mask_write 0XF80007CC 0x00003FFF 0x00001300

mask_write 0XF80007C8 0x00003FFF 0x00001340
mask_write 0XF80007CC 0x00003FFF 0x00001340

になっているという程度の違いでした。

この0xf80007c8と0xf80007ccのレジスタ以外の違いはありません。ug585を読むとMIO50/51をGPIOにするかI2Cにするかの選択だけで、それ以外の変化はありませんでした。

I2cdesign7

したがって、MIO50から出てくるのであればI2Cのモジュール自体は正しく設定されていて、動いているといえるでしょう。

すると、MIOから出すのとEMIOから出すの違いは一体何なのか。

実はMIO50とMIO51に入力される値の違いと、SDA_OやSCL_Oは'0'から動かないということでした。

まず、上にあるMITOUJTAGの波形を見てみるとわかりますが、動いているのはSDA_TとSCL_Tであって、scl1_iとsda1_i
は常に'0'となっています。

I2cdesign12

つまり、I2Cの信号を出力するときには、SCLとSDAはトライステートバッファを利用して、0かZかを出力しろというわけです。

したがって、

scl1_io <= scl1_i;

という書き方はダメで、SCLについてもIOBUFTを使うか、

scl1_io <= '0' when (scl1_t = '0') else '1';

と書かなければいけないようです。

もう一つはZYNQコアのSCL_Iに入れる値を'0'のままに固定してはいけないということです。具体的には、

scl1_o <= '0';

というのが間違っていて、

scl1_o <= '1';

にしなければならなかったのです。

入力値が'0'のままだとZYNQのI2C内蔵ペリフェラルは動作をしてくれないようです。

まとめると、

i2c_iobuf_inst : IOBUF port map (
IO => sda1_io,
O => sda1_o,
I => sda1_i,
T => sda1_t
);
scl1_io <= '0' when (scl1_t = '0') else '1';
scl1_o <= '1';

にするか、SCLに対しても

i2csda_iobuf_inst : IOBUF port map (
IO => sda1_io,
O => sda1_o,
I => sda1_i,
T => sda1_t
);
i2cscl_iobuf_inst : IOBUF port map (
IO => scl1_io,
O => scl1_o,
I => scl1_i,
T => scl1_t
);

と、3ステートバッファを使えばよいようです。

SDAだけではなくSCLについても、素直にIOBUFTを使えばよかったのですね。

I2CにつないだRTCのMPC79411も動くようになり、Linux起動時に下記のような波形が出てきました。

I2cdesign8

内蔵レジスタも読めた!

I2cdesign13

こんなことで1週間近くもハマっていました。

てゆーか、AR#56858によれば末尾に_t、_o、_iが付いている信号は自動的にIOBUFTが推論されるそうなので、そもそもIOBUFTをラッパするだけのIPなんていうのは作る必要さえなかったようでした。IP CatalogのUtility bufferにIOBUFTが無い理由はそこにあるのかもしれません。

結論を言うと、これでよいようです。

I2cdesign9

バスの信号をそのままMake Externalするのはとても心理的抵抗があるのですが、Vivadoは信号名の末尾に_i,_o,_tという信号を見つけると、自動的にIOBUFTを入れて、_ioという名前の信号に置き換えてしまうので、HDL Wrapperの出力は

I2cdesign10

となります。

XDCファイルには

I2cdesign11

と、_ioの名前でピン配置を指定すればよいというわけです。

やらなくていいことを自分でやろうとしてI2Cが動かないという結果になっていた典型的なパターンでした。もう少しVivadoを信頼してもいいのかもしれません。

 

| | コメント (0)

«TrenzElectronicの製品を続々入荷中