书接上文:
I2C控制器练习(1)_NoNoUnknow的博客-CSDN博客
SPI协议与FPGA的自动升级和多启动-CSDN博客
本文主要做一些基本知识的补充和工程参考。
写IIC需要注意的事情:
1.查询芯片手册获得slave地址,以及寄存器地址(或者叫寄存器命令)。
2.约定好每次读/写的数据长度。
对于这类芯片而言,读取一般都使用了顺序读,即读完一个地址自动读下一个地址,所以约定好长度通过no ack来打断很重要。
(SPI设备是通过停止输入时钟和拉高CS_N来打断的)
FLASH使用笔记~M25P64_m25p16_NoNoUnknow的博客-CSDN博客
操作时序:写(单字节写入)
随机读
顺序读
页写:(不是每个设备都有)
所有 I2C 设备均支持单字节数据写入操作,但只有部分 I2C 设备支持页写操作; 且支持页写操作的设备,一次页写操作写入的字节数不能超过设备单页包含的存储单元
本章节使用的 AT24CXX 系列的 EEPROM 存储芯片,单页存储单元个数为 32 个,一 次页写操作只能写入 32 字节数据。
PS端的API可以在板载支持包里找到。
SDK可以直接在简历平台的界面找到,Vitis则是被整合到了spr里。
BSP板级支持包(board support package)-CSDN博客
一些API。
主模式下中断驱动的接收:XIicPs_MasterRecv()
* 该函数在主模式下启动中断驱动的接收。
* 它设置传输大小寄存器,以便从机可以向我们发送数据。
* 其余工作由中断处理程序管理。
/*****************************************************************************/
/**
* @brief
* This function initiates an interrupt-driven receive in master mode.
*
* It sets the transfer size register so the slave can send data to us.
* The rest of the work is managed by interrupt handler.
*
* @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.
*
* @return None.
*
* @note This receive routine is for interrupt-driven transfer only.
*
****************************************************************************/
void XIicPs_MasterRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,u16 SlaveAddr)
{UINTPTR BaseAddr;/** Assert validates the input arguments.*/Xil_AssertVoid(InstancePtr != NULL);Xil_AssertVoid(MsgPtr != NULL);Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);Xil_AssertVoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);BaseAddr = InstancePtr->Config.BaseAddress;InstancePtr->RecvBufferPtr = MsgPtr;InstancePtr->RecvByteCount = ByteCount;InstancePtr->SendBufferPtr = NULL;InstancePtr->IsSend = 0;#if defined (XCLOCKING)if (InstancePtr->IsClkEnabled == 0) {Xil_ClockEnable(InstancePtr->Config.RefClk);InstancePtr->IsClkEnabled = 1;}
#endifif ((ByteCount > XIICPS_FIFO_DEPTH) ||((InstancePtr->IsRepeatedStart) !=0)){XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |(u32)XIICPS_CR_HOLD_MASK);}/** Initialize for a master receiving role.*/(void)XIicPs_SetupMaster(InstancePtr, RECVING_ROLE);/** Setup the transfer size register so the slave knows how much* to send to us.*/if (ByteCount > (s32)XIICPS_MAX_TRANSFER_SIZE) {XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,XIICPS_MAX_TRANSFER_SIZE);InstancePtr->CurrByteCount = (s32)XIICPS_MAX_TRANSFER_SIZE;InstancePtr->UpdateTxSize = 1;}else {InstancePtr->CurrByteCount = ByteCount;XIicPs_WriteReg(BaseAddr, (u32)(XIICPS_TRANS_SIZE_OFFSET),(u32)ByteCount);InstancePtr->UpdateTxSize = 0;}/** Clear the interrupt status register before use it to monitor.*/XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, XIICPS_IXR_ALL_INTR_MASK);XIicPs_EnableInterrupts(BaseAddr,(u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_DATA_MASK |(u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_COMP_MASK |(u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TO_MASK);/** Do the address transfer to signal the slave.*/XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);}
主模式下中断驱动的发送:XIicPs_MasterSend()
* 该函数在主模式下启动中断驱动的发送。
* 它尝试发送第一个 FIFO 满的数据,
* 然后让中断处理程序处理其余数据(如果有)。
#define TX_MAX_LOOPCNT 1000000U /**< Used to wait in polled function *//************************** Function Prototypes ******************************//************************* Variable Definitions *****************************//*****************************************************************************/
/**
* @brief
* This function initiates an interrupt-driven send in master mode.
*
* It tries to send the first FIFO-full of data, then lets the interrupt
* handler to handle the rest of the data if there is any.
*
* @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.
*
* @return None.
*
* @note This send routine is for interrupt-driven transfer only.
*****************************************************************************/
void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount,u16 SlaveAddr)
{UINTPTR BaseAddr;u32 Platform = XGetPlatform_Info();/** Assert validates the input arguments.*/Xil_AssertVoid(InstancePtr != NULL);Xil_AssertVoid(MsgPtr != NULL);Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);Xil_AssertVoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);BaseAddr = InstancePtr->Config.BaseAddress;InstancePtr->SendBufferPtr = MsgPtr;InstancePtr->SendByteCount = ByteCount;InstancePtr->RecvBufferPtr = NULL;InstancePtr->IsSend = 1;#if defined (XCLOCKING)if (InstancePtr->IsClkEnabled == 0) {Xil_ClockEnable(InstancePtr->Config.RefClk);InstancePtr->IsClkEnabled = 1;}
#endif/** Set repeated start if sending more than FIFO of data.*/if (((InstancePtr->IsRepeatedStart) != 0)||(ByteCount > XIICPS_FIFO_DEPTH)) {XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |(u32)XIICPS_CR_HOLD_MASK);}/** Setup as a master sending role.*/(void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE);(void)TransmitFifoFill(InstancePtr);/** Clear the interrupt status register before use it to monitor.*/XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, XIICPS_IXR_ALL_INTR_MASK);XIicPs_EnableInterrupts(BaseAddr,(u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK |(u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TO_MASK);/** Do the address transfer to notify the slave.*/XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);/* Clear the Hold bit in ZYNQ if receive byte count is less than* the FIFO depth to get the completion interrupt properly.*/if ((ByteCount < XIICPS_FIFO_DEPTH) && (Platform == (u32)XPLAT_ZYNQ)){XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) &(~(u32)XIICPS_CR_HOLD_MASK));}}
参考资料:
Zynq SDK开发之外设信息描述 - 简书 (jianshu.com)
zynq7000系列PS端GPIO初始化函数XGpioPs_LookupConfig()和XGpioPs_CfgInitialize()详解-CSDN博客
Xilinx sdk 学习笔记 之 IIC(二)-CSDN博客
配置查找函数:XIicPs_LookupConfig(DeviceId)
* 根据唯一设备ID查找设备配置表
* 表中包含系统中每个设备的配置信息。
DeviceId需要在xparameters.h中找到。
/************************** Constant Definitions *****************************//**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//************************** Function Prototypes ******************************//************************** Variable Definitions *****************************//*****************************************************************************/
/**
*
* @brief
* Looks up the device configuration based on the unique device ID. A table
* contains the configuration info for each device in the system.
*
* @param DeviceId contains the ID of the device to look up the
* configuration for.
*
* @return A pointer to the configuration found or NULL if the specified
* device ID was not found. See xiicps.h for the definition of
* XIicPs_Config.
*
* @note None.
*
******************************************************************************/
XIicPs_Config *XIicPs_LookupConfig(u16 DeviceId)
{XIicPs_Config *CfgPtr = NULL;s32 Index;for (Index = 0; Index < XPAR_XIICPS_NUM_INSTANCES; Index++) {if (XIicPs_ConfigTable[Index].DeviceId == DeviceId) {CfgPtr = &XIicPs_ConfigTable[Index];break;}}return (XIicPs_Config *)CfgPtr;
}
/** @} */
初始化函数:XIicPs_CfgInitialize
* 初始化特定的 XIicPs 实例,以便驱动程序可供使用。
* 初始化后设备的状态为:
* - 设备已禁用
* - 从机模式
ConfigPtr即Lookup函数的返回值。
/************************** Variable Definitions *****************************//*****************************************************************************/
/**
*
* @brief
* Initializes a specific XIicPs instance such that the driver is ready to use.
*
* The state of the device after initialization is:
* - Device is disabled
* - Slave mode
*
* @param InstancePtr is a pointer to the XIicPs instance.
* @param ConfigPtr is a reference to a structure containing information
* about a specific IIC device. This function initializes an
* InstancePtr object for a specific device specified by the
* contents of Config.
* @param EffectiveAddr is the device base address in the virtual memory
* address space. The caller is responsible for keeping the address
* mapping from EffectiveAddr to the device physical base address
* unchanged once this function is invoked. Unexpected errors may
* occur if the address mapping changes after this function is
* called. If address translation is not used, use
* ConfigPtr->BaseAddress for this parameter, passing the physical
* address instead.
*
* @return The return value is XST_SUCCESS if successful.
*
* @note None.
*
******************************************************************************/
s32 XIicPs_CfgInitialize(XIicPs *InstancePtr, XIicPs_Config *ConfigPtr,u32 EffectiveAddr)
{/** Assert validates the input arguments.*/Xil_AssertNonvoid(InstancePtr != NULL);Xil_AssertNonvoid(ConfigPtr != NULL);/** Set some default values.*/InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;InstancePtr->Config.BaseAddress = EffectiveAddr;InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz;
#if defined (XCLOCKING)InstancePtr->Config.RefClk = ConfigPtr->RefClk;InstancePtr->IsClkEnabled = 0;
#endifInstancePtr->StatusHandler = StubHandler;InstancePtr->CallBackRef = NULL;InstancePtr->IsReady = (u32)XIL_COMPONENT_IS_READY;/** Reset the IIC device to get it into its initial state. It is expected* that device configuration will take place after this initialization* is done, but before the device is started.*/XIicPs_Reset(InstancePtr);/** Keep a copy of what options this instance has.*/InstancePtr->Options = XIicPs_GetOptions(InstancePtr);/* Initialize repeated start flag to 0 */InstancePtr->IsRepeatedStart = 0;return (s32)XST_SUCCESS;
}
速率配置函数 XIicPs_SetSClk
* 该函数设置IIC 器件的串行时钟速率。
* 在设置这些设备选项之前,设备必须处于空闲状态而不是忙于传输数据。
* 数据速率由控制寄存器中的值设置。
* 确定正确寄存器值的公式为:
* Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
* 有关设置串行时钟速率的完整说明,请参阅硬件数据表。
/*****************************************************************************/
/**
*
* @brief
* This function sets the serial clock rate for the IIC device. The device
* must be idle rather than busy transferring data before setting these device
* options.
*
* The data rate is set by values in the control register. The formula for
* determining the correct register values is:
* Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
* See the hardware data sheet for a full explanation of setting the serial
* clock rate.
*
* @param InstancePtr is a pointer to the XIicPs instance.
* @param FsclHz is the clock frequency in Hz. The two most common clock
* rates are 100KHz and 400KHz.
*
* @return
* - XST_SUCCESS if options are successfully set.
* - XST_DEVICE_IS_STARTED if the device is currently transferring
* data. The transfer must complete or be aborted before setting
* options.
* - XST_FAILURE if the Fscl frequency can not be set.
*
* @note The clock can not be faster than the input clock divide by 22.
*
******************************************************************************/
s32 XIicPs_SetSClk(XIicPs *InstancePtr, u32 FsclHz)
{u32 Div_a;u32 Div_b;u32 ActualFscl;u32 Temp;u32 TempLimit;u32 LastError;u32 BestError;u32 CurrentError;u32 ControlReg;u32 CalcDivA;u32 CalcDivB;u32 BestDivA;u32 BestDivB;u32 FsclHzVar = FsclHz;Xil_AssertNonvoid(InstancePtr != NULL);Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);Xil_AssertNonvoid(FsclHzVar > 0U);if (0U != XIicPs_In32((InstancePtr->Config.BaseAddress) +XIICPS_TRANS_SIZE_OFFSET)) {return (s32)XST_DEVICE_IS_STARTED;}/** Assume Div_a is 0 and calculate (divisor_a+1) x (divisor_b+1).*/Temp = (InstancePtr->Config.InputClockHz) / ((u32)22U * FsclHzVar);/** If the answer is negative or 0, the Fscl input is out of range.*/if ((u32)(0U) == Temp) {return (s32)XST_FAILURE;}/** If frequency 400KHz is selected, 384.6KHz should be set.* If frequency 100KHz is selected, 90KHz should be set.* This is due to a hardware limitation.*/if(FsclHzVar > (u32)384600U) {FsclHzVar = (u32)384600U;}if((FsclHzVar <= (u32)100000U) && (FsclHzVar > (u32)90000U)) {FsclHzVar = (u32)90000U;}/** TempLimit helps in iterating over the consecutive value of Temp to* find the closest clock rate achievable with divisors.* Iterate over the next value only if fractional part is involved.*/TempLimit = (((InstancePtr->Config.InputClockHz) %((u32)22 * FsclHzVar)) != (u32)0x0U) ?(Temp + (u32)1U) : Temp;BestError = FsclHzVar;BestDivA = 0U;BestDivB = 0U;for ( ; Temp <= TempLimit ; Temp++){LastError = FsclHzVar;CalcDivA = 0U;CalcDivB = 0U;for (Div_b = 0U; Div_b < 64U; Div_b++) {Div_a = Temp / (Div_b + 1U);if (Div_a != 0U){Div_a = Div_a - (u32)1U;}if (Div_a > 3U){continue;}ActualFscl = (InstancePtr->Config.InputClockHz) /(22U * (Div_a + 1U) * (Div_b + 1U));if (ActualFscl > FsclHzVar){CurrentError = (ActualFscl - FsclHzVar);}else{CurrentError = (FsclHzVar - ActualFscl);}if (LastError > CurrentError) {CalcDivA = Div_a;CalcDivB = Div_b;LastError = CurrentError;}}/** Used to capture the best divisors.*/if (LastError < BestError) {BestError = LastError;BestDivA = CalcDivA;BestDivB = CalcDivB;}}/** Read the control register and mask the Divisors.*/ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress,(u32)XIICPS_CR_OFFSET);ControlReg &= ~((u32)XIICPS_CR_DIV_A_MASK | (u32)XIICPS_CR_DIV_B_MASK);ControlReg |= (BestDivA << XIICPS_CR_DIV_A_SHIFT) |(BestDivB << XIICPS_CR_DIV_B_SHIFT);XIicPs_WriteReg(InstancePtr->Config.BaseAddress, (u32)XIICPS_CR_OFFSET,ControlReg);return (s32)XST_SUCCESS;
}/*****************************************************************************/
轮询模式接收:XIicPs_MasterRecvPolled
* 该函数在主模式下启动轮询模式接收。
* 它重复设置传输大小寄存器,以便从机可以
* 向我们发送数据。它轮询数据寄存器以获取要输入的数据。
* 如果主机由于仲裁失败而无法读取数据,将返回 :仲裁失败状态。
* 如果从机无法向我们发送数据,则会因超时而失败。
/*****************************************************************************/
/**
* @brief
* This function initiates a polled mode receive in master mode.
*
* It repeatedly sets the transfer size register so the slave can
* send data to us. It polls the data register for data to come in.
* If master fails to read data due arbitration lost, will return
* with arbitration lost status.
* If slave fails to send us data, it fails with time out.
*
* @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.
*
* @return
* - XST_SUCCESS if everything went well.
* - XST_FAILURE if timed out.
* - XST_IIC_ARB_LOST if arbitration lost
*
* @note This receive routine is for polled mode transfer only.
*
****************************************************************************/
s32 XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,s32 ByteCount, u16 SlaveAddr)
{u32 IntrStatusReg;u32 Intrs;UINTPTR BaseAddr;s32 Result;s32 IsHold;s32 UpdateTxSize = 0;s32 ByteCountVar = ByteCount;u32 Platform;/** Assert validates the input arguments.*/Xil_AssertNonvoid(InstancePtr != NULL);Xil_AssertNonvoid(MsgPtr != NULL);Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);Xil_AssertNonvoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);BaseAddr = InstancePtr->Config.BaseAddress;InstancePtr->RecvBufferPtr = MsgPtr;InstancePtr->RecvByteCount = ByteCountVar;#if defined (XCLOCKING)if (InstancePtr->IsClkEnabled == 0) {Xil_ClockEnable(InstancePtr->Config.RefClk);InstancePtr->IsClkEnabled = 1;}
#endifPlatform = XGetPlatform_Info();if((ByteCountVar > XIICPS_FIFO_DEPTH) ||((InstancePtr->IsRepeatedStart) !=0)){XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |(u32)XIICPS_CR_HOLD_MASK);IsHold = 1;} else {IsHold = 0;}(void)XIicPs_SetupMaster(InstancePtr, RECVING_ROLE);/** Clear the interrupt status register before use it to monitor.*/IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);/** Set up the transfer size register so the slave knows how much* to send to us.*/if (ByteCountVar > (s32)XIICPS_MAX_TRANSFER_SIZE) {XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,XIICPS_MAX_TRANSFER_SIZE);ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE;UpdateTxSize = 1;}else {XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,ByteCountVar);}XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr);/** Intrs keeps all the error-related interrupts.*/Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_RX_OVR_MASK |(u32)XIICPS_IXR_RX_UNF_MASK | (u32)XIICPS_IXR_NACK_MASK;/** Poll the interrupt status register to find the errors.*/IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);while ((InstancePtr->RecvByteCount > 0) &&((IntrStatusReg & Intrs) == 0U)) {while ((XIicPs_RxDataValid(InstancePtr)) != 0U) {if ((InstancePtr->RecvByteCount <XIICPS_DATA_INTR_DEPTH) && (IsHold != 0) &&(InstancePtr->IsRepeatedStart == 0) &&(UpdateTxSize == 0)) {IsHold = 0;XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &(~XIICPS_CR_HOLD_MASK));}XIicPs_RecvByte(InstancePtr);ByteCountVar --;if (Platform == (u32)XPLAT_ZYNQ) {if ((UpdateTxSize != 0) &&(ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {break;}}}if (Platform == (u32)XPLAT_ZYNQ) {if ((UpdateTxSize != 0) &&(ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {/* wait while fifo is full */while (XIicPs_RxFIFOFull(InstancePtr, ByteCountVar) != 0U) { ;}if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) >(s32)XIICPS_MAX_TRANSFER_SIZE) {XIicPs_WriteReg(BaseAddr,XIICPS_TRANS_SIZE_OFFSET,XIICPS_MAX_TRANSFER_SIZE);ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE +XIICPS_FIFO_DEPTH;} else {XIicPs_WriteReg(BaseAddr,XIICPS_TRANS_SIZE_OFFSET,InstancePtr->RecvByteCount -XIICPS_FIFO_DEPTH);UpdateTxSize = 0;ByteCountVar = InstancePtr->RecvByteCount;}}} else {if ((InstancePtr->RecvByteCount > 0) && (ByteCountVar == 0)) {/** Clear the interrupt status register before use it to* monitor.*/IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr);if ((InstancePtr->RecvByteCount) >(s32)XIICPS_MAX_TRANSFER_SIZE) {XIicPs_WriteReg(BaseAddr,XIICPS_TRANS_SIZE_OFFSET,XIICPS_MAX_TRANSFER_SIZE);ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE;} else {XIicPs_WriteReg(BaseAddr,XIICPS_TRANS_SIZE_OFFSET,InstancePtr->RecvByteCount);UpdateTxSize = 0;ByteCountVar = InstancePtr->RecvByteCount;}}}IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);}if (InstancePtr->IsRepeatedStart == 0) {XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &(~XIICPS_CR_HOLD_MASK));}if ((IntrStatusReg & Intrs) != 0U) {if ((IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK) != 0U) {Result = (s32) XST_IIC_ARB_LOST;} else {Result = (s32)XST_FAILURE;}} else {Result = (s32)XST_SUCCESS;}return Result;
}
轮询模式发送:XIicPs_MasterSendPolled
* 该函数在主模式下启动轮询模式发送。
* 它将数据发送到 FIFO 并等待从机接收它们。
* 如果主设备由于仲裁丢失而无法发送数据,将停止传输
* 并处于仲裁丢失状态
* 如果从设备无法从 FIFO 中删除数据,则发送失败并
* 超时。
/*****************************************************************************/
/**
* @brief
* This function initiates a polled mode send in master mode.
*
* It sends data to the FIFO and waits for the slave to pick them up.
* If master fails to send data due arbitration lost, will stop transfer
* and with arbitration lost status
* If slave fails to remove data from FIFO, the send fails with
* time out.
*
* @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.
*
* @return
* - XST_SUCCESS if everything went well.
* - XST_FAILURE if timed out.
* - XST_IIC_ARB_LOST if arbitration lost
*
* @note This send routine is for polled mode transfer only.
*
****************************************************************************/
s32 XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr,s32 ByteCount, u16 SlaveAddr)
{u32 IntrStatusReg;u32 StatusReg;UINTPTR BaseAddr;u32 Intrs;s32 Status = (s32)XST_FAILURE;u32 timeout = 0;_Bool Value;/** Assert validates the input arguments.*/Xil_AssertNonvoid(InstancePtr != NULL);Xil_AssertNonvoid(MsgPtr != NULL);Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);Xil_AssertNonvoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);#if defined (XCLOCKING)if (InstancePtr->IsClkEnabled == 0) {Xil_ClockEnable(InstancePtr->Config.RefClk);InstancePtr->IsClkEnabled = 1;}
#endifBaseAddr = InstancePtr->Config.BaseAddress;InstancePtr->SendBufferPtr = MsgPtr;InstancePtr->SendByteCount = ByteCount;if (((InstancePtr->IsRepeatedStart) != 0) ||(ByteCount > XIICPS_FIFO_DEPTH)) {XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |(u32)XIICPS_CR_HOLD_MASK);}(void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE);/** Intrs keeps all the error-related interrupts.*/Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TX_OVR_MASK |(u32)XIICPS_IXR_NACK_MASK;/** Clear the interrupt status register before use it to monitor.*/IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);/** Transmit first FIFO full of data.*/(void)TransmitFifoFill(InstancePtr);XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);/** Continue sending as long as there is more data and* there are no errors.*/Value = ((InstancePtr->SendByteCount > (s32)0) &&((IntrStatusReg & Intrs) == (u32)0U));while (Value != FALSE) {StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);/** Wait until transmit FIFO is empty.*/if ((StatusReg & XIICPS_SR_TXDV_MASK) != 0U) {IntrStatusReg = XIicPs_ReadReg(BaseAddr,XIICPS_ISR_OFFSET);Value = ((InstancePtr->SendByteCount > (s32)0) &&((IntrStatusReg & Intrs) == (u32)0U));continue;}/** Send more data out through transmit FIFO.*/(void)TransmitFifoFill(InstancePtr);Value = ((InstancePtr->SendByteCount > (s32)0) &&((IntrStatusReg & Intrs) == (u32)0U));}/** Check for completion of transfer.*/while ((IntrStatusReg & XIICPS_IXR_COMP_MASK) != XIICPS_IXR_COMP_MASK){IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);/** If there is an error, tell the caller.*/if ((IntrStatusReg & Intrs) != 0U) {if ((IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK) != 0U) {Status = (s32) XST_IIC_ARB_LOST;}break;}/** Timeout if stuck for more than 1 second*/usleep(1);timeout++;if (timeout == TX_MAX_LOOPCNT) {break;}}if (InstancePtr->IsRepeatedStart == 0) {XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &(~XIICPS_CR_HOLD_MASK));}/* Set the Status for XST_SUCCESS */if (((IntrStatusReg & Intrs) == 0U) && (timeout != TX_MAX_LOOPCNT)) {Status = (s32)XST_SUCCESS;}return Status;
}
头文件导入:
#include "xiicps.h"
The xiicps.h header file is an implementation of IIC driver in the PS block.
#include "xparameters.h"
里面列出了各个外设对应的地址、Device_ID、中断号,等等。
运行步骤:
1.通过XIicPs_LookupConfig查找到设备的配置列表;
2.通过配置列表使用XIicPs_CfgInitialize进行初始化配置;
3.配置完成后使用XIicPs_SetSClk配置速率;
4.使用XIicPs_MasterSendPolled向指定的实例、从机发送寄存器地址
(MsgPtr is the pointer to the send buffer.)部分设备可能会将此项作为操作命令使用。
5.假如是读指令则还需要使用XIicPs_MasterRecvPolled来接收数据。
其中XIicPs_MasterRecvPolled API的MsgPtr是用以配置接收缓存的,可以定义合适的数组(寄存器)来存储它。