(続) SilentC で QSPI を使う [ColdFire V2]
「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月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2008/07/25
- メディア: 雑誌
楽天市場連動記念、無関係(でもないか)広告
- ショップ: ツクモ ロボット王国
- 価格: 4,179 円
int *pqspar =0x4010006c;
って
char *pqspar =0x40100059;
のだと思うのですが
by ゆい (2010-06-28 22:52)
ごめんなさい、あってました
見ているマニュアルを間違えてました
by ゆい (2010-06-28 23:50)
ゆいさん,いらっしゃいませ.
解決したようで,なによりです.
そういえば, ColdFire ずいぶん触っていませんね.
by noritan (2010-06-29 20:52)