ラベル Raspberry pi の投稿を表示しています。 すべての投稿を表示
ラベル Raspberry pi の投稿を表示しています。 すべての投稿を表示

2026年7月3日金曜日

RP2040 zero どうだかねぇ?

中華通販で¥400ぐらいで買ってみたRP2040-zero、さっそくLチカからやってみよう.といいつつも、Arduino nanoのようにUSBを繋いでBLINK example sketchでRUNとは簡単にいかなかったのであった・・・・

感想:

安くていい、小さくていい、しかしこの一品で俺はもう他に浮気しないと惚れるほどではなかった.開発環境も含めた総合的な事情で今後もSTM32を多く使うだろう.

内蔵DACをつかって信号発生器として使いたかったのだが、DACが内蔵されていなかった.ぎゃふん

DAC以外のperiheralは一通り載っているみたい

ADCも載ってる
ADCはTIMERによるトリガに依らずとも、ADC自体がclk分周周期で自走してDMAでメモリに積んでくれるみたいで便利っぽい

演算speedは不明
FPUが載っているか? →AIによると載ってない →そんなに高速ではないだろう

ボード回路図(pdf)

FLASHは16MBitのシリアルFLASHである、いかがなものか?

内蔵SRAMは264KB、、、案外大きいと思った

onboard LEDは3色LEDで、秋月でも売ってる.制御はチト特殊.WS2812B
それゆえ、いつもの単純なBLINKでは動かない.

USBは1.1.デバイスはもちろんだがホストにもなれるんですって.

焼く時はBOOTボタンを押しつつUSBケーブルを接続する.

開発環境は純正toolがあるようだが、Arduino IDEを地雷多数で使いこなすことになるのが一般的なのだろう.
↓こんなcodeで3色Lチカなのはちょっちかったるい
#include <Adafruit_NeoPixel.h>

// On the Waveshare RP2040-Zero, the onboard NeoPixel is tied to GPIO 16
#define NUMPIXELS    1  // There is only 1 onboard LED

// Initialize the NeoPixel library
Adafruit_NeoPixel pixel(NUMPIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

void setup() {
  pixel.begin(); // Initialize the NeoPixel hardware
}

void loop() {
  // Turn LED Red
  pixel.setPixelColor(0, pixel.Color(255, 0, 0)); // (Pixel index, R, G, B)
  pixel.show();                                  // Update the physical LED
  delay(500);                                    // Wait 0.5 seconds

  // Turn LED Green
  pixel.setPixelColor(0, pixel.Color(0, 255, 0)); 
  pixel.show();                                  
  delay(500);                                    

  // Turn LED Blue
  pixel.setPixelColor(0, pixel.Color(0, 0, 255)); 
  pixel.show();                                  
  delay(500);                                    

  // Turn LED Off
  pixel.setPixelColor(0, pixel.Color(0, 0, 0));   
  pixel.show();                                  
  delay(500);                                    
}

かしこ

2019年10月21日月曜日

Rapsberry-pi 搭載CPUのI2Sのdatasheetを読んでみる

AK4495でDSD再生をしたいと思っている.

しかしラズパイが出力するDSD仕様とAK4495が受信するDSD仕様には違いがあり、こちらでその違いについて検討した.
何らかの方法でその違いを吸収しなければならない.上のリンクではハードウエアで違いを吸収しようかなと結論した.
吸収するべき違いはこの3つである.
 1) Fsに応じて、master clockの切り替え、およびLRCK/BCK生成
 2) DSDかPCMかの監視
 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける

その後、PLDで3つの機能を組んでみたのだが、XC9572XLのような最底辺PLDでは容量不足だと判明した.XC95144XLが必要だった.な~んかかったるい.100pin TQFPなんか半田づけしたくねぇよ.

100pin TQFPを回避して、ラズパイのI2Sデバドラを自分で改造するやり方も考えてみるか、、、というわけで、ごにょごにょと調べているというのが現状である.

今回は、Raspberry pi 3B+に載っているCPUチップ BCM2837 のI2S仕様がどうなっているのかを調べてみた.

なお、以降ではI2Sについては細かく述べないので、軽く触れておくとこんな4本線のシリアルバスでステレオ音声の伝送に使われるのがI2Sだ.
 BCK               64fsだったり32fsだったりする
 LRCK             fs
 DATAOUT       DACへ行く音声データのシリアライズされた信号
 DATAIN          ADC用途なのでここでは使わないので無視


------
ラズパイ3のCPUチップはBCM2837であるが、datasheetが見つからない.
BCM2835というラズパイ2に載っているCPUチップのdatasheetならネットに在った.これを読んでみる.ペリフェラルはBCM2837と同じだと思う.
https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf


I2S IFのブロック図
FIFOがある.PCM dataを一定テンポで入出力してくれるように見受けられる.
外部ピンはPCM_CLK/PCM_FS/PCM_DIN/PCM_DOUTの4本である.
以下ではこれらをBCK/LRCK/DATAIN/DATAOUTと呼ぶ.DATAOUTは単にDATAとも呼ぶ.


I2Sピンアサインを変えられるか?
ラズパイのI2S ピンとしてよく見かけるのは、GPIO18~21にアサインされたこの絵である.これらを任意のピンに移動できるのだろうか?

残念ながらI2Sピンアサインの自由度はほとんどない.

GPIOのピンアサインは6種類(ALT0~ALT5)のいずれか、すなわち一括変更しかできないのだ.そしてこの6種類の中で、I2Sピンが存在するのはALT0とALT2だけ.その結果、I2Sピンはこの二者択一ということになる.
 ALT0   GPIO18~21    通常はこちら
 ALT5   GPIO28~31


I2S信号はどんだけプログラマブルか?
 ・DATAは常にMSB firstでserial出力される
 ・LRCKの位置と長さは任意に設定できる
 ・DATAは8~32bit幅で任意に設定できる
 ・BCKとLRCKはそれぞれ独立にin/out、slave/masterを設定できる
 ・通常は、DATAとLRCKはBCKの立ち上がりedgeで変化する
 ・BCKの極性を反転できる


I2S IF内部仕様
 ・FIFOは64段x32bitで、TX/RX独立にある
 ・FIFO稼働中にregisterを変えちゃいかん(EN、TXONは例外)
 ・ENはpowersave、TXONで出力オン
 ・送信FIFOが空になると、TXERRエラーフラグが立つが、停まりはしない
 ・TXFIFOが空になるとゼロが出力される
 ・FIFOデータは右揃えゼロ埋めで書くこと
 ・LchとRchで別個にFIFOに積むこと
 ・レジスタアドレスは、0x7E203000 から開始される
 ・32bitレジスタが9ヶある
  Offset
  0x0    CS_A     PCM Control and Status
  0x4    FIFO_A   PCM FIFO Data
  0x8    MODE_A   PCM Mode
  0xc    RXC_A    PCM Receive Configuration
  0x10   TXC_A    PCM Transmit Configuration
  0x14   DREQ_A   PCM DMA Request Level
  0x18   INTEN_A  PCM Interrupt Enables
  0x1c   INTSTC_A PCM Interrupt Status & Clear
  0x20   GRAY     PCM Gray Mode Control


ここまでで3つの機能をデバドラ改造で実現できるか?
 1) Fsに応じて、master clockの切り替え、LRCK/BCK生成
これはたぶんできるだろう.I2S IFにそういう機能があるからだ.

 2) DSDかPCMかの監視
source codeのどこかには、DSD再生を制御している部分があるはず.

 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける
ざんねーん、これは絶対に不可能だとわかった.


volumioのsource codeからI2S制御してるやつを探す
sourceの入手やビルド環境については、こちらを参照のこと.

I2Sのsource codeはこれである.レジスタ制御なんかもこれに記されている.
/usr/src/rpi-linux/sound/soc/bcm/bcm2835-i2s.c

paramsという構造体がFsなどの情報を格納しているようだ.
struct snd_pcm_hw_params *params,
出来合いの関数を利用するとparamsから情報をGETできる.
  int fs = params_rate(params);        44.1kHzとか
  int bit = params_width(params);     24bitとか
  snd_pcm_format_t  fmt = params_format(paras);     数字の0~50ぐらい

ラズパイのGPIOから外部へFs/bit/fmtを知らせることができる.
外部回路としては、このような対応が可能だ.
 ・Fsがわかれば、LRCK周波数を決定できる
 ・bitがわかれば、BCK周波数を決定できる
 ・fmtがわかれば、DSDかPCMかを決定できる

