■Owm Pedal ハードウェア編

03s_237_1owmp.jpg
STM32F405という32ビットマイコンを搭載した自作デジタルエフェクター「Owm Pedal」です。名前は同じマイコンを搭載した既存のペダル「OWL 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の歪率が思ったより悪いですが問題ないでしょう。ノイズも測定限界以下だったので、歪み系エフェクトでもおそらく大丈夫だと思います。

■STM32 NucleoボードとオーディオコーデックICとの通信

03s_234_1nuwmp.jpg
高品質なアナログデジタルコンバータ(ADC)とデジタルアナログコンバータ(DAC)が搭載されたオーディオコーデックと呼ばれるICがあります。デジタル信号処理をする場合はこのICを使いこなすことが必要です。ほとんどのオーディオコーデックはI2C(Inter-Integrated Circuit)とI2S(Inter-IC Sound)という通信方式を使うことが可能です。

今回はWM8731というICが搭載されたAUDIO CODEC Board(MIKROE-506)を使用します。I2C通信によりデータフォーマット等の設定を行い、I2S通信でオーディオデータを送受信します。今回もADCのときと同様DMAを使いました。



Nucleoボード(NUCLEO-F303RE)とMIKROE-506との接続は下図の通りです。

MIKROE-506はC23を1nF→2.2uFへ変更し、R34は取り外しています。特に必須な改造ではありませんが、C23を大きな値に変更しないと音量がかなり下がってしまうと思われます。MISO等の表記はMIKROE-506上の表記に合わせました。



<STM32CubeMX(5.0.0) Pinout & Configurationタブ>
左側列のConnectivity→I2C1を開く

・中央列上側 Mode
 I2C : I2C 

・中央列下側 Configuration→Parameter Settingsタブ
03s_234_3nuwmss1.png
 Rise Time (ns) : 1000
 Fall Time (ns) : 300
※STM32F303がマスター(送信側)、WM8731がスレーブ(受信側)

・右側列 IC画像
 ピン位置を変更
  (61)-PB8 : I2C1_SCL
  (62)-PB9 : I2C1_SDA

左側列のMultimedia→I2S2を開く

・中央列上側 Mode
Mode : Full-Duplex Slave ※STM32F303がスレーブ(受信側)、WM8731がマスター(送信側)

・中央列下側 Configuration→Parameter Settingsタブ
03s_234_4nuwmss2.png
Data and Frame Format : 16 Bits Data on 32 Bits Frame
Selected Audio Frequency : 48KHz

・中央列下側 Configuration→DMA Settingsタブ
03s_234_5nuwmss3.png
Addボタンで2行追加する
 DMA Request : SPI2_RX
  Mode : Circular
  Data Width (Peripheral) : Half Word
  Data Width (Memory) : Half Word
 DMA Request : SPI2_TX
  Mode : Circular
  Data Width (Peripheral) : Half Word
  Data Width (Memory) : Half Word



<TrueSTUDIO(9.1.0)>
main.cに2箇所追加記載する

/* USER CODE BEGIN 0 */の下 I2Cで送信するデータ、I2Sで受信するデータを定義
uint8_t DevAddr = 0b00110100;
uint8_t pdccAddr = 0b00001100 ; //Power Down Control
uint8_t pdccData[1] = {0b00000000};
uint8_t daifAddr = 0b00001110 ; //Digital Audio Interface Format
uint8_t daifData[1] = {0b01000010}; //48kHz 16bit I2S Master Mode
uint8_t aapcAddr = 0b00001000 ; //Analog Audio Path Control
uint8_t aapcData[1] = {0b00010100};
uint8_t dapcAddr = 0b00001010 ; //Digital Audio Path Control
uint8_t dapcData[1] = {0b00000000};
uint8_t aaccAddr = 0b00010010 ; //Active Control
uint8_t aaccData[1] = {0b00000001};
uint16_t RX_BUFFER[24] = {};

