/** * 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) { u32 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(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; InstancePtr->IsSend = 1; /* * Set repeated start if sending more than FIFO of data. */ if (((InstancePtr->IsRepeatedStart) != 0)|| ((ByteCount > XIICPS_FIFO_DEPTH) != 0U)) { 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); XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_ARB_LOST_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)); } }
/** * 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, int ByteCount, u16 SlaveAddr) { u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; InstancePtr->IsSend = 1; /* * Set repeated start if sending more than FIFO of data. */ if ((InstancePtr->IsRepeatedStart) || (ByteCount > XIICPS_FIFO_DEPTH)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } /* * Setup as a master sending role. */ XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); /* * Do the address transfer to notify the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); TransmitFifoFill(InstancePtr); XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_MASK); }
/* * This function handles continuation of sending data. It is invoked * from interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ static void MasterSendData(XIicPs *InstancePtr) { TransmitFifoFill(InstancePtr); /* * Clear hold bit if done, so stop can be sent out. */ if (InstancePtr->SendByteCount == 0) { /* * If user has enabled repeated start as an option, * do not disable it. */ if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET) & ~ XIICPS_CR_HOLD_MASK); } } return; }
/** * 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 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. * * @note This send routine is for polled mode transfer only. * ****************************************************************************/ int XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount, u16 SlaveAddr) { u32 IntrStatusReg; u32 StatusReg; u32 BaseAddr; u32 Intrs; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; if ((InstancePtr->IsRepeatedStart) || (ByteCount > XIICPS_FIFO_DEPTH)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Intrs keeps all the error-related interrupts. */ Intrs = XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_TX_OVR_MASK | 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. */ TransmitFifoFill(InstancePtr); IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Continue sending as long as there is more data and * there are no errors. */ while ((InstancePtr->SendByteCount > 0) && ((IntrStatusReg & Intrs) == 0)) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * Wait until transmit FIFO is empty. */ if ((StatusReg & XIICPS_SR_TXDV_MASK) != 0) { IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); continue; } /* * Send more data out through transmit FIFO. */ TransmitFifoFill(InstancePtr); } /* * 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) != 0) { return XST_FAILURE; } } if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } return XST_SUCCESS; }
/** * The interrupt handler for slave mode. It does the protocol handling for * the interrupt-driven transfers. * * Completion events and errors are signaled to upper layer for proper * handling. * * <pre> * * The interrupts that are handled are: * - DATA * If the instance is sending, it means that the master wants to read more * data from us. Send more data, and check whether we are done with this * send. * * If the instance is receiving, it means that the master has writen * more data to us. Receive more data, and check whether we are done with * with this receive. * * - COMP * This marks that stop sequence has been sent from the master, transfer * is about to terminate. However, for receiving, the master may have * written us some data, so receive that first. * * It is an error if the amount of transfered data is less than expected. * * - NAK * This marks that master does not want our data. It is for send only. * * - Other interrupts * These interrupts are marked as error. * * </pre> * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_SlaveInterruptHandler(XIicPs *InstancePtr) { u32 IntrStatusReg; u32 IsSend = 0U; u32 StatusEvent = 0U; s32 LeftOver; u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; /* * Read the Interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Write the status back to clear the interrupts so no events are missed * while processing this interrupt. */ XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Use the Mask register AND with the Interrupt Status register so * disabled interrupts are not processed. */ IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, XIICPS_IMR_OFFSET)); /* * Determine whether the device is sending. */ if (InstancePtr->RecvBufferPtr == NULL) { IsSend = 1U; } /* Data interrupt * * This means master wants to do more data transfers. * Also check for completion of transfer, signal upper layer if done. */ if ((u32)0U != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) { if (IsSend != 0x0U) { LeftOver = TransmitFifoFill(InstancePtr); /* * We may finish send here */ if (LeftOver == 0) { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } else { LeftOver = SlaveRecvData(InstancePtr); /* We may finish the receive here */ if (LeftOver == 0) { StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } } /* * Complete interrupt. * * In slave mode, it means the master has done with this transfer, so * we signal the application using completion event. */ if (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK)) { if (IsSend != 0x0U) { if (InstancePtr->SendByteCount > 0) { StatusEvent |= XIICPS_EVENT_ERROR; }else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } else { LeftOver = SlaveRecvData(InstancePtr); if (LeftOver > 0) { StatusEvent |= XIICPS_EVENT_ERROR; } else { StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } } /* * Nack interrupt, pass this information to application. */ if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { StatusEvent |= XIICPS_EVENT_NACK; } /* * All other interrupts are treated as error. */ if (0U != (IntrStatusReg & (XIICPS_IXR_TO_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))){ StatusEvent |= XIICPS_EVENT_ERROR; } /* * Signal application if there are any events. */ if (0U != StatusEvent) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); } }