コスモリサーチの凄腕エンジニアたちが日々、難題と格闘した記録
Copyright Cosmo Research Corp.

FX3(CYUSB30xx)のブートに関するメモ

FX3のコンフィグ

USBブートの場合、USB2.0接続でないと動作しない。
基板上の接続をUSB3.0/USB2.0ともに有効にする必要がある。

また、PMODEの設定はZ11としてUSBブート状態にする必要がある。

参考: EZ-USB® FX3™/FX3S™ブートオプションについて(AN76405)

USB Control Centerを使用する場合

FX3 SDKをインストールするとついてくるControl Centerを使用してコンフィグ出来る。

  1. PMODEの設定をZ11にして電源ONする。
  2. Program > FX3 > RAMにて、RAM上に任意プログラムを書き込んで起動する。
  3. RAMではなく、SPI FLASHも動作する。

この操作はGUIでの操作になるので、何度も実行するのは面倒である。

※SPIに書き込むイメージファイルは、通常のイメージファイルとは違うため、注意が必要である。

elf2img.exe -i XXXX.elf -o XXXX.img               # 通常(RAM書き込み用)イメージ作成
elf2img.exe -i XXXX.elf -o XXXX.img -i2cconf 0x00 # SPI書き込み用イメージ作成

libusb-1.0付属のfxload.cを使用する場合

事前準備その1(zadigによるドライバの変更)

事前の準備として、USB boot状態のFX3のドライバをWinUSB(libusb-1.0)に変更する必要がある。
この変更にはzadigを使用する。
恒久的にドライバが変更されるため、注意すること。
具体的な操作は、zadigにて、VendorID="04B4" ProductID="00F3"のドライバをWinUSBに変更する。

事前準備その2(libusb-1.0付属のfxloadのコンパイル)

msys2にて、コンパイル環境を構築し、pacmanにてlibusb-1.0のライブラリをインストールしておく。
その後、fxloadをコンパイルする。

git clone https://github.com/libusb/libusb.git
cd libusb/examples
gcc fxload.c exusb.c -o fxload.exe -lusb-1.0 -I/mingw32/include/libusb/libusb-1.0 -static

fxload.exeにてコンフィグ実行

  1. PMODEの設定をZ11にして電源ONする。
  2. fxload.exe -t fx3 -i <fx3 image file>

実行結果

C:\Users\cosmo\Desktop>fxload.exe -t fx3 -i SlaveFifoSync\Debug\SlaveFifoSync.img
found device 'Cypress FX3' [04b4:00f3] (3,8)
microcontroller type: fx3
SlaveFifoSync\Debug\SlaveFifoSync.
img: type Cypress IMG format
open firmware image SlaveFifoSync\Debug\SlaveFifoSync.img for RAM upload
normal FW binary executable image with checksum
FX3 bootloader version: 0x000000A9
writing image...
transfer execution to Program Entry at 0x4000c71c

一度ドライバをインストールしておけば、上記を実行するだけでFX3に任意のプログラムがロードされる。

XilinxのDDR4メモリコントローラについてのメモ

目的

DDR4メモリコントローラのオーバーヘッドに影響がある設定ついて調べる。 どの設定にしたらアクセス速度があがるか?

先に、内容のまとめ

DDR4メモリコンポーネントについては、8Gb:x4,x8,x16 DDR4 SDRAM Datasheetを参考にした。

  • x16デバイスでは、バンクグループは1bit、バンクが2bit存在する。
  • 違うバンクグループへのアクセスが早く、同じバンクグループへのアクセスは遅い。
  • データマスクが有効だと遅くなる。

メモリコントローラIPについては、UltraScaleアーキテクチャFPGAメモリIP v1.2 LogiCORE IP 製品ガイド(PG150)を参考にした。

  • 単調にインクリメントする場合はROW_COLUMN_BANKが有効だが、短いバースト長の場合はROW_COLUMN_BANK_INTLVが有効らしい。
  • DM/DBIのオプションは、NO_DM_DBI_WRがベターかもしれない。

