趣味のブログ

アクセスカウンタ

zoom RSS dsPICでグラフィック(ソフトウェアFFT)

<<   作成日時 : 2012/04/18 20:11   >>

ナイス ブログ気持玉 1 / トラックバック 0 / コメント 0

dsPIC33FJ32GP202を使うと、40MIPSの速度で実行できるので、時間のかかるグラフィックや浮動小数点の計算も苦にならなくなります。ソフトウェアによるFFTでもかなり速くなることが期待できますので、そのままコピーしてきました。ソースの変更もあまり必要なくあっさり動作しましたが、速度も速くなっています。時間軸のグラフを描画した後、FFTを計算して周波数軸のグラフを描くのですが、ほとんど時間を消費していません。リアルタイムのスペクトル表示の可能性が少し見えてきました。

画像HiTech-CとC30の違いは、おもにレジスタの指定の仕方が違っていることで、C30では、構造体によって指定するようになっています。HiTech-Cでも、新しい指定法は同様の方法になっているので、ますます移行が楽になります。このプログラムでは、レジスタの指定はほとんどなく、書き換えなければならないのは最小限ですみました。プログラムに大きな違いはありませんが、RAMが十分に使えるので、FFTの要素数を128ポイントにして見ました。これは、液晶画面の横サイズと同じですが、周波数軸では、右半分が折り返して表示されるため左半分のみ表示しています。そのため、1ドット置きの表示になります。画面をフルに使うなら要素数を2倍の256ポイントにするのがよいのですが、RAMはそこまでは使えないようです。
計算は速いようなので、画面のちらつきを抑えるために、毎回表示をクリアせず、XORによる表示によって描いた線を消していくのがよさそうです。今後試してみたいと思います。
FFTの計算は時間のかかる計算の例のつもりとしているのですが、dsPICにおいては、DSPを内蔵しているので、DSPによりFFTを計算することができます。ただし、DSPでは、固定小数点の計算になり、信号の大きさをあらかじめ合わせておく必要があります。DSPを使ったFFTの計算はライブラリを使うことになります。

サンプルプログラム:SFFT33FJ32.c
#include  <p33Fxxxx.h>
#include  "glcd_lib.h"
#include  <math.h>

/*****  コンフィギュレーションの設定  ********/
//  HSosc=20MHz  20MHz/4*32/2=80MHZ(Full)  Fcy=40MHz
_FOSCSEL(FNOSC_PRIPLL);
_FOSC(FCKSM_CSDCMD  &  OSCIOFNC_ON  &  POSCMD_HS);
_FWDT(FWDTEN_OFF);
_FPOR(FPWRT_PWR128);

static  void  InitializeSystem(void)
{
//  HS20MHz  ->  80MHz  40MIPS
       CLKDIVbits.PLLPRE  =  2;    //  1/4
       PLLFBDbits.PLLDIV  =  30;  //  32
       CLKDIVbits.PLLPOST  =  0;  //  1/2
       CLKDIVbits.FRCDIV  =  0;    //  1/1
       CLKDIVbits.DOZEN  =  0;
       CLKDIVbits.DOZE  =  0;        //Fcy/1
       AD1PCFGL  =  0xFFFF;
}//end  InitializeSystem

#define  DNUMB      128

double    u[DNUMB],v[DNUMB];
int  dn,powr,m,j1,j2,i,j,k,ndv2;
double    w,arg,c,s,t1,t2;

int
exp2_2(int  d)
{
       int  i;

       i=0;
       do{
               i++;  d=d>>1;
       }  while(d!=1);
       return  i;
}

void
fft(int  flag)
{
       dn=DNUMB;
       w=6.283185303/DNUMB;
       powr=exp2_2(DNUMB);
       for(i=0;i<powr;i++){
               m=dn;
               dn=dn/2;
               arg=0;
               for(j=0;j<dn;j++){
                       c=cos(arg);
                       s=-flag*sin(arg);
                       arg+=w;
                       k=m;
                       do{
                               j1=k-m+j;
                               j2=j1+dn;
                               t1=u[j1]-u[j2];
                               t2=v[j1]-v[j2];
                               u[j1]=u[j1]+u[j2];
                               v[j1]=v[j1]+v[j2];
                               u[j2]=c*t1  +  s*t2;
                               v[j2]=c*t2  -  s*t1;
                               k+=m;
                       }  while(k<=DNUMB);
               }
               w*=2;
       }
       /*  bit  reverse  */
       j=0;
       ndv2=DNUMB/2;
       for(i=0;i<DNUMB-1;i++){
               if(i<j){
                       t1=u[j];
                       t2=v[j];
                       u[j]=u[i];
                       v[j]=v[i];
                       u[i]=t1;
                       v[i]=t2;
               }
               k=ndv2;
               while(k<j+1){
                       j-=k;
                       k/=2;
               }
               j+=k;
       }
       if(flag==1){
               for(j=0;j<DNUMB;j++){
                       u[j]/=DNUMB;
                       v[j]/=DNUMB;
               }
       }
}

