2015年11月17日火曜日

PSoC 5LPのデジタル・フィルタを使ってみる CPUで波形生成

今作りかけのリズムマシンのWhite Noiseで作っている波形にフィルターをかけたいのでデジタルフィルタをもう少しやってみた。

デジタルフィルタなんてMatlabでもやったことがないし(あ?やったかな?覚えてない(^q^;)手探り状態ですが、PSoCのFilterコンポーネントはz変換とか行列すらも出てこないので見た目通りに試してみた。

前回やったExampleでは外部入力された波形をFilterで加工しているが、リズムマシンはCPUで波形を作っているのでCPUからFilterを通さないといけいない。

サンプリング間隔ごとに逐次波形を計算しているのでDMAは不要だ。(←とおもう)

PSoC Creatorのプロジェクト
https://github.com/ryood/PSoC_5LP_DigitalFilter_Test


TopDesign


CPUで波形を生成して、「Filter」コンポーネントを通して「VDAC8_1」と「Opamp_1」のボルテージフォロワを通して出力する。

「VDAC8_2」と「Opamp_2」はフィルターを通す前の波形の出力用。

「Timer」はサンプリング周波数で割り込みをかけるものだ。

「Pin_Timer_TC」はタイマーがオーバーフローした時(サンプリング間隔で)にパルスを発生、「Pin_ISR_Check」は割り込みルーチン内のタイミング計測用だ。

FilterのConfigureダイアログ


前回やったExampleからFilter TypeをHigh Passに、Cutoffを8kHzに変更した。

ソースコード

 #include <device.h>  
 #include <VDAC8.h>  
 #include <stdlib.h>  
 volatile uint8 cnt = 0;  
 CY_ISR(Timer_interrupt_handler)  
 {  
   uint16 v, fv;  
   /* Read Status register in order to clear the sticky Terminal Count (TC) bit   
      * in the status register. Note that the function is not called, but rather   
      * the status is read directly.  
      */  
       Timer_STATUS;  
   cnt++;  
   v = rand() % UINT16_MAX;  
   // Filterをかける前の波形を出力    
   VDAC8_2_SetValue(v >> 8);  
   Pin_ISR_Check_Write(1u);  
   Filter_Write16(Filter_CHANNEL_A, v);  
   /* Poll waiting for the holding register to have data to read */  
   while (Filter_IsInterruptChannelA() == 0) ;  
   fv = Filter_Read16(Filter_CHANNEL_A);  
     Pin_ISR_Check_Write(0u);  
   VDAC8_1_SetValue(fv >> 8);  
 }  
 int main()  
 {  
   /* Start all components used on schematic */  
   VDAC8_1_Start();  
   VDAC8_2_Start();  
   Opamp_1_Start();  
   Opamp_2_Start();  
   Filter_Start();  
   Timer_Start();  
   ISR_Timer_StartEx(Timer_interrupt_handler);  
     /* Enable the interrupt register bit to poll  
    Value 1 for Channel A, Value 2 for Channel B */  
   Filter_INT_CTRL_REG |= (1 << Filter_CHANNEL_A);  
   CyGlobalIntEnable;  
   for(;;)  
   {  
     //CyDelay(10);  
   }  
 } /* End of main */  


FilterをCPUから直接アクセスするにはFilter_Write**()とFilter_Read**()というAPIを使えば済むようだ。 ※**は引数のデータ型

rand()関数でWhite Noiseを作ってHPFを通してみた。

出力波形

PCのWavegeneでFFTしてみた。

Filterに入れる前

Filterを通した後

実行時間


Filterの演算が終わるまでCPUがWaitしているのでどれぐらい時間がかかっているか見てみた。


ch1:Pin_ISR_Check ch2:Pin_Timer_TC

Master_Clockを74.7MHzに設定。サンプリング周波数48kHz。

PWはデューティーの+側の時間で2.800us。周波数にすると357kHzぐらいだ。

メモ:


  • Filterの設定の「Filter gain:」を「1」にするとほとんどFilterが効かなくなる模様
  • PSoC 5LP Prototyping Kitで使われているCY8C5888LTI-LP097は最大クロックが80MHzだが内蔵クロックを使うとうまく設定できない。(クロックの誤差で80MHzを超えるため)
  • PSoC 5LPはPSoC4にくらべるとかなり強力。Cortex M0とCortexM3の差+UDBいっぱい+DFB+メモリもいっぱい(^q^/