GPIO制御などについては先達がいる.「やまちゃんのオーディオブログ」という人.
こちらの記事の、
ラズベリーパイのi2s外部クロック、その後8(2018年度版)
こちらのsource codeにわたしがやりたいようなことが書かれている.
https://audio-blog.jp/wp-content/uploads/2018/04/bcm2835-i2s.c


I2Sデバドラを改造してI2Sデバドラの内部状態を表示させた
printk()を使ってI2Sデバドラのfs/bit/fmtを表示させた.

44.1kHz 16bitのCDファイルを再生  →  fs=44100  bit=16  fmt=2
fsとbitは妥当な表示である.
fmtの2番は、SNDRV_PCM_FORMAT_S16_LE を意味している、妥当.

176kHz 24bitのHiResファイルを再生  →  fs=176400  bit=24  fmt=6
fmtの6番は、SNDRV_PCM_FORMAT_S24_LE を意味している.

352kHz 24bitのHiResファイルを再生  →  fs=192000  bit=24  fmt=6
ALSAの制限により352kHzを192kHzに下げているのがわかる.

さて、DSDを再生したらどうなるか?
DSD64 2.8MHz DSDファイルを再生  →  fs=176400  bit=24  fmt=6
うぅ、これはわからん.fmtは6番のままだ.これが50番ぐらいになってくれればDSDを捕捉できたことになるんだがなぁ.ただしDoPの仕様に従えば見かけ上は176k24bitで正しいのかもしれない.DoPについてはこちらを参照.

DSD128 5.6MHz DSDファイルを再生  →  fs=192000  bit=24  format=6
これはダメだ.ALSAの制限でPCM192kに落とされている.


ここまでで3つの機能をデバドラ改造で実現できるか?
 1) Fsに応じて、master clockの切り替え、LRCK/BCK生成   → できそう
 2) DSDかPCMかの監視   → 不明、別のsourceを探す必要あり(MPD側かも)
 3) LRchがインターリーブされたDATAを、DSDL/DSDRの2本線に分ける   →  無理

どのみち3番目の機能にはFPGAが必要なので、デバドラを改造する意味が薄い.....

今宵はここまでにしとうございます.

かしこ

2019年10月13日日曜日

Raspberry-piにてvolumio2のビルド環境を整えてみる

volumio2のkernelをビルドしてみたい.

正確にいうと、これを書いている時点で最新のvolumio2のOS上(ラズパイ)で自作moduleをコンパイルする環境を整えたいということなんだ.

ところがいろいろと地雷がありましてな.
・最新volumio2 kernel version 4.19.60のsourceが見つからないよ
・githubの最終upは4.9.xであるようで、そこからDLしたsourceだとmoduleをinsmodできなかったりしてうぎゃぎゃ
・kernel buildをせずに済ますため、apt-get install raspberry-kernel-headers みたいなことをやるのがお馴染みだけど、これで取得できるkernel versionも古くて使えないんだ
・ラズパイvolumio2のビルドで困っている人は多くないらしく、ネットの情報が少なく、また分散的である

台風19号が日本列島周辺をうろついてる間にこればっかりやっとたよ.

以下はその苦闘の結果得られたラッキー結果だ.クロスコンパイルはしない.

【ラズパイ volumio2の環境】
以下に書く情報は、これを書いている2019年10月の最新ラズパイvolumio2を使っている.ラズパイのハードウエアは3+Bとかそんなもの.

Linux volumio 4.19.60-v7+ #1247 SMP Thu Jul 25 14:41:19 BST 2019 armv7l
                       ___
                      /\_ \                        __
         __  __    ___\//\ \    __  __    ___ ___ /\_\    ___
        /\ \/\ \  / __`\\ \ \  /\ \/\ \ /' __` __`\/\ \  / __`\
        \ \ \_/ |/\ \L\ \\_\ \_\ \ \_\ \/\ \/\ \/\ \ \ \/\ \L\ \
         \ \___/ \ \____//\____\\ \____/\ \_\ \_\ \_\ \_\ \____/
          \/__/   \/___/ \/____/ \/___/  \/_/\/_/\/_/\/_/\/___/

             Free Audiophile Linux Music Player - Version 2.0

          C 2015 Michelangelo Guarise - Volumio Team - Volumio.org

uname -a
Linux volumio 4.19.60-v7+ #1247 SMP Thu Jul 25 14:41:19 BST 2019 armv7l GNU/Linux

mpd -V
Music Player Daemon 0.20.18 (128d910-dirty)


【ラズパイvolumioの調達とインスト】
これを使った.
volumio-2.599-2019-08-02-pi.img
ここからDLした.
https://volumio.org/get-started/

SDに焼く方法の説明は割愛.
めでたく起動できたとする.
ログインしよう.
login: root
pass: volmio     ←初期パスワード

【お好みでtoolをインスト】   不要な人はしなくてもいい
% apt-get update
% apt-get install ftpd  ftp  telnet  telnetd      ←適宜Yを打つ必要あり
/etc/ftpusers  をeditorで編集し、rootを削除
/etc/securetty  をeditorで編集し、末尾にでもpts/0とpts/1を追加
% shutdown -r now

【ビルドツールをインスト】
volumio環境には開発ツールがあまりインストされてないようだ.gccもmakeも入ってないので入れる.適宜Yを打つ必要あり.
% apt-get install git bc bison flex libssl-dev
% apt-get install libncurses5-dev
% apt-get install gcc make

【ソースをdownloadする】
冒頭で書いたように、最新volumio2のkernel versionは4.19.60-v7+なのである.
しかし、githubから取ろうとしても4.4.xが取れてしまったり、revisionを選んでも4.9.xまでしか無かった.
困っていたら、あまり知られていないかもしれない凄く簡単なやりかたがあるのだった.
% volumio kernelsource         ←これは偉大な神コマンド!
この後に、/usr/src/rpi-linux にsource一式ができあがる.
Makefileをみると、versionは4.19.60になっている.めでたい.
VERSION = 4
PATCHLEVEL = 19
SUBLEVEL = 60

【sourceにリンクを張る】
現行kernel versionを表示する.
% uname -r
4.19.60-v7+
リンクする.
% cd   /lib/modules/4.19.60-v7+         ←kernel versionに等しい場所へ行く
% ln -s   /usr/src/rpi-linux  build          ←DLしたsourceの場所をbuildにリンク!

↑これやらんでもいいみたい.rpi-linuxを得た時点でリンクが張られてるため.

【お試しbuildしたい人だけ】
moduleをコンパイルしてinsmodなどするだけならkernelのrebuildとreinstallは不要なのだが、動作確認したければどうぞ.数時間もかかるよ.buildの前には.configを用意せにゃいかんが、すでに入ってるので悩む必要なし.便利だね.
% cd  /usr/src/rpi-linux
% make

【簡単なサンプルmoduleの試運転】
rootでログインし、/rootに作業ディレクトリを作る.
% cd /root
% mkdir test
% cd test

editorでMakefileを作る.
obj-m := test.o
KDIR    := /lib/modules/$(shell uname -r)/build
PWD     := $(shell pwd)
VERBOSE = 0
all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        rm -f *.o *.ko *.mod.c

editorでtest.cを作っておく.insmod時にkermel messageを出すだけのもの.
#include <linux/module.h>
MODULE_LICENSE("GPL v2");
static int mymodule_init(void) {
        printk(KERN_ALERT "Hello world!\n");
        return 0;
}
static void mymodule_exit(void) {    /* Do nothing */   }
module_init(mymodule_init);
module_exit(mymodule_exit);

moduleをコンパイルする.
% make
% modinfo test.ko
filename:       /root/test/test.ko
license:        GPL v2
depends:
name:           test
vermagic:       4.19.60 ARMv7 p2v8      ←4.19.60になっておる
% insmod   test.ko      ←moduleを組み込む
% dmesg
[39935.415667] Hello world!        ←kernel messageが出てるのでOK
% rmmod  test    ←moduleを取り下げ



【追記:make installでトラブル多数あり】
上の簡単なmoduleは無問題だったが、既存のI2S moduleを単品コンパイルして組み込んだところ、動かなかった.稼働中のKernelと、単品コンパイルしたmoduleには依存関係に齟齬が在るようだ.(問題1)

そこで、rpi-linux配下のKernelとmoduleを全てリビルド → make install というマトモなやりかたを試みた.

