LoginSignup
8
10

More than 3 years have passed since last update.

AXI Quad SPIを使ったSPI Master (MicroBlaze編)

Posted at

概要

FPGAで外部のICとSPI通信をしたいケースは多くあると思います。
単純にコントロールレジスタを設定するような、通信のタイミングを厳密に一定にする必要はない場合、
HDLでSPIコントローラを自分で作成しなくても、MicroBlazeとAXI Quad SPIを使ってソフトウェアで開発すると便利です。
今回はMicroBlazeにAXI Quad SPIを接続し、SPI Master Modeで書き込みと読み出しを行う方法について紹介します。

環境

  • Vivado 2018.3

Block Designの作成

こちらの記事のデザインをベースに作成していきます。
基本的にはInterrupt Controllerが接続されたMicroBlazeがあれば問題ありません。
000.png

AXI Quad SPIを追加

AXI Quad SPIを追加し、IPの設定は下記画像のようにしました。
SPIはMaster Modeで動作させ、データ幅は8bitとします。
Slaveには2個のICを接続することを想定し、No. of Slavesを2に設定しています。

001.png

SPIバスは直接FPGAのピンに出力し、ip2intc_irptはMicroBlazeの割り込み入力に接続しています。
ext_spi_clkは100MHzのクロックを入力しています。
002.png

SCLKの周波数は次式のようになります。

f_{SCLK} = \frac{f_{in}}{D_{Frequency Ratio}} = \frac{100 \rm MHz}{16 \times 1} = 6.25 {\rm MHz}

全体的なデザインは次のようになりました。
001.png

サンプルコード

Hello Worldテンプレートをベースとして作成し、下記のコードをコピーしてください。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xintc.h"
#include "xspi.h"

// 送受信バッファサイズ
#define BUFFER_SIZE     32

// デバイスドライバのインスタンス
static XIntc Intc;
static XSpi Spi;

// SPI通信中フラグ
volatile static int TransferInProgress;

// 割り込み処理中に起きたエラーをカウント
int Error;

// SPI送受信バッファ
u8 WriteBuffer[BUFFER_SIZE];
u8 ReadBuffer[BUFFER_SIZE];

// SPI割り込みハンドラ
void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount)
{
    // 通信中フラグを降ろす
    TransferInProgress = FALSE;
    // 通信完了割り込み以外はエラー
    if (StatusEvent != XST_SPI_TRANSFER_DONE) {
        Error++;
    }
}

int main()
{
    int Status;
    XSpi_Config *ConfigPtr;

    init_platform();

    // SPIドライバの初期化
    ConfigPtr = XSpi_LookupConfig(XPAR_SPI_0_DEVICE_ID);
    if (ConfigPtr == NULL) return XST_DEVICE_NOT_FOUND;

    Status = XSpi_CfgInitialize(&Spi, ConfigPtr, ConfigPtr->BaseAddress);
    if (Status != XST_SUCCESS) return XST_FAILURE;

    // SPIコントローラが正しく動作しているかセルフテストを行う
    Status = XSpi_SelfTest(&Spi);
    if (Status != XST_SUCCESS) return XST_FAILURE;

    // XIntcの初期化
    Status = XIntc_Initialize(&Intc, XPAR_INTC_0_DEVICE_ID);
    if(Status != XST_SUCCESS) return XST_FAILURE;

    // SPIの割り込みハンドラを指定
    Status = XIntc_Connect(&Intc, XPAR_INTC_0_SPI_0_VEC_ID,
                (XInterruptHandler)XSpi_InterruptHandler,
                (void *)&Spi);
    if(Status != XST_SUCCESS) return XST_FAILURE;

    //XIntcをhardware interrupts onlyで開始
    Status = XIntc_Start(&Intc, XIN_REAL_MODE);
    if(Status != XST_SUCCESS) return XST_FAILURE;

    // SPIの割り込みを有効化
    XIntc_Enable(&Intc, XPAR_INTC_0_SPI_0_VEC_ID);

    // MicroBlazeの割り込み設定を初期化
    Xil_ExceptionInit();

    // MicroBlazeにXIntcからの割り込みを登録
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                (Xil_ExceptionHandler)XIntc_InterruptHandler,
                &Intc);

    // MicroBlazeの割り込みを有効化
    Xil_ExceptionEnable();

    // SPI割り込みハンドラによって呼び出される関数を指定
    XSpi_SetStatusHandler(&Spi, &Spi, (XSpi_StatusHandler)SpiHandler);

    // SPI動作モードを設定
    // XSP_MASTER_OPTION: マスターモードで動作
    // XSP_MANUAL_SSELECT_OPTION: SSピンマニュアル選択
    Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION |
                                   XSP_MANUAL_SSELECT_OPTION);
    if (Status != XST_SUCCESS) return XST_FAILURE;

    // スレーブを選択する
    Status = XSpi_SetSlaveSelect(&Spi, 1);
    if (Status != XST_SUCCESS) return XST_FAILURE;

    // SPIドライバをスタートし、デバイスと割り込みを有効にする
    XSpi_Start(&Spi);

    // 送受信バッファの初期化
    for(int i=0; i<BUFFER_SIZE; i++){
        WriteBuffer[i] = i+0xA0;
        ReadBuffer[i] = 0;
    }

    // 10回送信する
    for(int i=0; i<10; i++){
        // 通信中フラグを立てる
        TransferInProgress = TRUE;
        // 送信開始
        XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer, BUFFER_SIZE);
        // SPI割り込みが入るまで待つ
        while (TransferInProgress);
    }

    xil_printf("SPI Transfer Finished! (Error Count=%d", Error);

    cleanup_platform();
    return 0;
}

動作波形

データが連続で送信されました。BUFFER_SIZE分の長さが連続で送信されています。
BlockDesignでTransaction Widthを8bitに設定したので下位8bitだけにデータがのっていますね。
SPIは単純なシフトレジスタですので、上位24bit分は溢れて使われないので、
8bitタイプのSPIでも基本的にはこのプロトコルでも問題ありません。
image.png

次に、転送する長さを1としてみました。
転送終了後にChip Selectが上がっているのが確認できます。
image.png

SCLKの周波数は設定どおり6.25MHzとなりました。
image.png

参考

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10