Beispiel #1
0
/**
*
* 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);
}
Beispiel #2
0
/**
*
* 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;
}