/** * Send data as a master on the IIC bus. This function sends the data using * polled I/O and blocks until the data has been sent. It only supports 7 bit * addressing. The user is responsible for ensuring the bus is not busy if * multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC Device. * @param Address contains the 7 bit IIC address of the device to send the * specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. * @param Option: XIIC_STOP = end with STOP condition, * XIIC_REPEATED_START = don't end with STOP condition. * * @return The number of bytes sent. * * @note None. * ******************************************************************************/ unsigned XIic_DynSend(u32 BaseAddress, u16 Address, u8 *BufferPtr, u8 ByteCount, u8 Option) { unsigned RemainingByteCount; u32 StatusRegister; /* * Clear the latched interrupt status so that it will be updated with * the new state when it changes, this must be done after the address * is put in the FIFO */ XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* * Put the address into the Fifo to be sent and indicate that the * operation to be performed on the bus is a write operation. Upon * writing the address, a start condition is initiated. MSMS is * automatically set to master when the address is written to the Fifo. * If MSMS was already set, then a re-start is sent prior to the * address. */ if(!(Address & XIIC_TX_DYN_STOP_MASK)) { XIic_DynSend7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } else { XIic_DynSendStartStopAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } /* * Wait for the bus to go busy. */ StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) != XIIC_SR_BUS_BUSY_MASK) { StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); } /* * Clear the latched interrupt status for the bus not busy bit which * must be done while the bus is busy. */ XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); /* * Send the specified data to the device on the IIC bus specified by the * the address. */ RemainingByteCount = DynSendData(BaseAddress, BufferPtr, ByteCount, Option); /* * The send is complete return the number of bytes that was sent. */ return ByteCount - RemainingByteCount; }
/** * Receive data as a master on the IIC bus. This function receives the data * using polled I/O and blocks until the data has been received. It only * supports 7 bit addressing. The user is responsible for ensuring the bus is * not busy if multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC Device. * @param Address contains the 7 bit IIC Device address of the device to * send the specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. This value can't be * greater than 255 and needs to be greater than 0. * * @return The number of bytes received. * * @note Upon entry to this function, the IIC interface needs to be * already enabled in the CR register. * ******************************************************************************/ unsigned XIic_DynRecv(u32 BaseAddress, u8 Address, u8 *BufferPtr, u8 ByteCount) { unsigned RemainingByteCount; u32 StatusRegister; /* * Clear the latched interrupt status so that it will be updated with * the new state when it changes. */ XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* * Send the 7 bit slave address for a read operation and set the state * to indicate the address has been sent. Upon writing the address, a * start condition is initiated. MSMS is automatically set to master * when the address is written to the Fifo. If MSMS was already set, * then a re-start is sent prior to the address. */ XIic_DynSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); /* * Wait for the bus to go busy. */ StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) != XIIC_SR_BUS_BUSY_MASK) { StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); } /* * Clear the latched interrupt status for the bus not busy bit which * must be done while the bus is busy. */ XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); /* * Write to the Tx Fifo the dynamic stop control bit with the number of * bytes that are to be read over the IIC interface from the presently * addressed device. */ XIic_DynSendStop(BaseAddress, ByteCount); /* * Receive the data from the IIC bus. */ RemainingByteCount = DynRecvData(BaseAddress, BufferPtr, ByteCount); /* * The receive is complete. Return the number of bytes that were * received. */ return ByteCount - RemainingByteCount; }
/** * This function receives data as a master from a slave device on the IIC bus. * If the bus is busy, it will indicate so and then enable an interrupt such * that the status handler will be called when the bus is no longer busy. The * slave address which has been set with the XIic_SetAddress() function is the * address from which data is received. Receiving data on the bus performs a * read operation. * * @param InstancePtr is a pointer to the Iic instance to be worked on. * @param RxMsgPtr is a pointer to the data to be transmitted. * @param ByteCount is the number of message bytes to be sent. * * @return - XST_SUCCESS indicates the message reception processes has been * initiated. * - XST_IIC_BUS_BUSY indicates the bus was in use and that the * BusNotBusy interrupt is enabled which will update the * EventStatus when the bus is no longer busy. * - XST_IIC_GENERAL_CALL_ADDRESS indicates the slave address is * set to the general call address. This is not allowed for Master * receive mode. * * @note The receive FIFO threshold is a zero based count such that 1 * must be subtracted from the desired count to get the correct * value. When receiving data it is also necessary to not receive * the last byte with the prior bytes because the acknowledge must * be setup before the last byte is received. * ******************************************************************************/ int XIic_DynMasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, u8 ByteCount) { u32 CntlReg; u32 RxFifoOccy; /* * If the slave address is zero (general call) the master can't perform * receive operations, indicate an error. */ if (InstancePtr->AddrOfSlave == 0) { return XST_IIC_GENERAL_CALL_ADDRESS; } /* * Disable the Interrupts. */ XIic_IntrGlobalDisable(InstancePtr->BaseAddress); /* * Ensure that the master processing has been included such that events * will be properly handled. */ XIIC_DYN_MASTER_INCLUDE; InstancePtr->IsDynamic = TRUE; /* * If the busy is busy, then exit the critical region and wait for the * bus to not be busy, the function enables the bus not busy interrupt. */ if (IsBusBusy(InstancePtr)) { XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_IIC_BUS_BUSY; } /* * Save message state for event driven processing. */ InstancePtr->RecvByteCount = ByteCount; InstancePtr->RecvBufferPtr = RxMsgPtr; /* * Clear and enable Rx full interrupt. */ XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); /* * If already a master on the bus, the direction was set by Rx Interrupt * routine to Tx which is throttling bus because during Rxing, Tx reg is * empty = throttle. CR needs setting before putting data or the address * written will go out as Tx instead of receive. Start Master Rx by * setting CR Bits MSMS to Master and msg direction. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); if (CntlReg & XIIC_CR_MSMS_MASK) { /* * Set the Repeated Start bit in CR. */ CntlReg |= XIIC_CR_REPEATED_START_MASK; XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount); /* * Increment stats counts. */ InstancePtr->Stats.RepeatedStarts++; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); } /* * Set receive FIFO occupancy depth which must be done prior to writing * the address in the FIFO because the transmitter will immediately * start when in repeated start mode followed by the receiver such * that the number of bytes to receive should be set 1st. */ if (ByteCount == 1) { RxFifoOccy = 0; } else { if (ByteCount <= IIC_RX_FIFO_DEPTH) { RxFifoOccy = ByteCount - 2; } else { RxFifoOccy = IIC_RX_FIFO_DEPTH - 1; } } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, RxFifoOccy); /* * Send the Seven Bit address. Only 7 bit addressing is supported in * Dynamic mode and mark that the address has been sent. */ XIic_DynSend7BitAddress(InstancePtr->BaseAddress, InstancePtr->AddrOfSlave, XIIC_READ_OPERATION); InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; /* * Send the bytecount to be received and set the stop bit. */ XIic_DynSendStop(InstancePtr->BaseAddress, ByteCount); /* * Tx error is enabled incase the address has no device to answer * with Ack. When only one byte of data, must set NO ACK before address * goes out therefore Tx error must not be enabled as it will go off * immediately and the Rx full interrupt will be checked. If full, then * the one byte was received and the Tx error will be disabled without * sending an error callback msg. */ XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); /* * Enable the Interrupts. */ XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_SUCCESS; }
/** * This function sends data as a Dynamic master on the IIC bus. If the bus is * busy, it will indicate so and then enable an interrupt such that the status * handler will be called when the bus is no longer busy. The slave address is * sent by using XIic_DynSend7BitAddress(). * * @param InstancePtr points to the Iic instance to be worked on. * @param TxMsgPtr points to the data to be transmitted. * @param ByteCount is the number of message bytes to be sent. * * @return XST_SUCCESS if successful else XST_FAILURE. * * @note None. * ******************************************************************************/ int XIic_DynMasterSend(XIic *InstancePtr, u8 *TxMsgPtr, u8 ByteCount) { u32 CntlReg; XIic_IntrGlobalDisable(InstancePtr->BaseAddress); /* * Ensure that the Dynamic master processing has been included such that * events will be properly handled. */ XIIC_DYN_MASTER_INCLUDE; InstancePtr->IsDynamic = TRUE; /* * If the busy is busy, then exit the critical region and wait for the * bus not to be busy. The function enables the BusNotBusy interrupt. */ if (IsBusBusy(InstancePtr)) { XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_FAILURE; } /* * If it is already a master on the bus (repeated start), the direction * was set to Tx which is throttling bus. The control register needs to * be set before putting data into the FIFO. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); if (CntlReg & XIIC_CR_MSMS_MASK) { CntlReg &= ~XIIC_CR_NO_ACK_MASK; CntlReg |= XIIC_CR_DIR_IS_TX_MASK; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); InstancePtr->Stats.RepeatedStarts++; } /* * Save message state. */ InstancePtr->SendByteCount = ByteCount; InstancePtr->SendBufferPtr = TxMsgPtr; /* * Send the Seven Bit address. Only 7 bit addressing is supported in * Dynamic mode. */ XIic_DynSend7BitAddress(InstancePtr->BaseAddress, InstancePtr->AddrOfSlave, XIIC_WRITE_OPERATION); /* * Set the transmit address state to indicate the address has been sent * for communication with event driven processing. */ InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; /* * Fill the Tx FIFO. */ if (InstancePtr->SendByteCount > 1) { XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE); } /* * After filling fifo, if data yet to send > 1, enable Tx ½ empty * interrupt. */ if (InstancePtr->SendByteCount > 1) { XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_HALF_MASK); } /* * Clear any pending Tx empty, Tx Error and then enable them. */ XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK); /* * Enable the Interrupts. */ XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_SUCCESS; }