/** * * The IIC bus busy signals when a master has control of the bus. Until the bus * is released, i.e. not busy, other devices must wait to use it. * * When this interrupt occurs, it signals that the previous master has released * the bus for another user. * * This interrupt is only enabled when the master Tx is waiting for the bus. * * This interrupt causes the following tasks: * - Disable Bus not busy interrupt * - Enable bus Ack * Should the slave receive have disabled acknowledgement, enable to allow * acknowledgment of the sending of our address to again be addresed as * slave * - Flush Rx FIFO * Should the slave receive have disabled acknowledgement, a few bytes may * be in FIFO if Rx full did not occur because of not enough byte in FIFO * to have caused an interrupt. * - Send status to user via status callback with the value: * XII_BUS_NOT_BUSY_EVENT * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void BusNotBusyHandler(XIic *InstancePtr) { u32 Status; u32 CntlReg; /* * Should the slave receive have disabled acknowledgement, * enable to allow acknowledgment of the sending of our address to * again be addresed as slave. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg & ~XIIC_CR_NO_ACK_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); /* * 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); /* * Send Application messaging status via callbacks. Disable either Tx or * Receive interrupt. Which callback depends on messaging direction. */ Status = XIic_ReadIier(InstancePtr->BaseAddress); if (InstancePtr->RecvBufferPtr == NULL) { /* * Slave was sending data (master was reading), disable * all the transmit interrupts. */ XIic_WriteIier(InstancePtr->BaseAddress, (Status & ~XIIC_TX_INTERRUPTS)); } else { /* * Slave was receiving data (master was writing) disable receive * interrupts. */ XIic_WriteIier(InstancePtr->BaseAddress, (Status & ~XIIC_INTR_RX_FULL_MASK)); } /* * Send Status in StatusHandler callback. */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_BUS_NOT_BUSY_EVENT); }
/** * * When multiple IIC devices attempt to use the bus simultaneously, only * a single device will be able to keep control as a master. Those devices * that didn't retain control over the bus are said to have lost arbitration. * When arbitration is lost, this interrupt occurs sigaling the user that * the message did not get sent as expected. * * This function, at arbitration lost: * - Disables Tx empty, ½ empty and Tx error interrupts * - Clears any Tx empty, ½ empty Rx Full or Tx error interrupts * - Clears Arbitration lost interrupt, * - Flush Tx FIFO * - Call StatusHandler callback with the value: XII_ARB_LOST_EVENT * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void ArbitrationLostHandler(XIic *InstancePtr) { /* * Disable Tx empty and ½ empty and Tx error interrupts before clearing * them so they won't occur again. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS); /* * Clear any Tx empty, ½ empty Rx Full or Tx error interrupts. */ XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS); XIic_FlushTxFifo(InstancePtr); /* * Update Status via StatusHandler callback. */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_ARB_LOST_EVENT); }
/** * * This interrupt occurs four different ways: Two as master and two as slave. * Master: * <pre> * (1) Transmitter (IMPLIES AN ERROR) * The slave receiver did not acknowledge properly. * (2) Receiver (Implies Tx complete) * Interrupt caused by setting TxAck high in the IIC to indicate to the * the last byte has been transmitted. * </pre> * * Slave: * <pre> * (3) Transmitter (Implies Tx complete) * Interrupt caused by master device indicating last byte of the message * has been transmitted. * (4) Receiver (IMPLIES AN ERROR) * Interrupt caused by setting TxAck high in the IIC to indicate Rx * IIC had a problem - set by this device and condition already known * and interrupt is not enabled. * </pre> * * This interrupt is enabled during Master send and receive and disabled * when this device knows it is going to send a negative acknowledge (Ack = No). * * Signals user of Tx error via status callback sending: XII_TX_ERROR_EVENT * * When MasterRecv has no message to send and only receives one byte of data * from the salve device, the TxError must be enabled to catch addressing * errors, yet there is not opportunity to disable TxError when there is no * data to send allowing disabling on last byte. When the slave sends the * only byte the NOAck causes a Tx Error. To disregard this as no real error, * when there is data in the Receive FIFO/register then the error was not * a device address write error, but a NOACK read error - to be ignored. * To work with or without FIFO's, the Rx Data interrupt is used to indicate * data is in the Rx register. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * ******************************************************************************/ static void TxErrorHandler(XIic *InstancePtr) { u32 IntrStatus; u32 CntlReg; /* * When Sending as a slave, Tx error signals end of msg. Not Addressed * As Slave will handle the callbacks. this is used to only flush * the Tx fifo. The addressed as slave bit is gone as soon as the bus * has been released such that the buffer pointers are used to determine * the direction of transfer (send or receive). */ if (InstancePtr->RecvBufferPtr == NULL) { /* * Master Receiver finished reading message. Flush Tx fifo to * remove an 0xFF that was written to prevent bus throttling, * and disable all transmit and receive interrupts. */ XIic_FlushTxFifo(InstancePtr); XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* * If operating in Master mode, call status handler to indicate * NOACK occured. */ IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); if ((IntrStatus & XIIC_INTR_AAS_MASK) == 0) { InstancePtr->StatusHandler(InstancePtr-> StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); } else { /* Decrement the Tx Error since Tx Error interrupt * implies transmit complete while sending as Slave */ InstancePtr->Stats.TxErrors--; } return; } /* * Data in the receive register from either master or slave receive * When:slave, indicates master sent last byte, message completed. * When:master, indicates a master Receive with one byte received. When * a byte is in Rx reg then the Tx error indicates the Rx data was * recovered normally Tx errors are not enabled such that this should * not occur. */ IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Rx Reg/FIFO has data, Disable Tx error interrupts */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); return; } XIic_FlushTxFifo(InstancePtr); /* * Disable and clear Tx empty, � empty, Rx Full or Tx error interrupts. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* Clear MSMS as on Tx error when Rxing, the bus will be * stopped but MSMS bit is still set. Reset to proper state */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); CntlReg &= ~XIIC_CR_MSMS_MASK; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Set FIFO occupancy depth = 1 so that the first byte will throttle * next recieve msg. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Call the event callback. */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); }
/** * * 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; }