/** * * This function sets the options for the SPI device driver. The options control * how the device behaves relative to the SPI bus. The device must be idle * rather than busy transferring data before setting these device options. * * @param InstancePtr is a pointer to the XSpiPs instance. * @param Options contains the specified options to be set. This is a bit * mask where a 1 means to turn the option on, and a 0 means to * turn the option off. One or more bit values may be contained in * the mask. See the bit definitions named XSPIPS_*_OPTIONS in the * file xspips.h. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_BUSY if the device is currently transferring data. * The transfer must complete or be aborted before setting options. * * @note * This function is not thread-safe. * ******************************************************************************/ s32 XSpiPs_SetOptions(XSpiPs *InstancePtr, u32 Options) { u32 ConfigReg; u32 Index; u32 CurrentConfigReg; s32 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Do not allow the slave select to change while a transfer is in * progress. Not thread-safe. */ if (InstancePtr->IsBusy == TRUE) { Status = (s32)XST_DEVICE_BUSY; } else { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); CurrentConfigReg = ConfigReg; /* * Loop through the options table, turning the option on or off * depending on whether the bit is set in the incoming options flag. */ for (Index = 0U; Index < XSPIPS_NUM_OPTIONS; Index++) { if ((Options & OptionsTable[Index].Option) != (u32)0U) { /* Turn it on */ ConfigReg |= OptionsTable[Index].Mask; } else { /* Turn it off */ ConfigReg &= ~(OptionsTable[Index].Mask); } } /* * If CPOL-CPHA bits are toggled from previous state, * disable before writing the configuration register and then enable. */ if( ((CurrentConfigReg & XSPIPS_CR_CPOL_MASK) != (ConfigReg & XSPIPS_CR_CPOL_MASK)) || ((CurrentConfigReg & XSPIPS_CR_CPHA_MASK) != (ConfigReg & XSPIPS_CR_CPHA_MASK)) ) { XSpiPs_Disable(InstancePtr); } /* * Now write the Config register. Leave it to the upper layers * to restart the device. */ XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); /* * Enable */ if( ((CurrentConfigReg & XSPIPS_CR_CPOL_MASK) != (ConfigReg & XSPIPS_CR_CPOL_MASK)) || ((CurrentConfigReg & XSPIPS_CR_CPHA_MASK) != (ConfigReg & XSPIPS_CR_CPHA_MASK)) ) { XSpiPs_Enable(InstancePtr); } Status = (s32)XST_SUCCESS; } return Status; }
/** * * Transfers specified data on the SPI bus. If the SPI device is configured as * a master, this function initiates bus communication and sends/receives the * data to/from the selected SPI slave. If the SPI device is configured as a * slave, this function prepares the buffers to be sent/received when selected * by a master. For every byte sent, a byte is received. This function should * be used to perform interrupt based transfers. * * 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_Transfer(InstancePtr, SendBuf, RecvBuf, ByteCount) * The caller wishes to send and receive, and provides two different * buffers for send and receive. * * XSpiPs_Transfer(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_Transfer(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_Transfer(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> * Although this function takes entire buffers as arguments, the driver can only * transfer a limited number of bytes at a time, limited by the size of the * FIFO. A call to this function only starts the transfer, then subsequent * transfers of the data is performed by the interrupt service routine until * the entire buffer has been transferred. The status callback function is * called when the entire buffer has been sent/received. * * This function is non-blocking. As a master, the SetSlaveSelect function must * be called prior to this function. * * @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_Transfer(XSpiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, u32 ByteCount) { u32 ConfigReg; u8 TransCount = 0U; s32 StatusTransfer; /* * The RecvBufPtr argument can be null */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SendBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0U); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy == TRUE) { StatusTransfer = (s32)XST_DEVICE_BUSY; } else { /* * Set the busy flag, which will be cleared in the ISR 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) != FALSE) { 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); /* * Clear all the interrrupts. */ XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET, XSPIPS_IXR_WR_TO_CLR_MASK); /* * Fill the TXFIFO with as many bytes as it will take (or as many as * we have to send). */ while ((InstancePtr->RemainingBytes > 0U) && (TransCount < XSPIPS_FIFO_DEPTH)) { XSpiPs_SendByte(InstancePtr->Config.BaseAddress, *InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr += 1; InstancePtr->RemainingBytes--; TransCount++; } /* * Enable interrupts (connecting to the interrupt controller and * enabling interrupts should have been done by the caller). */ XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_IER_OFFSET, XSPIPS_IXR_DFLT_MASK); /* * 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); } StatusTransfer = (s32)XST_SUCCESS; } return StatusTransfer; }
/** * 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; }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XSpiPs * device driver in Slave mode. This function reads data from a SPI Master * and will echo it back to the Master. * * @param SpiDeviceId is the Instance Id of SPI in the system. * * @return * - XST_SUCCESS if successful * - XST_FAILURE if not successful * * @note None * * *****************************************************************************/ int SpiPsSlavePolledExample(u16 SpiDeviceId) { int Status; u8 *BufferPtr; XSpiPs_Config *SpiConfig; /* * Initialize the SPI driver so that it's ready to use */ SpiConfig = XSpiPs_LookupConfig(SpiDeviceId); if (NULL == SpiConfig) { return XST_FAILURE; } Status = XSpiPs_CfgInitialize((&SpiInstance), SpiConfig, SpiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * The SPI device is a slave by default and the clock phase * have to be set according to its master. In this example, CPOL is set * to quiescent high and CPHA is set to 1. */ Status = XSpiPs_SetOptions((&SpiInstance), (XSPIPS_CR_CPHA_MASK) | \ (XSPIPS_CR_CPOL_MASK)); if (Status != XST_SUCCESS) { return XST_FAILURE; } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set the Rx FIFO Threshold to the Max Data */ XSpiPs_SetRXWatermark((&SpiInstance),MAX_DATA); /* * Enable the device. */ XSpiPs_Enable((&SpiInstance)); /* * Read the contents of the Receive buffer * Master is expected to send MAX_DATA number of bytes */ SpiSlaveRead(MAX_DATA); /* * Setup a pointer to the start of the data that was read into the read * buffer and the same back */ BufferPtr = ReadBuffer; /* * Send the data received back to Master * Master is expected to send MAX_DATA number of dummy bytes for * the slave to be able to echo previously received data. */ SpiSlaveWrite(BufferPtr, MAX_DATA); /* * Disable the device. */ XSpiPs_Disable((&SpiInstance)); return XST_SUCCESS; }