static Xuint8 TXSuccess(Xuint32 BaseAddress) { Xuint32 IntrStatus, ErrorMask; ErrorMask = XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; do { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if( IntrStatus & ErrorMask ) return 0; } while(!(IntrStatus & XIIC_INTR_TX_EMPTY_MASK)); return 1; } // end RecvAck()
static Xuint8 SlaveRecvData(Xuint32 BaseAddress, Xuint8 *BufferPtr) { Xuint8 IntrStatus; while(1) { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if( IntrStatus & XIIC_INTR_NAAS_MASK ) { //xil_printf("Recv complete: %02x\r\n", IntrStatus); break; } if( IntrStatus & XIIC_INTR_RX_FULL_MASK ) { *(BufferPtr++) = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); //xil_printf("Data received: %d\r\n", *(BufferPtr-1)); XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); } } } // end SlaveRecvData()
/* * * Handle an interrupt from the Ethernet MAC when configured with scatter-gather * DMA. The only interrupts handled in this case are errors. * * @param InstancePtr is a pointer to the XEmac instance to be worked on. * * @return * * None. * * @note * * None. * ******************************************************************************/ static void HandleEmacDmaIntr(XEmac * InstancePtr) { u32 IntrStatus; /* * When configured with DMA, the EMAC generates interrupts only when errors * occur. We clear the interrupts immediately so that any latched status * interrupt bits will reflect the true status of the device, and so any * pulsed interrupts (non-status) generated during the Isr will not be lost. */ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus); /* * Check the MAC for errors */ XEmac_CheckEmacError(InstancePtr, IntrStatus); }
static Xuint8 RXSuccess(Xuint32 BaseAddress) { Xuint32 IntrStatus, ErrorMask; ErrorMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; /** Wait until the rx_fifo is full **/ while(1) { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if( IntrStatus & XIIC_INTR_RX_FULL_MASK ) { XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); return 1; } if( IntrStatus & ErrorMask ) return 0; } } // end RXSuccess()
static Xuint8 SendData(Xuint32 BaseAddress, Xuint8 SlaveAddress, Xuint8 *BufferPtr, Xuint8 ByteCount) { Xuint8 IntrStatus, CtrlReg; Xuint8 count = 0; for( count = 0; count < ByteCount-1; count++ ) XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, *(BufferPtr++)); /** Wait for tx_fifo empty **/ XI2c_mClearIisr(BaseAddress, XIIC_INTR_BNB_MASK | XIIC_INTR_TX_ERROR_MASK); if( !TXSuccess(BaseAddress) ) { //print("SendData : 1 : TXFailure\r\n"); return 0; } /** Generate the stop condition **/ CtrlReg = XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_DIR_IS_TX_MASK; XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, CtrlReg); /** Send the last byte **/ XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, *BufferPtr); /** Wait for tx_fifo empty **/ if( !TXSuccess(BaseAddress) ) { //print("SendData : 2 : TXFailure\r\n"); return 0; } /* The receive is complete, disable the IIC device and return the number of * bytes that was received, we must wait for the bnb flag to properly * disable the device. */ do { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); } while(!(IntrStatus & XIIC_INTR_BNB_MASK)); XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, 0); return ++count; } // end SendData()
Xuint8 XI2c_SlaveAccess(Xuint32 BaseAddress, Xuint8 SlaveAddress, Xuint8 *BufferPtr) { Xuint8 CtrlReg, StatusReg, SlaveSendFlag, DeviceAddress; Xuint8 IntrStatus, count = 0; XI2c_mClearTXFifo(BaseAddress); /** Set the device slave address **/ DeviceAddress = SlaveAddress << 1; XIo_Out8(BaseAddress + XIIC_ADR_REG_OFFSET, DeviceAddress); /** Wait until the device is addressed as slave **/ do { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); } while(!(IntrStatus & XIIC_INTR_AAS_MASK)); XIo_Out8(BaseAddress + XIIC_RFD_REG_OFFSET, 0); /** Clear the recieve-fifo interrupt register **/ XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); /** Read the status register to see if we need to receive or send data **/ StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); XI2c_mClearIisr(BaseAddress, XIIC_INTR_NAAS_MASK | XIIC_INTR_BNB_MASK); SlaveSendFlag = StatusReg & XIIC_SR_MSTR_RDING_SLAVE_MASK; if( SlaveSendFlag ) { SlaveSendData(BaseAddress, BufferPtr); } else { SlaveRecvData(BaseAddress, BufferPtr); } XI2c_mClearIisr(BaseAddress, XIIC_INTR_AAS_MASK); return 1; } // XI2c_SlaveAccess()
static void PrintStatus(Xuint32 BaseAddress) { Xuint8 CtrlReg, StatusReg, IntrStatus, DevAddress; Xuint8 RxFifoOcy, TxFifoOcy, RxFifoDepth; CtrlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); DevAddress = XIo_In8(BaseAddress + XIIC_ADR_REG_OFFSET); RxFifoOcy = XIo_In8(BaseAddress + XIIC_RFO_REG_OFFSET); TxFifoOcy = XIo_In8(BaseAddress + XIIC_TFO_REG_OFFSET); RxFifoDepth = XIo_In8(BaseAddress + XIIC_RFD_REG_OFFSET); xil_printf("\r\nControl Reg:\t\t 0x%02x\r\n", CtrlReg); xil_printf("Status Reg:\t\t 0x%02x\r\n", StatusReg); xil_printf("Interrupts:\t\t 0x%02x\r\n", IntrStatus); //xil_printf("Device Address:\t\t 0x%02x\r\n", DevAddress); //xil_printf("Rx Fifo Occupancy:\t 0x%02x\r\n", RxFifoOcy); //xil_printf("Tx Fifo Occupancy:\t 0x%02x\r\n", TxFifoOcy); //xil_printf("Rx Fifo Depth:\t\t 0x%02x\r\n", RxFifoDepth); } // end PrintStatus()
static Xuint8 SlaveSendData(Xuint32 BaseAddress, Xuint8 *BufferPtr) { Xuint8 IntrStatus; XI2c_mClearIisr(BaseAddress, XIIC_INTR_TX_ERROR_MASK); while(1) { do { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if( IntrStatus & (XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_NAAS_MASK) ) { //xil_printf("Send complete: %02x\r\n", IntrStatus); return; } } while( !(IntrStatus & XIIC_INTR_TX_EMPTY_MASK) ); //xil_printf("Data sent: %d\r\n", *BufferPtr); XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, *(BufferPtr++)); XI2c_mClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK); } } // end SlaveSendData()
/****************************************************************************** * * FUNCTION: * * IpIntrSelfTest * * DESCRIPTION: * * Perform a self test on the IP interrupt registers of the IPIF. This * function modifies registers of the IPIF such that they are not guaranteed * to be in the same state when it returns. Any bits in the IP interrupt * status register which are set are assumed to be set by default after a reset * and are not tested in the test. * * ARGUMENTS: * * InstancePtr points to the XIpIf to operate on. * * IpRegistersWidth contains the number of bits in the IP interrupt registers * of the device. The hardware is parameterizable such that only the number of * bits necessary to support a device are implemented. This value must be * between 0 and 32 with 0 indicating there are no IP interrupt registers used. * * RETURN VALUE: * * A status indicating XST_SUCCESS if the test was successful. Otherwise, one * of the following values is returned. * * XST_IPIF_RESET_REGISTER_ERROR The value of a register at reset was * not valid * XST_IPIF_IP_STATUS_ERROR A write to the IP interrupt status * register did not read back correctly * XST_IPIF_IP_ACK_ERROR One or more bits in the IP status * register did not reset when acked * XST_IPIF_IP_ENABLE_ERROR The IP interrupt enable register * did not read back correctly based upon * what was written to it * NOTES: * * None. * ******************************************************************************/ static XStatus IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth) { /* ensure that the IP interrupt interrupt enable register is zero * as it should be at reset, the interrupt status is dependent upon the * IP such that it's reset value is not known */ if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { return XST_IPIF_RESET_REGISTER_ERROR; } /* if there are any used IP interrupts, then test all of the interrupt * bits in all testable registers */ if (IpRegistersWidth > 0) { u32 BitCount; u32 IpInterruptMask = XIIF_V123B_FIRST_BIT_MASK; u32 Mask = XIIF_V123B_FIRST_BIT_MASK; /* bits assigned MSB to LSB */ u32 InterruptStatus; /* generate the register masks to be used for IP register tests, the * number of bits supported by the hardware is parameterizable such * that only that number of bits are implemented in the registers, the * bits are allocated starting at the MSB of the registers */ for (BitCount = 1; BitCount < IpRegistersWidth; BitCount++) { Mask = Mask << 1; IpInterruptMask |= Mask; } /* get the current IP interrupt status register contents, any bits * already set must default to 1 at reset in the device and these * bits can't be tested in the following test, remove these bits from * the mask that was generated for the test */ InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); IpInterruptMask &= ~InterruptStatus; /* set the bits in the device status register and verify them by reading * the register again, all bits of the register are latched */ XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); if ((InterruptStatus & IpInterruptMask) != IpInterruptMask) { return XST_IPIF_IP_STATUS_ERROR; } /* test to ensure that the bits set in the IP interrupt status register * can be cleared by acknowledging them in the IP interrupt status * register then read it again and verify it was cleared */ XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); if ((InterruptStatus & IpInterruptMask) != 0) { return XST_IPIF_IP_ACK_ERROR; } /* set the IP interrupt enable set register and then read the IP * interrupt enable register and verify the interrupts were enabled */ XIIF_V123B_WRITE_IIER(RegBaseAddress, IpInterruptMask); if (XIIF_V123B_READ_IIER(RegBaseAddress) != IpInterruptMask) { return XST_IPIF_IP_ENABLE_ERROR; } /* clear the IP interrupt enable register and then read the * IP interrupt enable register and verify the interrupts were disabled */ XIIF_V123B_WRITE_IIER(RegBaseAddress, 0); if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { return XST_IPIF_IP_ENABLE_ERROR; } } return XST_SUCCESS; }
/****************************************************************************** * * Handle an interrupt from the Ethernet MAC when configured for direct FIFO * communication. The interrupts handled are: * - Transmit done (transmit status FIFO is non-empty). Used to determine when * a transmission has been completed. * - Receive done (receive length FIFO is non-empty). Used to determine when a * valid frame has been received. * * In addition, the interrupt status is checked for errors. * * @param InstancePtr is a pointer to the XEmac instance to be worked on. * * @return * * None. * * @note * * None. * ******************************************************************************/ static void HandleEmacFifoIntr(XEmac * InstancePtr) { u32 IntrStatus; /* * The EMAC generates interrupts for errors and generates the transmit * and receive done interrupts for data. We clear the interrupts * immediately so that any latched status interrupt bits will reflect the * true status of the device, and so any pulsed interrupts (non-status) * generated during the Isr will not be lost. */ IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus); if (IntrStatus & XEM_EIR_RECV_DONE_MASK) { /* * Configured for direct memory-mapped I/O using FIFO with interrupts. * This interrupt means the RPLR is non-empty, indicating a frame has * arrived. */ InstancePtr->Stats.RecvInterrupts++; InstancePtr->FifoRecvHandler(InstancePtr->FifoRecvRef); /* * The upper layer has removed as many frames as it wants to, so we * need to clear the RECV_DONE bit before leaving the ISR so that it * reflects the current state of the hardware (because it's a level * interrupt that is latched in the IPIF interrupt status register). * Note that if we've reached this point the bit is guaranteed to be * set because it was cleared at the top of this ISR before any frames * were serviced, so the bit was set again immediately by hardware * because the RPLR was not yet emptied by software. */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_DONE_MASK); } /* * If configured for direct memory-mapped I/O using FIFO, the xmit status * FIFO must be read and the callback invoked regardless of success or not. */ if (IntrStatus & XEM_EIR_XMIT_DONE_MASK) { u32 XmitStatus; InstancePtr->Stats.XmitInterrupts++; XmitStatus = XIo_In32(InstancePtr->BaseAddress + XEM_TSR_OFFSET); /* * Collision errors are stored in the transmit status register * instead of the interrupt status register */ if (XmitStatus & XEM_TSR_EXCESS_DEFERRAL_MASK) { InstancePtr->Stats.XmitExcessDeferral++; } if (XmitStatus & XEM_TSR_LATE_COLLISION_MASK) { InstancePtr->Stats.XmitLateCollisionErrors++; } InstancePtr->FifoSendHandler(InstancePtr->FifoSendRef); /* * Only one status is retrieved per interrupt. We need to clear the * XMIT_DONE bit before leaving the ISR so that it reflects the current * state of the hardware (because it's a level interrupt that is latched * in the IPIF interrupt status register). Note that if we've reached * this point the bit is guaranteed to be set because it was cleared at * the top of this ISR before any statuses were serviced, so the bit was * set again immediately by hardware because the TSR was not yet emptied * by software. */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_XMIT_DONE_MASK); } /* * Check the MAC for errors */ XEmac_CheckEmacError(InstancePtr, IntrStatus); }
/** * * Receive an Ethernet frame into the buffer passed as an argument. This * function is called in response to the callback function for received frames * being called by the driver. The callback function is set up using * SetFifoRecvHandler, and is invoked when the driver receives an interrupt * indicating a received frame. The driver expects the upper layer software to * call this function, FifoRecv, to receive the frame. The buffer supplied * should be large enough to hold a maximum-size Ethernet frame. * * The buffer into which the frame will be received must be 32-bit aligned. If * using simple DMA and the PLB 10/100 Ethernet core, the buffer must be 64-bit * aligned. * * If the device is configured with DMA, simple DMA will be used to transfer * the buffer from the Emac to memory. This means that this buffer should not * be cached. See the comment section "Simple DMA" in xemac.h for more * information. * * @param InstancePtr is a pointer to the XEmac instance to be worked on. * @param BufPtr is a pointer to a aligned buffer into which the received * Ethernet frame will be copied. * @param ByteCountPtr is both an input and an output parameter. It is a pointer * to a 32-bit word that contains the size of the buffer on entry into * the function and the size the received frame on return from the * function. * * @return * * - XST_SUCCESS if the frame was sent successfully * - XST_DEVICE_IS_STOPPED if the device has not yet been started * - XST_NOT_INTERRUPT if the device is not in interrupt mode * - XST_NO_DATA if there is no frame to be received from the FIFO * - XST_BUFFER_TOO_SMALL if the buffer to receive the frame is too small for * the frame waiting in the FIFO. * - XST_DEVICE_BUSY if configured for simple DMA and the DMA engine is busy * - XST_DMA_ERROR if an error occurred during the DMA transfer (simple DMA). * The user should treat this as a fatal error that requires a reset of the * EMAC device. * * @note * * The input buffer must be big enough to hold the largest Ethernet frame. * * @internal * * The Ethernet MAC uses FIFOs behind its length and status registers. For this * reason, it is important to keep the length, status, and data FIFOs in sync * when reading or writing to them. * ******************************************************************************/ XStatus XEmac_FifoRecv(XEmac * InstancePtr, u8 * BufPtr, u32 * ByteCountPtr) { XStatus Result; u32 PktLength; u32 StatusReg; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(BufPtr != NULL); XASSERT_NONVOID(ByteCountPtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Be sure the device is not configured for polled mode and it is started */ if (InstancePtr->IsPolled) { return XST_NOT_INTERRUPT; } if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { return XST_DEVICE_IS_STOPPED; } /* * Make sure the buffer is big enough to hold the maximum frame size. * We need to do this because as soon as we read the MAC's packet length * register, which is actually a FIFO, we remove that length from the * FIFO. We do not want to read the length FIFO without also reading the * data FIFO since this would get the FIFOs out of sync. So we have to * make this restriction. */ if (*ByteCountPtr < XEM_MAX_FRAME_SIZE) { return XST_BUFFER_TOO_SMALL; } /* * Before reading from the length FIFO, make sure the length FIFO is not * empty. We could cause an underrun error if we try to read from an * empty FIFO. */ StatusReg = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); if (StatusReg & XEM_EIR_RECV_LFIFO_EMPTY_MASK) { /* * Clear the empty status so the next time through the current status * of the hardware is reflected (we have to do this because the status * is level in the device but latched in the interrupt status register). */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_LFIFO_EMPTY_MASK); return XST_NO_DATA; } /* * If configured with DMA, make sure the DMA engine is not busy */ if (XEmac_mIsDma(InstancePtr)) { if (XDmaChannel_GetStatus(&InstancePtr->RecvChannel) & XDC_DMASR_BUSY_MASK) { return XST_DEVICE_BUSY; } } /* * Determine, from the MAC, the length of the next packet available * in the data FIFO (there should be a non-zero length here) */ PktLength = XIo_In32(InstancePtr->BaseAddress + XEM_RPLR_OFFSET); if (PktLength == 0) { return XST_NO_DATA; } /* * We assume that the MAC never has a length bigger than the largest * Ethernet frame, so no need to make another check here. * * Receive either by directly reading the FIFO or using the DMA engine */ if (!XEmac_mIsDma(InstancePtr)) { /* * This is a non-blocking read. The FIFO returns an error if there is * not at least the requested amount of data in the FIFO. */ Result = XPacketFifoV200a_Read(&InstancePtr->RecvFifo, BufPtr, PktLength); if (Result != XST_SUCCESS) { return Result; } } else { /* * Call on DMA to transfer from the FIFO to the buffer. First set up * the DMA control register. */ XDmaChannel_SetControl(&InstancePtr->RecvChannel, XDC_DMACR_DEST_INCR_MASK | XDC_DMACR_SOURCE_LOCAL_MASK | XDC_DMACR_SG_DISABLE_MASK); /* * Now transfer the data */ XDmaChannel_Transfer(&InstancePtr->RecvChannel, (u32 *) (InstancePtr->BaseAddress + XEM_PFIFO_RXDATA_OFFSET), (u32 *) BufPtr, PktLength); /* * Poll here waiting for DMA to be not busy. We think this will * typically be a single read since DMA should be ahead of the SW. */ do { StatusReg = XDmaChannel_GetStatus(&InstancePtr->RecvChannel); } while (StatusReg & XDC_DMASR_BUSY_MASK); /* Return an error if there was a problem with DMA */ if ((StatusReg & XDC_DMASR_BUS_ERROR_MASK) || (StatusReg & XDC_DMASR_BUS_TIMEOUT_MASK)) { InstancePtr->Stats.DmaErrors++; return XST_DMA_ERROR; } } *ByteCountPtr = PktLength; InstancePtr->Stats.RecvFrames++; InstancePtr->Stats.RecvBytes += PktLength; return XST_SUCCESS; }
/** * * Send an Ethernet frame using direct FIFO I/O or simple DMA with interrupts. * The caller provides a contiguous-memory buffer and its length. The buffer * must be 32-bit aligned. If using simple DMA and the PLB 10/100 Ethernet core, * the buffer must be 64-bit aligned. The callback function set by using * SetFifoSendHandler is invoked when the transmission is complete. * * It is assumed that the upper layer software supplies a correctly formatted * Ethernet frame, including the destination and source addresses, the * type/length field, and the data field. * * If the device is configured with DMA, simple DMA will be used to transfer * the buffer from memory to the Emac. This means that this buffer should not * be cached. See the comment section "Simple DMA" in xemac.h for more * information. * * @param InstancePtr is a pointer to the XEmac instance to be worked on. * @param BufPtr is a pointer to a aligned buffer containing the Ethernet * frame to be sent. * @param ByteCount is the size of the Ethernet frame. * * @return * * - XST_SUCCESS if the frame was successfully sent. An interrupt is generated * when the EMAC transmits the frame and the driver calls the callback set * with XEmac_SetFifoSendHandler() * - XST_DEVICE_IS_STOPPED if the device has not yet been started * - XST_NOT_INTERRUPT if the device is not in interrupt mode * - XST_FIFO_NO_ROOM if there is no room in the FIFO for this frame * - XST_DEVICE_BUSY if configured for simple DMA and the DMA engine is busy * - XST_DMA_ERROR if an error occurred during the DMA transfer (simple DMA). * The user should treat this as a fatal error that requires a reset of the * EMAC device. * * @note * * This function is not thread-safe. The user must provide mutually exclusive * access to this function if there are to be multiple threads that can call it. * * @internal * * The Ethernet MAC uses FIFOs behind its length and status registers. For this * reason, it is important to keep the length, status, and data FIFOs in sync * when reading or writing to them. * ******************************************************************************/ XStatus XEmac_FifoSend(XEmac * InstancePtr, u8 * BufPtr, u32 ByteCount) { XStatus Result; volatile u32 StatusReg; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(BufPtr != NULL); XASSERT_NONVOID(ByteCount > XEM_HDR_SIZE); /* send at least 1 byte */ XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Be sure the device is configured for interrupt mode and it is started */ if (InstancePtr->IsPolled) { return XST_NOT_INTERRUPT; } if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { return XST_DEVICE_IS_STOPPED; } /* * Before writing to the data FIFO, make sure the length FIFO is not * full. The data FIFO might not be full yet even though the length FIFO * is. This avoids an overrun condition on the length FIFO and keeps the * FIFOs in sync. */ StatusReg = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); if (StatusReg & XEM_EIR_XMIT_LFIFO_FULL_MASK) { return XST_FIFO_NO_ROOM; } /* * Send either by directly writing to the FIFOs or using the DMA engine */ if (!XEmac_mIsDma(InstancePtr)) { /* * This is a non-blocking write. The packet FIFO returns an error if there * is not enough room in the FIFO for this frame. */ Result = XPacketFifoV200a_Write(&InstancePtr->SendFifo, BufPtr, ByteCount); if (Result != XST_SUCCESS) { return Result; } } else { u32 Vacancy; /* * Need to make sure there is room in the data FIFO for the packet * before trying to DMA into it. Get the vacancy count (in words) * and make sure the packet will fit. */ Vacancy = XPF_V200A_GET_COUNT(&InstancePtr->SendFifo); if ((Vacancy * sizeof (u32)) < ByteCount) { return XST_FIFO_NO_ROOM; } /* * Check the DMA engine to make sure it is not already busy */ if (XDmaChannel_GetStatus(&InstancePtr->SendChannel) & XDC_DMASR_BUSY_MASK) { return XST_DEVICE_BUSY; } /* * Set the DMA control register up properly */ XDmaChannel_SetControl(&InstancePtr->SendChannel, XDC_DMACR_SOURCE_INCR_MASK | XDC_DMACR_DEST_LOCAL_MASK | XDC_DMACR_SG_DISABLE_MASK); /* * Now transfer the data from the buffer to the FIFO */ XDmaChannel_Transfer(&InstancePtr->SendChannel, (u32 *) BufPtr, (u32 *) (InstancePtr->BaseAddress + XEM_PFIFO_TXDATA_OFFSET), ByteCount); /* * Poll here waiting for DMA to be not busy. We think this will * typically be a single read since DMA should be ahead of the SW. */ do { StatusReg = XDmaChannel_GetStatus(&InstancePtr->SendChannel); } while (StatusReg & XDC_DMASR_BUSY_MASK); /* Return an error if there was a problem with DMA */ if ((StatusReg & XDC_DMASR_BUS_ERROR_MASK) || (StatusReg & XDC_DMASR_BUS_TIMEOUT_MASK)) { InstancePtr->Stats.DmaErrors++; return XST_DMA_ERROR; } } /* * Set the MAC's transmit packet length register to tell it to transmit */ XIo_Out32(InstancePtr->BaseAddress + XEM_TPLR_OFFSET, ByteCount); /* * Bump stats here instead of the Isr since we know the byte count * here but would have to save it in the instance in order to know the * byte count at interrupt time. */ InstancePtr->Stats.XmitFrames++; InstancePtr->Stats.XmitBytes += ByteCount; return XST_SUCCESS; }
/** * * 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. * * @note * * No action is required to clear this interrupt in the device as it is a * pulse. The interrupt need only be cleared in the IpIf interface. * ******************************************************************************/ static void TxErrorHandler(XIic * InstancePtr) { u32 IntrStatus; u8 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_mFlushTxFifo(InstancePtr); XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); 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 = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Rx Reg/FIFO has data, Disable tx error interrupts */ XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); return; } XIic_mFlushTxFifo(InstancePtr); /* Disable and clear tx empty, empty, Rx Full or tx error interrupts */ XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); XIic_mClearIntr(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 = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); CntlReg &= ~XIIC_CR_MSMS_MASK; XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); /* set FIFO occupancy depth = 1 so that the first byte will throttle * next recieve msg */ XIo_Out8(InstancePtr->BaseAddress + XIIC_RFD_REG_OFFSET, 0); /* make event callback */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); }
/** * * 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. * * All XIic device interrupts are ORed into one device interrupt. This routine * reads the pending interrupts via the IpIf interface and masks that with the * interrupt mask to evaluate only the interrupts enabled. * ******************************************************************************/ void XIic_InterruptHandler(void *InstancePtr) { u8 Status; u32 IntrStatus; u32 IntrPending; u32 IntrEnable; XIic *IicPtr = NULL; u32 Clear = 0; /* * Verify that each of the inputs are valid. */ XASSERT_VOID(InstancePtr != NULL); /* * Convert the non-typed pointer to an IIC instance pointer */ IicPtr = (XIic *) InstancePtr; /* Get the interrupt Status from the IPIF. There is no clearing of * interrupts in the IPIF. Interrupts must be cleared at the source. * To find which interrupts are pending; AND interrupts pending with * interrupts masked. */ IntrPending = XIIF_V123B_READ_IISR(IicPtr->BaseAddress); IntrEnable = XIIF_V123B_READ_IIER(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) | (XIIF_V123B_IS_GINTR_ENABLED(IicPtr->BaseAddress) == FALSE)) { return; } /* Update interrupt stats and get the contents of the status register */ IicPtr->Stats.IicInterrupts++; Status = XIo_In8(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_mDisableIntr(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); } /* Clear Interrupts */ IntrStatus = XIIF_V123B_READ_IISR(IicPtr->BaseAddress); Clear = IntrStatus & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); } XIIF_V123B_WRITE_IISR(IicPtr->BaseAddress, Clear); }
/****************************************************************************** * * Send the specified buffer to 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 data to be sent. * @param ByteCount is the number of bytes to be sent. * * @return * * The number of bytes remaining to be sent. * * @note * * This function does not take advantage of the transmit 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. * ******************************************************************************/ static unsigned SendData(u32 BaseAddress, u8 * BufferPtr, unsigned ByteCount) { u32 IntrStatus; /* Send the specified number of bytes in the specified buffer by polling * the device registers and blocking until complete */ while (ByteCount > 0) { /* Wait for the transmit to be empty before sending any more data * by polling the interrupt status register */ while (1) { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK)) { return ByteCount; } if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) { break; } } /* If there is more than one byte to send then put the next byte to send * into the transmit FIFO */ if (ByteCount > 1) { XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, *BufferPtr++); } else { /* Set the stop condition before sending the last byte of data so that * the stop condition will be generated immediately following the data * This is done by clearing the MSMS bit in the control register. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_DIR_IS_TX_MASK); /* Put the last byte to send in the transmit FIFO */ XIo_Out8(BaseAddress + XIIC_DTR_REG_OFFSET, *BufferPtr++); } /* Clear the latched interrupt status register and this must be done after * the transmit FIFO has been written to or it won't clear */ XIic_mClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK); /* Update the byte count to reflect the byte sent and clear the latched * interrupt status so it will be updated for the new state */ ByteCount--; } /* Wait for the bus to transition to not busy before returning, the IIC * device cannot be disabled until this occurs. * Note that this is different from a receive operation because the stop * condition causes the bus to go not busy. */ while (1) { if (XIIF_V123B_READ_IISR(BaseAddress) & XIIC_INTR_BNB_MASK) { break; } } return ByteCount; }
/****************************************************************************** * * 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. * * @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 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 = XIIF_V123B_READ_IISR(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 = XIo_In8(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) { /* For 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. */ XIo_Out8(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. */ XIo_Out8(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++ = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); /* 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_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); ByteCount--; } /* 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 (XIIF_V123B_READ_IISR(BaseAddress) & XIIC_INTR_BNB_MASK) { break; } } return ByteCount; }