int  main(void)
{
       double    pai2=6.283185303;

       InitializeSystem();
       TRISA  =  0x0003;
       TRISB  =  0x0003;
       LATB    =  0x0000;

       PORTBbits.RB4=1;  //RST=H
       lcd_Init();
//----------------------------------------------------
//  Set  time  region  data
       lcd_Clear(0);              //表示クリア
       for(i=0;i<DNUMB;i++){
//  squere  wave
       //    if  (cos(i*6.283185303/DNUMB)>0)  u[i]=100.0;  else  u[i]=-100.0;
//  4Hz  +  (1/2)2Hz
       //    u[i]=128.0*cos(4.0*(double)i*6.283185303/(double)DNUMB)
       //              +64.0*cos(2.0*(double)i*6.283185303/(double)DNUMB);
//  AM  modulation
               u[i]=128.0*(1+cos(2.0*pai2*i/DNUMB))*cos(12.0*i*pai2/DNUMB);
//  delta  pulse
       //    if(i==1)  u[i]=2560;  else  u[i]=0.0;
//  display  graph  for  time  region
               if(i==0)
                       lcd_Pixel(1*i,(int)u[i]/8+32,1);
               else
                       lcd_Line(1*(i-1),(int)u[i-1]/8+32,1*i,(int)u[i]/8+32);
               v[i]=0.0;      //  imaginal  part
       }
//----------------------------------------------------
//  Fast  Fourie  Transration
       fft(1);
//----------------------------------------------------
//  Display  frequency  region  data(Only  real  part  u[i])
       lcd_Clear(0);              //表示クリア
       for(i=0;i<DNUMB/2;i++){
               lcd_Line(2*i,32,2*i,32+(int)u[i]/2);
       }
       lcd_Line(0,0,0,63);
       lcd_Line(0,32,127,32);
//----------------------------------------------------
       while(1)  ;
}
------------------------------------------------------------------
GLCD_DRV.c
#include  <p33Fxxxx.h>
#include  "glcd_lib.h"
#include  "GEO-FONT-KP.h"

void  lcd_Write(char  cs,  char  code,  char  DIflag){
       int  data;

       LCD_RW  =  0;
       if(cs==1){
               LCD_CS1  =  1;
               LCD_CS2  =  0;
       }else{
               LCD_CS1  =  0;
               LCD_CS2  =  1;
       }
       data  =  (int)code;

       LCD_DB  =  (data<<8)|(LCD_DB&0xff);

       if  (DIflag  ==  0)
               LCD_DI  =  1;
       else
               LCD_DI  =  0;
       Delay1u(1);
       LCD_E  =  1;
       Delay1u(1);
       LCD_E  =  0;
       Delay1u(3);
       LCD_CS1  =  0;
       LCD_CS2  =  0;
       LCD_RW  =  1;
       Delay1u(5);
}

char  lcd_Read(char  cs){
       int  data;

       LCD_TRIS  =  (0xFF00);

       LCD_RW  =  1;
       if(cs==1){
               LCD_CS1  =  1;
               LCD_CS2  =  0;
       }else{
               LCD_CS1  =  0;
               LCD_CS2  =  1;
       }
       LCD_DI  =  1;
       Delay1u(1);
       LCD_E  =  1;
       Delay1u(1);
       LCD_E  =  0;
       Delay1u(3);

       data  =  (LCD_DB  &  0xFF00)>>8;

       Delay1u(1);
       LCD_CS1  =  0;
       LCD_CS2  =  0;

       LCD_TRIS  =  (00);

       return((char)data);
}

途中省略

void  Delay1m(int  time){
       delay_ms(time);
}

void  Delay1u(int  time){
       delay_us(time);
}
/**********************************
*    ループ遅延関数 usec単位
**********************************/
void  delay_us(unsigned  short  usec){
       unsigned  short  i,  Max;
       
       Max  =  2*usec  *  Fosc/5;
       for(i=0;  i<Max;  i++)
       {      }
}
/**********************************
*    ループ遅延関数 msec単位
**********************************/            
void  delay_ms(unsigned  short  msec){
       unsigned  short  i;
       
       for(i=0;  i<msec;  i++)
               delay_us(1000);
}
------------------------------------------------------------
他に
GEO-FONT-KP.H
glcd_lib.h
が必要




LCD&タッチセンサ活用の素 (基礎入門)
技術評論社
後閑 哲也

amazon.co.jpで買う
Amazonアソシエイト by LCD&タッチセンサ活用の素 (基礎入門) の詳しい情報を見る / ウェブリブログ商品ポータル


テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 1
ナイス

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
本 文
dsPICでグラフィック(ソフトウェアFFT) 趣味のブログ/BIGLOBEウェブリブログ
文字サイズ:       閉じる