DDR4メモリコンポーネント

DDR4メモリコンポーネントのTimingパラメータの概要

-083E Device overview

0.937ns @ CL = 15 (DDR4-2133)
Data Rate    = 2133 MT/s
tRCD         = 14.06 ns
tRP          = 14.06 ns
CL           = 14.06 ns

Addressing(component)

Bank Group : BG0 (1bit only)
Bank       : BA[1:0] (per Bank Group)
Row        : A[15:0]
Column     : A[9:0]
Page Size  : 2KByte (per Bank)

DDR4メモリコンポーネントのモードレジスタ設定(メモリコントローラIPと照らし合わせ)

x16デバイスには8個のバンク(2バンクグループで各々4バンク)が存在する。
MIGではMT40A512M16HA-083Eを選択して938psのクロックサイクルとすると、以下の設定になる。

  • MR0 = 13'b0011100110000,

    • BL8(Mode : Burst Length 8)固定
      • tWR(WRITE recovery) = 16
        ここから、最小のWRサイクルは以下となる。
        roundup(tWR / tCK) = roundup(16 / 0.938) = roundup(17.057...) = 18 cycle
        ただし、DM(Data Mask)が有効な場合は上記から更に遅くなる。
      • tRTP(READ-to-PRECHARGE) = 8
        ここから、最小のRTPサイクルは以下となる。
        roundup(tRTP / tCK) = roundup(8 / 0.938) = roundup(8.428...) = 9 cycle
        同じバンクにアクセスする際のACTタイミングがこれで決まる。
  • MR1 = 13'b0001100000001,

    • AL(Additive Latency) = 0(AL disable)
      WL(WRITE latency) = AL + CWL(CAS WRITE latency) = CWL
      RL(READ latency) = AL + CL(CAS latency) = CL
  • MR2 = 13'b0000000010000,

    • CWL = 11
      WL = AL + CWL = 0 + 11 = 11
  • MR4 = 13'b0000000000000,

    • WRITE preamble setting = 1tCK
    • READ preamble setting = 1tCK
    • CAL(CMD address latency) = 0
  • MR5 = 13'b0010000000000,

    • DM(Data mask) enable ... 実際には使用しないがIPで有効になっているとWRには影響する?
      これがオーバヘッドに影響するかどうかは、要確認。
  • MR6 = 13'b0100000010100,

    • tCCD_L = 6 clocks

DDR4メモリコンポーネントのBank Access Operation

違うバンクグループへのアクセス(WRITE/READ)は、tCCD_S(or short)分遅延する。
同じバンクグループへのアクセス(WRITE/READ)は、tCCD_L(or long)分遅延する。

tCCD_S = 4 clocks (DDR4-2133) ... CAS_n-to-CAS_n command delay to different bank group
tCCD_L = 6 clocks             ... CAS_n-to-CAS_n command delay to same bank group

違うバンクグループのACTIVATEは、tRRD_S分遅延する。
同じバンクグループの違うバンクのACTIVATEは、tRRD_L分遅延する。

tRRD_S = 5.3 ns (DDR4-2133, page size 2KByte)  ... ACTIVATE-to-ACTIVATE command period to different bank groups
tRRD_L = 6.4 ns (DDR4-2133, page size 2KByte)  ... ACTIVATE-to-ACTIVATE command period to same bank groups

tWTR_S/L(WRITEからREADの切り替わり時間)については、とりあえず無視する。

メモリコントローラ

グループFSM

基本的にはバンクグループがコントローラのグループFSMに割り当てられ、各グループFSM間でタイミングを協調してアクセス効率を高める働きをする。
基本的には、と書いたのはDDR4のx16デバイスの場合に、バンクグループは1bitだが、グループFSMは2bit(4つ)存在するからである。

アクセス効率を高めるためには、グループFSMへのアクセスを均等にすることが必要である。

