Esempio n. 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);
}
/**
*
* 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 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;
}