SPIバスの読み書き
SPI (Serial Peripheral Interface)は4線式のシリアルインターフェースです。英語圏では SPI をスパイと読まれる事が有ります。
メモリーデバイスやADC、液晶ディスプレーなどの接続に用いられます。
SPI はマスター側、スレーブ側いずれでも使用できます。利用方法は、サンプルコードを参照してください。
API の捕捉(マスター側)
vAHI_SpiConfigure
SPI のマスター側の初期化を行います。
- 第一引数は、利用するデバイス数を予約します。
0を指定すると SPI_SEL0を予約、1を指定すると SPI_SEL0,1 を予約し、2を指定すると SPISEL_0,1,2 を予約します。
vAHI_SpiSelect
SPIのチップセレクトを行います。選択方法はビットマップになっており、0x1 は SPISEL0, 0x2 は SPISEL1, 0x4 は SPISEL2 を指定します。
※ TWELITE では DIO19 が割り当てられており通常のSPIセレクトピンの一つとして利用可能です(内蔵のフラッシュはSPIではありません)入出力
いくつかAPIがありますが、以下に一例を示します。
- vAHI_SpiConfigure() にて設定を行う
- SPI通信が必要になったら vAHI_SpiSelect() により、チップセレクト。
- 以下では 8bit のデータの入出力。
- vAHI_SpiStartTransfer8(出力データ)
- while (bAHI_SpiPollBusy()) にて送信待ち
- u8AHI_SpiReadTransfer8() にて入力データを読みだす
- 入出力が終われば vAHI_SpiStop() でチップセレクトを解除する
※ 入出力は同時に行います。入力だけ実行したい場合は、入力データと同じだけの出力をダミーで行います(クロックが出力分しか発生しないため)。
API の捕捉(スレーブ側)
プロトコル
スレーブ側へのデータ転送では、先頭の3バイトはステータスや転送長を決定するために交換されます。以下はサンプルソースコードをもとに利用例を記載しています。
マスター側の送信 | データ (MSB first) | スレーブ側の送信 (*2) |
---|---|---|
0x0300 | 16bit: ステータス情報 *3 | 0x0003 |
N+1 | 8bit: 総データ数 *4 | M+1 |
N | 32bit: データ数 *5 | M |
送信データ1 | 32bit | 送信データ1 |
... | ... | ... |
送信データN | 32bit | 送信データM-1 |
0x00000000 *1 | 32bit | 送信データM |
*1 スレーブ側の送信数のほうが多い場合は 0 でパディングします。
*2 スレーブ側の通信は自動で行われます。アプリケーション上で変更する余地は無く、送信したいデータの登録と、データ受信を行うかの設定のみです。
*3 0x1 は受信可能 0x2 は送信可能を示すビットマスクです。0x0300, 0x0003 は双方が送受信を行うことを示し、通常はこの操作で通信することをお勧めします。
*4,*5 総データ数の最大は63です。また続く4バイトは(総データ数-1)を格納しますので、実際に一度に転送可能なデータは62バイトまでです。
以下はマスター側のソース (common/ip.c) よりの抜粋です。
/* transfer status */ u16Out = 0xFF00 & (u8MasterStatus << 8); vAHI_SpiStartTransfer(15,u16Out); vAHI_SpiWaitBusy(); /* read slave status */ u16In = u16AHI_SpiReadTransfer16(); u8SlaveStatus = (uint8)u16In & 0xFF; vDebug("SlvStat "); vDisplayHex((uint32) u8SlaveStatus); vDebug("\r\n"); /* transfer length */ vAHI_SpiStartTransfer(7,u8TxMsgLength); vAHI_SpiWaitBusy(); /* read length */ u8RxMsgLength = u8AHI_SpiReadTransfer8();
送受信の方法
送受信の流れを解説します。
- SPI スレーブの有効化
vAHI_IpEnable(E_AHI_IP_TXPOS_EDGE, E_AHI_IP_RXPOS_EDGE, FALSE);
- 割り込みハンドラの登録(割り込み中ではデータ取得できません)
vAHI_IpRegisterCallback(vHandleInterrupt);
PRIVATE void vHandleInterrupt(uint32 u32Device, uint32 u32ItemBitmap) { ; }
- 送信データ登録(*1)。ここに登録されたデータを Master 側からの通信があった時に送り返します。
bAHI_IpSendData(MSG_SIZE,(uint8*)au8TxMsg, E_AHI_IP_BIG_ENDIAN); - 受信可能設定。マスターからの通信が有った時、内部バッファ(最大63バイト)にデータが記録されます。
vAHI_IpReadyToReceive(); - 割り込み待ち。サンプルでは DOZE により割り込みを待っていますが、通常のアプリケーションでは DOZE を解除する割り込みは多数あるため、割り込みハンドラーを起点に制御してください。
vAHI_CpuDoze(); - 受信完了待ち。割り込み直後、まだ受信データが用意されていません。
while (!bAHI_IpRxDataAvailable()) ; - データの読み出し。
bAHI_IpReadData(&u8RxMsgLength, (uint8*)au8RxMsg, E_AHI_IP_BIG_ENDIAN)
- 次のデータを待つには、(*1)の処理に戻ります。
サンプルコード
ダウンロード
- SPI マスター、スレーブのテストコード(137KB, ZIP) ※ TWELITE SDK ではそのままビルドは出来ません。コード例として参考にしてください。
接続方法
下表に示す通り2基板の信号線を接続します。2基板のGND同士を接続する事も忘れないでください。
マスター側 | スレーブ側 | |
---|---|---|
DIO0 (SPI_SEL1) | チップセレクト | DIO14 (IP_SEL) |
SPIMISO | Master Input Slave Output | DIO13 (IP_DO) |
SPIMOSI | Master Output Slave Input | DIO12 (IP_DI) |
SPICLK | Clock | DIO15 (IP_CLK) |
操作方法
- UART0, 38400bps 8N1 とし UART ポートに接続しておきます。
- マスターとスレーブの電源を投入します。
初期メッセージが出ます。Slave 側は、MsgRdy ... 00000013 13000000 と
長めのメッセージが出ますが、これは通信によるものではありません。 - マスター側の SW1 を押します。ボタンを押されると以下の表示が行われ、マスター、スレーブ側の動作が行われます。
表示例
マスター側の表示 CommStrt SlvStat 00000003 MstrLngth 0000000E SlvLngth 00000015 MaxLngth 00000015 00000000 Snd 0000000D Rcv 00000014 00000001 Snd 00000001 Rcv 00000001 00000002 Snd 00000101 Rcv 01000001 00000003 Snd 00000201 Rcv 02000001 00000004 Snd 00000301 Rcv 03000001 00000005 Snd 00000401 Rcv 04000001 00000006 Snd 00000501 Rcv 05000001 00000007 Snd 00000601 Rcv 06000001 00000008 Snd 00000701 Rcv 07000001 00000009 Snd 00000801 Rcv 08000001 0000000A Snd 00000901 Rcv 09000001 0000000B Snd 00000A01 Rcv 0A000001 0000000C Snd 00000B01 Rcv 0B000001 0000000D Snd 00000C01 Rcv 0C000001 0000000E Snd 00000000 Rcv 0D000001 0000000F Snd 00000000 Rcv 0E000001 00000010 Snd 00000000 Rcv 0F000001 00000011 Snd 00000000 Rcv 10000001 00000012 Snd 00000000 Rcv 11000001 00000013 Snd 00000000 Rcv 12000001 00000014 Snd 00000000 Rcv 13000001 SpiStop CommOk スレーブ側の表示 SPI Interrupt: MsgRcvd MsgLngth 0000000D 00000000 00000001 00000001 00000101 00000002 00000201 00000003 00000301 00000004 00000401 00000005 00000501 00000006 00000601 00000007 00000701 00000008 00000801 00000009 00000901 0000000A 00000A01 0000000B 00000B01 0000000C 00000C01