/****************************************************************************** * * 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); }
/***************************************************************************** * * This function checks to see if the IIC bus is busy. If so, it will enable * the bus not busy interrupt such that the driver is notified when the bus * is no longer busy. * * @param InstancePtr points to the Iic instance to be worked on. * * @return * - FALSE indicates the IIC bus is not busy. * - TRUE 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. * ******************************************************************************/ static int IsBusBusy(XIic *InstancePtr) { u32 CntlReg; u32 StatusReg; CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); StatusReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); /* * If this device is already master of the bus as when using the * repeated start and the bus is busy setup to wait for it to not be * busy. */ if (((CntlReg & XIIC_CR_MSMS_MASK) == 0) && /* Not master */ (StatusReg & XIIC_SR_BUS_BUSY_MASK)) { /* Is busy */ /* * The bus is busy, clear pending BNB interrupt incase * previously set and then enable BusNotBusy interrupt. */ InstancePtr->BNBOnly = TRUE; XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_BNB_MASK); InstancePtr->Stats.BusBusy++; return TRUE; } return FALSE; }
/** * * 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). * * @param InstancePtr is a pointer to the XIic instance to be worked on. * @param TxMsgPtr 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 sent. * * @note None. * ******************************************************************************/ int XIic_SlaveSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount) { u32 IntrStatus; u32 Status; /* * If the device is not a slave on the IIC bus then indicate an error * because data cannot be sent 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 receive buffer pointer to * indicate the direction of transfer is sending. */ InstancePtr->SendByteCount = ByteCount; InstancePtr->SendBufferPtr = TxMsgPtr; InstancePtr->RecvBufferPtr = NULL; /* * Start sending the specified data and then interrupt processing will * complete it. */ XIic_TransmitFifoFill(InstancePtr, XIIC_SLAVE_ROLE); /* Clear any pending Tx empty, Tx Error and interrupt then enable them. * The Tx error interrupt indicates when the message is complete. * If data remaining to be sent, clear and enable Tx ½ empty interrupt. */ IntrStatus = (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK); if (InstancePtr->SendByteCount > 1) { IntrStatus |= XIIC_INTR_TX_HALF_MASK; } /* * Clear the interrupts in the status and then enable them and then * exit the critical region. */ XIic_ClearEnableIntr(InstancePtr->BaseAddress, IntrStatus); XIic_IntrGlobalEnable(InstancePtr->BaseAddress); return XST_SUCCESS; }
/** * * 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; }
/** * * This function is called when the IIC device is Addressed As a Slave (AAS). * This occurs when another device on the bus, a master, has addressed this * device to receive a message. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void AddrAsSlaveHandler(XIic *InstancePtr) { u32 Status; int CallValue; /* * Disable AAS interrupt to clear the interrupt condition since this is * interrupt does not go away and enable the not addressed as a slave * interrrupt to tell when the master stops data transfer. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_AAS_MASK); XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_NAAS_MASK); /* * Determine how the slave is being addressed and call the handler to * notify the user of the event. */ Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); /* * Determine if the master is trying to perform a read or write * operation. */ if (Status & XIIC_SR_MSTR_RDING_SLAVE_MASK) { CallValue = XII_MASTER_READ_EVENT; } else { CallValue = XII_MASTER_WRITE_EVENT; } /* * If being addressed with general call also indicate to handler. */ if (Status & XIIC_SR_GEN_CALL_MASK) { CallValue |= XII_GENERAL_CALL_EVENT; } InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, CallValue); return; }
/** * 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; }
/** * 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; }
/** * * 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; }
/** * 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; }