ところがここでvolumioのSD構成にまつわるトラブルが発生する.(問題2)
make installが停まってしまうのだ.
原因は簡単明快、/bootが64MB割り当てられているのだが、既存ファイルが領域を100%使い切っていているため、新しいKernelをコピーできないのだ.

/bootの容量を拡張しなければならない.

それには別のLinuxマシンにSDを挿してGPartedでpartitionを移動などするのだが、詳細は割愛する.この辺のページを参考にしてどうぞどうぞ.

ただしここにも地雷が.Partitionのサイズ変更・移動にあたってはMB表示で操作するとしくじる確率が非常に高い.かならずシリンダー数表示で操作することをオススメする.(問題3)

なお、ネット情報にはext4fsのpartition移動ができないと書かれているものもあるが、これを書いている時点のGPartedはext4fsも移動できたよ.

/bootを200MBほどに拡張できvolumioの起動もできたが、ここまででヘトヘトなわたしだ.

ところがまだトラブルがある.make installするとまた停まる.
% make install
/bin/bash ./arch/arm/boot/install.sh "4.19.60-v7" .......
Makefileが参照する4.19.60-v7なんつうdirectoryは存在しないのだ.(問題4)
なぜなら、uname -rで表示されるのは4.19.60-v7+なのだから.どういうわけか末尾の+が消えちゃうんだね.

Makefile冒頭に「-v7+」を追加してみたが治らない.
VERSION = 4
PATCHLEVEL = 19
SUBLEVEL = 60
EXTRAVERSION = -v7+

仕方ないので、/lib/modules の下でリンクを張ってみたらmake installが動くようになったよ.
   4.19.60-v7 -> 4.19.60-v7+

volumioは開発用ディストリでなく、コンパクト志向で調整されたディストリだと思うので、リビルドするといろいろな地雷があるみたいだねぇ.

かしこ

2019年10月10日木曜日

【にわかAVマニアの難航】ラズパイ、AK4495をDSDで鳴らす難しさ(重箱の隅つつき)

旭化成のDAC AK4495基板を自作してPCM modeで動かして日常使いしている.
これとかがそれ.
【にわかAVマニアの僥倖】 板金工場でDAC BOXを私的生産
【にわかAVマニアの設計】AK4495 DAC私的設計資料(長文)

今度はAK4495をRapsberry piに接続しようと思って設計しているところである.
これとかがそれ.
【にわかAVマニアの計測】Arduino Nanoでオーディオサンプリング周波数を測定できるか?
OLED 0.91inch 128x32dot datasheetを読む読む (SSD1306)

ところで便利な事にAK4495はDSDでも使えるんで、ラズパイに繋ぐついでにDSDにも対応させちゃおうと思うわけだ.

だがしかし、ラズパイでDSDを再生するにはやたらと制約が多いぞ.わからないことも多い.

いろいろと調べてみて、ぼんやりと見えてきたことを書いてみる.推測を多く含むので間違いがあるかもしれない.内容が細かすぎるので誰得かもしれない.

なお、これを書いている時点で、OS等のversionはこうなっている.
% uname -a
Linux volumio 4.19.60-v7+ #1247 SMP Thu Jul 25 14:41:19 BST 2019 armv7l GNU/Linux

% mpd -V
Music Player Daemon 0.20.18 (128d910-dirty)

Volumio Audiophile Music Player for Raspberry Pi
VERSION: 2.632
RELEASE DATE: 03-10-2019


【やりたいこと】
システム面
・ラズパイの上に載せて使える子基板型のDAC
・DACはAK4495  (DAC基板がclock master)
・IFはI2S
・PCMだけでなくDSDも聞けるようにする
・OLEDにサンプリング周波数表示およびPCM/DSD表示をする
・ラズパイのソフトウエアはvolumio

性能面
・AK4495をモノラル使いする
・差動出力


【DSDの基礎】
サンプリング周波数によりいくつかの種類がある.
DSD64  :  サンプリング周波数= 2.8224MHz = 44.1kHz x 64
DSD128:  サンプリング周波数= 5.6448MHz = 44.1kHz x 128

もっと上のDSD256、DSD512もあるらしいが、ファイルサイズが巨大になるだろうなぁ.


【AK4495のDSD IFはどうなってるの?】
AK4495の音声信号IF pinはこの4つ
←AK4495

まずPCM modeについて説明する.

ラズパイとDACのIFでポピュラーなのはI2Sである.
ラズパイが出力するI2Sは3つの信号線である.
  BCK      サンプリング周波数の64倍とかいろいろ  (12pin)
  LRCK     サンプリング周波数そのもの      (35pin)
  DATA     LRchを1本線でシリアル伝送する     (40pin)
←ラズパイ

AK4495にはこの他にBCKの2~8倍ほどのMCLKを要するので、付加回路で作る必要がある.

つぎにDSD modeのAK4495について説明する.

DSDでは、物理的にはBCK/LRCK/DATA/MCLKのpinは同じだが、機能が化けるのである.
  BCK   → BCK      元のまま、5.6MHzとか2.8MHzとかそんなかんじ
  LRCK → DSDR    Rchの1bit streamに変わる
  DATA → DSDL    Lchの1bit streamに変わる
  MCLK → MCLK   元のまま、22MHzとか24MHzとかそんなかんじ

ゆえにだ、、、AK4495の都合から言えばラズパイに求めたいのはLRCKにDSD Rchが出てくるんだろうな? ということになる.

オシロで確認したり、ネットを徘徊してみたが、結論は「そんなモンは出てこない」であった.DSDでもLRCKはLRCKのままだ.したがってI2S接続でAK4495をDSD運用するのはひとまず不可能である.付加回路が必須である.

なお、DSDに対応しているES9038もAK4495と同様のIF仕様になっているようだ.


【ラズパイのDSDはどうしてBCLK/DSDL/DSDRを出力してくれないの?】
それにはまず、DoPというのを理解する必要がある.
DSD over PCMの略がDoPである.

DoPの意図するところは、I2Sは本来PCMを通すためのIFであるが、ここにDSDを乗せてしまおうという、I2Sの拡張規格である.
I2Sは上で説明したとおり、1本のdata信号線に時分割でLRchが乗るのが基本構成.
AK4495の求める仕様はLchとRchの2本線だが、それはI2Sの設計思想に反するのでそういう風にならなかったんじゃないかねぇ?

Linuxのデバドラを自作してI2SとDoPの制約から逃れるのがスカッと解決する美しいやり方だが、デバドラを自作する技術を持たないわたしには難易度が高いのでやめておく.


【DoPってどんな仕様なの?】
DoPの規格書はこれらしい.
・data仕様は、8bitDSDマーカ+16bit音声データ、1本線でLch+Rchを伝送
・たぶんLRCKとBCKはPCMに順ずる仕様
・したがって見た目は24bitPCMデータと同じなので、DSDマーカを監視してDSDだぁと検知しないかぎりPCM DACからnoiseが出る羽目になる
・DSDマーカという冗長さゆえに、DSD64(2.8MHz)までしか伝送できないらしい.ただしDSD128まで行けるという説も在る

DSDマーカの仕様は、05とFAをサンプリング周期で交互に繰り返すらしい.
  T=i        DSDマーカLch=05h      DSDマーカRch=05h
  T=i+1    DSDマーカLch=FAh      DSDマーカRch=FAh

なにかと制約の多いDoPのせいで断念すべきこと、ならびに追加すべき回路がある.
・DSDマーカを監視するロジック回路が必要である
・DSD128以上を再生するためにはDoPでない他のIFを使う必要がある.候補はUSB,HDMI,SPDIFであろうが、この中で生き残るのはUSBだけだそうだ.HDMIは規格帯域がHiResを通せない、SPDIFはもとより伝送帯域不足.→こちら
・AK4495のDSDL/DSDRにフィットさせるため、及びマーカ監視のため、FPGAを付加する必要がある

ちなみに、Terraberry-DACという市販DSCボードがあり、DSD256に対応していると謳っているけれど、その実態はI2S伝送帯域はDSD64で、ボード上でDSD256に変換しているのだそうだ. →こちら


【たくさんあるラズパイDAC基板のデバドラはどうなってる?】
ここまでの考察で、
 ・volumioをソフト的にカスタマイズするのは避ける
 ・AK4495を接続するための諸問題回避は回路で行う
という方針を得た.

