(3) SPI通信
次はSPI通信のテスト。最初はSPIモジュールでやってみます。USARTをMSPIモードで動かすやり方は次回。
まずは1バイトずつの転送。単純な方法。
// pin configuration
AVR32_GPIO.port[0].pmr1 = (1<<17)|(1<<18)|(1<<19);
AVR32_GPIO.port[0].gperc = (1<<16)|(1<<17)|(1<<18)|(1<<19);
// SPI configuration
AVR32_SPI.mr = 0;
AVR32_SPI.MR.mstr = 1;
AVR32_SPI.MR.modfdis = 1;
AVR32_SPI.MR.pcs = 0;
AVR32_SPI.MR.dlybcs = 250;
AVR32_SPI.CSR0.ncpha = 1;
AVR32_SPI.CSR0.scbr = 250;
AVR32_SPI.CSR0.csnaat = 1;
AVR32_SPI.CSR0.dlybct = 10;
// enable SPI
AVR32_SPI.cr = (1<<AVR32_SPI_CR_SPIEN);
while(1)
{
while(!AVR32_SPI.SR.tdre);
AVR32_SPI.tdr = 0x55;
AVR32_SPI.rdr;
while(!AVR32_SPI.SR.tdre);
AVR32_SPI.tdr = 0xaa;
AVR32_SPI.rdr;
}
接続は
・NPCS0(PA16) → CS#
・SCK(PA17) → SCK
・MISO(PA18) → MISO
・MOSI(PA19) → MOSI
としました。0xaaと0x55の繰り返しをオシロで確認。
次に、PDC(DMA)を使用した非同期一括転送。
char t[256];
int i;
while(1)
{
for(i = 0; i < sizeof(t); i++) t[i] = -1;
AVR32_PDCA.channel[0].mar = (unsigned long)t;
AVR32_PDCA.channel[0].psr = AVR32_PDCA_PID_SPI_RX;
AVR32_PDCA.channel[0].tcr = sizeof(t);
AVR32_PDCA.channel[0].marr = 0;
AVR32_PDCA.channel[0].tcrr = 0;
AVR32_PDCA.channel[0].MR.size = 0; // byte
AVR32_PDCA.channel[0].CR.ten = 1;
AVR32_PDCA.channel[1].mar = (unsigned long)t;
AVR32_PDCA.channel[1].psr = AVR32_PDCA_PID_SPI_TX;
AVR32_PDCA.channel[1].tcr = sizeof(t);
AVR32_PDCA.channel[1].marr = 0;
AVR32_PDCA.channel[1].tcrr = 0;
AVR32_PDCA.channel[1].MR.size = 0; // byte
AVR32_PDCA.channel[1].CR.ten = 1;
while(AVR32_PDCA.channel[0].tcr > 0);
}
コードは単純転送のwhileループの部分を上記のように変更。
思ったよりすんなり出来ました。注意点として、SPIでは送受信が必ず同時に行われるので、受信のみは不可であること。つまり、RX側の設定だけしてPDCを有効にしても、全く進まない。TX側も合わせて使って初めてクロックが生成されます。なお、データ受信が必要ない場合にTX側だけを使うのは問題なし。
なお、SDカードのセクタ読み出しなどでは、クロック生成の為の送信データは無難な 0xff などを利用する場合が多いと思われます。この場合、0xff で埋めたバッファを別に用意しても良いですが、メモリがもったいないので、受信バッファと共用できます。上の例がそうです。バッファtを送信データ(0xff = -1)で埋め、TX側・RX側の両方でMARに設定します。
こうすることで、0xff を送信しつつ、ひとつのバッファで処理できます。なお、PDCの優先度はRX<TXでもRX>TXでも大丈夫なようです。
今日はこの辺まで。
コメントする