2026年4月24日金曜日

【回路】STM32にDAC PT8211を取り付ける(重箱の隅)

昨日の投稿で、DAC搭載STM32が少ないので自分でつけるべくアキバへ行った件の続報.

秋月でPT8211を買いました.
↓weactのSTM32F401基板に取り付けました.動きました.

少してこづったので要点を書いときます.

まずclk構成です.
STM32F401のclkは84MHz
I2Sの内部で分周してサンプリングclk 8kHzをつくります(Master Mode)
I2SはLRCK=8kHzを出力します
DATAは16bitです(LRだから32bit)
BCKは8x32=256kHz
ここで、サンプリングclk(Fs)がI2Sによって生成されてしまうことを留意しておきましょう.後で気分が悪い事態に直面します.

気分が悪いことの1つを先に書いときますと、I2Sが生成するFsの選択肢はこれだけです.中間値は選択できません.
ならばSlave Modeを使えばいいと思うでしょうけど、SlaveだとBCKとLRCK=BCK/32を与えなくてはいけないので、外部clkでI2Sを動かしたければ外部にFPGAでも搭載して÷32までせにゃいけません.楽したいからSTM32を使うのにわざわざFPGAを載せたりするかフツー?

こうゆうclk系の不都合って出鼻を挫かれるのですごく嫌いなんです、わたしは.

一番遅い8kHzで動かすことにします.

ーーーー
それではSTM32CubeMXの設定をば.
↓キモの部分は赤線のところでしょう.
とりわけ MSB First(Left Justified)、16bit on 16bit は重要で、PT8211のI2S timingにマッチさせるにはこれ以外の選択肢はないと思います.
clock pol.は効いてるのか効いてないのかよくわかりません.というか何が変わったのか分かりません.

ーーーー
↓8kHzに間に合わせてI2Sを動かすにはDMAが必須です.I2SにDMAを紐づけときます.
bufferはCircularです.16bitなのでHalf Wordです.
↓DMAのcallback()を利用するので割込みも必要です.
↓STM32F401のピン配置.この3本をPT8211へ接続します.
↓PT8211のピン配置.WSはLRCKのことです.

ーーーー
codeへ.

まずデータ準備.

PT8211は2の補数の16bitです.実験ですので何も考えずにベタ並べしときます.
偶数番目がLch、奇数番目がRchということ.(逆かもw)
int16_t DACbuf[26];
  DACbuf[0]  = -30000;  DACbuf[1]  =  30000;
  DACbuf[2]  = -25000;  DACbuf[3]  =  25000;
  DACbuf[4]  = -20000;  DACbuf[5]  =  20000;
  DACbuf[6]  = -15000;  DACbuf[7]  =  15000;
  DACbuf[8]  = -10000;  DACbuf[9]  =  10000;
  DACbuf[10] = -5000;   DACbuf[11] =  5000;
  DACbuf[12] = 0;  DACbuf[13] =  0;
  DACbuf[14] = 5000;  DACbuf[15] = -5000;
  DACbuf[16] = 10000;  DACbuf[17] = -10000;
  DACbuf[18] = 15000;  DACbuf[19] = -15000;
  DACbuf[20] = 20000;  DACbuf[21] = -20000;
  DACbuf[22] = 25000;  DACbuf[23] = -25000;
  DACbuf[24] = 30000;  DACbuf[25] = -30000;

DMA関連
main()の始まりの方でDMAを起動.26wordを送信させるおまじない.
  HAL_I2S_Transmit_DMA( &hi2s3, DACbuf, 26);

DMAのcallback関数、何処かで_weak宣言されているので自作関数で上書きする.DMA送信完了したらすぐさま次のDMAを起動している.
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s){
HAL_I2S_Transmit_DMA( &hi2s3, DACbuf, 26);
}
追記:bufferがcircularなので↑このDMA都度起動はしなくても良いかもしれない.

以上で、こんな波形がでるというわけ.


続きます.
続きはADCとの連携動作.

ーーーーーーーー
DACはI2Sが生成するFsで動きました.
でも、これでおしまいじゃないです.
最終的には、ADC→信号処理→DAC のように信号を流したいわけです.つまり、ADCとDACが同じclkで動かなくちゃいけません.

でも、I2Sは勝手に動きます.
ADCはI2Sとは別の動きをします. ←こいつら同期しないじゃん! fuckでしょこんなの

ADCとI2Sをどうやって同期させるか?
↓無理やりですがこうすれば同期できると思います.
たぶん意味が判らんと思います.
I2Sの分周器の分周比と、TIM1の分周比を同じにすればADC系列とI2S系列を同期できるという理屈です.
84MHz→8kHzを作るのですから分周比=10500だと予想できます.

しかし、この分周比が10500じゃないんですよ.
精密に実測したところ、分周比は10495でした.厳密に8kHzじゃないんです.8003Hzとかそんななの.I2Sの内部回路なにやってんの? イミフすぎて腰が抜けるんだが....

ともあれ10495というmagic numberが判明したのですから、TIM1の分周比も同じくします.この操作によって、全処理系のclkが同期しました.

続きます.




あでゅ~

0 件のコメント:

コメントを投稿