/**
*
* 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;
}
Ejemplo n.º 2
0
/******************************************************************************
*
* When the IIC Tx FIFO/register goes empty, this routine is called by the
* interrupt service routine to fill the transmit FIFO with data to be sent.
*
* This function also is called by the Tx ½ empty interrupt as the data handling
* is identical when you don't assume the FIFO is empty but use the Tx_FIFO_OCY
* register to indicate the available free FIFO bytes.
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void SendMasterData(XIic *InstancePtr)
{
	u32 CntlReg;

	/*
	 * The device is a master on the bus.  If there is still more address
	 * bytes to send when in master receive operation and the slave device
	 * is 10 bit addressed.
	 * This requires the lower 7 bits of address to be resent when the mode
	 * switches to Read instead of write (while sending addresses).
	 */
	if (InstancePtr->TxAddrMode & XIIC_TX_ADDR_MSTR_RECV_MASK) {
		/*
		 * Send the 1st byte of the slave address in the read operation
		 * and change the state to indicate this has been done
		 */
		SendSlaveAddr(InstancePtr);
		InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT;
	}

	/*
	 * In between 1st and last byte of message, fill the FIFO with more data
	 * to send, disable the 1/2 empty interrupt based upon data left to
	 * send.
	 */
	else if (InstancePtr->SendByteCount > 1) {
		XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE);

		if (InstancePtr->SendByteCount < 2) {
			XIic_DisableIntr(InstancePtr->BaseAddress,
					  XIIC_INTR_TX_HALF_MASK);
		}
	}
	/*
	 * If there is only one byte left to send, processing differs between
	 * repeated start and normal messages.
	 */
	else if (InstancePtr->SendByteCount == 1) {
		/*
		 * When using repeated start, another interrupt is expected
		 * after the last byte has been sent, so the message is not
		 * done yet.
		 */
		if (InstancePtr->Options & XII_REPEATED_START_OPTION) {
			XIic_WriteSendByte(InstancePtr);
		}

		/*
		 * When not using repeated start, the stop condition must be
		 * generated after the last byte is written. The bus is
		 * throttled waiting for the last byte.
		 */
		else {
			/*
			 * Set the stop condition before sending the last byte
			 * of data so that the stop condition will be generated
			 * immediately following the data another transmit
			 * interrupt is not expected so the message is done.
			 */
			CntlReg = XIic_ReadReg(InstancePtr->BaseAddress,
					XIIC_CR_REG_OFFSET);
			CntlReg &= ~XIIC_CR_MSMS_MASK;
			XIic_WriteReg(InstancePtr->BaseAddress,
					XIIC_CR_REG_OFFSET,
					CntlReg);

			XIic_WriteSendByte(InstancePtr);

			/*
			 * Wait for bus to not be busy before declaring message
			 * has been sent for the no repeated start operation.
			 * The callback will be called from the BusNotBusy part
			 * of the Interrupt handler to ensure that the message
			 * is completely sent.
			 * Disable the Tx interrupts and enable the BNB
			 * interrupt.
			 */

			InstancePtr->BNBOnly = FALSE;
			XIic_DisableIntr(InstancePtr->BaseAddress,
						XIIC_TX_INTERRUPTS);
			XIic_EnableIntr(InstancePtr->BaseAddress,
					 XIIC_INTR_BNB_MASK);

		}
	} else {
		if (InstancePtr->Options & XII_REPEATED_START_OPTION) {

			/*
			 * The message being sent has completed. When using
			 * repeated start with no more bytes to send repeated
			 * start needs to be set in the control register so
			 * that the bus will still be held by this master.
			 */
			CntlReg = XIic_ReadReg(InstancePtr->BaseAddress,
					XIIC_CR_REG_OFFSET);
			CntlReg |= XIIC_CR_REPEATED_START_MASK;
			XIic_WriteReg(InstancePtr->BaseAddress,
					XIIC_CR_REG_OFFSET, CntlReg);

			/*
			 * If the message that was being sent has finished,
			 * disable all transmit interrupts and call the callback
			 * that was setup to indicate the message was sent,
			 * with 0 bytes remaining.
			 */

			XIic_DisableIntr(InstancePtr->BaseAddress,
					  XIIC_TX_INTERRUPTS);
			InstancePtr->SendHandler(InstancePtr->SendCallBackRef,
						 0);
		}
	}

	return;
}
/******************************************************************************
*
* When the IIC Tx FIFO/register goes empty, this routine is called by the
* interrupt service routine to fill the transmit FIFO with data to be sent.
*
* This function also is called by the Tx ½ empty interrupt as the data handling
* is identical when you don't assume the FIFO is empty but use the Tx_FIFO_OCY
* register to indicate the available free FIFO bytes.
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DynSendMasterData(XIic *InstancePtr)
{
    u32 CntlReg;

    /*
     * In between 1st and last byte of message, fill the FIFO with more data
     * to send, disable the 1/2 empty interrupt based upon data left to
     * send.
     */
    if (InstancePtr->SendByteCount > 1) {
        XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE);

        if (InstancePtr->SendByteCount < 2) {
            XIic_DisableIntr(InstancePtr->BaseAddress,
                             XIIC_INTR_TX_HALF_MASK);
        }
    }

    /*
     * If there is only one byte left to send, processing differs between
     * repeated start and normal messages.
     */
    else if (InstancePtr->SendByteCount == 1) {
        /*
         * When using repeated start, another interrupt is expected
         * after the last byte has been sent, so the message is not
         * done yet.
         */
        if (InstancePtr->Options & XII_REPEATED_START_OPTION) {
            XIic_WriteSendByte(InstancePtr);
        } else {
            XIic_DynSendStop(InstancePtr->BaseAddress,
                             *InstancePtr->SendBufferPtr);

            /*
             * Wait for bus to not be busy before declaring message
             * has been sent for the no repeated start operation.
             * The callback will be called from the BusNotBusy part
             * of the Interrupt handler to ensure that the message
             * is completely sent. Disable the Tx interrupts and
             * enable the BNB interrupt.
             */
            InstancePtr->BNBOnly = FALSE;
            XIic_DisableIntr(InstancePtr->BaseAddress,
                             XIIC_TX_INTERRUPTS);
            XIic_EnableIntr(InstancePtr->BaseAddress,
                            XIIC_INTR_BNB_MASK);
        }
    } else {
        if (InstancePtr->Options & XII_REPEATED_START_OPTION) {
            /*
             * The message being sent has completed. When using
             * repeated start with no more bytes to send repeated
             * start needs to be set in the control register so
             * that the bus will still be held by this master.
             */
            CntlReg = XIic_ReadReg(InstancePtr->BaseAddress,
                                   XIIC_CR_REG_OFFSET);
            CntlReg |= XIIC_CR_REPEATED_START_MASK;
            XIic_WriteReg(InstancePtr->BaseAddress,
                          XIIC_CR_REG_OFFSET, CntlReg);

            /*
             * If the message that was being sent has finished,
             * disable all transmit interrupts and call the callback
             * that was setup to indicate the message was sent,
             * with 0 bytes remaining.
             */
            XIic_DisableIntr(InstancePtr->BaseAddress,
                             XIIC_TX_INTERRUPTS);
            InstancePtr->SendHandler(InstancePtr->SendCallBackRef,
                                     0);
        }
    }

    return;
}