/** * This function enables the slave monitor mode. * * It enables slave monitor in the control register and enables * slave ready interrupt. It then does an address transfer to slave. * Interrupt handler will signal the caller if slave responds to * the address transfer. * * @param InstancePtr is a pointer to the XIicPs instance. * @param SlaveAddr is the address of the slave we want to contact. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr) { u32 BaseAddr; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* * Enable slave monitor mode in control register. */ XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_MS_MASK | XIICPS_CR_NEA_MASK | XIICPS_CR_SLVMON_MASK ); /* * Set up interrupt flag for slave monitor interrupt. */ XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_SLV_RDY_MASK); /* * Initialize the slave monitor register. */ XIicPs_WriteReg(BaseAddr, XIICPS_SLV_PAUSE_OFFSET, 0xF); /* * Set the slave address to start the slave address transmission. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); return; }
/** * 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, 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->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; InstancePtr->CurrByteCount = ByteCount; InstancePtr->SendBufferPtr = NULL; InstancePtr->IsSend = 0; InstancePtr->UpdateTxSize = 0; if ((ByteCount > XIICPS_DATA_INTR_DEPTH) || (InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } /* * Initialize for a master receiving role. */ XIicPs_SetupMaster(InstancePtr, RECVING_ROLE); /* * Do the address transfer to signal the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Setup the transfer size register so the slave knows how much * to send to us. */ if (ByteCount > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); InstancePtr->CurrByteCount = XIICPS_MAX_TRANSFER_SIZE; InstancePtr->UpdateTxSize = 1; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, ByteCount); } XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_DATA_MASK | XIICPS_IXR_RX_OVR_MASK | XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_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, 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 setup a slave interrupt-driven receive. * Data processing for the receive is handled by the 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. * * @return None. * * @note This routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_SlaveRecv(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount) { /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; InstancePtr->SendBufferPtr = NULL; XIicPs_EnableInterrupts(InstancePtr->Config.BaseAddress, (u32)XIICPS_IXR_DATA_MASK | (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_TO_MASK | (u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_RX_UNF_MASK); }
/** * This function enables the slave monitor mode. * * It enables slave monitor in the control register and enables * slave ready interrupt. It then does an address transfer to slave. * Interrupt handler will signal the caller if slave responds to * the address transfer. * * @param InstancePtr is a pointer to the XIicPs instance. * @param SlaveAddr is the address of the slave we want to contact. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr) { u32 BaseAddr; u32 ConfigReg; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* Clear transfer size register */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_TRANS_SIZE_OFFSET, 0x0U); /* * Enable slave monitor mode in control register. */ ConfigReg = XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET); ConfigReg |= (u32)XIICPS_CR_MS_MASK | (u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK | (u32)XIICPS_CR_SLVMON_MASK; ConfigReg &= (u32)(~XIICPS_CR_RD_WR_MASK); XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET, ConfigReg); /* * Set up interrupt flag for slave monitor interrupt. * Dont enable NACK. */ XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_SLV_RDY_MASK); /* * Initialize the slave monitor register. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_SLV_PAUSE_OFFSET, 0xFU); /* * Set the slave address to start the slave address transmission. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_ADDR_OFFSET, (u32)SlaveAddr); return; }
/** * This function setup a slave interrupt-driven send. It set the repeated * start for the device is the tranfer size is larger than FIFO depth. * Data processing for the send is initiated by the interrupt handler. * * @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. * * @return None. * * @note This send routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_SlaveSend(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount) { u32 BaseAddr; /* * Assert validates the input arguments */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_DATA_MASK | XIICPS_IXR_COMP_MASK | XIICPS_IXR_TO_MASK | XIICPS_IXR_NACK_MASK | XIICPS_IXR_TX_OVR_MASK); }
/** * The interrupt handler for the master 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 * This case is handled only for master receive data. * The master has to request for more data (if there is more data to * receive) and read the data from the FIFO . * * - COMP * If the Master is transmitting data and there is more data to be * sent then the data is written to the FIFO. If there is no more data to * be transmitted then a completion event is signalled to the upper layer * by calling the callback handler. * * If the Master is receiving data then the data is read from the FIFO and * the Master has to request for more data (if there is more data to * receive). If all the data has been received then a completion event * is signalled to the upper layer by calling the callback handler. * It is an error if the amount of received data is more than expected. * * - NAK and SLAVE_RDY * This is signalled to the upper layer by calling the callback handler. * * - All Other interrupts * These interrupts are marked as error. This is signalled to the upper * layer by calling the callback handler. * * </pre> * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr) { u32 IntrStatusReg; u32 StatusEvent = 0U; u32 BaseAddr; u16 SlaveAddr; s32 ByteCnt; s32 IsHold; u32 Platform; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; Platform = XGetPlatform_Info(); /* * Read the Interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, (u32)XIICPS_ISR_OFFSET); /* * Write the status back to clear the interrupts so no events are * missed while processing this interrupt. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_ISR_OFFSET, IntrStatusReg); /* * Use the Mask register AND with the Interrupt Status register so * disabled interrupts are not processed. */ IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, (u32)XIICPS_IMR_OFFSET)); ByteCnt = InstancePtr->CurrByteCount; IsHold = 0; if ((XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) & (u32)XIICPS_CR_HOLD_MASK) != 0U) { IsHold = 1; } /* * Send */ if (((InstancePtr->IsSend) != 0) && ((u32)0U != (IntrStatusReg & (u32)XIICPS_IXR_COMP_MASK))) { if (InstancePtr->SendByteCount > 0) { MasterSendData(InstancePtr); } else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } /* * Receive */ if (((!(InstancePtr->IsSend))!= 0) && ((0 != (IntrStatusReg & (u32)XIICPS_IXR_DATA_MASK)) || (0 != (IntrStatusReg & (u32)XIICPS_IXR_COMP_MASK)))){ while ((XIicPs_ReadReg(BaseAddr, (u32)XIICPS_SR_OFFSET) & XIICPS_SR_RXDV_MASK) != 0U) { if (((InstancePtr->RecvByteCount < XIICPS_DATA_INTR_DEPTH)!= 0U) && (IsHold != 0) && ((!InstancePtr->IsRepeatedStart)!= 0) && (InstancePtr->UpdateTxSize == 0)) { IsHold = 0; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } XIicPs_RecvByte(InstancePtr); ByteCnt--; if (Platform == (u32)XPLAT_ZYNQ) { if ((InstancePtr->UpdateTxSize != 0) && (ByteCnt == (XIICPS_FIFO_DEPTH + 1))) { break; } } } if (Platform == (u32)XPLAT_ZYNQ) { if ((InstancePtr->UpdateTxSize != 0) && (ByteCnt == (XIICPS_FIFO_DEPTH + 1))) { /* wait while fifo is full */ while (XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET) != (u32)(ByteCnt - XIICPS_FIFO_DEPTH)) { } if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCnt = (s32)XIICPS_MAX_TRANSFER_SIZE + XIICPS_FIFO_DEPTH; } else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH); InstancePtr->UpdateTxSize = 0; ByteCnt = InstancePtr->RecvByteCount; } } } else { if ((InstancePtr->RecvByteCount > 0) && (ByteCnt == 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); SlaveAddr = (u16)XIicPs_ReadReg(BaseAddr, (u32)XIICPS_ADDR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); if ((InstancePtr->RecvByteCount) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCnt = (s32)XIICPS_MAX_TRANSFER_SIZE; } else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount); InstancePtr->UpdateTxSize = 0; ByteCnt = InstancePtr->RecvByteCount; } 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); } } InstancePtr->CurrByteCount = ByteCnt; } if (((!(InstancePtr->IsSend)) != 0) && (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK))) { /* * If all done, tell the application. */ if (InstancePtr->RecvByteCount == 0){ if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } /* * Slave ready interrupt, it is only meaningful for master mode. */ if (0U != (IntrStatusReg & XIICPS_IXR_SLV_RDY_MASK)) { StatusEvent |= XIICPS_EVENT_SLAVE_RDY; } if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { if ((!(InstancePtr->IsRepeatedStart)) != 0 ) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_NACK; } /* * Arbitration lost interrupt */ if (0U != (IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK)) { StatusEvent |= XIICPS_EVENT_ARB_LOST; } /* * All other interrupts are treated as error. */ if (0U != (IntrStatusReg & (XIICPS_IXR_NACK_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))) { if ((!(InstancePtr->IsRepeatedStart)) != 0) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_ERROR; } /* * Signal application if there are any events. */ if (StatusEvent != 0U) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); } }