/** * * 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) { u8 CntlReg; XASSERT_VOID(InstancePtr != NULL); XIic_mEnterCriticalRegion(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 = XIo_In8(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 */ XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); XIic_mExitCriticalRegion(InstancePtr->BaseAddress); }
/** * 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. * ******************************************************************************/ XStatus XIic_MasterRecv(XIic * InstancePtr, u8 * RxMsgPtr, int ByteCount) { u8 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_mEnterCriticalRegion(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_mExitCriticalRegion(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_mClearEnableIntr(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 = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); if (CntlReg & XIIC_CR_MSMS_MASK) { CntlReg |= XIIC_CR_REPEATED_START_MASK; XIic_mSetControlRegister(InstancePtr, CntlReg, ByteCount); InstancePtr->Stats.RepeatedStarts++; /* increment stats counts */ XIo_Out8(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; } } XIo_Out8(InstancePtr->BaseAddress + XIIC_RFD_REG_OFFSET, 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_mSend10BitAddrByte1(InstancePtr->AddrOfSlave, XIIC_WRITE_OPERATION); XIic_mSend10BitAddrByte2(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_mClearEnableIntr(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_mSend7BitAddr(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_mClearEnableIntr(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 = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_MSMS_MASK) == 0) { CntlReg |= XIIC_CR_MSMS_MASK; XIic_mSetControlRegister(InstancePtr, CntlReg, ByteCount); XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); } XIic_mExitCriticalRegion(InstancePtr->BaseAddress); return XST_SUCCESS; }
/** * 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 * ******************************************************************************/ XStatus XIic_MasterSend(XIic * InstancePtr, u8 * TxMsgPtr, int ByteCount) { u8 CntlReg; XIic_mEnterCriticalRegion(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_mExitCriticalRegion(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 = XIo_In8(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); XIo_Out8(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 * 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_mSend10BitAddrByte1(InstancePtr->AddrOfSlave, XIIC_WRITE_OPERATION); XIic_mSend10BitAddrByte2(InstancePtr->AddrOfSlave); } else { XIic_mSend7BitAddr(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_mClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_HALF_MASK); } /* Clear any pending Tx empty, Tx Error and then enable them. */ XIic_mClearEnableIntr(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 = XIo_In8(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; XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); } XIic_mExitCriticalRegion(InstancePtr->BaseAddress); return XST_SUCCESS; }