アドレスオーダー

  • ROW_COLUMN_BANK
    app_addr[4:3]がグループFSMに割り当たる。
    長期間、単調にインクリメントする場合に最も効率的なアドレス配置となる。
    単調にインクリメントしない場合は、この配置を維持したまま、下位bitにトグルしやすいbitを持ってくると良い。

  • ROW_COLUMN_BANK_INTLV
    バースト長が短い場合にパフォーマンスを向上させる。
    この並びは、効果があるかもしれないが、書き込みが連続している場合は効果がなさそうではある。

  • ROW_BANK_COLUMNおよびBANK_ROW_COLUMNは推奨しないようだ。

データマスクとDBI(Data Bus Inversion)

データマスク(DM)は、特定のbitだけマスクしたりする機能であり、DBIはトグル回数(割合)を減らす機能である。
DBIの機能を使用することでノイズ低減や、消費電力の低減を期待できるらしい。
書き込みにおいて、DMとDBIは同時に使用することはできない。

DDR4メモリコンポーネントのデータシートを見る限り、書き込みにおいて、DBIが遅延を発生させることはないようだ(書き込みと同時に調整を行う)。
読み出しに関しては、レイテンシが2クロック増える。

MIGで選択できるDM/DBIのオプションは、以下から選ぶことができるが、レイテンシを考慮するとNO_DM_DBI_WRがベターかもしれない。

  • DM_NO_DBI(デフォルト)データマスク有効でDBI無効
  • DM_DBI_RDデータマスク有効で読み出しのみDBI有効
  • NO_DM_DBI_RDデータマスク無効で読み出しのみDBI有効
  • NO_DM_DBI_WRデータマスク無効で書き込みのみDBI有効
  • NO_DM_DBI_WR_RDデータマスク無効で読み出し/書き込みともDBI有効

Windows 10でWSLを有効時、Quartus PrimeのDDR3 Memory Controller IP生成でエラー

前置き

Windows 10でWSLを有効時、Quartus PrimeのDDR3 Memory Controller IP生成でエラーになって、IPの生成ができない現象に遭遇した。
ひとまずはWSLを無効にすれば正常に生成できるが、気になったので調査してみた。

エラー内容

Quartus Primeのバージョン16.1のエラー表示(17.1でも同様)。

Error: Error during execution of "{C:/intelfpga/16.1/quartus//../nios2eds/Nios II Command Shell.bat} make all 2>> stderr.txt": child process exited abnormally
Error: Execution of command "{C:/intelfpga/16.1/quartus//../nios2eds/Nios II Command Shell.bat} make all 2>> stderr.txt" failed

Quartusで自動生成されたMakefileの下記部分でエラーになっている。

D:/intelfpga/17.1/quartus//../nios2eds/sdk2/bin/nios2-bsp hal sequencer_bsp .. --default_sections_mapping sequencer_mem --use_bootloader DONT_CHANGE

調査内容

nios2-bspでエラーになるようだが、これの中身はシェルスクリプトであり、Quartus(Nios II)のmakeからシェルスクリプトを呼ぶとbash nios2-bspが実行される事がわかった。

このbashは、WSLが有効な環境ではC:\Windows\System32\bash.exeに展開されてしまうのでエラーになってしまう。本当はNIOS II Command Shellのbashを呼んでほしい。

対策

かなり無理矢理だが、自作のnios2-bsp.exeをオリジナルのnios2-bspと同じフォルダに置くことで解決した。

nios2-bsp.exeについては、特に理由はないが今回はgolangで作ってみた。(shebang書き換えでスマートに対応できたかもしれない)

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    cmd := exec.Command(
        os.Getenv("QUARTUS_ROOTDIR")+`\bin64\cygwin\bin\bash.exe`,
        append([]string{os.Getenv("SOPC_KIT_NIOS2") + "/sdk2/bin/nios2-bsp"}, os.Args[1:]...)...,
    )
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

複数の同一ブロックデザインを含むVivadoプロジェクトで、petalinuxからhdfファイルが読み込めないのを無理やり解決した話

現象(Vivado 2018.3)

