📄 xqspips.c
字号:
* calls when it encounters conditions that should be reported to upper* layer software. The handler executes in an interrupt context, so it must* minimize the amount of processing performed. One of the following status* events is passed to the status handler.** <pre>* XST_SPI_MODE_FAULT A mode fault error occurred, meaning the device* is selected as slave while being a master.** XST_SPI_TRANSFER_DONE The requested data transfer is done** XST_SPI_TRANSMIT_UNDERRUN As a slave device, the master clocked data* but there were none available in the transmit* register/FIFO. This typically means the slave* application did not issue a transfer request* fast enough, or the processor/driver could not* fill the transmit register/FIFO fast enough.** XST_SPI_RECEIVE_OVERRUN The QSPI device lost data. Data was received* but the receive data register/FIFO was full.** XST_SPI_SLAVE_MODE_FAULT A slave QSPI device was selected as a slave* while it was disabled. This indicates the* master is already transferring data (which is* being dropped until the slave application* issues a transfer).* </pre>* @param InstancePtr is a pointer to the XQspiPs instance.* @param CallBackRef is the upper layer callback reference passed back* when the callback function is invoked.* @param FuncPtr is the pointer to the callback function.** @return None.** @note** The handler is called within interrupt context, so it should do its work* quickly and queue potentially time-consuming work to a task-level thread.*******************************************************************************/void XQspiPs_SetStatusHandler(XQspiPs *InstancePtr, void *CallBackRef, XQspiPs_StatusHandler FuncPtr){ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(FuncPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); InstancePtr->StatusHandler = FuncPtr; InstancePtr->StatusRef = CallBackRef;}/*****************************************************************************//**** This is a stub for the status callback. The stub is here in case the upper* layers forget to set the handler.** @param CallBackRef is a pointer to the upper layer callback reference* @param StatusEvent is the event that just occurred.* @param ByteCount is the number of bytes transferred up until the event* occurred.** @return None.** @note None.*******************************************************************************/static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, unsigned ByteCount){ (void) CallBackRef; (void) StatusEvent; (void) ByteCount; Xil_AssertVoidAlways();}/*****************************************************************************//**** The interrupt handler for QSPI 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 QSPI 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* QSPI 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.** @param InstancePtr is a pointer to the XQspiPs 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 XQspiPs_InterruptHandler(void *InstancePtr){ XQspiPs *SpiPtr = (XQspiPs *)InstancePtr; u32 IntrStatus; u32 ControlReg; unsigned 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. This occurs because we * transmit from within the ISR, which could potentially cause another * TX_EMPTY interrupt. */ IntrStatus = XQspiPs_ReadReg(SpiPtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_SR_OFFSET, IntrStatus); /* * 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 (XQSPIPS_IXR_MODF_MASK == (IntrStatus & XQSPIPS_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. */ XQspiPs_Abort(SpiPtr); SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_MODE_FAULT, BytesDone); return; /* Do not continue servicing other interrupts. */ } while(TRUE){ u32 Data; /* * 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). */ if (0 !=(IntrStatus & XQSPIPS_IXR_RXNEMPTY_MASK)){ Data = XQspiPs_ReadReg(SpiPtr->Config.BaseAddress, XQSPIPS_RXD_OFFSET); if (SpiPtr->RequestedBytes < 4) { XQspiPs_GetReadData(SpiPtr, Data, SpiPtr->RequestedBytes); } else { XQspiPs_GetReadData(SpiPtr, Data, 4); } } /* * See if there is more data to send and RX FIFO is not full. */ if ((SpiPtr->RemainingBytes > 0) && (0 == (IntrStatus & (XQSPIPS_IXR_TXFULL_MASK | XQSPIPS_IXR_RXFULL_MASK)))) { /* * Send more data. */ if (SpiPtr->RemainingBytes < 4) { XQspiPs_GetWriteData(SpiPtr, &Data, SpiPtr->RemainingBytes); } else { XQspiPs_GetWriteData(SpiPtr, &Data, 4); } XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_TXD_00_OFFSET, Data); } /* * Exit the loop if all the data available at this time has been * received and either there is no more data to send, or the * FIFO is above the water mark. */ IntrStatus = XQspiPs_ReadReg(SpiPtr->Config.BaseAddress, XQSPIPS_SR_OFFSET); if ((0 == (IntrStatus & XQSPIPS_IXR_RXNEMPTY_MASK)) && ((0 == (IntrStatus & XQSPIPS_IXR_TXOW_MASK)) || (0 == SpiPtr->RemainingBytes))) { break; } } ControlReg = XQspiPs_ReadReg(SpiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); if ((SpiPtr->RemainingBytes == 0) && (SpiPtr->RequestedBytes == 0)) { /* * 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. */ XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_IDR_OFFSET, XQSPIPS_IXR_DFLT_MASK); SpiPtr->IsBusy = FALSE; /* * Disable the device. */ XQspiPs_Disable(SpiPtr->Config.BaseAddress); /* * If the Slave select lines are being manually controlled, * disable them because the transfer is complete. */ if (0 != (ControlReg & XQSPIPS_CR_SSFORCE_MASK)) { ControlReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ControlReg); } SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_TRANSFER_DONE, SpiPtr->RequestedBytes); } else { /* * If, in Manual Start mode, start the transfer. */ if ((ControlReg & (XQSPIPS_CR_MSTREN_MASK | XQSPIPS_CR_MANSTRTEN_MASK)) == (XQSPIPS_CR_MSTREN_MASK | XQSPIPS_CR_MANSTRTEN_MASK)) { ControlReg |= XQSPIPS_CR_MANSTRT_MASK; XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ControlReg); } } /* * Check for overflow and underflow errors. */ if (IntrStatus & XQSPIPS_IXR_RXOVR_MASK) { BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; SpiPtr->IsBusy = FALSE; /* * If the Slave select lines are being manually controlled, * disable them because the transfer is complete. */ if (0 != (ControlReg & XQSPIPS_CR_SSFORCE_MASK)){ ControlReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ControlReg); } SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_RECEIVE_OVERRUN, BytesDone); } if (IntrStatus & XQSPIPS_IXR_TXUF_MASK) { BytesDone = SpiPtr->RequestedBytes - SpiPtr->RemainingBytes; SpiPtr->IsBusy = FALSE; /* * If the Slave select lines are being manually controlled, * disable them because the transfer is complete. */ if (0 != (ControlReg & XQSPIPS_CR_SSFORCE_MASK)){ ControlReg |= XQSPIPS_CR_SSCTRL_MASK; XQspiPs_WriteReg(SpiPtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ControlReg); } SpiPtr->StatusHandler(SpiPtr->StatusRef, XST_SPI_TRANSMIT_UNDERRUN, BytesDone); }}/*****************************************************************************//**** Copies data from the Transmit buffer. Since QSPI supports only 32-bit* transfers, this function appends 0xFF if the requested size is less than 4.** @param InstancePtr is a pointer to the XQspiPs instance.* @param Data is a ouput parameter, to which the data read from the* Transmit buffer is to be copied.* @param Size is the number of bytes to be copied from the Transmit* buffer.** @return None.** @note None.*******************************************************************************/static void XQspiPs_GetWriteData(XQspiPs *InstancePtr, u32 *Data, u8 Size){ if (InstancePtr->SendBufferPtr) { switch (Size) { case 1: *Data = *((u8 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 1; *Data |= 0xFFFFFF00; break; case 2: *Data = *((u16 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 2; *Data |= 0xFFFF0000; break; case 3: *Data = *((u16 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 2; *Data |= (*((u8 *)InstancePtr->SendBufferPtr) << 16); InstancePtr->SendBufferPtr += 1; *Data |= 0xFF000000; break; case 4: *Data = *((u32 *)InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 4; break; default: /* This will never execute */ break; } } else *Data = 0; InstancePtr->RemainingBytes -= Size; if (InstancePtr->RemainingBytes < 0) { InstancePtr->RemainingBytes = 0; }}/*****************************************************************************//**** Copies data from Data to the Receive buffer.** @param InstancePtr is a pointer to the XQspiPs instance.* @param Data is the data which needs to be copied to the Rx buffer.* @param Size is the number of bytes to be copied to the Receive buffer.** @return None.** @note None.*******************************************************************************/static void XQspiPs_GetReadData(XQspiPs *InstancePtr, u32 Data, u8 Size){ u8 byte3; if (InstancePtr->RecvBufferPtr) { switch (Size) { case 1: *((u8 *)InstancePtr->RecvBufferPtr) = Data; InstancePtr->RecvBufferPtr += 1; break; case 2: *((u16 *)InstancePtr->RecvBufferPtr) = Data; InstancePtr->RecvBufferPtr += 2; break; case 3: *((u16 *)InstancePtr->RecvBufferPtr) = Data; InstancePtr->RecvBufferPtr += 2; byte3 = (u8)(Data >> 16); *((u8 *)InstancePtr->RecvBufferPtr) = byte3; InstancePtr->RecvBufferPtr += 1; break; case 4: (*(u32 *)InstancePtr->RecvBufferPtr) = Data; InstancePtr->RecvBufferPtr += 4; break; default: /* This will never execute */ break; } } InstancePtr->RequestedBytes -= Size; if (InstancePtr->RequestedBytes < 0) { InstancePtr->RequestedBytes = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -