embeddedsw/XilinxProcessorIPLib/drivers/spips/src/xspips.c
Venkata Naga Sai Krishna Kolapalli 764f7417ec spips : Removed armcc compiler warnings.
This patch rearranges declaration lines to come before
executable code lines. This fixes armcc compiler warnings.

Signed-off-by: Venkata Naga Sai Krishna Kolapalli <venkatan@xilinx.com>
2015-04-26 10:30:22 +05:30

1126 lines
37 KiB
C

/******************************************************************************
*
* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xspips.c
*
* Contains implements the interface functions of the XSpiPs driver.
* See xspips.h for a detailed description of the device and driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------ -------- -----------------------------------------------
* 1.00 drg/jz 01/25/10 First release
* 1.01 sg 03/07/12 Updated the code to always clear the relevant bits
* before writing to config register.
* Always clear the slave select bits before write and
* clear the bits to no slave at the end of transfer
* Modified the Polled transfer transmit/receive logic.
* Tx should wait on TXOW Interrupt and Rx on RXNEMTY.
* 1.03 sg 09/21/12 Added memory barrier dmb in polled transfer and
* interrupt handler to overcome the clock domain
* crossing issue in the controller. For CR #679252.
* 1.04a sg 01/30/13 Changed SPI transfer logic for polled and interrupt
* modes to be based on filled tx fifo count and receive
* based on it. RXNEMPTY interrupt is not used.
* SetSlaveSelect API logic is modified to drive the bit
* position low based on the slave select value
* requested. GetSlaveSelect API will return the value
* based on bit position that is low.
* 1.06a hk 08/22/13 Changed GetSlaveSelect function. CR# 727866.
* Added masking ConfigReg before writing in SetSlaveSel
* Added extended slave select support - CR#722569.
* Added check for MODF in polled transfer function.
*
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xspips.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/****************************************************************************/
/*
*
* Send one byte to the currently selected slave. A byte of data is written to
* transmit FIFO/register.
*
* @param BaseAddress is the base address of the device
*
* @return None.
*
* @note C-Style signature:
* void XSpiPs_SendByte(u32 BaseAddress, u8 Data);
*
*****************************************************************************/
#define XSpiPs_SendByte(BaseAddress, Data) \
XSpiPs_Out32((BaseAddress) + (u32)XSPIPS_TXD_OFFSET, (u32)(Data))
/****************************************************************************/
/*
*
* Receive one byte from the device's receive FIFO/register. It is assumed
* that the byte is already available.
*
* @param BaseAddress is the base address of the device
*
* @return The byte retrieved from the receive FIFO/register.
*
* @note C-Style signature:
* u8 XSpiPs_RecvByte(u32 BaseAddress);
*
*****************************************************************************/
#define XSpiPs_RecvByte(BaseAddress) \
XSpiPs_In32((u32)((BaseAddress) + (u32)XSPIPS_RXD_OFFSET))
/************************** Function Prototypes ******************************/
static void StubStatusHandler(void *CallBackRef, u32 StatusEvent,
u32 ByteCount);
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
*
* Initializes a specific XSpiPs instance such that the driver is ready to use.
*
* The state of the device after initialization is:
* - Device is disabled
* - Slave mode
* - Active high clock polarity
* - Clock phase 0
*
* @param InstancePtr is a pointer to the XSpiPs instance.
* @param ConfigPtr is a reference to a structure containing information
* about a specific SPI device. This function initializes an
* InstancePtr object for a specific device specified by the
* contents of Config. This function can initialize multiple
* instance objects with the use of multiple calls giving different
* Config information on each call.
* @param EffectiveAddr is the device base address in the virtual memory
* address space. The caller is responsible for keeping the address
* mapping from EffectiveAddr to the device physical base address
* unchanged once this function is invoked. Unexpected errors may
* occur if the address mapping changes after this function is
* called. If address translation is not used, use
* ConfigPtr->Config.BaseAddress for this device.
*
* @return
* - XST_SUCCESS if successful.
* - XST_DEVICE_IS_STARTED if the device is already started.
* It must be stopped to re-initialize.
*
* @note None.
*
******************************************************************************/
s32 XSpiPs_CfgInitialize(XSpiPs *InstancePtr, XSpiPs_Config *ConfigPtr,
u32 EffectiveAddr)
{
s32 Status;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
/*
* If the device is busy, disallow the initialize and return a status
* indicating it is already started. This allows the user to stop the
* device and re-initialize, but prevents a user from inadvertently
* initializing. This assumes the busy flag is cleared at startup.
*/
if (InstancePtr->IsBusy == TRUE) {
Status = (s32)XST_DEVICE_IS_STARTED;
} else {
/*
* Set some default values.
*/
InstancePtr->IsBusy = FALSE;
InstancePtr->Config.BaseAddress = EffectiveAddr;
InstancePtr->StatusHandler = StubStatusHandler;
InstancePtr->SendBufferPtr = NULL;
InstancePtr->RecvBufferPtr = NULL;
InstancePtr->RequestedBytes = 0U;
InstancePtr->RemainingBytes = 0U;
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
/*
* Reset the SPI device to get it into its initial state. It is
* expected that device configuration will take place after this
* initialization is done, but before the device is started.
*/
XSpiPs_Reset(InstancePtr);
Status = (s32)XST_SUCCESS;
}
return Status;
}
/*****************************************************************************/
/**
*
* Resets the SPI device. Reset must only be called after the driver has been
* initialized. The configuration of the device after reset is the same as its
* configuration after initialization. Any data transfer that is in progress
* is aborted.
*
* The upper layer software is responsible for re-configuring (if necessary)
* and restarting the SPI device after the reset.
*
* @param InstancePtr is a pointer to the XSpiPs instance.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void XSpiPs_Reset(XSpiPs *InstancePtr)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/*
* Abort any transfer that is in progress
*/
XSpiPs_Abort(InstancePtr);
/*
* Reset any values that are not reset by the hardware reset such that
* the software state matches the hardware device
*/
XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET,
XSPIPS_CR_RESET_STATE);
}
/*****************************************************************************/
/**
*
* 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;
}
/*****************************************************************************/
/**
*
* Selects or deselect the slave with which the master communicates. This setting
* affects the SPI_ss_outN signals. The behavior depends on the setting of the
* CR_SSDECEN bit. If CR_SSDECEN is 0, the SPI_ss_outN bits will be output with a
* single signal low. If CR_SSDECEN is 1, the SPI_ss_outN bits will reflect the
* value set.
*
* The user is not allowed to deselect the slave while a transfer is in progress.
* If no transfer is in progress, the user can select a new slave, which
* implicitly deselects the current slave. In order to explicitly deselect the
* current slave, a value of all 1's, 0x0F can be passed in as the argument to
* the function.
*
* @param InstancePtr is a pointer to the XSpiPs instance.
* @param SlaveSel is the slave number to be selected.
* Normally, 3 slaves can be selected with values 0-2.
* In case, 3-8 decode option is set, then upto 8 slaves
* can be selected. Only one slave can be selected at a time.
*
* @return
* - XST_SUCCESS if the slave is selected or deselected
* successfully.
* - XST_DEVICE_BUSY if a transfer is in progress, slave cannot be
* changed.
*
* @note
*
* This function only sets the slave which will be selected when a transfer
* occurs. The slave is not selected when the SPI is idle. The slave select
* has no affect when the device is configured as a slave.
*
******************************************************************************/
s32 XSpiPs_SetSlaveSelect(XSpiPs *InstancePtr, u8 SlaveSel)
{
u32 ConfigReg;
s32 Status_Slave;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Xil_AssertNonvoid(SlaveSel <= XSPIPS_CR_SSCTRL_MAXIMUM);
/*
* Do not allow the slave select to change while a transfer is in
* progress. Not thread-safe.
*/
if (InstancePtr->IsBusy == TRUE) {
Status_Slave = (s32)XST_DEVICE_BUSY;
} else {
/*
* If decode slave select option is set,
* then set slave select value directly.
* Update the Instance structure member.
*/
if ( XSpiPs_IsDecodeSSelect( InstancePtr ) == TRUE) {
InstancePtr->SlaveSelect = ((u32)SlaveSel) << XSPIPS_CR_SSCTRL_SHIFT;
}
else {
/*
* Set the bit position to low using SlaveSel. Update the Instance
* structure member.
*/
InstancePtr->SlaveSelect = ((~(1U << SlaveSel)) & \
XSPIPS_CR_SSCTRL_MAXIMUM) << XSPIPS_CR_SSCTRL_SHIFT;
}
/*
* Read the config register, update the slave select value and write
* back to config register.
*/
ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress,
XSPIPS_CR_OFFSET);
ConfigReg &= (u32)(~XSPIPS_CR_SSCTRL_MASK);
ConfigReg |= InstancePtr->SlaveSelect;
XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET,
ConfigReg);
Status_Slave = (s32)XST_SUCCESS;
}
return Status_Slave;
}
/*****************************************************************************/
/**
*
* Gets the current slave select setting for the SPI device.
*
* @param InstancePtr is a pointer to the XSpiPs instance.
*
* @return The slave number selected (starting from 0).
*
* @note None.
*
******************************************************************************/
u8 XSpiPs_GetSlaveSelect(XSpiPs *InstancePtr)
{
u32 ConfigReg;
u32 SlaveSel;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
ConfigReg = InstancePtr->SlaveSelect;
ConfigReg &= XSPIPS_CR_SSCTRL_MASK;
ConfigReg >>= XSPIPS_CR_SSCTRL_SHIFT;
ConfigReg &= XSPIPS_CR_SSCTRL_MAXIMUM;
/*
* If decode slave select option is set, then read value directly.
*/
if ( XSpiPs_IsDecodeSSelect( InstancePtr ) == TRUE) {
SlaveSel = ConfigReg;
}
else {
/*
* Get the slave select value
*/
if(ConfigReg == 0x0FU) {
/*
* No slave selected
*/
SlaveSel = 0xFU;
}else {
/*
* Get selected slave number (0,1 or 2)
*/
SlaveSel = ((~ConfigReg) & XSPIPS_CR_SSCTRL_MAXIMUM)/2;
}
}
return (u8)SlaveSel;
}
/*****************************************************************************/
/**
*
* Sets the status callback function, the status handler, which the driver
* 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 SPI device lost data. Data was received
* but the receive data register/FIFO was full.
*
* XST_SPI_SLAVE_MODE_FAULT A slave SPI 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 XSpiPs instance.
* @param CallBackRef is the upper layer callback reference passed back
* when the callback function is invoked.
* @param FunctionPtr 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 XSpiPs_SetStatusHandler(XSpiPs *InstancePtr, void *CallBackRef,
XSpiPs_StatusHandler FunctionPtr)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(FunctionPtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
InstancePtr->StatusHandler = FunctionPtr;
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,
u32 ByteCount)
{
(void) CallBackRef;
(void) StatusEvent;
(void) ByteCount;
Xil_AssertVoidAlways();
}
/*****************************************************************************/
/**
*
* 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);
}
}
/*****************************************************************************/
/**
*
* 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;
}