Microblazeを含むプロジェクトでLinuxを使いたかったので、簡単に済ませるためにpetalinuxを使うことになった。が、petalinux-config --get-hw-description=<path>コマンドでなぜかhdfが読み込めない([Hsi 55-2019] XXX.hwh file is emptyとか言われる)。

該当のhdfファイルをzip解凍して見てみると、中身はこうなっていた。

合計 12M
-rw-r--r-- 1 saido saido 187K 2月  18 22:01 network_stack_bd.hwh
-rw-r--r-- 1 saido saido  18K 2月  18 22:01 network_stack_bd_bd.tcl
-rw-r--r-- 1 saido saido  12M 2月  18 22:01 RoXGE_udp.bit
-rw-r--r-- 1 saido saido 8.1K 2月  18 22:01 RoXGE_udp.mmi
-rw-r--r-- 1 saido saido 1.5K 2月  18 22:01 sysdef.xml

まぁ、Microblaze関連の諸々がないのでそりゃあエラーになるよな。
ちなみに、正常なhdfファイルの中身はこうなっているはず。

合計 14M
-rw-r--r-- 1 saido saido 676K 2月  15 18:47 microblaze_bd.hwh
-rw-r--r-- 1 saido saido 2.2M 2月  15 18:47 microblaze_bd_axi_smc_periph_0.hwh
-rw-r--r-- 1 saido saido 293K 2月  15 18:47 microblaze_bd_axi_smc_periph_0_bd.tcl
-rw-r--r-- 1 saido saido  41K 2月  15 18:47 microblaze_bd_bd.tcl
-rw-r--r-- 1 saido saido 274K 2月  15 18:47 microblaze_bd_ddr4_0_microblaze_mcs.hwh
-rw-r--r-- 1 saido saido  13K 2月  15 18:47 microblaze_bd_ddr4_0_microblaze_mcs_bd.tcl
-rw-r--r-- 1 saido saido 187K 2月  15 18:47 network_stack_bd.hwh
-rw-r--r-- 1 saido saido  18K 2月  15 18:47 network_stack_bd_bd.tcl
-rw-r--r-- 1 saido saido 9.4M 2月  15 18:47 RoXGE_udp.bit
-rw-r--r-- 1 saido saido 8.1K 2月  15 18:47 RoXGE_udp.mmi
-rw-r--r-- 1 saido saido 1.4K 2月  15 18:47 sysdef.xml

このプロジェクトでは、Microblaze用のブロックデザイン(microblaze_bd)の他に、UDP/IPプロトコルスタックのブロックデザイン(network_stack_bd)を含んでいた。ハードウェアとしては複数のEthernet用の口があるので、network_stack_bdを複数インスタンシエートしたら、hdfファイルがおかしくなった。

原因は不明だが、複数の同じブロックデザインを含むプロジェクトでは、hdfファイル(正確にはsysdefファイル)を作成するためのwrite_hwdefコマンドがエラーになるようだ。手元で適当に試すと以下のようになる。多分2回同じファイルを開こうとしてるんだと思う。

$ write_hwdef -force temp.hdf
zip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingzip_exception: zip archive temp.hwdef is already open for writingtemp.hwdef

対応

hdfファイルが単なるzip圧縮したファイルだということは知っていたので、必要なファイルを集めてzip圧縮すればいいや、と単純に考えたが、なぜかpetalinux-config --get-hw-description=<path>コマンドで弾かれる。

どうやら、改ざんされたhdfファイルかどうかをチェックしている模様。

だがしかし、試行錯誤の末、write_sysdefというコマンドを使ってhdfファイルを作成すればpetalinux-config --get-hw-description=<path>コマンドを騙せるということが分かった。なので、これを使ってhdfファイルを作れば良し。

今回のプロジェクトでは、以下のtclを実行してhdfファイルを作った。

