e-tipsmemo

ごった煮

FPGAボードセレクション

昔と違って、それなりのスペックのFPGAが実装された評価ボードが、かなり簡単に手にはいるようになっているので、

  • スペック
  • 開発無料(Vivado webpackで開発できる not ISE)

の点で昔を懐かしみながらまとめてみた。
(面白い評価ボードがあったら、何かを始めてみたいとおもったので)

!!!2021年時点!!!

FPGAボード

純粋にFPGAだけが載っているボードを列挙
KintexとかでもWebpackで開発できるグレードもあるが、多分高いので除く。
HDLを勉強〜とか
Chisel〜とか
CPUつくる〜とかなら
こういうシンプルなボードの方がいい気がする。

Arty A7-35T

これはArtix7 35Tだが
もっとリソースの多いグレードでArty A7-100T(Artix7 100T)というものもある。

かなりシンプルな拡張性しか持っていないので、7セグとかUSBとかHDMIしたいときは回路を作ってつなげる必要がある。(実装されているUSBmicroAコネクタはSerialとJTAG用)

ボード上のピンヘッダはArduino互換の様に見えるが、物理的な位置が同じなだけであって、電源とかGNDとかは微妙に違った気がしなくもない。(そもそも2列なので、使い勝手悪い、Pmodを使ったほうがいい)

確か、Vivado Design Editionのボード限定&1年限定ライセンスコードも付属していた気がする(Arty A7しか開発できないDesign Edition)

評価ボードには小さいゴム足が付いていた気がする。

Nexys A7

Artix7 50TとArtix7 100Tのグレードがある。
Arty A7との差はUSBと7セグと大量のスイッチ。ボードには足がついてた気がする。

Arty S7

こちらはSpartan7という比較的新しいチップを載せた評価ボード。
Spartan6以上Artix7以下という立ち位置。
リソースはArtix7以下だが、価格も低い。
Artix7とどちらを選ぶかという点では価格、PLLの数やDSPの数、Block RAMの大きさというとこも考える必要もあるかもしれない。

DE0 nano

Cyclone4が乗っている。
こちらはTerasicが出しているAltera(intel)のFPGAの評価ボード。昔はDE0とか言うのがあって大きかったしちょっと高かった気がするが、nanoは小さくてよさそう。周辺回路は最低限という感じ。

Quartus Primeという開発環境で行うが基本的なところはVivadoと変わらない気がする。(Quartus 13?以降知らないので)

DE0 CV

Cyclone5が乗っている。
値段的にはDE0の後継っぽい?
周辺回路はそこそこだが、右列のボックスピンヘッダ?はあんまりユニバーサル基板フレンドリーじゃない気がする。

基本的にTerasic直販だと学割が効いた気がする。

AlteraはマルツでEP1C3T100C8Nの評価ボードを買ったのが最初で最後だった記憶。
趣味の人たちはみなXilinxを使っているようだ。(なんでだろう)

CPU+FPGAボード

FPGAとArmコアがくっついてる。
HLSでHWアクセラレータ〜とかコンピューティング〜とかだとこっちのほうがいいかもしれない。
Armのところで簡単にLinuxが動くようなサポートになってたりする。

ZynqやUltra Scale MPSocの評価ボードでリーズナブルなもの
Cyclone V SOCもあるが、インテルはあんまり推して無いのかな。

Zybo Z7

FPGAと一緒にArm Cortex-A9(Dual Core)が入ってるチップが載っている。
(前のバージョンはHDMI Sinkの代わりにAnalog RGBが載っていた)
Zynq-7010よりZynq-7020のほうがリソースが多い。

Artix7と違って、これのEth, USB, SDIOあたりは、Armコアのペリフェラルに直接繋がっている。

ネジ穴に足がついてた気がする。

Arty Z7

Arty A7やS7と紛らわしいが、Zynqが載っているバージョン。
Zyboの廉価版?
zynq 7010かZynq 7020のグレードもある。
Pmodの代わりにHDMI Sink/Sourceがある。

