/** * * Aborts a transfer in progress by disabling the device and resetting the FIFOs * if present. The byte counts are cleared, the busy flag is cleared, and mode * fault is cleared. * * @param InstancePtr is a pointer to the XSpiPs instance. * * @return None. * * @note * * This function does a read/modify/write of the Config register. The user of * this function needs to take care of critical sections. * ******************************************************************************/ void XSpiPs_Abort(XSpiPs *InstancePtr) { u8 Temp; u32 Check; XSpiPs_Disable(InstancePtr); /* * Clear the RX FIFO and drop any data. */ Check = (XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET) & XSPIPS_IXR_RXNEMPTY_MASK); while (Check != (u32)0U) { Temp = (u8)XSpiPs_RecvByte(InstancePtr->Config.BaseAddress); if(Temp != (u8)0U) { } Check = (XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET) & XSPIPS_IXR_RXNEMPTY_MASK); } /* * Clear mode fault condition. */ XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET, XSPIPS_IXR_MODF_MASK); InstancePtr->RemainingBytes = 0U; InstancePtr->RequestedBytes = 0U; InstancePtr->IsBusy = FALSE; }
/** * * Aborts a transfer in progress by disabling the device and resetting the FIFOs * if present. The byte counts are cleared, the busy flag is cleared, and mode * fault is cleared. * * @param InstancePtr is a pointer to the XSpiPs instance. * * @return None. * * @note * * This function does a read/modify/write of the Config register. The user of * this function needs to take care of critical sections. * ******************************************************************************/ void XSpiPs_Abort(XSpiPs *InstancePtr) { XSpiPs_Disable(InstancePtr); /* * Clear the RX FIFO and drop any data. */ while ((XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET) & XSPIPS_IXR_RXNEMPTY_MASK) == XSPIPS_IXR_RXNEMPTY_MASK) { (void) XSpiPs_RecvByte(InstancePtr->Config.BaseAddress); } /* * Clear mode fault condition. */ XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET, XSPIPS_IXR_MODF_MASK); InstancePtr->RemainingBytes = 0; InstancePtr->RequestedBytes = 0; InstancePtr->IsBusy = FALSE; }
/** * * The interrupt handler for SPI interrupts. This function must be connected * by the user to an interrupt controller. * * The interrupts that are handled are: * * - Mode Fault Error. This interrupt is generated if this device is selected * as a slave when it is configured as a master. The driver aborts any data * transfer that is in progress by resetting FIFOs (if present) and resetting * its buffer pointers. The upper layer software is informed of the error. * * - Data Transmit Register (FIFO) Empty. This interrupt is generated when the * transmit register or FIFO is empty. The driver uses this interrupt during a * transmission to continually send/receive data until the transfer is done. * * - Data Transmit Register (FIFO) Underflow. This interrupt is generated when * the SPI device, when configured as a slave, attempts to read an empty * DTR/FIFO. An empty DTR/FIFO usually means that software is not giving the * device data in a timely manner. No action is taken by the driver other than * to inform the upper layer software of the error. * * - Data Receive Register (FIFO) Overflow. This interrupt is generated when the * SPI device attempts to write a received byte to an already full DRR/FIFO. * A full DRR/FIFO usually means software is not emptying the data in a timely * manner. No action is taken by the driver other than to inform the upper * layer software of the error. * * - Slave Mode Fault Error. This interrupt is generated if a slave device is * selected as a slave while it is disabled. No action is taken by the driver * other than to inform the upper layer software of the error. * * @param InstancePtr is a pointer to the XSpiPs instance. * * @return None. * * @note * * The slave select register is being set to deselect the slave when a transfer * is complete. This is being done regardless of whether it is a slave or a * master since the hardware does not drive the slave select as a slave. * ******************************************************************************/ void XSpiPs_InterruptHandler(XSpiPs *InstancePtr) { XSpiPs *SpiPtr = InstancePtr; u32 IntrStatus; u32 ConfigReg; u32 BytesDone; /* Number of bytes done so far. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(SpiPtr->IsReady == XIL_COMPONENT_IS_READY); /* * Immediately clear the interrupts in case the ISR causes another * interrupt to be generated. If we clear at the end of the ISR, * we may miss newly generated interrupts. * Disable the TXOW interrupt because we transmit from within the ISR, * which could potentially cause another TX_OW interrupt. */ IntrStatus = XSpiPs_ReadReg(SpiPtr->Config.BaseAddress, XSPIPS_SR_OFFSET); XSpiPs_WriteReg(SpiPtr->Config.BaseAddress, XSPIPS_SR_OFFSET, (IntrStatus & XSPIPS_IXR_WR_TO_CLR_MASK)); XSpiPs_WriteReg(SpiPtr->Config.BaseAddress, XSPIPS_IDR_OFFSET, XSPIPS_IXR_TXOW_MASK); /* * Check for mode fault error. We want to check for this error first, * before checking for progress of a transfer, since this error needs * to abort any operation in progress. */ if ((u32)XSPIPS_IXR_MODF_MASK == (u32)(IntrStatus & XSPIPS_IXR_MODF_MASK)) { BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; /* * Abort any operation currently in progress. This includes * clearing the mode fault condition by reading the status * register. Note that the status register should be read after * the abort, since reading the status register clears the mode * fault condition and would cause the device to restart any * transfer that may be in progress. */ XSpiPs_Abort(SpiPtr); SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_MODE_FAULT, BytesDone); return; /* Do not continue servicing other interrupts. */ } if ((IntrStatus & XSPIPS_IXR_TXOW_MASK) != 0U) { u8 TempData; u32 TransCount; /* * A transmit has just completed. Process received data and * check for more data to transmit. * First get the data received as a result of the transmit that * just completed. Always get the received data, but only fill * the receive buffer if it is not null (it can be null when * the device does not care to receive data). * Initialize the TransCount based on the requested bytes. * Loop on receive FIFO based on TransCount. */ TransCount = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; while (TransCount != 0U) { TempData = (u8)XSpiPs_RecvByte(SpiPtr->Config.BaseAddress); if (SpiPtr->RecvBufferPtr != NULL) { *SpiPtr->RecvBufferPtr = TempData; SpiPtr->RecvBufferPtr += 1; } SpiPtr->RequestedBytes--; --TransCount; } /* * Fill the TXFIFO until data exists, otherwise fill upto * FIFO depth. */ while ((SpiPtr->RemainingBytes > 0U) && (TransCount < XSPIPS_FIFO_DEPTH)) { XSpiPs_SendByte(SpiPtr->Config.BaseAddress, *SpiPtr->SendBufferPtr); SpiPtr->SendBufferPtr += 1; SpiPtr->RemainingBytes--; ++TransCount; } if ((SpiPtr->RemainingBytes == 0U) && (SpiPtr->RequestedBytes == 0U)) { /* * No more data to send. Disable the interrupt and * inform the upper layer software that the transfer * is done. The interrupt will be re-enabled when * another transfer is initiated. */ XSpiPs_WriteReg(SpiPtr->Config.BaseAddress, XSPIPS_IDR_OFFSET, XSPIPS_IXR_DFLT_MASK); /* * Disable slave select lines as the transfer * is complete. */ if (XSpiPs_IsManualChipSelect(InstancePtr) == TRUE) { ConfigReg = XSpiPs_ReadReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_SSCTRL_MASK; XSpiPs_WriteReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } /* * Clear the busy flag. */ SpiPtr->IsBusy = FALSE; /* * Disable the device. */ XSpiPs_Disable(SpiPtr); /* * Inform the Transfer done to upper layers. */ SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_TRANSFER_DONE, SpiPtr->RequestedBytes); } else { /* * Enable the TXOW interrupt. */ XSpiPs_WriteReg(SpiPtr->Config.BaseAddress, XSPIPS_IER_OFFSET, XSPIPS_IXR_TXOW_MASK); /* * Start the transfer by not inhibiting the transmitter * any longer. */ if ((XSpiPs_IsManualStart(SpiPtr) == TRUE) && (XSpiPs_IsMaster(SpiPtr) == TRUE)) { ConfigReg = XSpiPs_ReadReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_MANSTRT_MASK; XSpiPs_WriteReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } } } /* * Check for overflow and underflow errors. */ if ((IntrStatus & XSPIPS_IXR_RXOVR_MASK) != 0U) { BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; SpiPtr->IsBusy = FALSE; /* * The Slave select lines are being manually controlled. * Disable them because the transfer is complete. */ if (XSpiPs_IsManualChipSelect(SpiPtr) == TRUE) { ConfigReg = XSpiPs_ReadReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_SSCTRL_MASK; XSpiPs_WriteReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_RECEIVE_OVERRUN, BytesDone); } if ((IntrStatus & XSPIPS_IXR_TXUF_MASK) != 0U) { BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; SpiPtr->IsBusy = FALSE; /* * The Slave select lines are being manually controlled. * Disable them because the transfer is complete. */ if (XSpiPs_IsManualChipSelect(SpiPtr) == TRUE) { ConfigReg = XSpiPs_ReadReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_SSCTRL_MASK; XSpiPs_WriteReg( SpiPtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_TRANSMIT_UNDERRUN, BytesDone); } }
/** * Transfers specified data on the SPI bus in polled mode. * * The caller has the option of providing two different buffers for send and * receive, or one buffer for both send and receive, or no buffer for receive. * The receive buffer must be at least as big as the send buffer to prevent * unwanted memory writes. This implies that the byte count passed in as an * argument must be the smaller of the two buffers if they differ in size. * Here are some sample usages: * <pre> * XSpiPs_PolledTransfer(InstancePtr, SendBuf, RecvBuf, ByteCount) * The caller wishes to send and receive, and provides two different * buffers for send and receive. * * XSpiPs_PolledTransfer(InstancePtr, SendBuf, NULL, ByteCount) * The caller wishes only to send and does not care about the received * data. The driver ignores the received data in this case. * * XSpiPs_PolledTransfer(InstancePtr, SendBuf, SendBuf, ByteCount) * The caller wishes to send and receive, but provides the same buffer * for doing both. The driver sends the data and overwrites the send * buffer with received data as it transfers the data. * * XSpiPs_PolledTransfer(InstancePtr, RecvBuf, RecvBuf, ByteCount) * The caller wishes to only receive and does not care about sending * data. In this case, the caller must still provide a send buffer, but * it can be the same as the receive buffer if the caller does not care * what it sends. The device must send N bytes of data if it wishes to * receive N bytes of data. * * </pre> * * @param InstancePtr is a pointer to the XSpiPs instance. * @param SendBufPtr is a pointer to a buffer of data for sending. * This buffer must not be NULL. * @param RecvBufPtr is a pointer to a buffer for received data. * This argument can be NULL if do not care about receiving. * @param ByteCount contains the number of bytes to send/receive. * The number of bytes received always equals the number of bytes * sent. * @return * - XST_SUCCESS if the buffers are successfully handed off to the * device for transfer. * - XST_DEVICE_BUSY indicates that a data transfer is already in * progress. This is determined by the driver. * * @note * * This function is not thread-safe. The higher layer software must ensure that * no two threads are transferring data on the SPI bus at the same time. * ******************************************************************************/ s32 XSpiPs_PolledTransfer(XSpiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, u32 ByteCount) { u32 StatusReg; u32 ConfigReg; u32 TransCount; u32 CheckTransfer; s32 Status_Polled; u8 TempData; /* * The RecvBufPtr argument can be NULL. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SendBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0U); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy == TRUE) { Status_Polled = (s32)XST_DEVICE_BUSY; } else { /* * Set the busy flag, which will be cleared when the transfer is * entirely done. */ InstancePtr->IsBusy = TRUE; /* * Set up buffer pointers. */ InstancePtr->SendBufferPtr = SendBufPtr; InstancePtr->RecvBufferPtr = RecvBufPtr; InstancePtr->RequestedBytes = ByteCount; InstancePtr->RemainingBytes = ByteCount; /* * If manual chip select mode, initialize the slave select value. */ if (XSpiPs_IsManualChipSelect(InstancePtr) == TRUE) { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); /* * Set the slave select value. */ ConfigReg &= (u32)(~XSPIPS_CR_SSCTRL_MASK); ConfigReg |= InstancePtr->SlaveSelect; XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } /* * Enable the device. */ XSpiPs_Enable(InstancePtr); while((InstancePtr->RemainingBytes > (u32)0U) || (InstancePtr->RequestedBytes > (u32)0U)) { TransCount = 0U; /* * Fill the TXFIFO with as many bytes as it will take (or as * many as we have to send). */ while ((InstancePtr->RemainingBytes > (u32)0U) && ((u32)TransCount < (u32)XSPIPS_FIFO_DEPTH)) { XSpiPs_SendByte(InstancePtr->Config.BaseAddress, *InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 1; InstancePtr->RemainingBytes--; ++TransCount; } /* * If master mode and manual start mode, issue manual start * command to start the transfer. */ if ((XSpiPs_IsManualStart(InstancePtr) == TRUE) && (XSpiPs_IsMaster(InstancePtr) == TRUE)) { ConfigReg = XSpiPs_ReadReg( InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_MANSTRT_MASK; XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } /* * Wait for the transfer to finish by polling Tx fifo status. */ CheckTransfer = (u32)0U; while (CheckTransfer == 0U) { StatusReg = XSpiPs_ReadReg( InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET); if ( (StatusReg & XSPIPS_IXR_MODF_MASK) != 0U) { /* * Clear the mode fail bit */ XSpiPs_WriteReg( InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET, XSPIPS_IXR_MODF_MASK); return (s32)XST_SEND_ERROR; } CheckTransfer = (StatusReg & XSPIPS_IXR_TXOW_MASK); } /* * A transmit has just completed. Process received data and * check for more data to transmit. * First get the data received as a result of the transmit * that just completed. Receive data based on the * count obtained while filling tx fifo. Always get the * received data, but only fill the receive buffer if it * points to something (the upper layer software may not * care to receive data). */ while (TransCount != (u32)0U) { TempData = (u8)XSpiPs_RecvByte( InstancePtr->Config.BaseAddress); if (InstancePtr->RecvBufferPtr != NULL) { *(InstancePtr->RecvBufferPtr) = TempData; InstancePtr->RecvBufferPtr += 1; } InstancePtr->RequestedBytes--; --TransCount; } } /* * Clear the slave selects now, before terminating the transfer. */ if (XSpiPs_IsManualChipSelect(InstancePtr) == TRUE) { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_SSCTRL_MASK; XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } /* * Clear the busy flag. */ InstancePtr->IsBusy = FALSE; /* * Disable the device. */ XSpiPs_Disable(InstancePtr); Status_Polled = (s32)XST_SUCCESS; } return Status_Polled; }