# hdlで複数のブロックデザインを呼び出すとhwdef生成で
# バグって正常にhdfファイルを生成できなくなる。
#
# これを回避するために、hdfファイルを改ざんする。
# ただ、`petalinux-config --get-hw-description=<path>`コマンドでは
# hdfファイルの改ざんを検知するため、改ざんしたhdfファイルは使えない。
#
# 改ざんを隠蔽するためには、`write_sysdef`コマンドを使って
# hdfファイルを再生成する必要がある。

set target_dir hdf/modified
exec mkdir -p $target_dir

# 壊れたhdfファイル(sysdefファイルと同じ)の中身を吸い出す。(sysdef.xmlが欲しい)
# 事前にbitstreamを生成しておく必要がある。
exec unzip -o udp_ip_roxge/udp_ip_roxge.runs/impl_1/RoXGE_udp.sysdef -d $target_dir

# hdf作成に必要なファイルたちを集める。
set bd_base            udp_ip_roxge/udp_ip_roxge.srcs/sources_1/bd
set microblaze_bd      microblaze_bd/hw_handoff/microblaze_bd
set ddr4_mb_mcs        microblaze_bd/ip/microblaze_bd_ddr4_0/bd_0/hw_handoff/microblaze_bd_ddr4_0_microblaze_mcs
set microblaze_axi_smc microblaze_bd/ip/microblaze_bd_axi_smc_periph_0/bd_0/hw_handoff/microblaze_bd_axi_smc_periph_0
set network_stack_bd   network_stack_bd/hw_handoff/network_stack_bd

exec cp -f $bd_base/${microblaze_bd}.hwh         $target_dir/
exec cp -f $bd_base/${microblaze_bd}_bd.tcl      $target_dir/
exec cp -f $bd_base/${ddr4_mb_mcs}.hwh           $target_dir/
exec cp -f $bd_base/${ddr4_mb_mcs}_bd.tcl        $target_dir/
exec cp -f $bd_base/${microblaze_axi_smc}.hwh    $target_dir/
exec cp -f $bd_base/${microblaze_axi_smc}_bd.tcl $target_dir/
exec cp -f $bd_base/${network_stack_bd}.hwh      $target_dir/
exec cp -f $bd_base/${network_stack_bd}_bd.tcl   $target_dir/

