/****************************************************************************** * * Receive the specified data from the device that has been previously addressed * on the IIC bus. This function assumes that the 7 bit address has been sent * and it should wait for the transmit of the address to complete. * * @param BaseAddress contains the base address of the IIC device. * @param BufferPtr points to the buffer to hold the data that is * received. * @param ByteCount is the number of bytes to be received. * @param Option indicates whether to hold or free the bus after reception * of data, XIIC_STOP = end with STOP condition, * XIIC_REPEATED_START = don't end with STOP condition. * * @return The number of bytes remaining to be received. * * @note * * This function does not take advantage of the receive FIFO because it is * designed for minimal code space and complexity. It contains loops that * that could cause the function not to return if the hardware is not working. * * This function assumes that the calling function will disable the IIC device * after this function returns. * ******************************************************************************/ static unsigned RecvData(u32 BaseAddress, u8 *BufferPtr, unsigned ByteCount, u8 Option) { u32 CntlReg; u32 IntrStatusMask; u32 IntrStatus; /* Attempt to receive the specified number of bytes on the IIC bus */ while (ByteCount > 0) { /* Setup the mask to use for checking errors because when * receiving one byte OR the last byte of a multibyte message an * error naturally occurs when the no ack is done to tell the * slave the last byte */ if (ByteCount == 1) { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; } else { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK; } /* Wait for the previous transmit and the 1st receive to * complete by checking the interrupt status register of the * IPIF */ while (1) { IntrStatus = XIic_ReadIisr(BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { break; } /* Check the transmit error after the receive full * because when sending only one byte transmit error * will occur because of the no ack to indicate the end * of the data */ if (IntrStatus & IntrStatusMask) { return ByteCount; } } CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); /* Special conditions exist for the last two bytes so check for * them. Note that the control register must be setup for these * conditions before the data byte which was already received is * read from the receive FIFO (while the bus is throttled */ if (ByteCount == 1) { if (Option == XIIC_STOP) { /* If the Option is to release the bus after the * last data byte, it has already been read and * no ack has been done, so clear MSMS while * leaving the device enabled so it can get off * the IIC bus appropriately with a stop */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK); } } /* Before the last byte is received, set NOACK to tell the slave * IIC device that it is the end, this must be done before * reading the byte from the FIFO */ if (ByteCount == 2) { /* Write control reg with NO ACK allowing last byte to * have the No ack set to indicate to slave last byte * read */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, CntlReg | XIIC_CR_NO_ACK_MASK); } /* Read in data from the FIFO and unthrottle the bus such that * the next byte is read from the IIC bus */ *BufferPtr++ = (u8) XIic_ReadReg(BaseAddress, XIIC_DRR_REG_OFFSET); if ((ByteCount == 1) && (Option == XIIC_REPEATED_START)) { /* RSTA bit should be set only when the FIFO is * completely Empty. */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_MSMS_MASK | XIIC_CR_REPEATED_START_MASK); } /* Clear the latched interrupt status so that it will be updated * with the new state when it changes, this must be done after * the receive register is read */ XIic_ClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); ByteCount--; } if (Option == XIIC_STOP) { /* If the Option is to release the bus after Reception of data, * wait for the bus to transition to not busy before returning, * the IIC device cannot be disabled until this occurs. It * should transition as the MSMS bit of the control register was * cleared before the last byte was read from the FIFO */ while (1) { if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) { break; } } } return ByteCount; }
/** * 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 mode of operation. 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 indicates whether to hold or free the bus after * transmitting the data. * * @return The number of bytes sent. * * @note None. * ******************************************************************************/ unsigned XIic_Send(u32 BaseAddress, u8 Address, u8 *BufferPtr, unsigned ByteCount, u8 Option) { unsigned RemainingByteCount; u32 ControlReg; volatile u32 StatusReg; /* Check to see if already Master on the Bus. * If Repeated Start bit is not set send Start bit by setting * MSMS bit else Send the address. */ ControlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* * Put the address into the FIFO to be sent and indicate * that the operation to be performed on the bus is a * write operation */ XIic_Send7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); /* 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); /* * MSMS must be set after putting data into transmit FIFO, * indicate the direction is transmit, this device is master * and enable the IIC device */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK | XIIC_CR_ENABLE_DEVICE_MASK); /* * Clear the latched interrupt * status for the bus not busy bit which must be done while * the bus is busy */ StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); } XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); } else { /* * Already owns the Bus indicating that its a Repeated Start * call. 7 bit slave address, send the address for a write * operation and set the state to indicate the address has * been sent. */ XIic_Send7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } /* Send the specified data to the device on the IIC bus specified by the * the address */ RemainingByteCount = SendData(BaseAddress, BufferPtr, ByteCount, Option); ControlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* * The Transmission is completed, disable the IIC device if * the Option is to release the Bus after transmission of data * and return the number of bytes that was received. Only wait * if master, if addressed as slave just reset to release * the bus. */ if ((ControlReg & XIIC_CR_MSMS_MASK) != 0) { XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, (ControlReg & ~XIIC_CR_MSMS_MASK)); StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) != 0) { StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); } } if ((XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET) & XIIC_SR_ADDR_AS_SLAVE_MASK) != 0) { XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, 0); } } return ByteCount - RemainingByteCount; }
/** * * This interrupt occurs four different ways: Two as master and two as slave. * Master: * <pre> * (1) Transmitter (IMPLIES AN ERROR) * The slave receiver did not acknowledge properly. * (2) Receiver (Implies Tx complete) * Interrupt caused by setting TxAck high in the IIC to indicate to the * the last byte has been transmitted. * </pre> * * Slave: * <pre> * (3) Transmitter (Implies Tx complete) * Interrupt caused by master device indicating last byte of the message * has been transmitted. * (4) Receiver (IMPLIES AN ERROR) * Interrupt caused by setting TxAck high in the IIC to indicate Rx * IIC had a problem - set by this device and condition already known * and interrupt is not enabled. * </pre> * * This interrupt is enabled during Master send and receive and disabled * when this device knows it is going to send a negative acknowledge (Ack = No). * * Signals user of Tx error via status callback sending: XII_TX_ERROR_EVENT * * When MasterRecv has no message to send and only receives one byte of data * from the salve device, the TxError must be enabled to catch addressing * errors, yet there is not opportunity to disable TxError when there is no * data to send allowing disabling on last byte. When the slave sends the * only byte the NOAck causes a Tx Error. To disregard this as no real error, * when there is data in the Receive FIFO/register then the error was not * a device address write error, but a NOACK read error - to be ignored. * To work with or without FIFO's, the Rx Data interrupt is used to indicate * data is in the Rx register. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * ******************************************************************************/ static void TxErrorHandler(XIic *InstancePtr) { u32 IntrStatus; u32 CntlReg; /* * When Sending as a slave, Tx error signals end of msg. Not Addressed * As Slave will handle the callbacks. this is used to only flush * the Tx fifo. The addressed as slave bit is gone as soon as the bus * has been released such that the buffer pointers are used to determine * the direction of transfer (send or receive). */ if (InstancePtr->RecvBufferPtr == NULL) { /* * Master Receiver finished reading message. Flush Tx fifo to * remove an 0xFF that was written to prevent bus throttling, * and disable all transmit and receive interrupts. */ XIic_FlushTxFifo(InstancePtr); XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* * If operating in Master mode, call status handler to indicate * NOACK occured. */ IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); if ((IntrStatus & XIIC_INTR_AAS_MASK) == 0) { InstancePtr->StatusHandler(InstancePtr-> StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); } else { /* Decrement the Tx Error since Tx Error interrupt * implies transmit complete while sending as Slave */ InstancePtr->Stats.TxErrors--; } return; } /* * Data in the receive register from either master or slave receive * When:slave, indicates master sent last byte, message completed. * When:master, indicates a master Receive with one byte received. When * a byte is in Rx reg then the Tx error indicates the Rx data was * recovered normally Tx errors are not enabled such that this should * not occur. */ IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Rx Reg/FIFO has data, Disable Tx error interrupts */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); return; } XIic_FlushTxFifo(InstancePtr); /* * Disable and clear Tx empty, ½ empty, Rx Full or Tx error interrupts. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* Clear MSMS as on Tx error when Rxing, the bus will be * stopped but MSMS bit is still set. Reset to proper state */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); CntlReg &= ~XIIC_CR_MSMS_MASK; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Set FIFO occupancy depth = 1 so that the first byte will throttle * next recieve msg. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Call the event callback. */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); }
/** * 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 mode of operation. 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 indicates whether to hold or free the bus after reception * of data, XIIC_STOP = end with STOP condition, * XIIC_REPEATED_START = don't end with STOP condition. * * @return The number of bytes received. * * @note None. * ******************************************************************************/ unsigned XIic_Recv(u32 BaseAddress, u8 Address, u8 *BufferPtr, unsigned ByteCount, u8 Option) { u32 CntlReg; unsigned RemainingByteCount; volatile u32 StatusReg; /* 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_ClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* Set receive FIFO occupancy depth for 1 byte (zero based) */ XIic_WriteReg(BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* Check to see if already Master on the Bus. * If Repeated Start bit is not set send Start bit by setting MSMS bit * else Send the address */ CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* 7 bit slave address, send the address for a read operation * and set the state to indicate the address has been sent */ XIic_Send7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); /* MSMS gets set after putting data in FIFO. Start the master * receive operation by setting CR Bits MSMS to Master, if the * buffer is only one byte, then it should not be acknowledged * to indicate the end of data */ CntlReg = XIIC_CR_MSMS_MASK | XIIC_CR_ENABLE_DEVICE_MASK; if (ByteCount == 1) { CntlReg |= XIIC_CR_NO_ACK_MASK; } /* Write out the control register to start receiving data and * call the function to receive each byte into the buffer */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* Clear the latched interrupt status for the bus not busy bit * which must be done while the bus is busy */ StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); } XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); } else { /* Before writing 7bit slave address the Direction of Tx bit * must be disabled */ CntlReg &= ~XIIC_CR_DIR_IS_TX_MASK; XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* Already owns the Bus indicating that its a Repeated Start * call. 7 bit slave address, send the address for a read * operation and set the state to indicate the address has been * sent */ XIic_Send7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); } /* Try to receive the data from the IIC bus */ RemainingByteCount = RecvData(BaseAddress, BufferPtr, ByteCount, Option); CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* The receive is complete, disable the IIC device if the Option * is to release the Bus after Reception of data and return the * number of bytes that was received */ XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, 0); } /* Return the number of bytes that was received */ return ByteCount - RemainingByteCount; }
/** * * This function handles data received from the IIC bus as a slave. * * When the slave expects more than the master has to send, the slave will stall * waiting for data. * * When more data is received than data expected a Nack is done to signal master * to stop sending data. The excess data is discarded to prevent bus throttling. * * The buffer may be full and the master continues to send data if the master * and slave have different message lengths. This condition is handled by sending * No Ack to the master and reading Rx data until the master stops sending data * to prevent but throttling from locking up the bus. To ever receive as a slave * again, must know when to renable bus ACKs. NAAS is used to detect when the * master is finished sending messages for any mode. * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void RecvSlaveData(XIic *InstancePtr) { u32 CntlReg; u8 BytesToRead; u8 LoopCnt; u8 Temp; /* * When receive buffer has no room for the receive data discard it. */ if (InstancePtr->RecvByteCount == 0) { /* * Set ACKnowlege OFF to signal master to stop sending data. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); CntlReg |= XIIC_CR_NO_ACK_MASK; XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Clear excess received data to prevent bus throttling and set * receive FIFO occupancy to throttle at the 1st byte received. */ XIic_FlushRxFifo(InstancePtr); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); return; } /* * Use occupancy count to determine how many bytes to read from the * FIFO, count is zero based so add 1, read that number of bytes from * the FIFO. */ BytesToRead = (XIic_ReadReg(InstancePtr->BaseAddress, XIIC_RFO_REG_OFFSET)) + 1; for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } /* * Set receive FIFO depth for the number of bytes to be received such * that a receive interrupt will occur, the count is 0 based, the * last byte of the message has to be received seperately to ack the * message. */ if (InstancePtr->RecvByteCount > IIC_RX_FIFO_DEPTH) { Temp = IIC_RX_FIFO_DEPTH - 1; } else { if (InstancePtr->RecvByteCount == 0) { Temp = 0; } else { Temp = InstancePtr->RecvByteCount - 1; } } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, (u32) Temp); return; }
/** * * This function is the interrupt handler for the XIic driver. This function * should be connected to the interrupt system. * * Only one interrupt source is handled for each interrupt allowing * higher priority system interrupts quicker response time. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @internal * * The XIIC_INTR_ARB_LOST_MASK and XIIC_INTR_TX_ERROR_MASK interrupts must have * higher priority than the other device interrupts so that the IIC device does * not get into a potentially confused state. The remaining interrupts may be * rearranged with no harm. * ******************************************************************************/ void XIic_InterruptHandler(void *InstancePtr) { u32 Status; u32 IntrStatus; u32 IntrPending; u32 IntrEnable; XIic *IicPtr = NULL; u32 Clear = 0; /* * Verify that each of the inputs are valid. */ Xil_AssertVoid(InstancePtr != NULL); /* * Convert the non-typed pointer to an IIC instance pointer */ IicPtr = (XIic *) InstancePtr; /* * Get the interrupt Status. */ IntrPending = XIic_ReadIisr(IicPtr->BaseAddress); IntrEnable = XIic_ReadIier(IicPtr->BaseAddress); IntrStatus = IntrPending & IntrEnable; /* * Do not processes a devices interrupts if the device has no * interrupts pending or the global interrupts have been disabled. */ if ((IntrStatus == 0) || (XIic_IsIntrGlobalEnabled(IicPtr->BaseAddress) == FALSE)) { return; } /* * Update interrupt stats and get the contents of the status register. */ IicPtr->Stats.IicInterrupts++; Status = XIic_ReadReg(IicPtr->BaseAddress, XIIC_SR_REG_OFFSET); /* * Service requesting interrupt. */ if (IntrStatus & XIIC_INTR_ARB_LOST_MASK) { /* Bus Arbritration Lost */ IicPtr->Stats.ArbitrationLost++; XIic_ArbLostFuncPtr(IicPtr); Clear = XIIC_INTR_ARB_LOST_MASK; } else if (IntrStatus & XIIC_INTR_TX_ERROR_MASK) { /* Transmit errors (no acknowledge) received */ IicPtr->Stats.TxErrors++; TxErrorHandler(IicPtr); Clear = XIIC_INTR_TX_ERROR_MASK; } else if (IntrStatus & XIIC_INTR_NAAS_MASK) { /* Not Addressed As Slave */ XIic_NotAddrAsSlaveFuncPtr(IicPtr); Clear = XIIC_INTR_NAAS_MASK; } else if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ IicPtr->Stats.RecvInterrupts++; if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { XIic_RecvSlaveFuncPtr(IicPtr); } else { XIic_RecvMasterFuncPtr(IicPtr); } Clear = XIIC_INTR_RX_FULL_MASK; } else if (IntrStatus & XIIC_INTR_AAS_MASK) { /* Addressed As Slave */ XIic_AddrAsSlaveFuncPtr(IicPtr); Clear = XIIC_INTR_AAS_MASK; } else if (IntrStatus & XIIC_INTR_BNB_MASK) { /* IIC bus has transitioned to not busy */ /* Check if send callback needs to run */ if (IicPtr->BNBOnly == TRUE) { XIic_BusNotBusyFuncPtr(IicPtr); IicPtr->BNBOnly = FALSE; } else { IicPtr->SendHandler(IicPtr->SendCallBackRef, 0); } Clear = XIIC_INTR_BNB_MASK; /* The bus is not busy, disable BusNotBusy interrupt */ XIic_DisableIntr(IicPtr->BaseAddress, XIIC_INTR_BNB_MASK); } else if ((IntrStatus & XIIC_INTR_TX_EMPTY_MASK) || (IntrStatus & XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty */ IicPtr->Stats.SendInterrupts++; if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { XIic_SendSlaveFuncPtr(IicPtr); } else { XIic_SendMasterFuncPtr(IicPtr); } IntrStatus = XIic_ReadIisr(IicPtr->BaseAddress); Clear = IntrStatus & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); } /* * Clear Interrupts. */ XIic_WriteIisr(IicPtr->BaseAddress, Clear); }
/****************************************************************************** * This function reads a number of bytes from an IIC chip into a * specified buffer. * * @param ChipAddress contains the address of the IIC core. * @param RegAddress contains the address of the register to write to. * @param pBuffer contains the address of the data buffer to be filled. * @param ByteCount contains the number of bytes in the buffer to be read. * This value is constrained by the page size of the device such * that up to 64K may be read in one call. * * @return The number of bytes read. A value less than the specified input * value indicates an error. * * @note None. * ******************************************************************************/ int zed_iic_axi_IicRead(zed_iic_t *pIIC, Xuint8 ChipAddress, Xuint8 RegAddress, Xuint8 *pBuffer, Xuint8 ByteCount) { Xuint8 ReceivedByteCount = 0; Xuint8 SentByteCount = 0; Xuint8 ControlReg; Xuint8 StatusReg; int cnt = 0; zed_iic_axi_t *pContext = (zed_iic_axi_t *)(pIIC->pContext); #if 1 // Make sure all the Fifo's are cleared and Bus is Not busy. do { StatusReg = Xil_In8(pContext->CoreAddress + XIIC_SR_REG_OFFSET); //xil_printf("[%s] Xil_In8(pContext->CoreAddress + XIIC_SR_REG_OFFSET) => 0x%02X\n\r", pContext->szName, StatusReg ); StatusReg = StatusReg & (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK); if ((StatusReg & XIIC_SR_RX_FIFO_EMPTY_MASK) != XIIC_SR_RX_FIFO_EMPTY_MASK) { /* * The RX buffer is not empty and it is assumed there is a stale * message in there. Attempt to clear out the RX buffer, otherwise * this loop spins forever. */ XIic_ReadReg(pContext->CoreAddress, XIIC_DRR_REG_OFFSET); } /* * Check to see if the bus is busy. Since we are master, if the bus is * still busy that means that arbitration has been lost. * * According to Product Guide PG090, October 16, 2012: * * Control Register (0x100), Bit 2 MSMS: * * "Master/Slave Mode Select. When this bit is changed from 0 to 1, * the AXI IIC bus interface generates a START condition in master * mode. When this bit is cleared, a STOP condition is generated and * the AXI IIC bus interface switches to slave mode. When this bit is * cleared by the hardware, because arbitration for the bus has been * lost, a STOP condition is not generated. (See also Interrupt(0): * Arbitration Lost in Chapter 3.)" * * According to this, it should be okay to clear the master/slave mode * select to clear a false start condition with a stop and regain * arbitration over the bus. */ if ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == XIIC_SR_BUS_BUSY_MASK) { ControlReg = Xil_In8(pContext->CoreAddress + XIIC_CR_REG_OFFSET); ControlReg = ControlReg & 0xFB; // Clear the MSMS bit. Xil_Out8(pContext->CoreAddress + XIIC_CR_REG_OFFSET, ControlReg); } } while (StatusReg != (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)); #endif // Position the Read pointer to specific location. do { StatusReg = Xil_In8(pContext->CoreAddress + XIIC_SR_REG_OFFSET); //xil_printf("[%s] Xil_In8(pContext->CoreAddress + XIIC_SR_REG_OFFSET) => 0x%02X\n\r", pContext->szName, StatusReg ); if(!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) { SentByteCount = XIic_DynSend(pContext->CoreAddress, ChipAddress, (Xuint8 *)&RegAddress, 1, XIIC_REPEATED_START); } cnt++; }while(SentByteCount != 1 && (cnt < 100)); // Error writing chip address so return SentByteCount if (SentByteCount < 1) { return SentByteCount; } // Receive the data. ReceivedByteCount = XIic_DynRecv(pContext->CoreAddress, ChipAddress, pBuffer, ByteCount); // Return the number of bytes received. return ReceivedByteCount; }
/** * * 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; }
/****************************************************************************** * * 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; }
/** * * This function is called when the receive register is full. The number * of bytes received to cause the interrupt is adjustable using the Receive FIFO * Depth register. The number of bytes in the register is read in the Receive * FIFO occupancy register. Both these registers are zero based values (0-15) * such that a value of zero indicates 1 byte. * * For a Master Receiver to properly signal the end of a message, the data must * be read in up to the message length - 1, where control register bits will be * set for bus controls to occur on reading of the last byte. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return None. * * @note None. * ******************************************************************************/ static void RecvMasterData(XIic *InstancePtr) { u8 LoopCnt; int BytesInFifo; int BytesToRead; u32 CntlReg; /* * Device is a master receiving, get the contents of the control * register and determine the number of bytes in fifo to be read out. */ CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); BytesInFifo = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_RFO_REG_OFFSET) + 1; /* * If data in FIFO holds all data to be retrieved - 1, set NOACK and * disable the Tx error. */ if ((InstancePtr->RecvByteCount - BytesInFifo) == 1) { /* * Disable Tx error interrupt to prevent interrupt * as this device will cause it when it set NO ACK next. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); /* * Write control reg with NO ACK allowing last byte to * have the No ack set to indicate to slave last byte read. */ XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg | XIIC_CR_NO_ACK_MASK)); /* * Read one byte to clear a place for the last byte to be read * which will set the NO ACK. */ XIic_ReadRecvByte(InstancePtr); } /* * If data in FIFO is all the data to be received then get the data * and also leave the device in a good state for the next transaction. */ else if ((InstancePtr->RecvByteCount - BytesInFifo) == 0) { /* * If repeated start option is off then the master should stop * using the bus, otherwise hold the bus, setting repeated start * stops the slave from transmitting data when the FIFO is read. */ if ((InstancePtr->Options & XII_REPEATED_START_OPTION) == 0) { CntlReg &= ~XIIC_CR_MSMS_MASK; } else { CntlReg |= XIIC_CR_REPEATED_START_MASK; } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); /* * Read data from the FIFO then set zero based FIFO read depth * for a byte. */ for (LoopCnt = 0; LoopCnt < BytesInFifo; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); /* * Disable Rx full interrupt and write the control reg with ACK * allowing next byte sent to be acknowledged automatically. */ XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, (CntlReg & ~XIIC_CR_NO_ACK_MASK)); /* * Send notification of msg Rx complete in RecvHandler callback. */ InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, 0); } else { /* * Fifo data not at n-1, read all but the last byte of data * from the slave, if more than a FIFO full yet to receive * read a FIFO full. */ BytesToRead = InstancePtr->RecvByteCount - BytesInFifo - 1; if (BytesToRead > IIC_RX_FIFO_DEPTH) { BytesToRead = IIC_RX_FIFO_DEPTH; } /* * Read in data from the FIFO. */ for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { XIic_ReadRecvByte(InstancePtr); } } }
/** * 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 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; }
/** * 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; }