/* USER CODE BEGIN 2 */の下 データを送受信
HAL_I2C_Mem_Write(&hi2c1,DevAddr,pdccAddr,1,(uint8_t*)pdccData,1,1000);
HAL_I2C_Mem_Write(&hi2c1,DevAddr,daifAddr,1,(uint8_t*)daifData,1,1000);
HAL_I2C_Mem_Write(&hi2c1,DevAddr,aapcAddr,1,(uint8_t*)aapcData,1,1000);
HAL_I2C_Mem_Write(&hi2c1,DevAddr,dapcAddr,1,(uint8_t*)dapcData,1,1000);
HAL_I2C_Mem_Write(&hi2c1,DevAddr,aaccAddr,1,(uint8_t*)aaccData,1,1000);
HAL_I2SEx_TransmitReceive_DMA(&hi2s2,(uint16_t*)RX_BUFFER,(uint16_t*)RX_BUFFER,24);

・I2C
HAL_I2C_Mem_Writeという関数を使い、データを2進数で8桁(8ビット)ずつ、3つのデータを送ります。
 1つ目…WM8731のアドレス7桁(0011010)と0→DevAddr
 2つ目…設定先アドレス7桁と設定データ1桁
 3つ目…設定データ8桁
「0b」がついているのは2進数という意味です(「0x」は16進数)。個別の設定データの詳細はWM8731のデータシートを参照してください。※音量に関する設定はデフォルトのままなので、マイク入力への音は約5倍増幅されます。

・I2S
HAL_I2SEx_TransmitReceive_DMAという関数により、データ送信と受信を同時に行います。バッファデータサイズはテストしやすいようにとりあえず24としました。今回は受信データと送信データに同一の配列を用いているので、マイク入力への音とヘッドフォン出力からの音が同じになるはずです(※音量注意)。波形が乱れる場合は、Nucleoボード上の黒いスイッチでリセットするとうまくいく場合があります。I2Sはもう一つ利用することが可能(I2S3)なので、そちらを接続し受信(Mode Slave Receive)に設定した場合は、データ送信と受信を分けることができます。



<参考ページ>
I2Cモジュールの使い方 - 電子工作の実験室
SPI/I2C シリアル通信 - Crescent

■タグ : マイコン

■2019年

あけましておめでとうございます。今年もよろしくお願いいたします。
とりあえずSTM32マイコン搭載デジタルエフェクターを完成させ、解説記事を書いていければいいなと思います。

■STM32 Nucleoボード スイッチ割り込み


AVRマイコンでのスイッチ処理は、今までメインループの中で行っていました(→MOSリレーバイパス)。しかしながらメインループでは別の処理をしたい場合が出てくると思われるので、割り込みを使ってみます。

スイッチが押されたときに指定した割り込み処理が起きるわけですが、スイッチのチャタリングにより割り込みが何度も発生してしまうことになります。今回は対策が楽なハードウェア(抵抗とコンデンサ)によるチャタリング除去を行うことにしました。テストとしてボード上のLEDの点滅速度をスイッチにより変更します。

Nucleoボードにはすでに青いスイッチが付いており、さらにもう一つタクトスイッチを下図の通り接続します。コンデンサに直列に抵抗を入れるのはあまり見かけませんが、Nucleoボード上の青いスイッチ周辺に採用されていました。




<STM32CubeMX(5.0.0) Pinout & Configurationタブ>
右側IC画像
 14番ピン(PA0)にGPIO_EXTI0を設定
 2番ピン(PC13)がデフォルトでGPIO_EXTI13に設定済
 21番ピン(PA5)がデフォルトでGPIO_Outputに設定済

左側列のSystem Core→GPIOを開く
・中央列下側 Configuration→GPIOタブ

 PA0 GPIO mode : External Interrupt Mode with Falling edge trigger detection
 PA0 GPIO Pull-up/Pull-down : Pull up
・中央列下側 Configuration→NVICタブ

 EXTI line0 interrupt : Enabledにチェックを入れる
 EXTI line[15:10] interrupts : Enabledにチェックを入れる



<TrueSTUDIO(9.1.0)>
main.cに3箇所追加記載する

/* USER CODE BEGIN 0 */の下 変数(LED点滅間隔時間)を定義
volatile uint16_t interval = 200;

