VC707开发板的IIC控制

1 篇文章 0 订阅


最近学习VC707的使用,需要用到VC707的FMC接口,因此涉及到IIC控制,作为笔记简单记录一下。

VC707开发板上的IIC连接方式

通过VC707开发板的开发文档,了解到开发板上的IIC连接方式如下:
在这里插入图片描述
首先,左侧的是FPGA开发板上的默认IIC引脚,通过一组引脚(AT35、AU32)引出,连接到板上一块TI的芯片(PCA9548),这块芯片作为IIC路由,再进一步连接到开发板上的各类IIC设备(FMC、EEPROM、HDMI芯片等)。

硬件连接

提供一种相对简单的连接方式——使用AXI IIC IP核:
在这里插入图片描述
这个IP核是AXI4-Lite接口控制的IIC控制IP,通过AXI Interconnect连接到MicroBlaze的M_AXI_DP接口,此处省略。
在这里插入图片描述
在IP核的设置选项中,选择IIC_main,系统会自动根据VC707开发板的默认配置分配到iic_main的引脚(AT35、AU32)。

SDK开发过程

从VC707的官方文档了解到,由于使用了路由芯片(PCA9548),在使用时需要做一些特别处理:

配置路由芯片

0x74(0b1110100)位置的寄存器为路由芯片的选择寄存器,需要通过配置才能选中对应的iic设备,具体对应规则如下:
在这里插入图片描述
SDK实现代码如下,其中变量select就是写入0x74地址的内容,可以根据需要进行调整。
此处有一个很重要的点,PCA9548的选择寄存器使用的是One Hot编码,具体如下:

因此这里选择0x74寄存器的值填入范围是:0x0000_0001, 0x0000_0010, 0x0000_0100, 0x0000_10000… 以此类推。

代码实现

#define TESTAPP_GEN
#include "xparameters.h"
#include "xiic.h"
#include "xil_printf.h"
#include "xintc.h"

#ifdef XPAR_INTC_0_DEVICE_ID
 #define INTC_DEVICE_ID	XPAR_INTC_0_DEVICE_ID
 #define IIC_INTR_ID	XPAR_INTC_0_IIC_0_VEC_ID
 #define INTC			XIntc
 #define INTC_HANDLER	XIntc_InterruptHandler
#else
 #define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
 #define IIC_INTR_ID		XPAR_FABRIC_IIC_0_VEC_ID
 #define INTC			 	XScuGic
 #define INTC_HANDLER		XScuGic_InterruptHandler
#endif



XIic IicInstance;	/* The instance of the IIC device. */
XIntc InterruptController;	/* The instance of the Interrupt Controller. */

volatile u8 TransmitComplete;	/* Flag to check completion of Transmission */
volatile u8 ReceiveComplete;	/* Flag to check completion of Reception */

static void SendHandler(XIic *InstancePtr)
{
	TransmitComplete = 0;
	xil_printf("iic sending data... \n\r");
}

static void ReceiveHandler(XIic *InstancePtr)
{
	ReceiveComplete = 0;
	xil_printf("iic receiving data... \n\r");
}

static void StatusHandler(XIic *InstancePtr, int Event)
{

}
int IicSelfTestExample(u16 DeviceId);

static int SetupInterruptSystem(XIic * IicInstPtr)
{
	int Status;

	if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) {
		return XST_SUCCESS;
	}
	XIntc_Initialize(&InterruptController, INTC_DEVICE_ID);
	XIntc_Connect(&InterruptController, IIC_INTR_ID,
			       (XInterruptHandler) XIic_InterruptHandler,
			       IicInstPtr);
	XIntc_Start(&InterruptController, XIN_REAL_MODE);
	XIntc_Enable(&InterruptController, IIC_INTR_ID);

#ifdef __PPC__
	/*
	 * Initialize the PPC exception table.
	 */
	XExc_Init();

	/*
	 * Register the interrupt controller handler with the exception table.
	 */
	XExc_RegisterHandler(XEXC_ID_NON_CRITICAL_INT,
			     (XExceptionHandler) XIntc_InterruptHandler,
			     &InterruptController);

	/*
	 * Enable non-critical exceptions.
	 */
	XExc_mEnableExceptions(XEXC_NON_CRITICAL);
#endif

#ifdef __MICROBLAZE__
	/*
	 * Enable the Microblaze Interrupts.
	 */
	microblaze_enable_interrupts();
#endif

	return XST_SUCCESS;
}


int IicSelfTestExample(u16 DeviceId)
{
	int Status;
	XIic_Config *ConfigPtr;	/* Pointer to configuration data */

	ConfigPtr = XIic_LookupConfig(DeviceId);
	XIic_CfgInitialize(&IicInstance, ConfigPtr, ConfigPtr->BaseAddress);
	SetupInterruptSystem(&IicInstance);

	// Set the Handlers for transmit and reception.
	XIic_SetSendHandler(&IicInstance, &IicInstance,
				(XIic_Handler) SendHandler);
	XIic_SetRecvHandler(&IicInstance, &IicInstance,
				(XIic_Handler) ReceiveHandler);
	XIic_SetStatusHandler(&IicInstance, &IicInstance,
				  (XIic_StatusHandler) StatusHandler);

	// Set the address of the slave.
	XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, 0x74);

	//Write to the PCA9548.
	TransmitComplete = 1;
	IicInstance.Stats.TxErrors = 0;
	u8 select = 0x02;
	Status = XIic_Start(&IicInstance);
	Status |= XIic_MasterSend(&IicInstance, &select, 1);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) {} // wait

	// read back for test
	ReceiveComplete = 1;
	u8 back;
	Status |= XIic_MasterRecv(&IicInstance, &back, 1);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) {} // wait
	Status = XIic_Stop(&IicInstance);
	if (back == select)
		xil_printf("IIC device select initial success!\n\r");
	else
		xil_printf("IIC device select initial failed!\n\r");

	return XST_SUCCESS;
}

经过初步测试,可以成功往0x74地址里面写值,接下来就是具体到FMC接口的配置了。

规律小结

在使用AXI IIC IP核的时候,可以使用Xilinx SDK提供的相关控制驱动简化IIC的控制(不用自己实现IIC时序),可以提高开发的效率。可以在sdk提供的例程上进行修改使用。
在学习的过程中也发现了一些坑,这里稍微小结一下:

  1. Xilinx 提供的AXI IIC IP核的使用与系统中断控制关系密切,建议开发人员要对中断的相关概念有一定了解,否则可能会出现数据读写失败的问题。
  2. IIC控制应用程序可以分为下面几个小部分:IIC IP核初始化、中断控制初始化、设置IIC从设备地址、读数据、写数据。
  3. 读数据和写数据的时候需要配合Xil_start 和 Xil_stop使用,我的理解是:Xil_start 可以把IIC总线变成受FPGA控制的状态;而在结束数据一次读写之后,需要及时调用Xil_stop,这样IIC总线就恢复到正常状态。(事实上,start和stop还涉及到了中断寄存器的控制)
  4. 配置PCA9548的时候,注意选择寄存器是采用one-hot编码
  5. Xilinx的官网上提供了一些参考设计(Si570等),大家可以自己找找看。
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值