AXI IICの使い方

概要

XilinxのAXI IICの使い方について書いていこうと思います。
今回はZYNQでAXI IICを制御する方法について書きます。

AXI IICの接続と設定

AXI IICとの接続は次のようになっています。
AXIバスでZYNQと接続しています。
IICポートは外部のピンと接続されており、IIC接続するデバイスと繋がっています。
f:id:taltalp:20180506035016p:plain

IPコアの設定は次のようになっています。
f:id:taltalp:20180506035054p:plain

デバイスドライバの使い方

次にXilinx SDKでCPUのプログラムを書いていきます。
ソースコードは次の通りです。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xiic.h"

// 接続するIICデバイスのアドレス
#define LCD_DEVICE_ADDRESS 0x3E

int WriteData(u16 ByteCount, u8 *WriteBuffer);

XIic xiic;

int main()
{
	int Status;
	XIic_Config *ConfigPtr;
	u8 WriteBuffer[16];

    init_platform();

    // AXI IICの初期化
	ConfigPtr = XIic_LookupConfig(XPAR_IIC_0_DEVICE_ID);
	if (ConfigPtr == NULL) {
		return XST_FAILURE;
	}

	Status = XIic_CfgInitialize(&xiic, ConfigPtr, ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// 送信するデータ (今回はアドレス+データで、合計3byte送信)
	WriteBuffer[0] = 0x00;
	WriteBuffer[1] = 0x38;

	Status = WriteData(2, WriteBuffer);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

    cleanup_platform();
    return 0;
}

int WriteData(u16 ByteCount, u8 *WriteBuffer)
{
	int Status;

	Status = XIic_Start(&xiic);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// STOP conditionを発行するためにXIic_DynSendを使っている
	Status = XIic_DynSend(xiic.BaseAddress, LCD_DEVICE_ADDRESS, WriteBuffer, ByteCount, XIIC_STOP);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	Status = XIic_Stop(&xiic);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}

実行結果

ロジック・アナライザを使って出力波形を見た結果がこちらです。
START → ADDRESS → DATA → DATA → STOP
の順に出力されていることが確認できました。
f:id:taltalp:20180506040237p:plain

XIic_MasterSendでSTOP conditionにならない?

今回データの送信にはXIic_DynSendという関数を使っています。
普通このデバイスドライバではXIic_MasterSendや、XIic_DynMasterSendを使って送信するはずです。
しかし、これらを使って記述したとろ、STOPビットが発行されず、うまく通信が行えませんでした。(下図参考)
f:id:taltalp:20180506040930p:plain

データシートをよく読んでみたところ、AXI IICのレジスタ Transmit FIFO (Address: 0x108) の
8bit目と9bit目にそれぞれStartとStop Conditionを発行するためのレジスタがありました。
これらを1にしてあげればよいのですが、XIic_MasterSendや、XIic_DynMasterSendにはその記述が見当たりませんでした。

一方で、XIic_DynSendの中身を見てみると、DynSendDataという関数を呼び出しており、

XIic_WriteReg(BaseAddress,  XIIC_DTR_REG_OFFSET, XIIC_TX_DYN_STOP_MASK | *BufferPtr++);

という記述があります。
XIIC_TX_DYN_STOP_MASK によってTransmit FIFOレジスタの9bit目をセットしているようです。

以上の理由により、今回はXIic_DynSendという関数を使っていますが、
このコードでも割り込みが正しく動作するのかなどは未確認です。