PYNQ Z1

store.digilentinc.com

Arty Z7のピンク色Ver?
細かく見ていないのでArty Z7との違いは分からないが、(USBの向きが違う)
Digilentのストアで学割が効くので、学生でzynqボードがほしいならこれが最安かもしれない。
PYNQ-Z2もあるが別のメーカーが出しているようだ。(オーディオCHIPが乗っていることとラズパイがつながるヘッダーが乗っている。いるか?)

Ultra 96V2

www.avnet.com
ZYNQ UltraScale+(zynqMP)の評価ボードで
Zynq UltraScale + MPSoC ZU3EGを載せている。
Webpackでも開発できるグレード。

TE0802

akizukidenshi.com
これもZYNQ UltraScale+だがUltra 96よりは周辺機器がついていてなんか良さそう。
HDMIじゃないのが残念。
XCZU2CG なのでUltra 96のグレードよりは1個下?

MPSocはCortex A53とCortex A9とMicroblazeが入っている。
LinuxをブートするためにVivadoとは別に、Petalinuxとかいうものをインストールしなければならないのが苦痛(もちろんしなくても出来るかもしれないがとても面倒くさそうだった)

DE1-Soc

www.digikey.jp
AlteraのFPGA-SocでCyclone V Socが乗っており周辺回路も豊富

DE10-nano

www.digikey.jp
昔はなかった気がする。安い。

FPGA(Soc)+α

本当はSDRボードを調べていたのでついでにFPGAボードもまとめただけ。
やっぱりFPGA単体では、それ上で完結してしまう...ということで、SDR方面で探すと、面白いボードもいくつかあったりする。

ADRV9364-Z7020

www.digikey.jp
AD9364というチップがすごくて、割とワイドバンドなTRXをワンチップで乗せている。LVDSが出ててそれがFPGAに直結している。
もう一個上のグレードでAD9361+Z7035という組み合わせがあるがこれはTRXが2x2でMIMOとかもできるのだが、Z7035はWebpackでは開発できない。

このボード単体だと意味をなさなくて、下側につけるキャリアーボードが必要。ピンヘッダもついていていい感じ?
ADRV1CRR-BOB Analog Devices Inc. | RF/IFおよびRFID | DigiKey
とか
ADRV1CRR-FMC Analog Devices Inc. | RF/IFおよびRFID | DigiKey
microSDがついてきた気がするが、Debianがインストールされていた。

AD9363 + Z7010という構成だとADALM-PLUTOの構成となる。(AD9364はAD9363の選別品らしい?)
ADI ADRV936x System on Module (SOM) SDR [Analog Devices Wiki]
サポートページ

FreeSRP

freesrp.org
さすがにADRVのやつは高いなってなると、Artix7と接続したSDRボードがあった。
拡張性は背の低いコネクタが一つだけ。
USB3.0で接続できるらしい。
アクリル板もある。

LimeSDR

wiki.myriadrf.org
MAX10とTRXチップで構成されているやつ
評価ボードというよりはすでに構成されているものとして、GNURadioで何かを受信しましょうという感じかもしれない。


他にもUSRPというワードで検索すると高いのか安いものがでてくるが、安いほうだとSpartan6で、Vivadoでは開発できないので、除外した。

感想

記事を書き上げてから、こんな記事書くまでもなく、英語で調べればでてくるなと思った。
Cheap FPGA Development Boards | Joel's Compendium of Total Knowledge

それなりの値段でFPGAが買えるし開発環境も無料だし調べれば無料だしいい時代だなと思った。
ただVivadoのインストールで要求する容量が尋常じゃない(Petalinuxとは別)上に、
ビルドで細かいファイルをたくさん作りまくるので、評価ボードよりも大容量SSDとか買ったほうがいい気がする。

libiio rust binding for Windows

前置き

ADALM PLUTOからデータをもらうのに、用意されている方法として、Industrial-ioを使用する方法がある。
Linux Industrial I/O Subsystem [Analog Devices Wiki]

