/** * * This function handles data received from the IIC bus as a slave. * * When the slave expects more than the master has to send, the slave will stall * waiting for data. * * When more data is received than data expected a Nack is done to signal master * to stop sending data. The excess data is discarded to prevent bus throttling. * * The buffer may be full and the master continues to send data if the master * and slave have different message lengths. This condition is handled by sending * No Ack to the master and reading Rx data until the master stops sending data * to prevent but throttling from locking up the bus. To ever receive as a slave * again, must know when to renable bus ACKs. NAAS is used to detect when the * master is finished sending messages for any mode. * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void RecvSlaveData(XIic *InstancePtr) { u32 CntlReg; u8 BytesToRead; u8 LoopCnt; u8 Temp; /* * When receive buffer has no room for the receive data discard it. */ if (InstancePtr->RecvByteCount == 0) { /* * Set ACKnowlege OFF to signal master to stop sending data. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); CntlReg |= XIIC_CR_NO_ACK_MASK; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Clear excess received data to prevent bus throttling and set * receive FIFO occupancy to throttle at the 1st byte received. */ XIic_FlushRxFifo(InstancePtr); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); return; } /* * Use occupancy count to determine how many bytes to read from the * FIFO, count is zero based so add 1, read that number of bytes from * the FIFO. */ BytesToRead = (XIic_ReadReg(InstancePtr->BaseAddress, XIIC_RFO_REG_OFFSET)) + 1; for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } /* * Set receive FIFO depth for the number of bytes to be received such * that a receive interrupt will occur, the count is 0 based, the * last byte of the message has to be received seperately to ack the * message. */ if (InstancePtr->RecvByteCount > IIC_RX_FIFO_DEPTH) { Temp = IIC_RX_FIFO_DEPTH - 1; } else { if (InstancePtr->RecvByteCount == 0) { Temp = 0; } else { Temp = InstancePtr->RecvByteCount - 1; } } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, (u32) Temp); return; }
/** * * This function is called when the receive register is full. The number * of bytes received to cause the interrupt is adjustable using the Receive FIFO * Depth register. The number of bytes in the register is read in the Receive * FIFO occupancy register. Both these registers are zero based values (0-15) * such that a value of zero indicates 1 byte. * * For a Master Receiver to properly signal the end of a message, the data must * be read in up to the message length - 1, where control register bits will be * set for bus controls to occur on reading of the last byte. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void RecvMasterData(XIic *InstancePtr) { u8 LoopCnt; int BytesInFifo; int BytesToRead; u32 CntlReg; /* * Device is a master receiving, get the contents of the control * register and determine the number of bytes in fifo to be read out. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); BytesInFifo = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_RFO_REG_OFFSET) + 1; /* * If data in FIFO holds all data to be retrieved - 1, set NOACK and * disable the Tx error. */ if ((InstancePtr->RecvByteCount - BytesInFifo) == 1) { /* * Disable Tx error interrupt to prevent interrupt * as this device will cause it when it set NO ACK next. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); /* * Write control reg with NO ACK allowing last byte to * have the No ack set to indicate to slave last byte read. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg | XIIC_CR_NO_ACK_MASK)); /* * Read one byte to clear a place for the last byte to be read * which will set the NO ACK. */ XIic_ReadRecvByte(InstancePtr); } /* * If data in FIFO is all the data to be received then get the data * and also leave the device in a good state for the next transaction. */ else if ((InstancePtr->RecvByteCount - BytesInFifo) == 0) { /* * If repeated start option is off then the master should stop * using the bus, otherwise hold the bus, setting repeated start * stops the slave from transmitting data when the FIFO is read. */ if ((InstancePtr->Options & XII_REPEATED_START_OPTION) == 0) { CntlReg &= ~XIIC_CR_MSMS_MASK; } else { CntlReg |= XIIC_CR_REPEATED_START_MASK; } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Read data from the FIFO then set zero based FIFO read depth * for a byte. */ for (LoopCnt = 0; LoopCnt < BytesInFifo; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Disable Rx full interrupt and write the control reg with ACK * allowing next byte sent to be acknowledged automatically. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg & ~XIIC_CR_NO_ACK_MASK)); /* * Send notification of msg Rx complete in RecvHandler callback. */ InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, 0); } else { /* * Fifo data not at n-1, read all but the last byte of data * from the slave, if more than a FIFO full yet to receive * read a FIFO full. */ BytesToRead = InstancePtr->RecvByteCount - BytesInFifo - 1; if (BytesToRead > IIC_RX_FIFO_DEPTH) { BytesToRead = IIC_RX_FIFO_DEPTH; } /* * Read in data from the FIFO. */ for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } } }
/** * * This function is called when the IIC device receives Not Addressed As Slave * (NAAS) interrupt which indicates that the master has released the bus implying * a data transfer is complete. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void NotAddrAsSlaveHandler(XIic *InstancePtr) { u32 Status; u32 CntlReg; u8 BytesToRead; u8 LoopCnt; /* * Disable NAAS so that the condition will not continue to interrupt * and enable the addressed as slave interrupt to know when a master * selects a slave on the bus. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_NAAS_MASK); XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_AAS_MASK); /* * Flush Tx FIFO by toggling TxFIFOResetBit. FIFO runs normally at 0 * Do this incase needed to Tx FIFO with more than expected if what * was set to Tx was less than what the Master expected - read more * from this slave so FIFO had junk in it. */ XIic_FlushTxFifo(InstancePtr); /* * NAAS interrupt was asserted but received data in recieve FIFO is * less than Rc_FIFO_PIRQ to assert an receive full interrupt,in this * condition as data recieved is valid we have to read data before FIFO * flush. */ Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); if (!(Status & XIIC_SR_RX_FIFO_EMPTY_MASK)) { BytesToRead = (XIic_ReadReg(InstancePtr->BaseAddress, XIIC_RFO_REG_OFFSET)) + 1; if (InstancePtr->RecvByteCount > BytesToRead) { for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } } } InstancePtr->RecvByteCount = 0; /* * Flush Rx FIFO should slave Rx had a problem, sent No ack but * still received a few bytes. Should the slave receive have disabled * acknowledgement, clear Rx FIFO. */ XIic_FlushRxFifo(InstancePtr); /* * Set FIFO occupancy depth = 1 so that the first byte will throttle * next recieve msg. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Should the slave receive have disabled acknowledgement, * enable to allow acknowledgment for receipt of our address to * again be used as a slave. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg & ~XIIC_CR_NO_ACK_MASK)); /* * Which callback depends on messaging direction, the buffer pointer NOT * being used indicates the direction of data transfer. */ Status = XIic_ReadIier(InstancePtr->BaseAddress); if (InstancePtr->RecvBufferPtr == NULL) { /* * Slave was sending data so disable all transmit interrupts and * call the callback handler to indicate the transfer is * complete. */ XIic_WriteIier(InstancePtr->BaseAddress, (Status & ~XIIC_TX_INTERRUPTS)); InstancePtr->SendHandler(InstancePtr->SendCallBackRef, InstancePtr->SendByteCount); } else { /* * Slave was receiving data so disable receive full interrupt * and call the callback handler to notify the transfer is * complete. */ XIic_WriteIier(InstancePtr->BaseAddress, (Status & ~XIIC_INTR_RX_FULL_MASK)); InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, InstancePtr->RecvByteCount); } return; }