■タグ「自作エフェクター」

■Owm Pedal ソフトウェア編

自作デジタルエフェクター「Owm Pedal」の各設定、内部プログラミングをしていきます。
Owm Pedal ハードウェア編はこちら
内部データ、STM32CubeMX用iocファイルはGitHub



<ピン、クロック設定>
・ST-LINK接続
STM32CubeMX設定:System Core→SYS→Debug [Serial Wire]

上写真右上に見える2つのジャンパを外し、NucleoボードのST-LINK部分のみ使用します。SWDピンをそのままの順番でOwmボードへ接続できます。今回は外部から電源供給するため、3.3Vピンは接続しません。

・クロック源として外部水晶振動子を使用
STM32CubeMX設定:System Core→RCC→High Speed Clock (HSE) [Crystal/Ceramic Resonator]

▽クロック設定図

I2Sクロックは、オーディオサンプリングレート48kHzに対する誤差が少なくなるような設定としました(48×2048=98304)。

▽全ピン設定図

PC2はデバッグ時オシロスコープを接続する場合に利用しています。

<スイッチ>
割り込みではなくメインループで処理しています。今までAVRマイコンでやっていたカウントを増やす方式なので、長押しにも対応できます。

<ADC>
設定方法は過去記事(→NucleoボードのADCを使う)と同じで、チャンネル数が増えるだけです。ポットの値の取得は低速で構わないため、Sampling Time : 144 Cycles としています。

<I2S>
設定方法は過去記事(→NucleoボードとオーディオコーデックICとの通信)と同じですが、I2Cは不使用です。信号処理を優先するため、DMAのPriorityは[Very High]に、他の割り込みの優先度は下記の通り変更しました。
STM32CubeMX設定:System Core→NVIC→
 Time base: System tick timer→Preemption Priority [10]
 DMA2 stream0 global interrupt→Preemption Priority [5]

今回は受信したデータを信号処理後に送信することになります。I2Sの受信バッファに半分データがたまると「HAL_I2SEx_TxRxHalfCpltCallback」という関数(以下Half関数)が呼び出されます。しかしデータが全て溜まったときの「HAL_I2SEx_TxRxCpltCallback」は呼び出されないバグがあるようです。修正方法がわからない(あまり調べていません)ので、このままHalf関数のみで処理するようにしました。Half関数は送信と受信で2回起こってしまうので、送信側(DMA1 Stream4)の割り込みは無効化しています。

※処理方法を変更しました。→HAL_I2SEx_TransmitReceive_DMA使用時の割り込み修正(2019年3月25日追記)