組み込み機器が得たデータを簡単にPCとやり取りできる。
(組み込み機器上でLinuxが動いていたら簡単、Busyboxも可、ベアメタルではなさそう。)
物理層をラップしてくれる(速度の問題はあると思うが)

Windowsのドライバもあって、コマンドで簡単に接続を確認できる。
f:id:katakanan:20210516221649p:plain
これを利用している測定器が、
ADALM2000 評価用ボード | アナログ・デバイセズ

PythonC#バインディングがった。
RustではLinux向けにはあったが、Windowsでは動かなかった。
そこでdllをダイナミックにロードするcrateを使用してWindowsで動くように変更した。

但し、前回動作を確認したdlopenは使用せず、windows-dllを使用したところ、より簡単に実現できた。
https://github.com/katakanan/rust-industrial-io

本当はConditional Compilationを利用して、linux向けにもビルドできるようにもしたかったが、nix crateに依存していて、これに対応するWindowsの動作が分からなかったので、
それっぽく置き換えて、とりあえずWindowsだけでビルドできるようにした。

サンプルコード

autodetectでbackendを指定しなければ、接続方法に関わらず、接続方法を列挙する。(iio_info -sと同じ)

#[test]
fn autodetect() {
    let _ = iio::Context::autodetect_context(false, "", "");
}

####

backendを指定して、見つかったものが1つだと接続できる。
名前とdescriptionを得る。

#[test]
fn usb_scan() {
    let scan = "usb";
    let ctx = iio::Context::autodetect_context(true, "", scan).unwrap_or_else(|err| {
        eprintln!("Error find {} context: {}", scan, err);
        std::process::exit(1);
    });

    println!("{}", ctx.name());
    println!("{}", ctx.description());
}
running 1 test
Using auto-detected IIO context at URI
usb
Linux (none) 5.4.0-212055-gb05d16429dac #403 SMP PREEMPT Tue Mar 30 12:57:31 CEST 2021 armv7l
test usb_scan ... ok

対象の機器のデバイスから電圧データを得る

バイスというのは1個の機器に対してぶら下がっているコントロールされる個々の機能だと思う
DDSとかphyとかADC..etc
(iio_attr -u usb:x.xx.x -s -B で分かる)

fn main() {
    println!("Hello, world!");
    let scan = "usb";
    let ctx = iio::Context::autodetect_context(true, "", scan).unwrap_or_else(|err| {
        eprintln!("Error find {} context: {}", scan, err);
        std::process::exit(1);
    });

    let dev = ctx.get_device(0).unwrap_or_else(|err| {
        eprintln!("Error opening first device: {}", err);
        std::process::exit(1);
    });

    let unknown = "unknown".to_string();
    let tick = periodic(Duration::from_millis(1000));

    println!("Device: {}", dev.name().unwrap_or_else(|| unknown.clone()));

    for chan in dev.channels() {
        if chan.has_attr("raw") {
            print!(" {:>9}", chan.id().unwrap_or_else(|| unknown.clone()));
        }
    }
    println!();

    loop {
        tick.recv().unwrap();
        for chan in dev.channels() {
            if let Ok(val) = chan.attr_read_int("raw") {
                print!(" {:>8} ", val);
            }
        }
        println!();
    }
}
Hello, world!
Using auto-detected IIO context at URI
Device: ad9361-phy
  voltage3  voltage2  voltage2
      306       306      1523 
      306       306      1520 
      306       306      1517 
      306       306      1518 
      306       306      1518 
      306       306      1524 
      306       306      1520 
      306       306      1522 
error: process didn't exit successfully: `target\debug\readpluto.exe` (exit code: 0xc000013a, STATUS_CONTROL_C_EXIT)

どこかの電圧を連続で読み取る。

うまくいっているようだ。

Import dll from Rust dinamically

RustのFFIでdllを使う方法として、

#[link(name = "my_c_library")]
extern "C" {
    fn my_c_function(x: i32) -> bool;
}

extern - Rust
ただ.libが無いと言われてしまった。
windows - Rust linker seeks a LIB, rather than a DLL - Stack Overflow

