おはよーございます。
セカイの信号処理LOVERSの皆さんこんにちは。今回は中目黒スタバからお送りしています。
今日の目標:
32kサンプルデータを8kサンプルに下げる
8kサンプルでDACへ出力する
サンプリング周波数下げをdecimatorといいます(サンプリング周波数上げはinterporator)
どちらもCMSIS関数にあるのですが、1024個入れたら256個出てくるんだろうなぁ やってみなくちゃわからない
簡単に言えばdataを4つおきに採用して、間の3つを捨てればいいのですが、ただそうしたのではエイリアシングノイズが発生してSN悪化しちゃいます
そこで間引く前に4kHzのLPFを通しておけばOK、というのが1/4 decimatorの原理です
実際の実装はLPFと3つ捨てを同時にやるとか簡素化テクがあるんですがねー
ここまで書いて珈琲が無くなったので帰宅します
エイリアン・ロムルス観にいこうかなという煩悩がアタマをもたげつつある......
ーーーー
帰宅してエイリアンロムルスの劇場を検索する...
評判良いけど、劇場はあまり熱を入れてないですね.
・映写室が教室みたいな小さい部屋ばかり(とくにTOHOが不熱心)
・IMAXとかいう+700円の部屋なら大きいけど¥2700払うのは嫌
・上映回数が多くない
この映画を教室で観る気ないんで、急速にやる気が減退しました.
ーーーー
やっと動きました
↓8kサンプルと32kサンプルの比較(DAC出力)
↓拡大しないとわからないーーーー
ブロック図
これを実現するにはADC~DACのclock設定で一苦労する必要があります.
・下段は、32KサンプルのままストレートでDACへ出します
・上段は、1/4に間引いて、8kサンプルでDACから出します
・DACのbufferサイズが異なります.下段1024、上段256になります
・演算量が1/4になって嬉しいな
・DACを駆動する8kHzは32kHzと同期してなくちゃいけません
・そのためTIM4→TIM5のslave modeでタイマを動かします
ーーーー
TIM4→TIM5のslave modeについて
これに一番苦労したんだよなぁ...
STM32H723 reference manual(pdfサイズ大きいので注意)のtable 355にこういう表があります.これを探すのに苦労しました.
timerのmaster-slave運用とは何かというと、まぁ読者がイメージする通りですよ.TIM4の出力でTIM5を動かすということ.
ここでは、TIM4が出力する32kHzをTIM5に与え、TIM5が4カウントして8kHzを作る.
32kと8kは同期する.
なのですが、、、TIM4→TIM5が連結しているってどうやったら判るんですか?
それが上のtable355の赤の注記です.日本語に翻訳するとこうゆうこと.
TIM4のトリガ出力(32k)が、TIM5のITR3に接続されているので、TIM5をslave modeにしてITR3をTIM5のclockにすれば8kを発生できる.
table355によれば、TIM4→TIM5だけでなく、いろいろなペアが採用できる.なのにどうしてTIM4とTIM5を使ったのか?
それは、ADCとDACがTIM4とTIM5を変換トリガとして選択できるからです.
まずADCはこんな選択肢がある.TIM4 32kHzを選択可.めでたし.
DACはch1とch2にそれぞれTIM5 8kとTIM4 32kを選択.めでたし.そしたら、TIM4とTIM5の設定をします.
TIM4はsystem clk 275MHzを8593分周する普通の動きです.masterともいう.
TIM5はslaveで設定は少し複雑.
TIM4の設定
①275MHz/8593=32kHz
②32kHzを出力する意味 →ADC/DACへ供給
①外部clock mode
②外部clock=ITR3=TIM4のトリガが接続される=32kHz
③4分周
ーーーー
ブロック図に描いたring-bufferの取り扱いについては、こちらに書きましたので割愛します.
ーーーー
ーーーー
DACのDMA設定
CH1とCH2のDMAを追加します
main()の初期化
↓ring-bufferを確保
uint32_t ADCfifo[1024];
uint32_t DAC1CH1fifo[256]; // 1/4 decimated
uint32_t DAC1CH2fifo[1024]; // No decimation
↓構造体初期化
decimation4_init();
fir_init();
↓ADC,DACをDMAでstartさせる、あとは自走する
HAL_ADC_Start_DMA(hadc1, ADCfifo, 1024);
HAL_Delay(1); // DAC runs 1mSec after ADC
HAL_DAC_Start_DMA(hdac1, DAC_CHANNEL_1, DAC1CH1fifo, 256,
DAC_ALIGN_12B_R); 8kHzサンプル
HAL_DAC_Start_DMA(hdac1, DAC_CHANNEL_2, DAC1CH2fifo, 1024,
DAC_ALIGN_12B_R); 32kHzサンプル
↓decimation4_init()界隈
extern float32_t fir_decimate_taps[]; ←別途記述、タップ係数
float32_t fir_decimate_variables[TAP_NUM_DECIMATE+BLOCKSIZE];
arm_fir_decimate_instance_f32 fir_decimate_params;
void decimation4_init(void){
arm_fir_decimate_init_f32(
&fir_decimate_params,
TAP_NUM_DECIMATE, // 79
DECIMATION, // 4
fir_decimate_taps,
fir_decimate_variables,
BLOCKSIZE //512
);
}
↓fir_init()界隈
arm_fir_instance_f32 fir_params;
arm_fir_instance_f32 fir_params2;
float32_t fir_variables[TAP_NUM_DECIMATE+BLOCKSIZE];
float32_t fir_variables2[TAP_NUM_DECIMATE+BLOCKSIZE];
void fir_init(void){
arm_fir_init_f32(
&fir_params,
TAP_NUM_DECIMATE,
fir_decimate_taps, ←decimateと同じタップ係数
fir_variables,
BLOCKSIZE
);
arm_fir_init_f32(
&fir_params2,
TAP_NUM_DECIMATE,
fir_decimate_taps,
fir_variables2,
BLOCKSIZE
);
}
ーーーー
ring-buffer半分割り込み
ring-buffer全部割り込み
ADCがring-bufferに半分までdataを積んだら割り込みがかかります.
ADCがring-bufferの全部までdataを積んだら割り込みがかかります.
ring-bufferが良く判らない人はこちらを読んでください.
q31_t ADCcopy[512]; ←512はring-bufferの半分のサイズ
float32_t ADCcopyf[512];
float32_t firout[512];
float32_t decimated[512/4]; ←1/4に間引かれたもの
↓ring-buffer半分割り込み weak宣言されているので上書きします
void HAL_ADC_ConvHalfCpltCallback(){
arm_copy_q31( (q31_t*)&ADCfifo[0], ADCcopy, 512);
arm_q31_to_float( ADCcopy, ADCcopyf, 512);
arm_fir_f32( &fir_params, ADCcopyf, firout, 512);
arm_fir_decimate_f32( &fir_decimate_params, ADCcopyf,
decimated, 512);
arm_float_to_q31( decimated, (q31_t*)&DAC1CH1fifo[512/4], 512/4);
arm_float_to_q31( firout, (q31_t*)&DAC1CH2fifo[512], 512);
}
↓ring-buffer全部割り込み weak宣言されているので上書きします
void HAL_ADC_ConvCpltCallback(){
arm_copy_q31( (q31_t*)&ADCfifo[512], ADCcopy, 512);
arm_q31_to_float( ADCcopy, ADCcopyf, 512);
arm_fir_f32( &fir_params, ADCcopyf, firout, 512);
arm_fir_decimate_f32( &fir_decimate_params, ADCcopyf,
decimated, 512);
arm_float_to_q31( decimated, (q31_t*)&DAC1CH1fifo[0], 512/4);
arm_float_to_q31( firout, (q31_t*)&DAC1CH2fifo[0], 512);
}
追記:FLASH容量をずいぶん食ってるので調べたら、、、twiddleってのが入ってます.twiddleっていうのはsin/cos tableみたいな係数なのでFFTに関連したものなのは明らかです.でも、2048点FFTや4096点FFTは使ってないので余計なものを入れないで欲しいんだけどなぁ.
twiddleCoef_2048 16 KB
twiddleCoef_rfft_4096 16 KB
twiddleCoef_1024 8 KB
twiddleCoef_rfft_2048 8 KB
armBitRevIndexTable2048 7.44 KB
twiddleCoef_512 4 KB
twiddleCoef_rfft_1024 4 KB
以上です
かしこ
0 件のコメント:
コメントを投稿