下図はブロックサイズを32(ステレオなのでバッファ配列の要素数は64)で処理する場合のものです。配列の1グループは16...31, 0...15の順番となります。
03s_238_4owmI2S.png
最初の割り込みでグループAを一旦全て信号処理配列へ移し、次の割り込みで信号処理後のグループA(A')を送信バッファに送ります。このときA'[16]は送信されずA'[17]から送信されてしまいます。そこで処理後データA'を送信バッファへ代入するとき、1サンプルずらしています。もっとスマートに解決する方法(FIFO?)がありそうですが、現状問題が起こっていないので追求していません。遅延時間(レイテンシ)実測値は、ブロックサイズ16で1.7ms、32で2.4ms程度でした。

通常のやり方は、最初の割り込みの時にグループAのデータを1つずつ信号処理と送信を行うというものだと思います。しかしその場合たまに波形が乱れることがあったので、今回は少し回りくどい方法を採用しています。遅延が余計に発生してしまいますが…


<I2Sエラー対処>
たまにI2S通信がうまくいかないことがありましたが、フレームエラーというのが起こっていました。マスター(オーディオコーデックV4220M)がクロック送信する前にスレーブ側(マイコン)のI2S設定をする方がいいようです。デバッグ時は先にV4220Mが起動しているためかエラーが起こりやすく、エラー時はソフトリセットで対応するようにしました。本来はI2Sのみのリセットで済むかもしれませんが、DMAを使っているため全リセットするのが確実でしょう。電源を入れなおした際はV4220Mが後から起動するため、エラーはほぼ発生しません。とはいえオーディオコーデックのリセットピンはマイコンと繋げておくべきだったと思います。

<エフェクト処理>
main.cとmain.hのユーザーコード部分を編集する以外に、2つのファイル(fx.c、overdrive.c)を追加しています。詳細はコード内のコメントをご参照ください。エフェクトはとりあえずオーバードライブで、操作はフットスイッチ(バイパス)、左上ポット(LEVEL)、右上ポット(GAIN)、中央LEDのみ使っています。

overdrive.cでフィルタを使っていますが、過去のデータ(x1、y1)を利用するため、static修飾子を付けて前の計算結果を残したままにしておく必要があります。その結果、フィルタの数だけ関数を準備しておく状態となっています。今後複雑なエフェクトに対応するために、C++言語を使う必要性が出てきそうです。

■Owm Pedal ハードウェア編

03s_237_1owmp.jpg
STM32F405という32ビットマイコンを搭載した自作デジタルエフェクター「Owm Pedal」です。名前は同じマイコンを搭載した既存のペダル「OWL Pedal」をもじってつけました。(Owm Pedal ソフトウェア編はこちら

オーディオコーデックはCS4220のセカンドソース品V4220Mです。サンプリングレートが48kHzまでですが差動入出力で価格が安く(秋月電子で240円)、エフェクターに最適だと考えました。

▽回路図
03s_237_2owms.png
<V4220M周辺>
データシートに入出力の回路が記載してあるのですが、抵抗値はよく使う値へと変更しました。バイアス電圧用に8.25kΩの抵抗があるところは、10kΩと100kΩ2個を並列にして8.33kΩとしています。

V4220Mのデータシートでは音量等をコントロールできそうに書いてありますが、実際はできないようです。マスターモードで動作させる場合は8番(DOUT)ピンに47kΩのプルダウン抵抗を入れます。また、CS4220のデータシートには電源オン時に27番(RSTN)ピンを10msの間LOWにしておくように書いてあるため、10uFのコンデンサを入れました。4・5・8・9番ピンからマイコンへ接続しますが、通信線の長さが短いためダンピング抵抗は不要かと思います。

<電源>
電源はレギュレータで以下のように分けました。
・マイコン用→デジタル3.3V(100mA)
・V4220M用→デジタル5V(20mA) デジタル3.3V(5mA) アナログ5V(60mA)
・OPA1678×3用→アナログ5V(20mA)
アナログ5V電源は通常分離する必要はありませんが、万一問題があったとき基板発注し直すのが嫌なので分けています。

▽DSP基板(Owm Borad)レイアウトについて(KiCadデータはGitHubへ)
真ん中あたりに電源、上側がデジタル、下側がアナログという配置となっています。GNDは裏面を一面プレーンにしました。入力のカップリングコンデンサはPMLCAPを使っており、やや大きくて高価ですが歪率は下がるでしょう。残念ながらBIASに接続すべきところをGNDにつなぐというありがちな間違いをしてしまいましたので、内部写真では妙なジャンパー線が写っています(KiCadデータは修正済)。

ピン間隔が狭いICはパッドを1mm程度長くすると半田付けしやすいです。マイコンのピンはほとんど使えるように引き出しました。一応I2C用にプルアップ抵抗の取り付けもできます。マイコン上側のLEDはデバッグ用のつもりです。水晶振動子周りのパターン設計は下記ページを参考にしました。
水晶振動子 ガイド - RSオンライン

▽ポット類基板レイアウト
03s_237_3owml.png
ポット類基板と筐体はRasPd4のものを使いまわしました。回路図は描いていません。無理やりジャンパーを飛ばしてチャタリング対策の抵抗やコンデンサを入れました。下写真のように基板を合体させます。
03s_237_4owmpp.jpg

とりあえず何もエフェクトをかけないスルー音が出るようにプログラミングし、周波数特性と歪率を測定しました。歪率は、クリップしない最大入力約0.7Vrmsでの結果です。
03s_237_5owmf.png
100Hzの歪率が思ったより悪いですが問題ないでしょう。ノイズも測定限界以下だったので、歪み系エフェクトでもおそらく大丈夫だと思います。

■RasPd3 操作方法

RasPd3の内部プログラムが概ね完成したので、自分用に取扱説明書のようなものを記載しておきます。LCDの文字が小さいですがなんとか大丈夫そうです。そのうちタップテンポやチューナーも実装できたらいいなと思っています。



03_230_1raspd3sh.jpg
<コントロール類と略称>
・左側ロータリーエンコーダ:LR
・中央ロータリーエンコーダ:CR
・右側ロータリーエンコーダ:RR
・左側押しボタンスイッチ:LS
・中央押しボタンスイッチ:CS
・右側押しボタンスイッチ:RS
・左側フットスイッチ:LF
・右側フットスイッチ:RF



<画面中央 緑色領域>
・エフェクトの種類とエフェクトパラメータを「プリセット」として8パターン(A~H)保存
(Pure Dataのプログラムを「パッチ」と呼ぶので、混同しないよう「プリセット」という呼称にしている。)
・プリセット1つにつき直列に6つのエフェクト(上3つ→下3つへ繋がっている)
・エフェクトは内蔵エフェクト20種類から選択(1つのプリセット内で複数重複使用は不可)
・エフェクトオン状態のエフェクトの名前右横に白色の丸印がつく
・「RF割当」を設定したエフェクトの名前右横に紫色の四角形がつく

※RF割当:プリセット内部モード(後述)時、RF押下でオンオフが切り替わるエフェクトを割り当てられる。
【例】ディストーション(オン)とコーラス(オフ)にRF割当を設定しておくと、RF押下時にディストーションをオフ、コーラスをオンという風に切り替えられる。

<画面右側 青色領域>
・プリセットの切替順番を3パターン保存
・フットスイッチで上下にプリセットを切り替える

<画面下側 灰色領域>
・エフェクトパラメータを表示
・エフェクトオンの場合、右に[ON]が表示される
・「RF割当」を設定している場合、右に[EN]が表示される



<2種類のモード(●プリセット切替、◆プリセット内部)と操作方法>
※LSを押しながらCSを押す:データ保存、押し続けるとシャットダウン(両モード共通)

●プリセット切替モード
複数のプリセットをフットスイッチで切り替えるモード。プリセット切替の順番を編集できる。

LR:カーソル左右移動
CR:カーソル上下移動
RR:プリセットA~Hまたは「X」を選択
※「X」を選択すると、フットスイッチでのプリセット切替時にX以降への切替がキャンセルされる。
【例】A→B→C→D→X→F→E→Gの場合…Dの後はA、Aの前はDに切り替わる。

LS:「プリセット内部モード」へ切替
CS、RS:なし
LF:プリセット切替(下側へ)
RF:プリセット切替(上側へ)

◆プリセット内部モード
1つのプリセット内で単独もしくは複数のエフェクトのオン・オフを切り替えるモード。エフェクトの種類やパラメータを編集できる。

LR:カーソル左右(エフェクト順番)移動
CR:カーソル上下(プリセット間)移動
RR:エフェクトの種類またはバイパスを選択
(エフェクトパラメータ編集時は、各ロータリーエンコーダでパラメータを増減させる)

LS:押す度にエフェクトパラメータ上段→エフェクトパラメータ下段→エフェクトの種類へと編集箇所切替
CS:「プリセット切替モード」へ切替
RS:「RF割当」設定/解除
LF:選択中のエフェクトをオン/オフ(オンの時、左側LED点灯)
RF:「RF割当」が設定されたエフェクトをオン/オフ

■2ループスイッチャー+絶縁型パワーサプライ

02_224_1lpswp.jpg
直列可2ループボックス+パワーサプライのスイッチが経年劣化のためか接触不良となっていました。もう一度配線をやり直す気にはなれなかったので、AVRマイコンを使ったスイッチャーとして生まれ変わらせました。当初はアナログスイッチICを使おうと思っていましたが、バッファーが必要で複雑になりすぎるようです。普通にメカニカルリレーを使うことにして、ついでにパワーサプライ部分はなんとなく絶縁型へと変更しました。

▽回路図
02_224_2lpsws.png
マイコンはATtiny13Aだとプログラムメモリが足りないので、ATtiny85です。ATtiny13Aの使用方法と同様に、Arduino IDEをATtiny85にも対応させます。参考ページ→Arduino IDE で ATtiny 他の開発

5Vレギュレーターは念のため78M05としていますが、9V入力であれば78L05でも大丈夫でしょう。リレー941H-2C-5Dのコイル駆動電流は30mAで、マイコンから直接流し続けるのは無理があるため、トランジスタを使用します。

▽レイアウト(KiCadデータはこちらへ)
02_224_3lpswl.png
パワーサプライ部分は別基板となっています。絶縁型DC-DCコンバータが大きいので内部がかなり窮屈になってしまいました。

▽Arduinoスケッチ
表示/非表示切替(133行)
スイッチに関する部分はMOSリレーバイパスと同じで、長押しの判定はsw_countを増やすだけです。メインループが1msごとなので長押しは1秒となるはずですが、処理に時間がかかるので実測では1.8秒ぐらいでした。

▽操作方法
 ・マニュアルモード(中央LED消灯)
   左スイッチ: ループBのオンオフ切替、長押しで特殊モードへ
   右スイッチ: ループAのオンオフ切替
 ・特殊モード(中央LED点灯)
   左スイッチ: ループA→ループBの順で直列接続
    ※直列切替後は右スイッチでAのみ、左スイッチでBのみオンの状態に戻る
   右スイッチ: ループAのみオンとループBのみオンを切り替え、長押しでマニュアルモードへ

■MOSリレーバイパス

02_223_1mrbP.jpg
ソリッドステートリレーを利用したエフェクトのバイパス方法をバッファーなしで検討していました(別記事参照)が、音漏れやポップノイズの問題が解決できなかったため結局バッファードバイパスにすることにしました。BOSS筐体BD-2に採用しています。あまり利点がないバイパス方式となってしまいましたので、再度作ることはなさそうです。素直にラッチングリレーを使った方がよいでしょう。

▽回路図
02_223_2mrbs.png
秋月電子で安売りしている光MOSFET PS7200K-1Aを使用しましたが、フォトリレーTLP222Aでも問題ないと思います。エフェクト側の入力部分の回路によってはバイパス音に影響が出るので、本来は入力の分岐前にもバッファーを入れた方がよさそうです。バイアス電圧Vbはエフェクト回路から引っ張ってきています。

▽レイアウト
02_223_3mrbp.png

▽Arduinoスケッチ(ATtiny13A用)
#define SW_PIN 3
#define BYPASS_PIN 0
#define FX_ON_PIN 1
#define LED_PIN 4

int sw_value = 0;
long sw_count = 0; // intだとオーバーフローするかも
boolean fx_state = false;

void setup() {
pinMode(SW_PIN, INPUT_PULLUP); // 内部プルアップ抵抗有効
pinMode(BYPASS_PIN, OUTPUT);
pinMode(FX_ON_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(BYPASS_PIN, HIGH); // 初期値はバイパス
digitalWrite(FX_ON_PIN, LOW);
digitalWrite(LED_PIN, HIGH); // 電源オン時LEDが2回点灯
delay(300);
digitalWrite(LED_PIN, LOW);
delay(300);
digitalWrite(LED_PIN, HIGH);
delay(300);
digitalWrite(LED_PIN, LOW);
}

void loop() {
sw_value = digitalRead(SW_PIN);
if (sw_value == LOW) {
sw_count += 1;
} else {
sw_count = 0;
}

if (sw_count == 10) { // 10msスイッチ押すとエフェクト切替(チャタリング対策)
fx_state = !fx_state;
if (fx_state) {
digitalWrite(FX_ON_PIN, HIGH); // HIGHにするピンの順番が逆だとポップノイズあり
delay(2); // これがないとポップノイズあり
digitalWrite(BYPASS_PIN, LOW);
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(BYPASS_PIN, HIGH);
delay(2);
digitalWrite(FX_ON_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
}
delay(1);
}
チャタリング対策の参考ページ→Arduinoの基礎 – スイッチのオン・オフを読み取る
ATtiny13Aの使用方法はこちらの記事へ

ブログ内検索

メールフォーム

当ブログに関するお問い合わせはこちらからお願いします。 ※FAQ(よくある質問)もお読みください。

お名前
メールアドレス
件名
本文

アクセスカウンター