# 改竄したhdfファイルをhwdefファイルとして生成する。(単にzip圧縮する)
exec zip -j ${target_dir}.hwdef $target_dir/*

# write_sysdefコマンドで本物のhdfファイルを作ってもらう。
write_sysdef -force \
    -hwdef   ./hdf/modified.hwdef \
    -bitfile ./hdf/modified/RoXGE_udp.bit \
    -meminfo ./hdf/modified/RoXGE_udp.mmi \
    ./modified.hdf

もう一つのバグ

Vivado 2018.3でMicroblazeを使用する場合、AR# 71948 UpdateMEM/SDK 2018.3 デザイン アドバイザリ – MicroBlaze および MicroBlaze MCS の MMI ファイルの生成が原因で発生していた機能的な問題を回避するための緊急パッチにハマるので必ずパッチを当てておく必要がある。
このパッチを当てないとMicroblazeが起動しない。

宣伝

上記の作業は、10GbE向けのUDP/IPプロトコルスタックの性能比較などを行うための実験の一貫だった(RoXGEというのは、RF over 10Gb Ethernetの略)。
コスモリサーチでは、RoF(Radio on Fiber 技術)を実現するためのボードを開発して、様々な実験を行っている。

Xilinx ZynqのSDカードイメージ(BOOT.bin)の構造

Vivado 2017.2でなぜかQSPIブートできない現象にハマった際のメモをここで供養する。
QSPIブートできないのはfsblのバグ(後述)で、おそらく2017.4では修正されているはず。

実際に参考にしたBOOT.binはxilinxが提供しているxilinx-zc702-v2017.2-final.bspというファイルのpre-buildに入っているもの。

BootROM

参考資料1(UG585)の6.3.2 BootROM ヘッダーに記載。以下、表6-5を抜粋。

ヘッダーアドレス 説明 道祖土コメント
0x000 - 0x01F Interrupt Table for Execution-in-Place
0x020 Width Detection 0xAA995566固定
0x024 Image Identification 'XLNX'固定
0x028 Encryption Status
0x02C FSBL/ユーザー定義
0x030 Source Offset
0x034 Length of Image
0x038 0
0x03C Start of Execution
0x040 Total Image Length
0x044 0 実際は1
0x048 Header Checksum
0x04C - 0x09F FSBL/ユーザー定義 (84バイト)
0x0A0 - 0x89F Register Initialization (2048バイト) ALL 0xFFFF0000
0x8A0 - 0x8BF FSBL/ユーザー定義 ALL 0xFFFFFFFF
0x8C0 - FSBLイメージまたはユーザーコード イメージヘッダー

以下でファイルの内容を見てみる。

od -tx4 -v -Ax --endian little BOOT.BIN | less

先頭からBootROMヘッダーが始まっている。

000000 eafffffe eafffffe eafffffe eafffffe
000010 eafffffe eafffffe eafffffe eafffffe
000020 aa995566 584c4e58 00000000 01010000
000030 00001700 00018008 00000000 00000000
000040 00018008 00000001 fc164530 00000000
000050 00000000 00000000 00000000 00000000
000060 00000000 00000000 00000000 00000000
000070 00000000 00000000 00000000 00000000
000080 00000000 00000000 00000000 00000000
000090 00000000 00000000 000008c0 00000c80

イメージヘッダーテーブル

参考資料2(UG821)の付録A: Bootgenの使用の表A-4を抜粋。

オフセット 名前 注記
0x0 バージョン 0x01020000
0x4 イメージヘッダー数
0x8 パーティションヘッダーのワードオフセット
0xC 最初のイメージヘッダーのワードオフセット
0x10 ヘッダー認証のワードオフセット
0x1C パディング 64バイト境界までALL 0xFF

0x000008A0からイメージヘッダーが始まると書いているが、実際のBOOT.binでは0x000008C0から始まっている。 BootROMヘッダーの説明(UG585)ではBootROMヘッダー自体のサイズが0x8C0と書かれているので誤記だと思う。

BootROMと同様に、odでBOOT.binを見てみる。

0008c0 01020000 00000003 00000320 00000240
0008d0 00000000 ffffffff ffffffff ffffffff
0008e0 ffffffff ffffffff ffffffff ffffffff
0008f0 ffffffff ffffffff ffffffff ffffffff
  • イメージヘッダー数: 3
  • パーティションヘッダーのワードオフセット: 0x320(バイトでは0xC80)
  • 最初のイメージヘッダーのワードオフセット: 0x240(バイトでは0x900)

イメージヘッダー

イメージヘッダーテーブルのあとにはBootgenの作ったイメージヘッダーが並ぶ。

参考資料2(UG821)の付録A: Bootgenの使用の表A-7を抜粋。

オフセット 名前
0x0 次のイメージヘッダーのワードオフセット
0x4 最初のパーティションヘッダーのワードオフセット
0x8 0固定
0xC 1固定(パーティション数)
0x10 ここからファイル名 + 0x00000000
0x10 + ファイル名分 + 0x4 64バイト境界までALL 0xFF

先程と同様にodの出力を見てみる。

000900 00000250 00000320 00000000 00000001
000910 7a796e71 5f667362 6c2e656c 66000000 # zynq_fsbl.elf
000920 00000000 ffffffff ffffffff ffffffff
000930 ffffffff ffffffff ffffffff ffffffff
000940 00000260 00000330 00000000 00000001
000950 646f776e 6c6f6164 2e626974 00000000 # download.bit
000960 00000000 ffffffff ffffffff ffffffff
000970 ffffffff ffffffff ffffffff ffffffff
000980 00000000 00000340 00000000 00000001
000990 752d626f 6f742e65 6c660000 00000000 # u-boot.elf

なので、このBOOT.binでは以下の位置にパーティションヘッダーがいる事がわかる。

  • zynq_fsbl.elf: 0x320(バイトで0xC80)
  • download.bit: 0x330(バイトで0xCC0)
  • u-boot.elf: 0x340(バイトで0xD00)

パーティションヘッダーテーブル

参考資料2(UG821)の付録A: Bootgenの使用の表A-5を抜粋。

オフセット 名前
0x0 Partition Data Word Length (Encrypted)
0x4 Extracted Data Word Length (Unencrypted)
0x8 Total Partition Word Length
0x0C Destination Load Address
0x10 Destination Execution Address
0x14 Data Word Offset in Image
0x18 Attribute Bits
0x1C Section Count
0x20 Checksum Word Offset
0x24 Image Header Word Offset
0x28 Authentication Certification Word Offset
0x2C unused (Must be 0x00000000)
0x30 unused (Must be 0x00000000)
0x34 unused (Must be 0x00000000)
0x38 unused (Must be 0x00000000)
0x3C Header Checksum

例によって、odでBOOT.binを見てみる。

000c80 00006002 00006002 00006002 00000000 # 0x00 (zynq_fsbl.elf)
000c90 00000000 000005c0 00000010 00000001 # 0x10 (zynq_fsbl.elf)
000ca0 00000000 00000240 00000000 00000000 # 0x20 (zynq_fsbl.elf)
000cb0 00000000 00000000 00000000 fffed7e8 # 0x30 (zynq_fsbl.elf)

000cc0 000f6ec0 000f6ec0 000f6ec0 00000000 # 0x00 (download.bit)
000cd0 00000000 000065d0 00000020 00000001 # 0x10 (download.bit)
000ce0 00000000 00000250 00000000 00000000 # 0x20 (download.bit)
000cf0 00000000 00000000 00000000 ffd14b7e # 0x30 (download.bit)

000d00 00019090 00019090 00019090 00400000 # 0x00 (u-boot.elf)
000d10 00400000 000fd490 00000010 00000001 # 0x10 (u-boot.elf)
000d20 00000000 00000260 00000000 00000000 # 0x20 (u-boot.elf)
000d30 00000000 00000000 00000000 ff6b774e # 0x30 (u-boot.elf)

特に変なところもなく、以下のことが分かる。

  • u-bootだけ0x0C/0x10のロード/実行アドレスが0x00400000
  • 0x18のAttributeは、bitファイルだけPL(0x00000020)、その他はPS(0x00000010)

(参考)QSPIブートできない現象のデバッグ

s25fl256s1というFlashメモリで起動しようとすると、以下の表示になる。(fsblでシンボルFSBL_DEBUG_INFOを有効にしてシリアル出力させる)

Xilinx First Stage Boot Loader
Release 2017.1  Jul  7 2017-16:40:46
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60400000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000880          <==== 0xC80のはず
Partition Count: 14
Invalid Partition Count
Partition Header Load Failed
FSBL Status = 0xA00E
...(以下Fallback bootの結果)

u-bootやlinuxでQSPIの中身を読んでみると正常に書き込めている。 fsblでは、polled transferをしているようなので、xqspips_flash_polled_example.c(サンプルデザイン)を実行してみる。 printf()爆弾を仕込んだxqspips_flash_polled_example.cで動作確認したところ、

#define FAST_READ_CMD       0x0B
#define DUAL_READ_CMD      0x3B
#define QUAD_READ_CMD      0x6B

のうち、QUAD_READ_CMDがNGであることがわかった。

fsbl内で同様の操作をしている箇所は、qspi.cのFlashRead()であるので、 リードコマンドになるであろう、WriteBuffer[COMMAND_OFFSET]をモニタしてみたところ、 0x04とかいう謎の値が入っていた。

これを以下のように、FAST_READ_CMDにハードコードすることで読み出しできるようになった。

diff -r e93b7f0ac8b0 xsdk/fsbl/src/qspi.c
--- a/xsdk/fsbl/src/qspi.c    Fri Jul 07 16:23:45 2017 +0900
+++ b/xsdk/fsbl/src/qspi.c    Mon Jul 10 09:11:51 2017 +0900
@@ -91,7 +91,9 @@
  * The following constants define the commands which may be sent to the FLASH
  * device.
  */
