/** * * This function sends data as a slave on the IIC bus and should not be called * until an event has occurred that indicates the device has been selected by * a master attempting read from the slave (XII_MASTER_READ_EVENT). * * If more data is received than specified a No Acknowledge will be sent to * signal the Master to stop sending data. Any received data is read to prevent * the slave device from throttling the bus. * * @param InstancePtr is a pointer to the Iic instance to be worked on. * @param RxMsgPtr is a pointer to the data to be transmitted. * @param ByteCount is the number of message bytes to be sent. * * @return * - XST_SUCCESS indicates the message transmission has been * initiated. * - XST_IIC_NOT_SLAVE indicates the device has not been selected * to be a slave on the IIC bus such that data cannot be received. * * @internal * * The master signals the message completion differently depending on the * repeated start options. * * When the master is not using repeated start: * - Not Adressed As Slave NAAS interrupt signals the master has sent a stop * condition and is no longer sending data. This doesn't imply that the master * will not send a No Ack. It covers when the master fails to send No * Ackowledge before releasing the bus. * - Tx Error interrupt signals end of message. * * When the master is using repeated start: * - the Tx Error interrupt signals the master finished sending the msg. * - NAAS interrupt will not signal when message is complete as the * master may want to write or read another message with this device. * * To prevent throttling, the slave must contine to read discard the data * when the receive buffer is full. When unexpected bytes are received, No Ack * must be set and the Rx buffer continually read until either NAAS * or Bus Not Busy BND interrupt signals the master is no longer * interacting with this slave. At this point the Ack is set to ON allowing * this device to acknowlefge the an address sent to it for the next * slave message. * * The slave will always receive 1 byte before the bus is throttled causing a * receive pending interrupt before this routine is executed. After one byte * the bus will throttle. The depth is set to the proper amount immediatelly * allowing the master to send more bytes and then to again throttle, but at the * proper fifo depth. The interrupt is a level. Clearing and enabling will cause * the Rx interrupt to pend at the correct level. * ******************************************************************************/ int XIic_SlaveRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount) { u32 Status; /* * If the device is not a slave on the IIC bus then indicate an error * because data cannot be received on the bus. */ Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); if ((Status & XIIC_SR_ADDR_AS_SLAVE_MASK) == 0) { return XST_IIC_NOT_SLAVE; } XIic_IntrGlobalDisable(InstancePtr->BaseAddress); /* * Save message state and invalidate the send buffer pointer to indicate * the direction of transfer is receive. */ InstancePtr->RecvByteCount = ByteCount; InstancePtr->RecvBufferPtr = RxMsgPtr; InstancePtr->SendBufferPtr = NULL; /* * Set receive FIFO occupancy depth so the Rx interrupt will occur * when all bytes received or if more bytes than will fit in FIFO, * set to max depth. */ if (ByteCount > IIC_RX_FIFO_DEPTH) { XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1); } else { XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, ByteCount - 1); } /* * Clear and enable receive full interrupt except when the bytes to * receive is only 1, don't clear interrupt as it is the only one your * going to get. */ if (ByteCount > 1) { XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); } XIic_EnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_SUCCESS; }
/** * * This function starts the IIC device and driver by enabling the proper * interrupts such that data may be sent and received on the IIC bus. * This function must be called before the functions to send and receive data. * * Before XIic_Start() is called, the interrupt control must connect the ISR * routine to the interrupt handler. This is done by the user, and not * XIic_Start() to allow the user to use an interrupt controller of their choice. * * Start enables: * - IIC device * - Interrupts: * - Addressed as slave to allow messages from another master * - Arbitration Lost to detect Tx arbitration errors * - Global IIC interrupt * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return XST_SUCCESS always. * * @note * * The device interrupt is connected to the interrupt controller, but no * "messaging" interrupts are enabled. Addressed as Slave is enabled to * reception of messages when this devices address is written to the bus. * The correct messaging interrupts are enabled when sending or receiving * via the IicSend() and IicRecv() functions. No action is required * by the user to control any IIC interrupts as the driver completely * manages all 8 interrupts. Start and Stop control the ability * to use the device. Stopping the device completely stops all device * interrupts from the processor. * ****************************************************************************/ int XIic_Start(XIic *InstancePtr) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Mask off all interrupts, each is enabled when needed. */ XIic_WriteIier(InstancePtr->BaseAddress, 0); /* * Clear all interrupts by reading and rewriting exact value back. * Only those bits set will get written as 1 (writing 1 clears intr). */ XIic_ClearIntr(InstancePtr->BaseAddress, 0xFFFFFFFF); /* * Enable the device. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK); /* * Set Rx FIFO Occupancy depth to throttle at * first byte(after reset = 0). */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Clear and enable the interrupts needed. */ XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK); InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; InstancePtr->IsDynamic = FALSE; /* * Enable the Global interrupt enable. */ XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_SUCCESS; }
/** * * 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 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 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); }