ところで、ラズパイ用DAC基板は多数販売されている.
これらの基板は各社が独自のデバドラをリリースし、ユーザーはvolumioにデバドラを組み込んで使っているのだろうか? だとしたらスゲーかったるい.
だがそれは違うのだ.
あまたあるラズパイDAC基板の多くは「ほにゃららのクローン基板」なのである.
たとえばラズパイDACで数が多いのはPCM5122を搭載した基板である.
PCM5122搭載DAC基板のご本家は「HiFiBerry DAC plus」である.
他メーカーのPCM5122基板は、HiFiBerryのデバドラを流用しているのだ.

Linuxに実装されたDevice tree overlayというデバドラ後付けの仕組みを利用している.
こちらのURLを見てもらうとそれがわかる.
「overlay:hifiberry-dac」という文字がたくさんあるでしょ.みんなで相乗り.


【こんなブロックを設計すりゃいいんじゃね?】
・ラズパイには「僕にはHiFiBerry DAC plusが繋がっているんだ」と誤解してもらう.
ちなみに、HiFiBerryのデバドラにはslave/masterの2種類がある.
  slave: HiFiBerry DAC
  master:HiFiBerry DAC plus

・ラズパイのI2Cの先にArduinoで作った「fake PCM5122」をつけておくことで、HiFiBerry DAC plusが繋がっていると誤解させる.

・ラズパイのI2Sからは、例の3本線のオーディオデータが出る.

・I2Sの先にはPLDを置く.機能は3つ.
 1) master clockの切り替え、LRCK/BCK生成   (volumioのFsとの連繋手法は不明)
 2) DSDマーカの監視、AK4495のPCM/DSD切り替え
 3) dataをDSDL/DSDRに振り分ける

追記:困ったよ.3番の機能には64bit分のFlip-Flopが最低でも必要だが、XC9572XLのような廉価なCPLDだとFFが72個しか載ってないわけで、容量不足でもうたいへん.目処が立たない.高価なデバイスを使う気はないし.

・ここまで読む根性のある人なら判ると思うが、24.576MHzは48kHz系源発振、22.579MHzは44.1kHz系源発振である.

・AK4495のレジスタ設定はArduinoで行う.またOLED制御もArduinoで行う.


【fake PCM5122をArduinoで作ってみた】
まずはI2Cアドレスを知る必要がある.再びこちらのURLを見てもらうと、4Dhだとわかる.
    {"id":"hifiberry-dacplus","name":"HiFiBerry DAC Plus","overlay":"hifiberry-dacplus","alsanum":"1","mixer":"Digital","modules":"","script":"","eeprom_name":"HiFiBerry DAC+","i2c_address":"4d","needsreboot":"no"},

I2Cアドレス4DをArduinoで監視したところ、起動時にラズパイがする操作は単純だ.resetと並行してprobingしているらしい.
ラズパイはPCM5122のpageレジスタを読む、非0ならPCM5122 probing断念
ラズパイはPCM5122をresetする
ラズパイはPCM5122のpageレジスタを読む、非0ならPCM5122 probing断念
ラズパイはPCM5122をpower down modeにする
ラズパイはPCM5122のpageレジスタを読む、非0ならPCM5122 probing断念

この操作をかいくぐればPCM5122 probingにひとまず成功したかもしれない.なぜなら、「Please connect HiFiBerry DAC Plus to the unit」という起動時メッセージが出なくなるからだ.
ただし、aplay -lではPlusと認識させるには至っていない.何かまだ地雷があるみたいだ.
card 1: sndrpihifiberry [snd_rpi_hifiberry_dac], device 0: HifiBerry DAC HiFi pcm5102a-hifi-0 []

恐らく地雷はclockではないかと思う.HiFiBerry DAC plusの場合はDACがmasterなので、clock供給無しの現状では不具合があるのだろう.(PCM5122と発振器を中華通販に発注したのでさらなる探求はまた後日)

こちらのサイトは大変有用で、回路図なども載っている.発振器の処理がわかる.

参考:起動時のI2Cの動き (bit7はinncrement modeの意味)
slave is written 1 bytes        80    readadrs
slave is requested to send data [80]    read命令  ゼロを返す
slave is written 2 bytes        80-0    reg0write
slave is written 2 bytes        81-11   reg1write
slave is written 1 bytes        80
slave is requested to send data [80]
slave is written 2 bytes        80-0
slave is written 2 bytes        81-0
slave is written 1 bytes        80
slave is requested to send data [80]
slave is written 2 bytes        80-0
slave is written 2 bytes        82-10
slave is written 1 bytes        80
slave is requested to send data [80]
slave is written 2 bytes        80-0
slave is written 2 bytes        82-11


【HiFiBerry DACデバドラでvolumioの動作状況は?】
fake PCM5122はこのくらいにしておく(発振器が無いのでこれ以上のことは出来ない).

volumioのDAC modelには「HiFiBerry DAC」を設定して各種音楽ファイルを再生してみる.I2Sに何が出てくるのだろうか?

まずPCMファイルをAuto Resamplingなしで再生してみる.
  44.1k16bit/88k24bit/176k24bit     →これらはそのままI2Sへ出てくる
  352k24bit       →これは192k24bitに落とされてI2Sへ出てくる
PCM5122やPCM5102は385kHzまで対応しているのでどうして192k落ちさせるのか不明である.

次にDSDファイルはどうか? DoPオンで再生してみる.
  DSD64(2.8MHz)     →I2SにDSDっぽい信号が出てくる.音出しは出来てないが
  DSD128(5.6MHz)    →192k24bitにPCM落ちしてI2Sへ出てくる

なお、DoPオフ(DSD direct)だと、DSD64も192k24bitにPCM落ちしてI2Sに出てくる.


今宵はここまでにしとうございます.さて、FPGAをやるか.

かしこ

2019年9月14日土曜日

【にわかAVマニアのvolmio】Rasbperry pi + AK4495 まだできてない、許せっっ!!

こんにちは.滅多に平日に家に居ないため、趣味を行うチャンスは週末だけという、フツーの人のような生活になっている9月のわたしです.


当ブログで書いたsambaのファイルサーバをアニメデータ置場として使っています.
サーバ本体を屋根裏部屋に置いてるのですが、夏の暑い日には気付くとサーバがdownしてるのが何度もありました.屋根裏の気温が40度を超える日もあったでしょうから無理もなし.
何度も落ちた後遺症で本格的にサーバのOS volumeが死んでしまい、今日はKona linux 4.0を再インストールして復旧させました.アニメデータは生きてるっぽい.ほっと一息.

-----
Rapsberry pi + AK4495 DAC の試作が遅々として進みません.

↓現状はこんなテストベンチで火入れしているところ.いろんな基板が乗っているけど解説は割愛します.右下のがRapsberryですね.まずはRapsberryのI2SにDACを接続して音出し確認をやっています.
↓暫定DACは中華通販のI2S DACでPCM5102が載った¥400ぐらいのもの.意外にマトモな音が出るでやんの.中域リッチで豊かな音質って方向性です.
↓Rapsberry piで音出しするためのアプリは「volumio」を使ってみました.便利でよろしいんじゃないでしょうか?
volumioってLinux系OS上で動くGUIアプリなのかと思っていました.つまり、RapsberryをHDMIモニタに接続し、KBDとmouseで操作するアプリなのだろうという予想でした.

ですが、、、volumioの実態はwebアプリなのでした.それは便利でいいねぇ.上の写真はchromeの画面ですから.

具体的にどうやってvolumioを動かすのかを説明します.6stepです.
 1)Rapsberryにvolumioをinstallしておく
 2)我が家の家庭内LANでは、当該Rapsberry piに192.168.0.19を固定割り当てしてある
 3)RapsberryをLANに接続する(KBD,monitorなどは不要)
 4)PCから、chromeのURL窓に192.168.0.19を打ち込む
 5)するとvolumioの画面が開く
 6)あとはごにょごにょと使う(CD dataを擬似HiResに変換することもできる)

1)のvolumio installにも特徴があります.
https://volumio.org からdownloadするわけですが、稼動中のLinuxマシンにvolumioをinstallするのではありませんでした.
volumioのinstallは、Repasberryの専用OSであるRapsbianをinstallする時に似ています.
つまりdownloadしたのはOS imageなんです.それをSDに焼いて、volumio向けにカスタマイズされたLinuxもろともvolumioをinstallする仕組みになっています.(アプリ風のinstallも出来るのかどうかは知りません)


ともあれ意外に便利なラズパイオーディオでした.やる気がでるぞー

かしこ

2019年4月2日火曜日

ラズパイにADC PCM1803A(master)をI2S接続する地雷回避情報