-#define QUAD_READ_CMD     0x6B
+#define FAST_READ_CMD      0x0B // s25fl256s1 OK
+#define DUAL_READ_CMD      0x3B // s25fl256s1 OK
+#define QUAD_READ_CMD      0x6B // s25fl256s1 NG
 #define READ_ID_CMD            0x9F
 
 #define WRITE_ENABLE_CMD   0x06
@@ -441,12 +443,8 @@
     * Setup the write command with the specified address and data for the
     * FLASH
     */
-  u32 LqspiCrReg;
-  u8  ReadCommand;
-
-  LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr);
-  ReadCommand = (u8) (LqspiCrReg & XQSPIPS_LQSPI_CR_INST_MASK);
-  WriteBuffer[COMMAND_OFFSET]   = ReadCommand;
+   /* XQspiPs_GetLqspiConfigReg()で得られる値がおかしい */
+   WriteBuffer[COMMAND_OFFSET]   = FAST_READ_CMD; // for s25fl256s1
    WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
    WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
    WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

直流安定化電源(TEXIO PDS-Aシリーズ)の電源OFF/ONプログラムを作る

前提

提供されているドライバのAPI調査

  • IF-70GUのドライバのzipファイルが公開されているので中身を眺めてみるが、どうやら、GUIのサンプルしか入っておらず、自作プログラムに組み込むのが面倒くさそう。
  • 一応、上記のドライバをインストールするとC:\Windows\System32\IF_60.dllがインストールされる模様。

