Exemplo n.º 1
0
/**
* Send data as a master on the IIC bus. This function sends the data using
* polled I/O and blocks until the data has been sent. It only supports 7 bit
* addressing. The user is responsible for ensuring the bus is not busy if
* multiple masters are present on the bus.
*
* @param	BaseAddress contains the base address of the IIC Device.
* @param	Address contains the 7 bit IIC address of the device to send the
*		specified data to.
* @param	BufferPtr points to the data to be sent.
* @param	ByteCount is the number of bytes to be sent.
* @param	Option: XIIC_STOP = end with STOP condition,
*		XIIC_REPEATED_START = don't end with STOP condition.
*
* @return	The number of bytes sent.
*
* @note		None.
*
******************************************************************************/
unsigned XIic_DynSend(u32 BaseAddress, u16 Address, u8 *BufferPtr,
			u8 ByteCount, u8 Option)
{
	unsigned RemainingByteCount;
	u32 StatusRegister;

	/*
	 * Clear the latched interrupt status so that it will be updated with
	 * the new state when it changes, this must be done after the address
	 * is put in the FIFO
	 */
	XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK |
			XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK);

	/*
	 * Put the address into the Fifo to be sent and indicate that the
	 * operation to be performed on the bus is a write operation. Upon
	 * writing the address, a start condition is initiated. MSMS is
	 * automatically set to master when the address is written to the Fifo.
	 * If MSMS was already set, then a re-start is sent prior to the
	 * address.
	 */
	if(!(Address & XIIC_TX_DYN_STOP_MASK)) {

		XIic_DynSend7BitAddress(BaseAddress, Address,
				XIIC_WRITE_OPERATION);
	} else {
		XIic_DynSendStartStopAddress(BaseAddress, Address,
					XIIC_WRITE_OPERATION);
	}

	/*
	 * Wait for the bus to go busy.
	 */
	StatusRegister = XIic_ReadReg(BaseAddress,  XIIC_SR_REG_OFFSET);

	while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) !=
			XIIC_SR_BUS_BUSY_MASK) {
		StatusRegister = XIic_ReadReg(BaseAddress,
				XIIC_SR_REG_OFFSET);
	}

	/*
	 * Clear the latched interrupt status for the bus not busy bit which
	 * must be done while the bus is busy.
	 */
	XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK);

	/*
	 * Send the specified data to the device on the IIC bus specified by the
	 * the address.
	 */
	RemainingByteCount = DynSendData(BaseAddress, BufferPtr, ByteCount,
					 Option);

	/*
	 * The send is complete return the number of bytes that was sent.
	 */
	return ByteCount - RemainingByteCount;
}
Exemplo n.º 2
0
/**
* Receive data as a master on the IIC bus. This function receives the data
* using polled I/O and blocks until the data has been received. It only
* supports 7 bit addressing. The user is responsible for ensuring the bus is
* not busy if multiple masters are present on the bus.
*
* @param	BaseAddress contains the base address of the IIC Device.
* @param	Address contains the 7 bit IIC Device address of the device to
*		send the specified data to.
* @param	BufferPtr points to the data to be sent.
* @param	ByteCount is the number of bytes to be sent. This value can't be
*		greater than 255 and needs to be greater than 0.
*
* @return	The number of bytes received.
*
* @note		Upon entry to this function, the IIC interface needs to be
*		already enabled in the CR register.
*
******************************************************************************/
unsigned XIic_DynRecv(u32 BaseAddress, u8 Address, u8 *BufferPtr, u8 ByteCount)
{
	unsigned RemainingByteCount;
	u32 StatusRegister;

	/*
	 * Clear the latched interrupt status so that it will be updated with
	 * the new state when it changes.
	 */
	XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK |
			XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK);

	/*
	 * Send the 7 bit slave address for a read operation and set the state
	 * to indicate the address has been sent. Upon writing the address, a
	 * start condition is initiated. MSMS is automatically set to master
	 * when the address is written to the Fifo. If MSMS was already set,
	 * then a re-start is sent prior to the address.
	 */
	XIic_DynSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION);

	/*
	 * Wait for the bus to go busy.
	 */
	StatusRegister = XIic_ReadReg(BaseAddress,  XIIC_SR_REG_OFFSET);

	while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK)
			!= XIIC_SR_BUS_BUSY_MASK) {
		StatusRegister = XIic_ReadReg(BaseAddress,
				XIIC_SR_REG_OFFSET);
	}

	/*
	 * Clear the latched interrupt status for the bus not busy bit which
	 * must be done while the bus is busy.
	 */
	XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK);

	/*
	 * Write to the Tx Fifo the dynamic stop control bit with the number of
	 * bytes that are to be read over the IIC interface from the presently
	 * addressed device.
	 */
	XIic_DynSendStop(BaseAddress, ByteCount);

	/*
	 * Receive the data from the IIC bus.
	 */
	RemainingByteCount = DynRecvData(BaseAddress, BufferPtr, ByteCount);

	/*
	 * The receive is complete. Return the number of bytes that were
	 * received.
	 */
	return ByteCount - RemainingByteCount;
}
/**
* This function receives data as a master from a slave device on the IIC bus.
* If the bus is busy, it will indicate so and then enable an interrupt such
* that the status handler will be called when the bus is no longer busy. The
* slave address which has been set with the XIic_SetAddress() function is the
* address from which data is received. Receiving data on the bus performs a
* read operation.
*
* @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 reception processes has been
* 		initiated.
*		- XST_IIC_BUS_BUSY indicates the bus was in use and that the
*		BusNotBusy interrupt is enabled which will update the
*		EventStatus when the bus is no longer busy.
*		- XST_IIC_GENERAL_CALL_ADDRESS indicates the slave address is
*		set to the general call address. This is not allowed for Master
*		receive mode.
*
* @note		The receive FIFO threshold is a zero based count such that 1
*		must be subtracted from the desired count to get the correct
*		value. When receiving data it is also necessary to not receive
*		the last byte with the prior bytes because the acknowledge must
*		be setup before the last byte is received.
*
******************************************************************************/
int XIic_DynMasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, u8 ByteCount)
{
    u32 CntlReg;
    u32 RxFifoOccy;

    /*
     * If the slave address is zero (general call) the master can't perform
     * receive operations, indicate an error.
     */
    if (InstancePtr->AddrOfSlave == 0) {
        return XST_IIC_GENERAL_CALL_ADDRESS;
    }

    /*
     * Disable the Interrupts.
     */
    XIic_IntrGlobalDisable(InstancePtr->BaseAddress);

    /*
     * Ensure that the master processing has been included such that events
     * will be properly handled.
     */
    XIIC_DYN_MASTER_INCLUDE;
    InstancePtr->IsDynamic = TRUE;

    /*
     * If the busy is busy, then exit the critical region and wait for the
     * bus to not be busy, the function enables the bus not busy interrupt.
     */
    if (IsBusBusy(InstancePtr)) {
        XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

        return XST_IIC_BUS_BUSY;
    }

    /*
     * Save message state for event driven processing.
     */
    InstancePtr->RecvByteCount = ByteCount;
    InstancePtr->RecvBufferPtr = RxMsgPtr;

    /*
     * Clear and enable Rx full interrupt.
     */
    XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK);

    /*
     * If already a master on the bus, the direction was set by Rx Interrupt
     * routine to Tx which is throttling bus because during Rxing, Tx reg is
     * empty = throttle. CR needs setting before putting data or the address
     * written will go out as Tx instead of receive. Start Master Rx by
     * setting CR Bits MSMS to Master and msg direction.
     */
    CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);
    if (CntlReg & XIIC_CR_MSMS_MASK) {
        /*
         * Set the Repeated Start bit in CR.
         */
        CntlReg |= XIIC_CR_REPEATED_START_MASK;
        XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount);

        /*
         * Increment stats counts.
         */
        InstancePtr->Stats.RepeatedStarts++;
        XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET,
                      CntlReg);
    }

    /*
     * Set receive FIFO occupancy depth which must be done prior to writing
     * the address in the FIFO because the transmitter will immediately
     * start when in repeated start mode followed by the receiver such
     * that the number of bytes to receive should be set 1st.
     */
    if (ByteCount == 1) {
        RxFifoOccy = 0;
    }
    else {
        if (ByteCount <= IIC_RX_FIFO_DEPTH) {
            RxFifoOccy = ByteCount - 2;
        } else {
            RxFifoOccy = IIC_RX_FIFO_DEPTH - 1;
        }
    }

    XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET,
                  RxFifoOccy);

    /*
     * Send the Seven Bit address. Only 7 bit addressing is supported in
     * Dynamic mode and mark that the address has been sent.
     */
    XIic_DynSend7BitAddress(InstancePtr->BaseAddress,
                            InstancePtr->AddrOfSlave, XIIC_READ_OPERATION);
    InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT;

    /*
     * Send the bytecount to be received and set the stop bit.
     */
    XIic_DynSendStop(InstancePtr->BaseAddress, ByteCount);

    /*
     * Tx error is enabled incase the address has no device to answer
     * with Ack. When only one byte of data, must set NO ACK before address
     * goes out therefore Tx error must not be enabled as it will go off
     * immediately and the Rx full interrupt will be checked. If full, then
     * the one byte was received and the Tx error will be disabled without
     * sending an error callback msg.
     */
    XIic_ClearEnableIntr(InstancePtr->BaseAddress,
                         XIIC_INTR_TX_ERROR_MASK);

    /*
     * Enable the Interrupts.
     */
    XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

    return XST_SUCCESS;
}
/**
* This function sends data as a Dynamic master on the IIC bus. If the bus is
* busy, it will indicate so and then enable an interrupt such that the status
* handler will be called when the bus is no longer busy. The slave address is
* sent by using XIic_DynSend7BitAddress().
*
* @param	InstancePtr points to the Iic instance to be worked on.
* @param	TxMsgPtr points to the data to be transmitted.
* @param	ByteCount is the number of message bytes to be sent.
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int XIic_DynMasterSend(XIic *InstancePtr, u8 *TxMsgPtr, u8 ByteCount)
{
    u32 CntlReg;

    XIic_IntrGlobalDisable(InstancePtr->BaseAddress);

    /*
     * Ensure that the Dynamic master processing has been included such that
     * events will be properly handled.
     */
    XIIC_DYN_MASTER_INCLUDE;
    InstancePtr->IsDynamic = TRUE;

    /*
     * If the busy is busy, then exit the critical region and wait for the
     * bus not to be busy. The function enables the BusNotBusy interrupt.
     */
    if (IsBusBusy(InstancePtr)) {
        XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

        return XST_FAILURE;
    }

    /*
     * If it is already a master on the bus (repeated start), the direction
     * was set to Tx which is throttling bus. The control register needs to
     * be set before putting data into the FIFO.
     */
    CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);
    if (CntlReg & XIIC_CR_MSMS_MASK) {
        CntlReg &= ~XIIC_CR_NO_ACK_MASK;
        CntlReg |= XIIC_CR_DIR_IS_TX_MASK;
        XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET,
                      CntlReg);
        InstancePtr->Stats.RepeatedStarts++;
    }

    /*
     * Save message state.
     */
    InstancePtr->SendByteCount = ByteCount;
    InstancePtr->SendBufferPtr = TxMsgPtr;

    /*
     * Send the Seven Bit address. Only 7 bit addressing is supported in
     * Dynamic mode.
     */
    XIic_DynSend7BitAddress(InstancePtr->BaseAddress,
                            InstancePtr->AddrOfSlave,
                            XIIC_WRITE_OPERATION);

    /*
     * Set the transmit address state to indicate the address has been sent
     * for communication with event driven processing.
     */
    InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT;

    /*
     * Fill the Tx FIFO.
     */
    if (InstancePtr->SendByteCount > 1) {
        XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE);
    }

    /*
     * After filling fifo, if data yet to send > 1, enable Tx ½ empty
     * interrupt.
     */
    if (InstancePtr->SendByteCount > 1) {
        XIic_ClearEnableIntr(InstancePtr->BaseAddress,
                             XIIC_INTR_TX_HALF_MASK);
    }

    /*
     * Clear any pending Tx empty, Tx Error and then enable them.
     */
    XIic_ClearEnableIntr(InstancePtr->BaseAddress,
                         XIIC_INTR_TX_ERROR_MASK |
                         XIIC_INTR_TX_EMPTY_MASK);

    /*
     * Enable the Interrupts.
     */
    XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

    return XST_SUCCESS;
}