コード例 #1
0
ファイル: xiic.c プロジェクト: Genihoust/academic_project_3
/**
*
* This function sets the bus addresses. The addresses include the device
* address that the device responds to as a slave, or the slave address
* to communicate with on the bus.  The IIC device hardware is built to
* allow either 7 or 10 bit slave addressing only at build time rather
* than at run time. When this device is a master, slave addressing can
* be selected at run time to match addressing modes for other bus devices.
*
* Addresses are represented as hex values with no adjustment for the data
* direction bit as the software manages address bit placement.
* Example: For a 7 address written to the device of 1010 011X where X is
* the transfer direction (send/recv), the address parameter for this function
* needs to be 01010011 or 0x53 where the correct bit alllignment will be
* handled for 7 as well as 10 bit devices. This is especially important as
* the bit placement is not handled the same depending on which options are
* used such as repeated start.
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
* @param	AddressType indicates which address is being modified, the
*		address which this device responds to on the IIC bus as a slave,
*		or the slave address to communicate with when this device is a
*		master. One of the following values must be contained in
*		this argument.
* <pre>
*   XII_ADDR_TO_SEND_TYPE	Slave being addressed by a this master
*   XII_ADDR_TO_RESPOND_TYPE	Address to respond to as a slave device
* </pre>
*
* @param	Address contains the address to be set, 7 bit or 10 bit address.
*		A ten bit address must be within the range: 0 - 1023 and a 7 bit
*		address must be within the range 0 - 127.
*
* @return
*		- XST_SUCCESS is returned if the address was successfully set.
*		- XST_IIC_NO_10_BIT_ADDRESSING indicates only 7 bit addressing
*		  supported.
*		- XST_INVALID_PARAM indicates an invalid parameter was
*		  specified.
*
* @note
*
* Upper bits of 10-bit address is written only when current device is built
* as a ten bit device.
*
****************************************************************************/
int XIic_SetAddress(XIic *InstancePtr, int AddressType, int Address)
{
	u32 SendAddr;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(Address < 1023);

	/*
	 * Set address to respond to for this device into address registers.
	 */
	if (AddressType == XII_ADDR_TO_RESPOND_TYPE) {
		/*
		 * Address in upper 7 bits.
		 */
		SendAddr = ((Address & 0x007F) << 1);
		XIic_WriteReg(InstancePtr->BaseAddress, XIIC_ADR_REG_OFFSET,
				SendAddr);

		if (InstancePtr->Has10BitAddr == TRUE) {
			/*
			 * Write upper 3 bits of addr to DTR only when 10 bit
			 * option included in design i.e. register exists.
			 */
			SendAddr = ((Address & 0x0380) >> 7);
			XIic_WriteReg(InstancePtr->BaseAddress,
					XIIC_TBA_REG_OFFSET, SendAddr);
		}
コード例 #2
0
/**
*
* 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;
}
コード例 #3
0
ファイル: xiic_options.c プロジェクト: aalonso/xilinx-ml405
/**
*
* This function sets the options for the IIC device driver. The options control
* how the device behaves relative to the IIC bus. If an option applies to
* how messages are sent or received on the IIC bus, it must be set prior to
* calling functions which send or receive data.
*
* To set multiple options, the values must be ORed together. To not change
* existing options, read/modify/write with the current options using
* XIic_GetOptions().
*
* <b>USAGE EXAMPLE:</b>
*
* Read/modify/write to enable repeated start:
* <pre>
*   u8 Options;
*   Options = XIic_GetOptions(&Iic);
*   XIic_SetOptions(&Iic, Options | XII_REPEATED_START_OPTION);
* </pre>
*
* Disabling General Call:
* <pre>
*   Options = XIic_GetOptions(&Iic);
*   XIic_SetOptions(&Iic, Options &= ~XII_GENERAL_CALL_OPTION);
* </pre>
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
* @param	NewOptions are the options to be set.  See xiic.h for a list of
*		the available options.
*
* @return	None.
*
* @note
*
* Sending or receiving messages with repeated start enabled, and then
* disabling repeated start, will not take effect until another master
* transaction is completed. i.e. After using repeated start, the bus will
* continue to be throttled after repeated start is disabled until a master
* transaction occurs allowing the IIC to release the bus.
* <br><br>
* Options enabled will have a 1 in its appropriate bit position.
*
****************************************************************************/
void XIic_SetOptions(XIic *InstancePtr, u32 NewOptions)
{
	u32 CntlReg;

	Xil_AssertVoid(InstancePtr != NULL);

	XIic_IntrGlobalDisable(InstancePtr->BaseAddress);

	/*
	 * Update the options in the instance and get the contents of the
	 * control register such that the general call option can be modified.
	 */
	InstancePtr->Options = NewOptions;
	CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);

	/*
	 * The general call option is the only option that maps directly to
	 * a hardware register feature.
	 */
	if (NewOptions & XII_GENERAL_CALL_OPTION) {
		CntlReg |= XIIC_CR_GENERAL_CALL_MASK;
	} else {
		CntlReg &= ~XIIC_CR_GENERAL_CALL_MASK;
	}

	/*
	 * Write the new control register value to the register.
	 */
	XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg);

	XIic_IntrGlobalEnable(InstancePtr->BaseAddress);
}
コード例 #4
0
/**
*
* This function sends data on the IIC bus as a slave.
*
* When message data has been sent, but the master keeps reading data, the FIFO
* is filled to prevent bus throttling. There is no way to notify master of this
* condition. While sending data as a slave a transmit error indicates the
* master has completed the data transfer.
*
* NAAS interrupt signals when repeated start occurred and the msg is finished
* and BNB signals when the master sent a stop.
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void SendSlaveData(XIic *InstancePtr)
{
    /*
     * When message has been sent, but master keeps reading data, must put a
     * byte in the FIFO or bus will throttle. There is no way to notify
     * master of this condition.
     */
    if (InstancePtr->SendByteCount == 0) {
        XIic_WriteReg(InstancePtr->BaseAddress,
                      XIIC_DTR_REG_OFFSET, 0xFF);
        return;
    }

    /*
     * Send the data by filling the transmit FIFO.
     */
    XIic_TransmitFifoFill(InstancePtr, XIIC_SLAVE_ROLE);
    /*
     * When the amount of data remaining to send is less than the half mark
     * of the FIFO making the use of ½ empty interrupt unnecessary,
     * disable it. Is this a problem that it's checking against 1 rather
     * than half?
     */
    if (InstancePtr->SendByteCount < 1) {
        XIic_DisableIntr(InstancePtr->BaseAddress,
                         XIIC_INTR_TX_HALF_MASK);
    }
    return;
}
コード例 #5
0
ファイル: xiic_master.c プロジェクト: aalonso/xilinx-ml405
/******************************************************************************
*
* This function sends the proper byte of the address as well as generate the
* proper address bit fields depending on the address byte required and the
* direction of the data (write or read).
*
* A master receiving has the restriction that the direction must be switched
* from write to read when the third address byte is transmitted.
* For the last byte of the 10 bit address, repeated start must be set prior
* to writing the address. If repeated start options is enabled, the
* control register is written before the address is written to the Tx reg.
*
* @param	InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return	None.
*
* @note
*
* This function does read/modify/write to the device control register. Calling
* functions must ensure critical sections are used.
*
******************************************************************************/
static void SendSlaveAddr(XIic *InstancePtr)
{
	u32 CRreg;

	/*
	 * Set the control register for Master Receive, repeated start must be
	 * set before writing the address, MSMS should be already set, don't
	 * set here so if arbitration is lost or some other reason we don't
	 * want MSMS set incase of error.
	 */
	CRreg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);

	CRreg |= XIIC_CR_REPEATED_START_MASK;
	CRreg &= ~XIIC_CR_DIR_IS_TX_MASK;

	XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CRreg);

	/*
	 * Send the 1st byte of the 10 bit address as a read operation, enable
	 * the receive interrupt to know when data is received, assuming that
	 * the receive FIFO threshold has been previously set.
	 */
	XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave, XIIC_READ_OPERATION);

	XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK);
}
コード例 #6
0
ファイル: xiic.c プロジェクト: Genihoust/academic_project_3
/**
*
* Resets the IIC device.
*
* @param    InstancePtr is a pointer to the XIic instance to be worked on.
*
* @return	None.
*
* @note     The complete IIC core is Reset on giving a software reset to
*           the IIC core. Some previous versions of the core only reset
*           the Interrupt Logic/Registers, please refer to the HW specification
*           for futher details about this.
*
****************************************************************************/
void XIic_Reset(XIic *InstancePtr)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RESETR_OFFSET,
			XIIC_RESET_MASK);
}
コード例 #7
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);
}
コード例 #8
0
ファイル: xiic.c プロジェクト: Genihoust/academic_project_3
/**
*
* 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;
}
コード例 #9
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/******************************************************************************
*
* Initialize the IIC core for Dynamic Functionality.
*
* @param	BaseAddress contains the base address of the IIC Device.
*
* @return	XST_SUCCESS if Successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int XIic_DynInit(u32 BaseAddress)
{
	u32 Status;

	/*
	 * Reset IIC Core.
	 */
	XIic_WriteReg(BaseAddress, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);

	/*
	 * Set receive Fifo depth to maximum (zero based).
	 */
	XIic_WriteReg(BaseAddress,  XIIC_RFD_REG_OFFSET,
			IIC_RX_FIFO_DEPTH - 1);

	/*
	 * Reset Tx Fifo.
	 */
	XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
			XIIC_CR_TX_FIFO_RESET_MASK);

	/*
	 * Enable IIC Device, remove Tx Fifo reset & disable general call.
	 */
	XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET,
			XIIC_CR_ENABLE_DEVICE_MASK);

	/*
	 * Read status register and verify IIC Device is in initial state. Only
	 * the Tx Fifo and Rx Fifo empty bits should be set.
	 */
	Status = XIic_ReadReg(BaseAddress,  XIIC_SR_REG_OFFSET);
	if(Status == (XIIC_SR_RX_FIFO_EMPTY_MASK |
		XIIC_SR_TX_FIFO_EMPTY_MASK)) {
		return XST_SUCCESS;
	}

	return XST_FAILURE;
}
コード例 #10
0
ファイル: xiic_master.c プロジェクト: aalonso/xilinx-ml405
/**
* This function sends data as a 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 which has
* been set with the XIic_SetAddress() function is the address to which the
* specific data is sent.  Sending data on the bus performs a write operation.
*
* @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 indicates the message transmission 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.
*
* @note		None.
*
******************************************************************************/
int XIic_MasterSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount)
{
	u32 CntlReg;

	XIic_IntrGlobalDisable(InstancePtr->BaseAddress);

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

	/*
	 * 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;
	}

	/*
	 * 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_CR_REPEATED_START_MASK);

		XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET,
				CntlReg);
		InstancePtr->Stats.RepeatedStarts++;
	}

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

	/*
	 * Put the address into the FIFO to be sent and indicate that the
	 * operation to be performed on the bus is a write operation,
	 * a general call address is handled the same as a 7 bit address even
	 * if 10 bit address is selected.
	 * Set the transmit address state to indicate the address has been sent.
	 */
	if ((InstancePtr->Options & XII_SEND_10_BIT_OPTION) &&
		(InstancePtr->AddrOfSlave != 0)) {
		XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave,
					 XIIC_WRITE_OPERATION);
		XIic_Send10BitAddrByte2(InstancePtr->AddrOfSlave);
	} else {
		XIic_Send7BitAddr(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 remaining available FIFO with message data.
	 */
	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);

	/*
	 * When repeated start not used, MSMS must be set after putting data
	 * into transmit FIFO, start the transmitter.
	 */
	CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET);
	if ((CntlReg & XIIC_CR_MSMS_MASK) == 0) {
		CntlReg &= ~XIIC_CR_NO_ACK_MASK;
		CntlReg |= XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK;
		XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET,
			 CntlReg);
	}

	XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

	return XST_SUCCESS;
}
コード例 #11
0
/**
*
* 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);
}
コード例 #12
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/******************************************************************************
*
* Send the specified buffer to the device that has been previously addressed
* on the IIC bus. This function assumes that the 7 bit address has been sent.
*
* @param	BaseAddress contains the base address of the IIC Device.
* @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 remaining to be sent.
*
* @note		This function does not take advantage of the transmit Fifo
*		because it is designed for minimal code space and complexity.
*
******************************************************************************/
static unsigned DynSendData(u32 BaseAddress, u8 *BufferPtr,
			    u8 ByteCount, u8 Option)
{
	u32 IntrStatus;

	while (ByteCount > 0) {
		/*
		 * Wait for the transmit to be empty before sending any more
		 * data by polling the interrupt status register.
		 */
		while (1) {
			IntrStatus = XIic_ReadIisr(BaseAddress);
			if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK |
					  XIIC_INTR_ARB_LOST_MASK |
					  XIIC_INTR_BNB_MASK)) {
				/*
				 * Error condition (NACK or ARB Lost or BNB
				 * Error Has occurred. Clear the Control
				 * register to send a STOP condition on the Bus
				 * and return the number of bytes still to
				 * transmit.
				 */
				XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
						0x03);
				XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
						0x01);

				return ByteCount;
			}

			/*
			 * Check for the transmit Fifo to become Empty.
			 */
			if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) {
				break;
			}
		}

		/*
		 * Send data to Tx Fifo. If a stop condition is specified and
		 * the last byte is being sent, then set the dynamic stop bit.
		 */
		if ((ByteCount == 1) && (Option == XIIC_STOP)) {
			/*
			 * The MSMS will be cleared automatically upon setting
			 *  dynamic stop.
			 */
			XIic_WriteReg(BaseAddress,  XIIC_DTR_REG_OFFSET,
					XIIC_TX_DYN_STOP_MASK | *BufferPtr++);
		} else {
			XIic_WriteReg(BaseAddress,  XIIC_DTR_REG_OFFSET,
					*BufferPtr++);
		}

		/*
		 * Update the byte count to reflect the byte sent.
		 */
		ByteCount--;
	}

	if (Option == XIIC_STOP) {
		/*
		 * If the Option is to release the bus after transmission of
		 * data, Wait for the bus to transition to not busy before
		 * returning, the IIC device cannot be disabled until this
		 * occurs.
		 */
		while (1) {
			if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) {
				break;
			}
		}
	}

	return ByteCount;
}
コード例 #13
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/******************************************************************************
*
* Send the specified buffer to the device that has been previously addressed
* on the IIC bus.  This function assumes that the 7 bit address has been sent
* and it should wait for the transmit of the address to complete.
*
* @param	BaseAddress contains the base address of the IIC device.
* @param	BufferPtr points to the data to be sent.
* @param	ByteCount is the number of bytes to be sent.
* @param	Option indicates whether to hold or free the bus after
*		transmitting the data.
*
* @return	The number of bytes remaining to be sent.
*
* @note
*
* This function does not take advantage of the transmit FIFO because it is
* designed for minimal code space and complexity.  It contains loops that
* that could cause the function not to return if the hardware is not working.
*
******************************************************************************/
static unsigned SendData(u32 BaseAddress, u8 *BufferPtr,
			 unsigned ByteCount, u8 Option)
{
	u32 IntrStatus;

	/*
	 * Send the specified number of bytes in the specified buffer by polling
	 * the device registers and blocking until complete
	 */
	while (ByteCount > 0) {
		/*
		 * Wait for the transmit to be empty before sending any more
		 * data by polling the interrupt status register
		 */
		while (1) {
			IntrStatus = XIic_ReadIisr(BaseAddress);

			if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK |
					  XIIC_INTR_ARB_LOST_MASK |
					  XIIC_INTR_BNB_MASK)) {
				return ByteCount;
			}

			if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) {
				break;
			}
		}
		/* If there is more than one byte to send then put the
		 * next byte to send into the transmit FIFO
		 */
		if (ByteCount > 1) {
			XIic_WriteReg(BaseAddress,  XIIC_DTR_REG_OFFSET,
				 *BufferPtr++);
		}
		else {
			if (Option == XIIC_STOP) {
				/*
				 * If the Option is to release the bus after
				 * the last data byte, Set the stop Option
				 * before sending the last byte of data so
				 * that the stop Option will be generated
				 * immediately following the data. This is
				 * done by clearing the MSMS bit in the
				 * control register.
				 */
				XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
					 XIIC_CR_ENABLE_DEVICE_MASK |
					 XIIC_CR_DIR_IS_TX_MASK);
			}

			/*
			 * Put the last byte to send in the transmit FIFO
			 */
			XIic_WriteReg(BaseAddress,  XIIC_DTR_REG_OFFSET,
				 *BufferPtr++);

			if (Option == XIIC_REPEATED_START) {
				XIic_ClearIisr(BaseAddress,
						XIIC_INTR_TX_EMPTY_MASK);
				/*
				 * Wait for the transmit to be empty before
				 * setting RSTA bit.
				 */
				while (1) {
					IntrStatus =
						XIic_ReadIisr(BaseAddress);
					if (IntrStatus &
						XIIC_INTR_TX_EMPTY_MASK) {
						/*
						 * RSTA bit should be set only
						 * when the FIFO is completely
						 * Empty.
						 */
						XIic_WriteReg(BaseAddress,
							 XIIC_CR_REG_OFFSET,
						   XIIC_CR_REPEATED_START_MASK |
						   XIIC_CR_ENABLE_DEVICE_MASK |
						   XIIC_CR_DIR_IS_TX_MASK |
						   XIIC_CR_MSMS_MASK);
						break;
					}
				}
			}
		}

		/*
		 * Clear the latched interrupt status register and this must be
		 * done after the transmit FIFO has been written to or it won't
		 * clear
		 */
		XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK);

		/*
		 * Update the byte count to reflect the byte sent and clear
		 * the latched interrupt status so it will be updated for the
		 * new state
		 */
		ByteCount--;
	}

	if (Option == XIIC_STOP) {
		/*
		 * If the Option is to release the bus after transmission of
		 * data, Wait for the bus to transition to not busy before
		 * returning, the IIC device cannot be disabled until this
		 * occurs. Note that this is different from a receive operation
		 * because the stop Option causes the bus to go not busy.
		 */
		while (1) {
			if (XIic_ReadIisr(BaseAddress) &
				XIIC_INTR_BNB_MASK) {
				break;
			}
		}
	}

	return ByteCount;
}
コード例 #14
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/**
* 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 mode of operation.  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 indicates whether to hold or free the bus after
* 		transmitting the data.
*
* @return	The number of bytes sent.
*
* @note		None.
*
******************************************************************************/
unsigned XIic_Send(u32 BaseAddress, u8 Address,
		   u8 *BufferPtr, unsigned ByteCount, u8 Option)
{
	unsigned RemainingByteCount;
	u32 ControlReg;
	volatile u32 StatusReg;

	/* Check to see if already Master on the Bus.
	 * If Repeated Start bit is not set send Start bit by setting
	 * MSMS bit else Send the address.
	 */
	ControlReg = XIic_ReadReg(BaseAddress,  XIIC_CR_REG_OFFSET);
	if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) {
		/*
		 * Put the address into the FIFO to be sent and indicate
		 * that the operation to be performed on the bus is a
		 * write operation
		 */
		XIic_Send7BitAddress(BaseAddress, Address,
					XIIC_WRITE_OPERATION);
		/* 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);

		/*
		 * MSMS must be set after putting data into transmit FIFO,
		 * indicate the direction is transmit, this device is master
		 * and enable the IIC device
		 */
		XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
			 XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK |
			 XIIC_CR_ENABLE_DEVICE_MASK);

		/*
		 * Clear the latched interrupt
		 * status for the bus not busy bit which must be done while
		 * the bus is busy
		 */
		StatusReg = XIic_ReadReg(BaseAddress,  XIIC_SR_REG_OFFSET);
		while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) {
			StatusReg = XIic_ReadReg(BaseAddress,
						  XIIC_SR_REG_OFFSET);
		}

		XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK);
	}
	else {
		/*
		 * Already owns the Bus indicating that its a Repeated Start
		 * call. 7 bit slave address, send the address for a write
		 * operation and set the state to indicate the address has
		 * been sent.
		 */
		XIic_Send7BitAddress(BaseAddress, Address,
					XIIC_WRITE_OPERATION);
	}

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

	ControlReg = XIic_ReadReg(BaseAddress,  XIIC_CR_REG_OFFSET);
	if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) {
		/*
		 * The Transmission is completed, disable the IIC device if
		 * the Option is to release the Bus after transmission of data
		 * and return the number of bytes that was received. Only wait
		 * if master, if addressed as slave just reset to release
		 * the bus.
		 */
		if ((ControlReg & XIIC_CR_MSMS_MASK) != 0) {
			XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
				 (ControlReg & ~XIIC_CR_MSMS_MASK));
			StatusReg = XIic_ReadReg(BaseAddress,
					XIIC_SR_REG_OFFSET);
			while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) != 0) {
				StatusReg = XIic_ReadReg(BaseAddress,
						XIIC_SR_REG_OFFSET);
			}
		}

		if ((XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET) &
		    XIIC_SR_ADDR_AS_SLAVE_MASK) != 0) {
			XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET, 0);
		}
	}

	return ByteCount - RemainingByteCount;
}
コード例 #15
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 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;
}
コード例 #16
0
ファイル: xiic_master.c プロジェクト: aalonso/xilinx-ml405
/******************************************************************************
*
* 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;
}
コード例 #17
0
/**
*
* 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;
}
コード例 #18
0
/**
*
* 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;
}
コード例 #19
0
/**
* 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;
}
コード例 #20
0
ファイル: xiic_master.c プロジェクト: aalonso/xilinx-ml405
/**
* 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 the general call address. This is not allowed
*		for Master receive mode.
*
* @internal
*
* 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_MasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount)
{
	u32 CntlReg;
	u8 Temp;

	/*
	 * 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;
	}

	XIic_IntrGlobalDisable(InstancePtr->BaseAddress);

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

	/*
	 * 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 if using 7 bit, If 10 bit, wait
	 * until last address byte sent incase arbitration gets lost while
	 * sending out address.
	 */
	if ((InstancePtr->Options & XII_SEND_10_BIT_OPTION) == 0) {
		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) {
		CntlReg |= XIIC_CR_REPEATED_START_MASK;
		XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount);

		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 immediatedly
	 * 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) {
		Temp = 0;
	} else {
		if (ByteCount <= IIC_RX_FIFO_DEPTH) {
			Temp = ByteCount - 2;
		} else {
			Temp = IIC_RX_FIFO_DEPTH - 1;
		}
	}
	XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET,
			(u32) Temp);

	if (InstancePtr->Options & XII_SEND_10_BIT_OPTION) {
		/*
		 * Send the 1st and 2nd byte of the 10 bit address of a write
		 * operation, write because it's a 10 bit address.
		 */
		XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave,
					 XIIC_WRITE_OPERATION);
		XIic_Send10BitAddrByte2(InstancePtr->AddrOfSlave);

		/*
		 * Set flag to indicate the next byte of the address needs to be
		 * send, clear and enable Tx empty interrupt.
		 */
		InstancePtr->TxAddrMode = XIIC_TX_ADDR_MSTR_RECV_MASK;
		XIic_ClearEnableIntr(InstancePtr->BaseAddress,
					XIIC_INTR_TX_EMPTY_MASK);
	} else {
		/*
		 * 7 bit slave address, send the address for a read operation
		 * and set the state to indicate the address has been sent.
		 */
		XIic_Send7BitAddr(InstancePtr->AddrOfSlave,
				   XIIC_READ_OPERATION);
		InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT;
	}

	/*
	 * Tx error is enabled incase the address (7 or 10) 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);

	/*
	 * When repeated start not used, MSMS gets set after putting data
	 * in Tx reg. 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) == 0) {
		CntlReg |= XIIC_CR_MSMS_MASK;
		XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount);
		XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET,
				CntlReg);
	}

	XIic_IntrGlobalEnable(InstancePtr->BaseAddress);

	return XST_SUCCESS;
}
コード例 #21
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/**
* 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 mode of operation. 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 indicates whether to hold or free the bus after reception
*		of data, XIIC_STOP = end with STOP condition,
*		XIIC_REPEATED_START = don't end with STOP condition.
*
* @return	The number of bytes received.
*
* @note		None.
*
******************************************************************************/
unsigned XIic_Recv(u32 BaseAddress, u8 Address,
			u8 *BufferPtr, unsigned ByteCount, u8 Option)
{
	u32 CntlReg;
	unsigned RemainingByteCount;
	volatile u32 StatusReg;

	/* Tx error is enabled incase the address (7 or 10) 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_ClearIisr(BaseAddress,
			XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK |
			XIIC_INTR_ARB_LOST_MASK);

	/* Set receive FIFO occupancy depth for 1 byte (zero based) */
	XIic_WriteReg(BaseAddress,  XIIC_RFD_REG_OFFSET, 0);


	/* Check to see if already Master on the Bus.
	 * If Repeated Start bit is not set send Start bit by setting MSMS bit
	 * else Send the address
	 */
	CntlReg = XIic_ReadReg(BaseAddress,  XIIC_CR_REG_OFFSET);
	if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) {
		/* 7 bit slave address, send the address for a read operation
		 * and set the state to indicate the address has been sent
		 */
		XIic_Send7BitAddress(BaseAddress, Address,
					XIIC_READ_OPERATION);


		/* MSMS gets set after putting data in FIFO. Start the master
		 * receive operation by setting CR Bits MSMS to Master, if the
		 * buffer is only one byte, then it should not be acknowledged
		 * to indicate the end of data
		 */
		CntlReg = XIIC_CR_MSMS_MASK | XIIC_CR_ENABLE_DEVICE_MASK;
		if (ByteCount == 1) {
			CntlReg |= XIIC_CR_NO_ACK_MASK;
		}

		/* Write out the control register to start receiving data and
		 * call the function to receive each byte into the buffer
		 */
		XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET, CntlReg);

		/* Clear the latched interrupt status for the bus not busy bit
		 * which must be done while the bus is busy
		 */
		StatusReg = XIic_ReadReg(BaseAddress,  XIIC_SR_REG_OFFSET);

		while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) {
			StatusReg = XIic_ReadReg(BaseAddress,
						  XIIC_SR_REG_OFFSET);
		}

		XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK);
	} else {
	        /* Before writing 7bit slave address the Direction of Tx bit
		 * must be disabled
		 */
		CntlReg &= ~XIIC_CR_DIR_IS_TX_MASK;
		XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET, CntlReg);
		/* Already owns the Bus indicating that its a Repeated Start
		 * call. 7 bit slave address, send the address for a read
		 * operation and set the state to indicate the address has been
		 * sent
		 */
		XIic_Send7BitAddress(BaseAddress, Address,
					XIIC_READ_OPERATION);
	}
	/* Try to receive the data from the IIC bus */

	RemainingByteCount = RecvData(BaseAddress, BufferPtr,
				      ByteCount, Option);

	CntlReg = XIic_ReadReg(BaseAddress,  XIIC_CR_REG_OFFSET);
	if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) {
		/* The receive is complete, disable the IIC device if the Option
		 * is to release the Bus after Reception of data and return the
		 * number of bytes that was received
		 */
		XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET, 0);
	}

	/* Return the number of bytes that was received */
	return ByteCount - RemainingByteCount;
}
コード例 #22
0
ファイル: xiic_l.c プロジェクト: Akaname/Arty
/******************************************************************************
*
* Receive the specified data from the device that has been previously addressed
* on the IIC bus.  This function assumes that the 7 bit address has been sent
* and it should wait for the transmit of the address to complete.
*
* @param	BaseAddress contains the base address of the IIC device.
* @param	BufferPtr points to the buffer to hold the data that is
*		received.
* @param	ByteCount is the number of bytes to be received.
* @param	Option indicates whether to hold or free the bus after reception
*		of data, XIIC_STOP = end with STOP condition,
*		XIIC_REPEATED_START = don't end with STOP condition.
*
* @return	The number of bytes remaining to be received.
*
* @note
*
* This function does not take advantage of the receive FIFO because it is
* designed for minimal code space and complexity.  It contains loops that
* that could cause the function not to return if the hardware is not working.
*
* This function assumes that the calling function will disable the IIC device
* after this function returns.
*
******************************************************************************/
static unsigned RecvData(u32 BaseAddress, u8 *BufferPtr,
			 unsigned ByteCount, u8 Option)
{
	u32 CntlReg;
	u32 IntrStatusMask;
	u32 IntrStatus;

	/* Attempt to receive the specified number of bytes on the IIC bus */

	while (ByteCount > 0) {
		/* Setup the mask to use for checking errors because when
		 * receiving one byte OR the last byte of a multibyte message an
		 * error naturally occurs when the no ack is done to tell the
		 * slave the last byte
		 */
		if (ByteCount == 1) {
			IntrStatusMask =
				XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK;
		} else {
			IntrStatusMask =
				XIIC_INTR_ARB_LOST_MASK |
				XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK;
		}

		/* Wait for the previous transmit and the 1st receive to
		 * complete by checking the interrupt status register of the
		 * IPIF
		 */
		while (1) {
			IntrStatus = XIic_ReadIisr(BaseAddress);
			if (IntrStatus & XIIC_INTR_RX_FULL_MASK) {
				break;
			}
			/* Check the transmit error after the receive full
			 * because when sending only one byte transmit error
			 * will occur because of the no ack to indicate the end
			 * of the data
			 */
			if (IntrStatus & IntrStatusMask) {
				return ByteCount;
			}
		}

		CntlReg = XIic_ReadReg(BaseAddress,  XIIC_CR_REG_OFFSET);

		/* Special conditions exist for the last two bytes so check for
		 * them. Note that the control register must be setup for these
		 * conditions before the data byte which was already received is
		 * read from the receive FIFO (while the bus is throttled
		 */
		if (ByteCount == 1) {
			if (Option == XIIC_STOP) {

				/* If the Option is to release the bus after the
				 * last data byte, it has already been read and
				 * no ack has been done, so clear MSMS while
				 * leaving the device enabled so it can get off
				 * the IIC bus appropriately with a stop
				 */
				XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
					 XIIC_CR_ENABLE_DEVICE_MASK);
			}
		}

		/* Before the last byte is received, set NOACK to tell the slave
		 * IIC device that it is the end, this must be done before
		 * reading the byte from the FIFO
		 */
		if (ByteCount == 2) {
			/* Write control reg with NO ACK allowing last byte to
			 * have the No ack set to indicate to slave last byte
			 * read
			 */
			XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
				 CntlReg | XIIC_CR_NO_ACK_MASK);
		}

		/* Read in data from the FIFO and unthrottle the bus such that
		 * the next byte is read from the IIC bus
		 */
		*BufferPtr++ = (u8) XIic_ReadReg(BaseAddress,
						  XIIC_DRR_REG_OFFSET);

		if ((ByteCount == 1) && (Option == XIIC_REPEATED_START)) {

			/* RSTA bit should be set only when the FIFO is
			 * completely Empty.
			 */
			XIic_WriteReg(BaseAddress,  XIIC_CR_REG_OFFSET,
				 XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_MSMS_MASK
				 | XIIC_CR_REPEATED_START_MASK);

		}

		/* Clear the latched interrupt status so that it will be updated
		 * with the new state when it changes, this must be done after
		 * the receive register is read
		 */
		XIic_ClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK |
				XIIC_INTR_TX_ERROR_MASK |
				XIIC_INTR_ARB_LOST_MASK);
		ByteCount--;
	}

	if (Option == XIIC_STOP) {

		/* If the Option is to release the bus after Reception of data,
		 * wait for the bus to transition to not busy before returning,
		 * the IIC device cannot be disabled until this occurs. It
		 * should transition as the MSMS bit of the control register was
		 * cleared before the last byte was read from the FIFO
		 */
		while (1) {
			if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) {
				break;
			}
		}
	}

	return ByteCount;
}
コード例 #23
0
ファイル: xiic_master.c プロジェクト: aalonso/xilinx-ml405
/**
*
* 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);
		}
	}
}
コード例 #24
0
/**
* 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;
}