音声信号をPCのwav fileに落とす装置を作りたい.

もっともそれは以前のこの投稿にてPC+Linux+ALSAで実現済みなのだが、PCにアタッチしてゴニョゴニョするのではなく、なるべくADC装置単体で動かせるような物を作りたくなった.

Arduino UNO+usb host shield で作れないかなぁと思ったが、UNOのCPUにはI2S interfaceがHW実装されていない.96kHz24bitのI2S信号をUNOのCPUで毎bit処理して速度が足りるはずが無い.よってArduino UNOを利用するのは断念.

ArduinoにはARMが乗ってる派生機種があるらしく、そういった機種ではI2S HWが実装されているので円満に処理できそう.でも手持ちが無いので断念.

USB2.0のEZ-USBを使ったらどうか? EZ-USBはI2S IFを内蔵していないので、FPGAを搭載して、ADC→I2S→シリパラ変換(FPGA)→EZ-USB→USB2.0 という信号の流れにせざるを得ない.FPGAを追加する気はないので却下.

それじゃぁと持ち出したのが、使ってない Raspberry pi 3B+ だ.これならI2SがHW実装されているのでなんとかなるだろう.

ADCはなるべく単純なものがいい.外付け部品が少なくて、CPUからの設定が不要で、しかも値段が安いICを探した.TIのPCM1803Aがお手軽で良さそうだ.96kHz24bit、I2Sなのでspecは充分.PCM1803Aがmaster(ラズパイがslave)に成れるところもいい感じ.中華通販で5ヶで¥360だった.

結果として、Raspberry pi 3B+、Raspbian、ALSA、PCM1803A(master) の組み合わせでstereo音声をwav fileに落とすことに成功した.

しかし、I2S interfaceを甘く見ていたため、いろいろな地雷があったので回避情報を以下に記す.

間違い情報で貴方がどんな損害を蒙ってもわたしは知らないのではまったら素直に死んでくれ.

------
まずは地雷の説明からしよう.

I2S interfaceというのを今回初めて扱った.I2Cになら馴染みがあったがI2Sは初めてであった.I2SはII2とも呼ばれることがあるようだ.

I2Sは音声データのIN/OUTに良く使われる.
ADCの場合の信号は3つだけ.
・LRCKは48kHzだったり96kHzだったりするいわゆるサンプリング周波数である.
・DOUTは音声データで、16bit,24bit,32bitなどである.Signed, MSB-first
・BCKは音声データのbit毎のclockである.
単純な仕様なので「こんなの実装は簡単だ」と思っていたわたしであった.






地雷1: 音声データの16/24/32bitに対応して、BCKは32fs/48fs/64fsになるのだろうと思っていたのが甘かった.24bitの場合が地雷だ.PCM1803Aの仕様では、24bitであってもBCKは64fsなのである.PCM1803Aが24bit目(LSB)を送出した後には、埋め合わせの8bitのゼロと8発のBCKが送出されるのだ.これはすなわち、ラズパイ側からPCM1803Aを見ると32bit転送に見えるのである.

次に、LRCKとBCKは誰が発生するのかという問題がある.
PCM1803Aは、発生源(master)にもなれるし、受信側(slave)にもなれる.
ラズパイも同様に、master/slaveのどちらにもなれる.さらにLRCKとBCKを独立にmaster/slave設定できる.
いまわたしがやりたいのは、PCM1803A=master、ラズパイ=slaveである.
地雷2: ネットから拾ったドライバを使ったら、両者がmasterになっていて信号が衝突してしまっていた.

clockにまつわる地雷がもうひとつある.
PCM1803Aがデルタシグマ演算するための源発振clock(SCLK)の調達である.
まずPCM1803Aがmasterの場合の周波数関係はこうなる.
SCLKにXtal発振器をつなぐ.PCM1803Aの仕様でSCLKには256fs/384fs/512fsのいずれかが許される.
256fsなどという高い周波数を分周して、BCK(64fs)やLRCK(fs)が作られる.PCM1803Aがmasterの場合はこのようにシンプルでよい.
ところが、PCM1803Aがslaveの場合は厄介だ.
ラズパイは256fsなどという高い周波数を供給してくれはしない.
なので256fsはXtalから独自供給することを余儀なくされる.
するとデルタシグマ回路の出力で異種clockの周波数不一致という厄介事が生じるのだ.
PCM1803Aの仕様書には、この異種clock問題について書かれている.「僅かな周波数ズレならOKだよ」という主旨なのだがそんな設計したくないわ!
合理的設計としてはこのようにPLLでBCKを4逓倍することで解決するが、ADCのclockにPLLをブチ込むのは気が進まない.
地雷3: PCM1803Aをslave使いする場合は、SCLKとBCK/LRCKの非同期問題が悩ましい

ソフトウエア面の地雷について.
地雷4: ラズパイには、I2S DACの応用例が多く、対応ドライバも豊富である.しかし、ラズパイは何故かI2S ADCのドライバがほとんど無いのである.

というわけで、「I2S ADCの実装なんか簡単じゃん」と言ってられなくなってしまったのだった.

-----
以下では、PCM1803A=master、ラズパイ=slave を実装する.

PCM1803Aの回路図はたったこれだけ.
未結線の端子は内部でpull-downされているので配線をサボッた.
10/11/12pinがラズパイへ配線されるI2Sの3本線である.
16~20pinの設定により、Master、96kHz、24bitが決めうちされる.
BCK=64LRCKの関係はPCM1803Aを24bit使いすると自動的にそうなる.
















ラズパイのI2S配線箇所はこの3箇所.あとGNDも.

-----
ここからはOSやドライバについての情報.

参考にしたのは、I2Sマイクロフォンをラズパイに接続するという、ネットに多くあるネタである.マイクロフォンでもADCでも似たようなものだから少し変更すればいいんじゃね?という目論見だ.
ただし、こういったページで紹介されているマイクロフォンは、マイクロフォンICがslaveで動く(ラズパイがmaster)構成になっている.(=地雷3)

【Raspbian焼き】
最新のraspbianをSDに焼いてラズパイを起動した.これを書いている時点ではこれが最新だった.
   Rapsbian 2018-11-13-raspbian-stretch.zip

【I2S関係のmoduleを動かす】
以後はrootでloginしての作業とする.

/boot/config.txt を編集する.
dtparam=i2s=on      ←コメントはずし
dtoverlay=hifiberry-dac    ←追記
dtoverlay=i2s-mmap        ←追記

/etc/modules を編集する.
i2c-dev
snd-bcm2835    ←追記
my_loader         ←追記

reboot     ←以後のブルー文字はコマンドライン

lsmod | grep snd
サウンド関連moduleにこの2つが見えてればここまではOK.
snd_soc_bcm2835_i2s
snd_bcm2835

【kernelビルドのもろもろの準備】
apt-get update
apt-get install build-essential git bc libncurses5-dev bison flex libssl-dev rpi-update
rpi-update
reboot

【kernel をビルドする】
wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source
chmod +x /usr/bin/rpi-source
/usr/bin/rpi-source -q --tag-update
rpi-source --skip-gcc         ←/rootにsourceが展開される.しばらくかかる.
いろいろ質問されたら全てEnterkeyを押せばいいだろう.

ビルドが終わったら、ビルドdirectoryを/usr/srcにリンクする.
cd /usr/src
ln -s /root/linux-0ae7718e0c............08d67713 linux
ここの長ったらしい名前のdirectoryは各位の/rootに在るそれっぽいのを当てはめること.

【PCM1803Aを動かすmodule作成】
cd /root
git clone https://github.com/PaulCreaser/rpi-i2s-audio   ←source download
cd /root/rpi-i2s-audio

my_loader.cを編集する.このように直すと、地雷2で述べた衝突を回避できる.
SND_SOC_DAIFMT_CBS_CFS   →   SND_SOC_DAIFMT_CBM_CFM
Sはslaveの意味、Mはmasterの意味.
CBMは、Clock Bit Masterの省略形だろう.つまりBCKはPCM1803Aがmasterになってくれという意味だと思う.またCFMは、Clock Frame Masterの省略形だろう.Frame ClockとはLRCKの別称だと思う.

moduleコンパイル
make -C /lib/modules/$(uname -r )/build M=$(pwd) modules
my_loader.ko が出来るのでloadしてみる.
insmod my_loader.ko
lsmodでmy_loaderが見つかればmoduleがloadされているのでひとまずOK.