なので、IF_60.dllの中にあるAPIコマンドラインから呼べるようにすれば良い。
dll内のAPIpexportsを使えば、以下のように抜き出すことができる。

# `.def`ファイルを作成
pexports IF_60.dll > IF_60.def
# gcc用のライブラリファイルを作成(`dlltool`はmsys2のものを使った)
dlltool IF_60.dll -d IF_60.def -l libIF_60.a

これで、あとはgcc実行時に-L. -lif_60としてdllとリンクすれば良い。

電源ONするサンプル

IF70_on.cとして以下を作成した。(OFFしたいときはOUTPUT 0とすれば良い) コンパイルしたIF70_on.exeを実行すれば電源ONできる!捗る!

#include <windows.h>
#include <tchar.h>

#include <stdio.h>
#include "IF70.h"

#define ADDR (1)

/* msys2でのコンパイルの方法

事前に以下の2つを実行して必要なものをインストールしておく
(コンパイルするPCでは後述の.dllファイル以外は不要)
   PSA_Dr_API310\API\setup64.exe
   PSA_Dr_API310\Driver\Setup64.exe

以下の.dllファイルから、ライブラリファイルを作る
C:\Windows\System32\IF_60.dll

ここからpexportsのWindowsバイナリをダウンロード
https://sourceforge.net/projects/mingw/files/MinGW/Extension/pexports/
以下のコマンドで、.defファイルを作る
   pexports IF_60.dll >IF_60.def

以下コマンドでライブラリファイルを作る
   dlltool IF_60.dll -d IF_60.def -l libIF_60.a

以下のコマンドで実行ファイルを作る
   gcc -o IF70_on.exe IF70_on.c -L. -lif_60
*/

int main(int argc, char *argv[]) {

    int ret;

    // addrを引数に取るが、何を指定するのか不明
    ret = USB488_DeviceOpen(ADDR);
    if (ret <= 0) {
        printf("USB488_DeviceOpen() Error!\n");
        return -1;
    }

    ret = USB488_Send(ADDR, "OUTPUT 1\n");
    if (ret <= 0) {
        printf("USB488_Send() Error!\n");
        return -1;
    }

    ret = USB488_Send(ADDR, "GTL\n");
    if (ret <= 0) {
        printf("USB488_Send() Error!\n");
        return -1;
    }

    USB488_DeviceClose(ADDR);

    return 0;
}