代わりに、dllを動的にインポートするcrateを使用した。

loading dlls in rust : rust

dlopenがシンプルそうなので、
Windowsでどのように使用するのかテストした。

DLLをテストする(from C++)

公式チュートリアルは.libがある前提の書き方なので、
動的にロードして使う時は、以下を参考にした。
【C++/C#】C++で作成したDLLをC#で呼ぶ - Qiita

#include <iostream>
#include <windows.h>

typedef void(*FUNC1)(const unsigned long long a, const unsigned long long b);
typedef bool(*FUNC2)();
typedef unsigned long long(*FUNC3)();
typedef unsigned(*FUNC4)();

int main()
{

	HMODULE hModule = LoadLibrary(L"testdll.dll");
	if (NULL == hModule)
	{
		std::cout << "Failed to load dll!\n";
		return 1;
	}

	FUNC1 fibonacci_init = (FUNC1)GetProcAddress(hModule, "fibonacci_init");
	FUNC2 fibonacci_next = (FUNC2)GetProcAddress(hModule, "fibonacci_next");
	FUNC3 fibonacci_current = (FUNC3)GetProcAddress(hModule, "fibonacci_current");
	FUNC4 fibonacci_index = (FUNC4)GetProcAddress(hModule, "fibonacci_index");

	std::cout << "Hello World!\n";

	// Initialize a Fibonacci relation sequence.
	fibonacci_init(1, 1);
	// Write out the sequence values until overflow.
	do {
		std::cout << fibonacci_index() << ": " << fibonacci_current() << std::endl;
	} while (fibonacci_next());
	// Report count of values written before overflow.
	std::cout << fibonacci_index() + 1 << " Fibonacci sequence values fit in an " << "unsigned 64-bit integer." << std::endl;
}

GetProcAddressが失敗したときのチェックをした方がよいかもしれないが、とりあえず動いたので良し。

Rust dlopenを使う

dlopenのdocを参考に、
dlopen::symbor - Rust

extern crate dlopen;
#[macro_use]
extern crate dlopen_derive;
extern crate libc;
use dlopen::symbor::{Library, SymBorApi, Symbol};
use libc::{c_char, c_ulonglong};

#[derive(SymBorApi)]
struct FibApi<'a> {
    pub fibonacci_init: Symbol<'a, unsafe extern "C" fn(c_ulonglong, c_ulonglong)>,
    pub fibonacci_next: Symbol<'a, unsafe extern "C" fn() -> c_char>,
    pub fibonacci_current: Symbol<'a, unsafe extern "C" fn() -> c_ulonglong>,
    pub fibonacci_index: Symbol<'a, unsafe extern "C" fn() -> u32>,
}

fn main() {
    let lib = Library::open("testdll.dll").expect("Could not open library");
    let mut api = unsafe { FibApi::load(&lib) }.expect("Could not load Symbols");

    println!("Hello, world!");

    unsafe { (api.fibonacci_init)(1, 1) };

    while {
        let index = unsafe { (api.fibonacci_index)() };
        let current = unsafe { (api.fibonacci_current)() };
        println!("{}:{}", index, current);
        let ret = unsafe { (api.fibonacci_next)() };
        ret != 0
    } {}

    let index = unsafe { (api.fibonacci_index)() };
    println!(
        "{} Fibonacci sequence values fit in an unsigned 64-bit integer.",
        index + 1
    );
}

f:id:katakanan:20210509212102p:plain

DLLが
32bitの時は、i686-pc-windows-msvcで
64bitの時は、x86_64-pc-windows-msvcでビルドする。

関数の引数や、戻り値の型はlibcの定義を使用した方が間違いがないが、boolなど無いものもある。
windowsに使われている型は以下のようになっているらしいので、
データ型の範囲 | Microsoft Docs
もしlibc crateに定義されていない型があっても、これを参照してビット幅などを合わせておけば大丈夫だと思われる。

なので、boolなら1byteなので、とりあえずc_char
unsignedはunsigned intと同じなので、u32