※余談だが動作中のmy_loaderを削除するには、
modprobe -r -v my_loader
とするとうまくいくようだ.rmmodではうまくいかない.

【起動時にmy_loaderがloadされるように】
cp my_loader.ko /lib/modules/$(uname -r)
depmod -a
modprobe my_loader
reboot

【動かしてみる】
ALSAライブラリ付属の録音アプリ「arecord」がOS標準で入っている.
まずは、my_loaderで組み込んだmoduleが認識されているかを確認する.
arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: sndrpisimplecar [snd_rpi_simple_card], デバイス 0: simple-card_codec_link snd-soc-dummy-dai-0 []
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0

音声をcaptureしてwav fileを生成してみる.
arecord -D plughw:1 -c 2 -r 96000 -f S32_LE -t wav -v -d 3 adc.wav
ここでfs=96000以外だとデータ化けすると思う.
またPCM1803Aは24bitで動くが、地雷1で述べた理由によりS32_LEのように32bitのふりをしてあげる必要がある.S24_LEだとデータ化けする.
その他のoptionについては arecord --helpを参照のこと.

wav fileを可視化するアプリを使ってadc.wav表示させてみる.
これはPCM1803Aで1kHz/333Hz 3.5Vppを音声キャプチャし、wav fileを表示した画面である.PCM1803Aの仕様どおり、入力レベル3Vppでサチっている.

かしこ

2018年3月30日金曜日

ラズパイに挿したSDカードが死んだ、書き込みできない

Flashメモリのメモリセルは、書き込む度に少しずつ死んでゆくと云われます.電荷を蓄積する絶縁膜が次第に傷んでゆくのだと思います.

Flashの信頼性はそういうものなので、SSDではSATA越しに同じセクタに書き込んでいるつもりでも、SSD controlerが「同じアドレスへの多重書き込みを防ぐ」ように調停してくれています.要するにライトアドレスを自動的に散らしてくれているんです.こういうところは特許です.

SSDは値段が高いだけあってそのような賢いチラシをやってくれていますけど、SDカードやUSBメモリではどうでしょうか?

USBメモリでも、SSDほど賢いかどうかは知りませんがcontrolerにチラシが入っていると聞いたことがあります.

けれどSDはどうかな? SDはむき出しのFlashに近いデバイスと思われ、凝ったチラシをしている気はあまりしません.

つまりFlashデバイスの信頼性は、SSD > USB > SD だと思って生活しているわたしです.

------
そういうSDの信頼性の弱みが、ラズパイを使っていて表面化したように思われるトラブルに遭遇しました.

ラズパイのTFコネクタに16GBのSDを挿して、毎日100MBぐらいのデータが蓄積してゆく用途で1年間ぐらい使ったところでSDが死にました.右写真は死んだADATAのSD.
(ほぼ同条件で稼動しているSanDiskの16GBは生存中)

症状はこうです.
 ・rapsbian OSは正常に起動する
 ・ファイルアクセスも一見して正常ではある
 ・だがファイル削除や新規作成などの操作後にrebootすると、元に戻っている
 ・windowsに同SDを挿すと「書き込み保護されています」と警告が出る
 ・SDフォーマットツールでもフォーマットできない

SDフォーマットツールとして最強と云われるAOMEI Partition Assistantを使って同SDをフォーマットしようとしましたが、80%のところで進捗が止まり、重篤なエラーが生じているみたいです.やがてAOMEI Partition Assistantは「不能」と言い残して断念してくれました.
同SDはもう使えそうにありません.捨てるしかなさそう.

わたしはこのトラブルは初体験ですが、SDの書き込めないトラブルは広く知られているようですね.

わたしのラズパイにおける故障モードを次のように想像します.
 ・毎日大量のデータが蓄積される使い方のせいで多くのFlashセルが死んだ
 ・死にセルがある量を超えた時点で、SD controlerがサーキットブレーカー的にwrite protect modeに移行した
 ・WP modeから復帰させることは出来ず、もはや捨てるしかない
SDの信頼性はこんなものでしょう.ラズパイがSDをHDDのように使うのに一抹の不安を感じていましたが、悪い予感が当たったようです.

一方で、ストレージが書き込み不能になっていてもOSが動くというのには感心しました.フラッシュするまで馬脚を顕さないのですから、ext4 file systemは優秀なんだなぁ.

かしこ

2017年6月8日木曜日

【raspberry pi】 SPIの波形はどうなってるの?(3) 転送レート測定

今回は、SPIを動かしてみて、転送レートを測定してみたというハナシなのですが、最近書いたいくつかの記事と関連しているんです.

まず最初は、こちらの記事です.
【にわかAVマニアの二匹目のどじょう】セットトップボックス A95X R1+5.1chデコーダ+PAM8610 試用レポ
この記事にて、5.1chデコーダーのDACの写真を載せました.これは確かTIの既知のICですから、このピンから5.1ch音声データを取り出せるはずです.レートは600kB/sぐらいです.
取り出した音声データをデジタル信号処理して、イコライジングだとか音場補正システムを自作したいと思っています.昔からやりたかったんです.

それで、デジタル信号処理はラズパイでやらせりゃいいかなと思います.だとすると、5.1chデコーダからラズパイへデジタルデータを注入してやらなくちゃいけません.それで調査した経緯を書いたのがコチラの記事だったのです.
【rapsberry pi】 外部データストリームをDMAでメモリへ展開したいんだが
調査結果としては、選択肢はSPIであろうが、SPIにはフロー制御が無いので難しいぞという結果になりました.

ラズパイのSPIの動作モードを知りたくて、オシロで観測したのがこちらの記事でした.
【raspberry pi】 SPIの波形はどうなってるの?(1)
【raspberry pi】 SPIの波形はどうなってるの?(2)

------
今回はSPIの転送レートを実測してみました.

使ったラズパイマシンは以前HDMIモニタを製作したこちらのPCです.
液晶の裏面の右下のがFPGAボードで、SPI slave回路を載せてあります.
FPGAに実装したSPI slaveには、次の機能を持たせます.
・50kHzで16bit 6chのインクリメンタルデータ生成.50k*2*6=600kB/S
・FIFOはdualportで、入力は16bit6ch、出力はSPI slaveである
・FIFOサイズは、97bit*512word =約4kB
・16bit 6ch=96bitだが、FIFO fullフラグを1bit追加して97bit幅にしてある
・FIFOサイズが512wordなのでおよそ10mS分しかバッファできないため、SPI slaveが10mS以内にFIFOを空にしてくれないとover flowしてしまう
・SPI slaveがPCから0x01を受信すると、SPI slaveはfull/emptyフラグをPCへ返す (擬似フロー制御のカラクリ)
・SPI slaveがPCから0x00を受信すると、SPI slaveは16bit 6chを順次PCへ返す

ラズパイ上で動くソフトの機能は、
・SPIライブラリはとりあえずwiringPiを使った
・wiringPiのAPIの制限と思われるが、最大バッファサイズ=4kBらしい
・SPI_SCLK=20MHzで動かす
・13バイトに1回0x01を送信することで、FIFOのfull/emptyを調査し、擬似フロー制御と成す (fullなら失敗、emptyなら破棄)
・main loopは4kBYTE転送の無限loopである.loopにdelay()を入れておく
・転送レートを計算する

以上のカラクリにより、FIFOがoverflowしない速度でラズパイのmain loopが動けば成功と定義します.具体的には、
SPI転送時間(4KB) + いろいろなoverhead + delay() < 10mSec
が成功の条件でしょう.

-----
転送レートの測定結果

loopに挿入したdelay(xx)のxxをパラメータとして転送レートをメモりました.
 delay    rate       FIFO status
 10mS    316kB/S    overflowしている  NG
 8mS     375kB/S    overflowしている  NG
 7mS     413kB/S    overflowしている  NG
 6mS     458kB/S    overflowしている  NG
 5mS     510kB/S    overflowしている  NG
 4mS     588kB/S    overflowしている  NG
 3mS     630kB/S    overflowなし、emptyあり   OK
 2mS     542kB/S    overflowなし、emptyあり   OK
 1mS     414kB/S    overflowなし、emptyあり   OK

・合格ラインはdelay()を3mSec以下にしてようやくoverflowが止まりました.意外に余裕が少ない印象です.
・20Mbpsで4kB=32kbit転送に要する期間は計算上1.6mSに過ぎません.さらにdelay 3msですから、いろいろなoverheadで半分以上喰っていると推測されます.
・delay 3msのときの転送レートは630kB/Sで最大でした.650じゃない理由は追求不足です.
・delay 2msや1msで転送レートが劣化したのは不思議ですが、loopのoverheadを省みず忙しなく読みに行き過ぎる上に、empty=空読みが増えてグダグダになってしまった結果と思われます.


