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