SSブログ

(続) SilentC で QSPI を使う [ColdFire V2]このエントリーを含むはてなブックマーク#

2090522

「QSPI」再び。 QSPIを使うためには、同一番地に連続書き込みをする必要があります。 ところが、SilentCを使うと書き込みだけを行ってくれないようで限界があるらしいことがわかりました。 でも、SilentCの手軽さは、捨てがたい。 と考えあぐねていたある日、メモリ空間に書き込みを行うのは、何もプログラム、つまりCPUに限らないことに気がつきました。

QSPIのRAMをDMAで初期化する

MCF52233には、DMAが備わっています。 そして、DMAには、あるメモリ空間の内容を特定のアドレスに連続して書き込む機能が備わっています。 そうだ、プログラム(CPU)で書き込めないなら、DMAで書き込んじゃえ。

int  *pqspar =0x4010006c;
int  *qmr    =0x40000340;
int  *qdlyr  =0x40000344;
int  *qwr    =0x40000348;
int  *qir    =0x4000034c;
int  *qar    =0x40000350;
int  *qdr    =0x40000354;
main(){
  int v;
  init();
  #stop 0
  v=0
  for(;;){
    if(Getc(0)=='q')break;
    SystemSleep();
    send((v<<1)&0x1FFE);
    v+=80;
    if (v>2480) v=0;
  }
}
init(){
  int *command = MemoryAlloc(4);
  *pqspar=0x0051; // PQSPAR[3,2,0]=01 (QSPI)
  *qmr   =0x801E; // See table
  *qdlyr =0x0404; // See table
  *qir   =0x000F; // clear all flags
  command[0] = 0x4E00; // Send 16-bit
  writeQDR(0x0020,command,1); // Put a command
  *qwr   =0x1000; // See table
  MemoryFree(command);
}
send(int value){
  int *data = MemoryAlloc(4);
  data[0] = value;
  writeQDR(0x0000,data,1); // Put a TX data
  *qdlyr|=0x8000; // SPE=1
  while (!(*qir&0x0001));// wait SPI completed
  *qir   =0x000F; // clear all flags
  MemoryFree(data);
}
writeQDR(int addr, char *buf, int len){
  char *pacr4 =0x40000028;
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  *pacr4= 0x04; // Enable QSPI access
  *bcr1 = 0x01000000; // clear DONE
  *qar  = addr; // RAM address
  *sar1 = buf; // source
  *dar1 = qdr; // destination
  *bcr1 = len*2; // byte count
  *dcr1 = 0x00650000; // Simple word transfer
}

QSPIのRAMにデータを書き込むための関数 writeQDR を作りました。 書き込み先アドレスと書き込むデータのアドレスと長さを指定します。 これで、コマンド部も送信データ部も書き込みが可能です。

GPIOのレジスタにDMAで書き込みを行ったときにわかったように、レジスタへのユーザ・モードでの書き込みアクセスを許可しなくてはなりません。 QSPIのレジスタへの許可を与えるのは、PACR4レジスタのACCESS_CTRL0というフィールドです。 GPIOのときと同じようにユーザ・モードでQSPIのレジスタに読み書きが出来るように設定します。

QSPIが受け取ったデータを取り出す関数は作成していませんので、各自、お考えください。

QSPIから周期的にデータを送り出す

QSPIは、キューの内容を繰り返し送り出す機能を持っています。 もし、キューの送出データに正弦波データを入れてあれば、D/Aコンバータの出力からは正弦波が出力されるはずです。 この場合のデータ更新の周期は、データ転送間隔で決まります。 そのため、データ転送間隔、たとえばボーレートを制御すると、音程も変えられるはずです。 しかも、音を出す動作にソフトウェアの関与は不要です。

int  *pqspar =0x4010006c;
int  *qmr    =0x40000340;
int  *qdlyr  =0x40000344;
int  *qwr    =0x40000348;
int  *qir    =0x4000034c;
int  *qar    =0x40000350;
int  *qdr    =0x40000354;
main(){
  int v;
  init();
  #stop 0
  v=255;
  for(;;){
    if(Getc(0)=='q')break;
    Sleep(3);
    *qmr=0x8000+v;
    v--;
    if (v<60) v=255;
  }
}
init(){
  int *command = MemoryAlloc(34);
  int *data = MemoryAlloc(34);
  *pqspar=0x0051; // PQSPAR[3,2,0]=01 (QSPI)
  *qmr   =0x80FF; // See table
  *qdlyr =0x0404; // See table
  *qir   =0x000F; // clear all flags
  for (int i=0;i<16;i++){
    command[i] = 0x4E00; // Send 16-bit
  }
  writeQDR(0x0020,command,16); // Put a command
  *qwr   =0x5F00; // 16-word transfer
  data[ 0]=data[ 8]=1000*2; // sin0
  data[ 1]=data[ 7]=1383*2; // sin22.5
  data[ 2]=data[ 6]=1707*2; // sin45
  data[ 3]=data[ 5]=1924*2; // sin67.5
  data[ 4]         =2000*2; // sin90
  data[ 9]=data[15]= 617*2; // sin112.5
  data[10]=data[14]= 293*2; // sin135
  data[11]=data[13]=  76*2; // sin157.5
  data[12]         =   0*2; // sin180
  writeQDR(0x0000,data,16); // Put a TX data
  *qdlyr|=0x8000; // SPE=1
  MemoryFree(data);
  MemoryFree(command);
}
send(int value){
}
writeQDR(int addr, char *buf, int len){
  char *pacr4 =0x40000028;
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  *pacr4= 0x04; // Enable QSPI access
  *bcr1 = 0x01000000; // clear DONE
  *qar  = addr; // RAM address
  *sar1 = buf; // source
  *dar1 = qdr; // destination
  *bcr1 = len*2; // byte count
  *dcr1 = 0x00650000; // Simple word transfer
}

ソフトウェアが全く関与しないのも面白くないので、メインプログラムでQSPIのボーレートを変更して音階を変化させるようにしてみました。 回路は、LEDピカピカと同じものを使っています。 トランジスタのエミッタにクリスタル・イヤホンを当てて出力をとりだします。 D/Aコンバータで曲がりなりにも正弦波を作っているので、矩形波にくらべると柔らかな音が出てきました。 音階の精度は、QSPIの転送間隔時間によっているので、少しビブラートがかかったように聞こえます。 正式には、割り込みを使って、QSPIにトリガをかけた方がよいのでしょうね。

参考物件

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

楽天市場連動記念、無関係(でもないか)広告


nice!(0)  コメント(3)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 3

ゆい

int *pqspar =0x4010006c;
って
char *pqspar =0x40100059;
のだと思うのですが
by ゆい (2010-06-28 22:52) 

ゆい

ごめんなさい、あってました
見ているマニュアルを間違えてました

by ゆい (2010-06-28 23:50) 

noritan

ゆいさん,いらっしゃいませ.
解決したようで,なによりです.

そういえば, ColdFire ずいぶん触っていませんね.
by noritan (2010-06-29 20:52) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。