今後は、main loopをDMAだのスレッドだのにしなくちゃいけないと思います.それじゃないと6ch分の畳み込み演算をしてる暇がない気がします.

かしこ

2017年6月4日日曜日

【raspberry pi】 SPIの波形はどうなってるの?(2)

一つ前の記事の続きです.

ラズパイのSPIの波形をチェックしているところです.

今回は、ラズパイのRaspbian OSのIO関連ライブラリである「Wiringpi」が持つSPI制御関数を試用します.

参考にさせてもらったのはこちらのサイトのサンプルプログラムです.
コンパイルするには、
gcc xxx.c -lwiringPi
のようにライブラリoptionをつけてください.
同プログラムを見ると、1秒毎に0x24を1バイトだけSPIから出力し、同時にSPIから読み込むという動作をエンドレスで実行するだけのプログラムです.

前回図示しましたように、SPI_MOSIとSPI_MISOをショートしてプログラムを実行すると、送信した1バイトすなわち0x24が受信され表示されます.MOSI/MISOショートを外すと表示が00になってしまいますので、loopback動作しているんだなぁと想像されます.

↓その時のSPI端子波形を示します.SCLKは8発です.それでloopback出来ていますので、MOSI/MISOが同時なのでしょう.

↓CEは1バイト毎にパタパタしているのかどうかをチェックしました.プログラムを変更して、3バイト送信/3バイト受信にしてオシロで観測したのがこれです.
CEは1バイト毎にパタパタさせないものなんですね.

前回の検証で得たことと同じでした.

かしこ

【raspberry pi】 SPIの波形はどうなってるの?(1)

ラズパイのSPIを動かそうとしています.

SPIライブラリはいろいろとあるので順次試用したく思いますが、ソフトウエアのサイトを読んでも、肝心のSPI端子の波形がどうなっているのかはちっとも判りません.ひら的には、SPI端子の先に繋がる回路を設計したいわけですので、SPI端子波形を知らないと困ってしまうという状況なわけです.

raspberry piのメインLSIのデータシートにはこのような図が掲載されています.
このタイミングチャートからは、沢山の情報を読み取れます.
・最初に8bit送信、後で8bit受信である  (MSB first)
・1バイトの送受信毎にCEが動くみたいだ   (違うかもだが)
・送信データはneg-edgeでFFを駆動する.受信データはpos-edgeでラッチする

だけど、、、本当かなぁ?
SPIバスを有効活用するためには、送受信を同時にやればいいじゃん.上図のような、送受信をわざわざ時間ずらしなんかするかね? 疑問を感ずる.
SPIバスには様々なタイミング仕様があるのだと思います.だとすると、ラズパイのSPIはどういう仕様で動いてるんだろう?

実際にオシロでモニタしてみました.


-----
いくつかあるSPIのデバドラのうち、raspberry piサイトにあるSPI loopback Cプログラムを動かしてみました.

まずラズパイの回路は、右図のSPI_MOSIとSPI_MISOをショートしてloopbackとします.loopbackという文字が目に入った時点で上のtiming chartはウソだろって想像がついちゃいます.
オシロで観測するのは、SPI_CE0/SPI_MOSI/SPI_SCLKの3箇所です.

次にプログラムは、上のリンクページの一番下の方にあります.ラズパイのターミナルから、そこに書いてある通りに操作します.

ソースをdownloadします.
wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-3.10.y/Documentation/spi/spidev_test.c

コンパイル
gcc -o spidev_test spidev_test.c

実行ファイルを起動し、SPIを動かします.
./spidev_test -D /dev/spidev0.0

すると、次の結果が表示されます.16進数が38バイト表示されます.これが、SPIバスを通じてloopbackした結果です.
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D

ちなみに、ラズパイコネクタのMISOとMOSIのloopback接続をせずに動かすと、全部00になってしまいます.

蛇足ながら、spidev_test のoptionで、16bit転送や24bit転送や32bit転送を試みましたが、8bit以外はエラーで断られました


↓それで、38バイトのloopbackをさせたときのSPIバスの実測波形を示します.
SCLKの赤い四角で囲った範囲には8発のclockを含んでいますから、1バイト分です.この波形写真には先頭15バイト分のデータが表示されています.
MOSIを1バイトづつに区切ると、FF,FF,FF,FF,FF,FF,40,00,00....というシーケンスが見えます.
このオシロ波形は、次のことを示しています.
・沢山のバイトデータを一気読みする最中に、CEはパタパタしない
・送信データと受信データは同時である   (あぁやっぱり)


------
raspberry piサイトには他にもSPIをドライブする手段が案内されていますので、後日それらも試みたいと思います.

その中にshellでSPIへ出力できる手段が記載されています.
echo -ne "\x81\x00\xff" > /dev/spidev0.0
簡単なので早速試してみました.
spidev_testで得たのと同じ結果でした.




↓なんだ、これとは全然違うじゃんということが判りました.


かしこ

2017年6月1日木曜日

【rapsberry pi】 外部データストリームをDMAでメモリへ展開したいんだが

よろずハードウエア処理を好むわたしとしてはDMAって好きなんです.DMAした経験はあるけれど、Linux上でDMAしてthreadを起動したりした経験は無いんです.どうしたらrapsberry piでDMAできるんだろう? 楽チンなライブラリってあるのだろうか?

そんな目論見はあれど、よく判らないのがひら的な実情です.

ラズパイでロボット制御するために、DMAでPWMを発生させようとする試行例はネットに多々紹介されているようです.でも、外部から到来するデータストリームをDMAで取得してメモリに整列させる判りやすい例は見当たらない気がしています.

まずはメインLSIの仕様を読んでみようかと思います.以下、散文的に感想を記します.間違いがあっても許してくれ.


【ラズパイのメインLSI】
wikiによると、1,2,3,zeroとあるラズパイの世代のメインLSIは皆少しづつ異なります.
 ラズパイ1: Broadcom BCM2835
 ラズパイ2: Broadcom BCM2836 と BCM2837 が混ざってる
 ラズパイ3: Broadcom BCM2837
 ラズパイ0: Broadcom BCM2835

これらのペリフェラルの読み物としては、BCM2835版だけがネットに存在し、36と37についてはロクな資料が見つかりません.ペリフェラルについては基本的に35=36=37と思えばOKという考え方のようです.

だがしかし、ペリフェラルのベースアドレスが違うんです.
 BCM2835  0x20000000
 BCM2836  0x3F000000
 BCM2837  0x3F000000
ラズパイ0と1のグループと、ラズパイ2と3のグループに分かれている状況です.

Rasbian OSのデバドラを利用している分にはこのペリフェラルアドレス違いで悩まされる場面は無いと思われますが、GPIO制御などでペリフェラルを直接叩いているようなprogramでは動かないなんていう場面がありそうですから注意が必要と思います.
実際に、ラズパイ1ベースで書かれた古い解説記事を参考にして、それをラズパイ3で動かそうとしたら、このアドレス問題で最初は動きませんでした.

今わたしが使っているのはラズパイ3なので、以下ではラズパイ3を念頭に書くつもりです.


【ラズパイのアドレスマップ】
LSI内部アドレスは3つあるそうです.SDRAMやペリフェラルなどが3つの異なるアドレスに配置されているわけですが、それはMMUで配置された結果であって本体は3つとも同じであるのは言うまでもありません.
  virtual address           ペリフェラル=0xF2000000
  bus address               ペリフェラル=0x7E000000
  physical address         ペリフェラル=0x3F000000

ペリフェラルを直接叩くなら、physical addressを使うので 0x3F000000 がベースアドレスということになります.


【GPIOピン】
DMAにとっての外部窓口はGPIOにしたいです.まずはGPIOがどうなっているのかを調べました.

メインLSIのGPIOは54本あるらしいです.各GPIOはSPIやI2CやUARTを機能重複しているので、例えばGPIO機能を生かすかUART機能を生かすかのセレクトになります.(機能詳細図)

ラズパイ1の初期モデルを除き、GPIOの外部コネクタ配置は右図になっているらしいです.GPIO2~27までの26本しかコネクタに配線されていません.
残りの26本が何をしているのかは知りませんが、たぶんカメラコネクタに配線されたりしているのではないでしょうか.


