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