免责声明
本文所提供的信息和内容仅供参考。作者对本文内容的准确性、完整性、及时性或适用性不作任何明示或暗示的保证。在任何情况下,作者不对因使用本文内容而导致的任何直接或间接损失承担责任,包括但不限于数据丢失、业务中断或其他经济损失。
读者在使用本文信息时,应自行验证其准确性和适用性,并对其使用结果负责。本文内容不构成专业技术咨询或建议,具体的技术实现和应用应根据实际情况和需要进行详细分析和验证。
本文所涉及的任何商标、版权或其他知识产权均属于其各自的所有者。若本文中引用了第三方的资料或信息,引用仅为学术交流目的,不构成对第三方内容的认可或保证。
若有任何疑问或需进一步信息,请联系本文作者或相关专业人士。
前言
I2C是FPGA入门总线之一,相信大家已经编写过无数遍了,本篇文章将讲述ZYNQ系列---I2C控制器使用方法。
一、搭建SOC系统工程
1.调出ZYNQ核;
2.检查DDR配置是否正确;
3.打开I2C控制器,并选择EMIO,通过EMIO可以路由到PL端的引脚上。
二、搭建 Vitis-sdk 工程
1.创建 SDK Platform 工程
创建成功后,可以在驱动中看见I2C
2.了解I2C的读写函数
本文的用途为配置从设备的寄存器。
* @param InstancePtr is a pointer to the XIicPs instance.
* @param MsgPtr is the pointer to the send buffer.
* @param ByteCount is the number of bytes to be sent.
* @param SlaveAddr is the address of the slave we are sending to.
****************************************************************************/
I2C的写数据函数,MsgPtr指向数据buffer;ByteCount表示要写入的数据字节个数;SlaveAddr表示从设备的设备地址。
XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr);
那怎么往一个寄存器里写一个数据呢?
我们可以把寄存器号也当成数据,假设从设备地址0xa1,待写入的寄存器号为0x3033,待写入的数据为0x01,
即:
u8 RegAddrBytes[3];
RegAddrBytes[0] = 0x30;
RegAddrBytes[1] = 0x33;
RegAddrBytes[2] = 0x01;
XIicPs_MasterSendPolled(XIicPs *InstancePtr, RegAddrBytes, 3, 0xa1);
* @param InstancePtr is a pointer to the XIicPs instance.
* @param MsgPtr is the pointer to the receive buffer.
* @param ByteCount is the number of bytes to be received.
* @param SlaveAddr is the address of the slave we are receiving from.
****************************************************************************
I2C的读数据函数,MsgPtr指向数据buffer;ByteCount表示要接收的数据字节个数;SlaveAddr表示从设备的设备地址。
XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,s32 ByteCount, u16 SlaveAddr)
这个读函数与写函数类似,但要注意它是从当前的寄存器地址读取数据,因此我们在读取想要的寄存器数据时,需要先把待读取的寄存器号用写函数写入。
3.完整的程序
/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
//下面两个头文件不能缺少
#include "xiicps.h"
#include "xparameters.h"
#define IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID
//IIC 的速率 300K
#define IIC_SCLK_RATE 300000
int main()
{
XIicPs Iic;
XIicPs_Config *Config;
s32 Status;
// 1.查找IIC设备
Config = XIicPs_LookupConfig(IIC_DEVICE_ID);
if (Config == NULL) {
print("IIC_DEVICE_ID ERROR\n\r");
return XST_FAILURE;
}
// 2.初始化
Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
print("initial IIC failed \n\r");
return XST_FAILURE;
}
//设置IIC速率
Status = XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);
if(Status != XST_SUCCESS)
{
print("set IIC clock rate failed \n\r");
return XST_FAILURE;
}
///写入
u8 RegAddrBytes[3];
RegAddrBytes[0] = 0x30;
RegAddrBytes[1] = 0x05;
RegAddrBytes[2] = 0x01;
XIicPs_MasterSendPolled(&Iic, RegAddrBytes,3,0x1A);
///读取
//
u8 receivedData;
u8 RegAddr[2];
RegAddr[0] = 0x30;
RegAddr[1] = 0x05;
XIicPs_MasterSendPolled(&Iic, RegAddr,2,0x1A);
XIicPs_MasterRecvPolled(&Iic, &receivedData, 1, 0x1A);
return 0;
}
4.调试验证
读到的数据与写入的数据一致,因此I2C配置没有任何问题。
总结
I2C控制器使用起来简单方便,底层驱动已经很完善了,我们只需要了解对应的函数就可以完成I2C的读写,是不是又学会一个偷懒的技巧,最后强调一下,I2C的设备ID和ZYNQ的DDR配置不要搞错。