【GPIOレジスタ】
例として、GPIO0の設定に関係するレジスタを記します.

GPFSEL0[2:0]        pin機能をセレクトする
  000 = GPIO Pin 9 is an input
  001 = GPIO Pin 9 is an output
  100 = GPIO Pin 9 takes alternate function 0
                            中略
  010 = GPIO Pin 9 takes alternate function 5
alternate functionの具体例はさておきます.6種類もあるのかいな?

GPSET0[0]        ここに1を書くとGPIO0=1が出力される
GPCLR0[0]        ここに1を書くとGPIO0=0が出力される
SET/CLRが独立していると、read modify writeをしなくて済むそうだ.

GPLEV0[0]         GPIO0のロジックレベル、GPIO入力としての機能

GPPUD[1:0]       GPIO一括のプルアップ/プルダウンの設定
   00 = Off – disable pull-up/down
   01 = Enable Pull Down control
   10 = Enable Pull Up control
   11 = Reserved

GPPUDCLK0[0]     GPIO0のプルアップ/プルダウンの設定
設定シーケンスがチト面倒臭い.GPIO0をプルアップにする例.
GPPUD[1:0]=10 → 150clk待つ
        → GPPUDCLK0[0]=1 → 150clk待つ
              → GPPUD[1:0]=00 → GPPUDCLK0[0]=0

以上はI/Oに関するものでした.思ったよりもシンプルです.

以下はGPIOポート監視に関するもの.

GPEDS0[0]         GPIO0のレベル/エッジ監視結果
GPIO0に生じた変化をキャッチする.1で変化あり.ここに1をwriteするとクリアされる.

GPREN0[0]         1→GPIO0の立ち上がりエッジ検出をenable
GPFEN0[0]         1→GPIO0の立下りエッジ検出をenable
両方とも1にすると両エッジを検出することになる.
エッジ検出はsystem clkの同期サンプルで動作する.

GPAREN0[0]        1→GPIO0の立ち上がりエッジ検出をenable
GPAFEN0[0]        1→GPIO0の立下りエッジ検出をenable
両方とも1にすると両エッジを検出することになる.
こちらだと非同期サンプルで動作する.

GPHEN0[0]        1→GPIO0がHighを検出するのをenable
GPLEN0[0]         1→GPIO0がLowを検出するのをenable

ポート監視は割り込みに関係すると思われますが、GPIOの項には割り込みについての解説はありませんでした.

以下はGPIO CLOCKに関するもの.

ラズパイの40pinコネクタに出てきているGPIO2~27の中に在るGPIO CLKは5箇所あります.GPFSELで機能選択するとGPIO CLKを使えるようになります.
   GPIO4     GPCLK0
   GPIO5     GPCLK1
   GPIO6     GPCLK2
   GPIO20   GPCLK0
   GPIO21   GPCLK1
これを見ると判るように、GPIO CLKは3系統あります.

GPIO CLKの仕様は、
・最高で125MHz          (BCM2835の場合.36/37でも同じかどうかは不明)
・出力周波数=源発振周波数÷(DIVI + DIVF/1024)
・PLL jitterをオーディオ帯域外に飛ばす効果のあるMASHフィルタ回路がある

レジスタのうちGPCLK0に関する主なものだけを記す.
CM_GP0CTL[3:0]           源発振セレクト
   0 = GND
   1 = oscillator
   2 = testdebug0
   3 = testdebug1
   4 = PLLA per
   5 = PLLC per
   6 = PLLD per
   7 = HDMI auxiliary
CM_GP0DIV[23:12]         DIVI
CM_GP0DIV[11:0]           DIVF


【DMA】
次はDMAについて.
・16個のDMAチャンネルを内蔵している.
・バスマスタである.
・ペリフェラルからDMAへ、DREQ信号を発行することによってDMAのデータ出力に待ったをかけることができる.

ここで、「DMAのデータ出力に待った」が気になります.なぜなら、今わたしが知りたいことは、
Q1:「DMAのデータ受信に待ったをかける」
ですので逆向きのDMAフロー制御になります.
データシートを読みましたが、
A1: ユーザーに開放されたこの機能はありません!
さらにGPIOについて言えば、DREQすらありません!
つまり、GPIOのDMAには入りにも出にもフロー制御手段が一切無いらしいんです.

ありゃりゃ、、、GPIO経由のDMAでデータ受信をしたいんですけど、フロー制御が出来ないなら無理だ、詰んでいると悟りました.

目論見が崩壊したところで、
Q2: 「XXX経由のDMAデータ受信でフロー制御」のXXXは何なら可能なのだ?
これが初心に還っての疑問となりました.

↓答はこのブロックダイヤグラムにあります.I2C/PCM-IFの図です.
右の4本の信号が外部I2C信号線です.
DREQは左下にあります.たぶんですがDREQはTX-FIFO FULLから内部で生成されているのではないかと想像します.=送信フロー制御
わたしが知りたいのは受信フロー制御ですが、データシートには「受信データが無ければDMAは一時停止する」とさらりと書かれています.
けれど上図にはどこにもそれっぽい信号が見えません.たぶんですが、APBがRX-FIFO EMPTYを監視しているのではないかと想像します.=受信フロー制御

というわけで、
A2: DMAフロー制御をしたくば、所定のペリフェラルを使うしかない
というのがここまでの結論となりました.GPIO経由のDMAは断念しました.

次の疑問は、
Q3: DMAにペリフェラルを結合させるにはどうするんだろ?
Q4: 所定のペリフェラルってどれ?
DMA0のレジスタですが、
0_TI[20:16]      PERMAP[4:0]
A3: これがペリフェラル番号を設定するレジスタであるらしい
そしてPERMAPに入る番号は、抜粋でこのようなのがあります.各種ペリフェラルが見られます.なおGPIOはリストに在りません.
   0 DREQ=1
   2 PCM TX
   3 PCM RX
   6 SPI TX
   7 SPI RX
   8  BSC/SPI Slave TX
   9  BSC/SPI Slave RX
   12 UART TX
   14 UART RX
   17 HDMI
0はどのペリフェラルにも繋がず、DREQが常に1とみなされます.これはmemory同士のDMAで使われるのではないでしょうか?

汎用的なDMAに使えそうなペリフェラルをデータシートから読むと、
A4: SPIまたはI2Cしか使えそうなのがありません
SPIの方が高速動作と考えますので、I2Cは捨てます.

ところが、まだ問題があります.
DMAとSPI-IFの間でフロー制御しているのは想像に難くありません.しかし、わたしが欲しいのは、SPI-IFと外部FIFOの間でのフロー制御です.SPIにフロー制御なんか規格自体に在りませんから、無理ってことで終了です.
それでもしぶとく粘るとしたら、SPI slaveならSPI clockをGO/STOPさせることでフロー制御が出来るかもしれません.
Q5: BCM2835にはSPI slave機能があるのか?
すぐ上に答えがあります.
A5: BSC/SPI Slave RX という文字があります
でもたぶん期待とは意味が違うと思います.BCM2835のSPI CLKは出力onlyであり、外部SPI CLKによるGO/STOPは不可能とデータシートから読めます.

どうやら結論としては、こうなったようです.
 ・外部データストリームをDMAでメモリへ展開したい.フロー制御は必須
 ・だが、フロー制御の点でBCM2835には使えそうなIFがない


【DMAレジスタ】
DMA0のためのレジスタのうちめぼしいものを抜粋します.

0_TI[20:16]      PERMAP[4:0]    上で述べました

0_TI[10]   SRC_DREQ        1:DREQが有効で、ソースリードが抑制される

0_TI[8]       SRC_INC           0:ソースアドレスが固定される
ペリフェラルのようにアドレスが固定されたポートで使われるのでしょう.

0_TI[6]   DEST_DREQ      1:DREQが有効で、デスチネーションライトが抑制される

0_TI[4]       DEST_INC           0:デスチネーションアドレスが固定される
ペリフェラルのようにアドレスが固定されたポートで使われるのでしょう.

0_SOURCE_AD[31:0]        ソースアドレス

0_DEST_AD[31:0]         デスチネーションアドレス

0_TXFR_LEN[15:0]      XLENGTH[15:0]       転送BYTE数

INT_STATUS[0]          INT0          DMA0割り込みフラグ

ENABLE[0]           EN0      DMA0イネーブル


ふ~ん、ラズパイのDMAはこうなってるのか、と判ったような気がしたところで、今宵はこれまでにしとうございます.

詰みました