/* USER CODE BEGIN 3 */の下 LED点滅
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(interval);

/* USER CODE BEGIN 4 */の下 スイッチによりLED点滅間隔時間を変更
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) interval = 2 * interval;
if (GPIO_Pin == GPIO_PIN_0) interval = interval / 2;
}



<参考ページ>
割り込みを使う - DSP空挺団

(ハードウェア以外でのチャタリング対策)
割り込み処理 -第3回:チャタリング防止 - Arduinoで遊ぶブログ
マイコンにおけるチャタリング&ノイズ対策 - 味わい尽くせ!

■タグ : マイコン

■STM32 NucleoボードのADCを使う


前回Lチカを行ったNucleoボードですが、今度はエフェクターのパラメータ変更を想定してADC(アナログ・デジタル・コンバータ)を使ってみます。アナログ電圧値をデジタル数値に変換することにより、ポット(可変抵抗)をどれだけ回転させたか取得できます。

実際の運用ではバックグラウンドで自動的に複数ポットの値を取得し続ける必要が出てくると思いますので、DMA(Direct Memory Access)を利用します。DMAとは、CPUを介さずデータ転送できるというよくわからないけど便利な機能らしいです。



Nucleoボード(NUCLEO-F303RE)とポットとの接続は下記の通りです。ポットは抵抗値5kΩ以上でBカーブのものがよいでしょう。

ポットの1番ピン→NucleoボードのGND
ポットの2番ピン→NucleoボードのA0
ポットの3番ピン→Nucleoボードの3V3(5Vと間違えないように!)

ポットは1つですが、2チャネル分セットアップしていきます。ソフトの基本操作については前回記事をご参照ください。変更する箇所を記載していますが、ソフトのバージョンによりデフォルト値が違うかもしれませんので、スクリーンショットも確認した方がよいだろうと思います。



<STM32CubeMX(5.0.0) Pinout & Configurationタブ>
左側列のAnalog→ADC1を開く

・中央列上側 Mode
 IN1 : IN1 Single-ended
 IN2 : IN2 Single-ended
 →右側IC画像の14番ピン(PA0)と15番ピン(PA1)が自動的に切り替わる

・中央列下側 Configuration→Parameter Settingsタブ

Clock Prescaler : Syncronous clock mode divided by 4
Continuous Conversion Mode : Enabled
DMA Continous Request : Enabled
Number Of Conversion : 2
 →Scan Conversion Mode がEnableに切り替わり、Rank 2 が追加される
Rank 1 Sampling Time : 19.5 Cycles
Rank 2 Channel : Channel 2
Rank 2 Sampling Time : 19.5 Cycles

・中央列下側 Configuration→DMA Settingsタブ

Addボタンで行が追加される
 DMA Request : ADC1
 Mode : Circular ※Normalの場合ADC値取得が1回だけとなる



<TrueSTUDIO(9.1.0)>
main.cに2箇所追加記載する

/* USER CODE BEGIN 0 */の下 ADC値を格納する配列を定義
uint16_t adcValue[2];

/* USER CODE BEGIN 2 */の下 ADC値取得開始
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adcValue, 2);

デバッグ画面で一時停止中adcValueにマウスカーソルを合わせると、取得したADC値が確認できます。

ポットのシャフトを動かし、再開と一時停止をするとadcValue[0]が0~4095の間で変化します。ポットの2番ピンをNucleoボードのA1につないだ場合は、adcValue[1]が変化します。細かい設定はまた別の機会に見直すとして、とりあえず値を取得できているようなのでOKでしょう。



<補足情報>
・設定したチャネル数のADC値取得後に何かしらの処理を行う場合、/* USER CODE BEGIN 4 */の下に以下のように記載する
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc){
// 処理
}

・ADC値取得を中止する場合は下記関数を使う
HAL_ADC_Stop_DMA(&hadc1);



<参考ページ>
STM32でADCをやってみる2(DMAを使ったレギュラ変換) - ガレスタさんのDIY日記
STM32マイコンでADCを使ってみる話 - JP7FKFの備忘録

■タグ : マイコン

ブログ内検索

メールフォーム

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

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

アクセスカウンター