とりあえずDLLをインポートできるということはわかったので、
次は本当に使いたいAPIのDLLが利用できるかを試す。

      • 追記----

rustにもbool型があったのでそれを使えばよかった。
Types · A Guide to Porting C and C++ code to Rust

PythonでFMを直交復調を試す2

以前、PythonでFM復調を試した、
そのとき、変調指数が大きいときは素朴に、位相の差分を取るところで特別な処理を入れて対処していたが、
Interfaceを読んで、直交復調を真の意味で?活用することでその問題を回避できるということを確認した。

e-tipsmemo.hatenablog.com

# arctan & diff
phi_sig = np.ndarray(0)

for index, (i, q) in enumerate(zip(bbi2, bbq2)):
    if index == 0:
        continue

    xn = bbq2[index-1]+1j*bbi2[index-1]
    xm = q + 1j*i
    phi_sig = np.append(phi_sig, np.angle(xn*np.conj(xm)))

demod = phi_sig

分かりやすい図がInterfaceのp80に乗っている。
QとIから①位相を求めてから②差分を取るのではなくて、
複素数の掛け算で②差分を取ってから、①位相を求める。

またpythonなら

demod = np.angle(samp[1:]*np.conj(samp[:-1])

こうも書けるらしい

複素数の掛け算による偏角の差が十分に小さく
(信号周波数にたいしてサンプリング周波数が十分に大きいので)
π/2以上になることがない。
変調指数が小さくても大きくても同様の処理で行える。

その他

復調信号のノイズはサンプリング周波数とフィルターでうまい組み合わせによる?

f:id:katakanan:20210505200513p:plain:w300f:id:katakanan:20210505201059p:plain:w300
Interface(インターフェース) 2021年 5 月号

Interface(インターフェース) 2021年 5 月号

  • 発売日: 2021/03/25
  • メディア: 雑誌

VNWA3Eを再セットアップする

本来はベクトルネットワークアナライザだけど
スペアナみたいに使えたりもする。
昔買ったVNWA3Eをセットアップし直す。
https://www.sdr-kits.net/documents/VNWA_W10_W8_W7_Installation.pdf

ADALM-PLUTOに付属していたアンテナを単に突き刺して
S11を見てみた。
https://wiki.analog.com/_media/university/tools/pluto/users/jcg401.pdf

f:id:katakanan:20210428231732p:plain
あんまり合っていない?
SWR値はどのくらいまで大丈夫?SWR値から分かる反射波電力の割合。 – beizのノート

本当はこんなふうにGNDを用意して測定すべきもの?
http://www.rf-world.jp/bn/RFW39/samples/p083-084.pdf

時間があればもっと他の物を測ろうと思う。

VNWAは前はSDR-Kitから直接買ったが、その時は外貨が安かった時だった気がする。
今は高い。
AmazonにはVNWAは売っていなかったが、前には存在しなかったようなお手軽なVNAが売っていた。
S22とS12は測れないようだ(逆につなげばいいだけだけど)

ついでにSMAのトルクレンチもあったらいいかもしれないと思ったけど高い高周波でもないので指でいいか,,,,

Pythonでwavファイルを作る。

InterfaceでwavファイルをFM変調をする章があるが、
いきなり曲を変調するのではなく、
まずは単音を変調してスペクトラムなどを確認しようと思う。
そのためにwavファイルを準備する。

モノラルwavファイル作成

まずモノラルのwavファイルを出力する方法は出てきて、
[python] sin波の音をWAV形式で出力する - Qiita


そのままではあまりにもつまらないので、周波数を確かめる。

f:id:katakanan:20210501190631p:plain
0.1秒なので、4410点の波形と、fs/2までのスペクトラム

ステレオwavファイル作成

次に、ステレオのwavファイルを出力する方法ためには、
LRLRLR...と並べればよいだけらしいので、

となるだけなのと、

出力パラメータが

#(チャンネル数(1:モノラル,2:ステレオ)、
#サンプルサイズ(バイト)、
#サンプリング周波数、
#フレーム数、
#圧縮形式(今のところNONEのみ)、
#圧縮形式を人に判読可能な形にしたもの?通常、 'NONE' に対して 'not compressed' が返されます。)

であることに気をつけて

となる。

f:id:katakanan:20210501191527p:plain

これで
左から440Hz
右から220Hz
の音が出るwavファイルができる。

Interface(インターフェース) 2021年 5 月号

Interface(インターフェース) 2021年 5 月号

  • 発売日: 2021/03/25
  • メディア: 雑誌

Vector Network Analyzer の調査

オシロスコープは中国でもすごいものがたくさんでてきているので、
今度はVNAだろうということで調べた。
(スペクトラムアナライザーは結構あるので、VNA対象)

SAA2 NanoVNA V2

まず適当にAmazonで検索するとでてくるVNAの一例

前に見たときは赤い基盤がむき出しだった気がするが、ケース付に進化している。

おそらくこれが中に入っているのではないかと思う。
2.8"LCD SAA-2N NanoVNA V2.2 3G Vector Network Analyzer VNA HF VHF UHF 50KHz~3GHz | eBay

S12,S22は測れないが、価格にわりに、測定範囲が広い。
バッテリー内臓らしいので、もしかしたら海外から直接買えない?(もしリチウムイオン電池なら)

Amazonで買うよりもAliexpressで買う方が、$30~$50ぐらい安い。
1万円ぐらい

VNA-PR1

次はAmazonには売ってなくてAliexpress/ebayで見つけたVNA
www.ebay.com
3.2インチのタッチスクリーンで
上のよりも、5倍の値段がするが、
ケースもしっかりしていそうで、6GHzまで測れる。
S12,S22は測れない
バッテリー内臓らしいのでSAA2と同様に海外から送れないかもしれない?(もしリチウムイオン電池なら)

http://arinst.ru/files/2114-ARINST-VNA-PR1/User-manual-ARINST-VNA-PR1-1-6200_ENG.pdf
STM32を使っているらしい。
5万円ぐらい
(最初ANRITSUかと思った)

miniVNA Tiny

webshop.tupartners.com
1MHz~ 3GHzと結構広い
VNWA3Eと迷った記憶がある。
S22、S12が測れない。
かなり小さいのはよさそう。
6万円ぐらい?

VNWA3E

DG8SAQ VNWA 3 and 3EC Low Cost Vector 1.3 GHz Network Analyzer VNA
今持っているやつ。
1GHz超えてて、S22、S12も測れるという点だけで、頑張って買った気がする。
ただ500MHzを超えての範囲は、DDSをオーバークロックして使っているので精度がどうとかいう免責事項がある。
イギリスから直接買った。
ちょっと?高い。
8万円~10万円ぐらい

RIGOL RSA3000N

中々低価格帯はないので、もう少し出すとここら辺になる。
www.rigolna.com
黒いほうが格好いいが高い。

RSA3000 Real-Time Spectrum Analyzers | RIGOL
1.5GHzまでの一番安いものでも18万なので高い。
S22は測れない?
VNA App Note | RIGOL
筐体もしっかりしていそうだし、おもしろい機能として、ASKやFSKを復調できるらしい。(オプション)
将来的にはQAMとかも見れるようになるのかな?

感想

オシロスコープはすでに中国のメーカーもいろいろとあって、敷居が低くなっているが、
VNAはそこまで必要でもないからか、あんまりなさそう?
(スペクトラムアナライザで十分なのかもしれない)

ポートを逆につなげる手間を惜しまなければ、VNA-PR1あたりがよさそう。
昔なんでS22とS12にそんなにこだわってVNWA3Eを買ったのか全然覚えていない。

というかVNWA3EあるけどVNA-PR1が欲しくなってきたかもしれない(単に周波数が広いという理由で)
もしくはRIGOLがすごいエントリー機を出してくれないかと期待している。

以前オシロスコープの時にでてきたOWONやHantekはVNAを売ってなかった。