📄 xiicps_master.c
字号:
/* Tell slave to send more to us */ if (BytesToRecv > XIICPS_FIFO_DEPTH) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_FIFO_DEPTH); } else{ XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, BytesToRecv); } BytesToRead = XIICPS_FIFO_DEPTH - TransSize; } Tmp = 0; IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); while ((Tmp < BytesToRead) && ((IntrStatusReg & Intrs) == 0)) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); if ((StatusReg & XIICPS_SR_RXDV_MASK) == 0) { /* No data in fifo */ continue; } XIicPs_RecvByte(InstancePtr); Tmp ++; } } if (IntrStatusReg & Intrs) { return XST_FAILURE; } return XST_SUCCESS;}/*****************************************************************************//*** 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_TO_MASK | 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 disables slave monitor mode.** @param InstancePtr is a pointer to the XIicPs instance.** @return None.** @note None.*****************************************************************************/void XIicPs_DisableSlaveMonitor(XIicPs *InstancePtr){ u32 BaseAddr; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* * Clear slave monitor control bit. */ XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_SLVMON_MASK)); /* * Clear interrupt flag for slave monitor interrupt. */ XIicPs_DisableInterrupts(BaseAddr, XIICPS_IXR_SLV_RDY_MASK); return;}/*****************************************************************************//*** 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 IsSend = 0; u32 StatusEvent = 0; u32 BaseAddr; int Tmp; int BytesToRecv; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == 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)); /* * Data interrupt. * * In master mode, this means master receiving needs to put more data * into the FIFO. In order to avoid slave times out waiting for ack, * transfer size register must be set before data is processed. * */ if (0 != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) { /* * Only greater than FIFO size is handled here, otherwise, the * COMP interrupt will be triggered shortly, and we will handle * those receives there. */ if ((InstancePtr->RecvByteCount) > XIICPS_FIFO_DEPTH){ /* First find out how many bytes slave has sent us */ BytesToRecv = XIICPS_FIFO_DEPTH - XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET); if ((InstancePtr->RecvByteCount - BytesToRecv) > XIICPS_FIFO_DEPTH) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_FIFO_DEPTH); } else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, (InstancePtr->RecvByteCount - BytesToRecv)); } /* * Receive the data out of the FIFO. */ for(Tmp = 0; Tmp < BytesToRecv; Tmp ++) { XIicPs_RecvByte(InstancePtr); } /* * For receiving of larger than FIFO size, this is all * the handling we need to do. */ return; } } /* * Determine whether the device is sending. */ if (InstancePtr->RecvBufferPtr == NULL) { IsSend = 1; } /* * Complete flag. */ if (0 != (IntrStatusReg & XIICPS_IXR_COMP_MASK)) { if (IsSend) { if (InstancePtr->SendByteCount > 0) { MasterSendData(InstancePtr); } else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } else { /* * Get the data out of FIFO first, if not done, * tell the slave to send more. */ while (XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET) & XIICPS_SR_RXDV_MASK) { XIicPs_RecvByte(InstancePtr); } /* * Continue to tell slave to send data if not done. */ if (InstancePtr->RecvByteCount > XIICPS_FIFO_DEPTH) { XIicPs_WriteReg( InstancePtr->Config.BaseAddress, XIICPS_TRANS_SIZE_OFFSET, XIICPS_FIFO_DEPTH); } else if (InstancePtr->RecvByteCount > 0) { XIicPs_WriteReg( InstancePtr->Config.BaseAddress, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount); } /* * If all done, tell the application. */ if (InstancePtr->RecvByteCount == 0){ StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } /* * If received more than expected, it is an error. */ if (InstancePtr->RecvByteCount < 0){ StatusEvent |= XIICPS_EVENT_ERROR; } } } /* * Slave ready interrupt, it is only meaningful for master mode. */ if (0 != (IntrStatusReg & XIICPS_IXR_SLV_RDY_MASK)) { StatusEvent |= XIICPS_EVENT_SLAVE_RDY; } if (0 != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { StatusEvent |= XIICPS_EVENT_NACK; } /* * All other interrupts are treated as error. */ if (0 != (IntrStatusReg & (XIICPS_IXR_TO_MASK | XIICPS_IXR_NACK_MASK | XIICPS_IXR_ARB_LOST_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 (0 != StatusEvent) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); }}/*****************************************************************************//** This function prepares a device to transfers as a master.** @param InstancePtr is a pointer to the XIicPs instance.** @param Role specifies whether the device is sending or receiving.** @return* - XST_SUCCESS if everything went well.* - XST_FAILURE if bus is busy.** @note Interrupts are always disabled, device which needs to use* interrupts needs to setup interrupts after this call.*****************************************************************************/static int XIicPs_SetupMaster(XIicPs *InstancePtr, int Role){ u32 ControlReg; u32 BaseAddr; u32 EnabledIntr = 0x0; Xil_AssertNonvoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; ControlReg = XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET); /* * Only check if bus is busy when repeated start option is not set. */ if ((ControlReg & XIICPS_CR_HOLD_MASK) == 0) { if (XIicPs_BusIsBusy(InstancePtr)) { return XST_FAILURE; } } /* * Set up master, AckEn, nea and also clear fifo. */ ControlReg |= XIICPS_CR_ACKEN_MASK | XIICPS_CR_CLR_FIFO_MASK | XIICPS_CR_NEA_MASK | XIICPS_CR_MS_MASK; if (Role == RECVING_ROLE) { ControlReg |= XIICPS_CR_RD_WR_MASK; EnabledIntr = XIICPS_IXR_DATA_MASK |XIICPS_IXR_RX_OVR_MASK; }else { ControlReg &= ~XIICPS_CR_RD_WR_MASK; } EnabledIntr |= XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_MASK; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, ControlReg); XIicPs_DisableAllInterrupts(BaseAddr); return XST_SUCCESS;}/*****************************************************************************//** 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 repeated start 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->Options & XIICPS_REP_START_OPTION) == 0) { XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET) & ~ XIICPS_CR_HOLD_MASK); } } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -