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