Exemple #1
0
/***************************************************************************//**
 * @brief spi_read
*******************************************************************************/
int32_t spi_read(uint8_t *data,
				 uint8_t bytes_number)
{
	uint32_t cnt		 = 0;
#ifdef _XPARAMETERS_PS_H_
	uint32_t base_addr	 = 0;
	uint32_t control_val = 0;
	uint32_t status	  	 = 0;

	base_addr = spi_config->BaseAddress;
	control_val = XSpiPs_ReadReg(base_addr, XSPIPS_CR_OFFSET);

	XSpiPs_WriteReg(base_addr, XSPIPS_CR_OFFSET,
					control_val & ~(1 << XSPIPS_CR_SSCTRL_SHIFT));

	XSpiPs_WriteReg(base_addr, XSPIPS_TXWR_OFFSET, 0x01);

	XSpiPs_WriteReg(base_addr, XSPIPS_SR_OFFSET, XSPIPS_IXR_TXOW_MASK);
	XSpiPs_WriteReg(base_addr, XSPIPS_IER_OFFSET, XSPIPS_IXR_TXOW_MASK);

	while(cnt < bytes_number)
	{
		XSpiPs_WriteReg(base_addr, XSPIPS_TXD_OFFSET, data[cnt]);
		cnt++;
	}

	XSpiPs_WriteReg(base_addr, XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK);

	do
	{
		status = XSpiPs_ReadReg(base_addr, XSPIPS_SR_OFFSET);
	}
	while((status & XSPIPS_IXR_TXOW_MASK) == 0x0);

	XSpiPs_WriteReg(base_addr, XSPIPS_SR_OFFSET, XSPIPS_IXR_TXOW_MASK);

	XSpiPs_WriteReg(base_addr, XSPIPS_CR_OFFSET, control_val);

	cnt = 0;
	while(cnt < bytes_number)
	{
		data[cnt] = XSpiPs_ReadReg(base_addr, XSPIPS_RXD_OFFSET);
		cnt++;
	}

	XSpiPs_WriteReg(base_addr, XSPIPS_ER_OFFSET, 0x0);
#else
	uint8_t send_buffer[20];

	for(cnt = 0; cnt < bytes_number; cnt++)
	{
		send_buffer[cnt] = data[cnt];
	}

	XSpi_Transfer(&spi_instance, send_buffer, data, bytes_number);
#endif
	return SUCCESS;
}
/**
*
* This function sets the delay register for the SPI device driver.
* The delay register controls the Delay Between Transfers, Delay After
* Transfers, and the Delay Initially. The default value is 0x0. The range of
* each delay value is 0-255.
*
* @param	InstancePtr is a pointer to the XSpiPs instance.
* @param	DelayNss is the delay for which the chip select outputs will
*		be de-asserted between words when CPHA=0.
* @param	DelayBtwn is the delay between one Slave Select being
*		de-activated and the activation of another slave. The delay is
*		the number of master clock periods given by DelayBtwn + 2.
* @param	DelayAfter define the delay between the last bit of the current
*		byte transfer and the first bit of the next byte transfer.
*		The delay in number of master clock periods is given as:
*		CPHA=0:DelayInit+DelayAfter+3
*		CPHA=1:DelayAfter+1
* @param	DelayInit is the delay between asserting the slave select signal
*		and the first bit transfer. The delay int number of master clock
*		periods is DelayInit+1.
*
* @return
*		- XST_SUCCESS if delays are successfully set.
*		- XST_DEVICE_BUSY if the device is currently transferring data.
*		The transfer must complete or be aborted before setting options.
*
* @note		None.
*
******************************************************************************/
s32 XSpiPs_SetDelays(XSpiPs *InstancePtr, u8 DelayNss, u8 DelayBtwn,
			 u8 DelayAfter, u8 DelayInit)
{
	u32 DelayRegister;
	s32 Status;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * Do not allow the delays to change while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy == TRUE) {
		Status = (s32)XST_DEVICE_BUSY;
	} else {

		/* Shift, Mask and OR the values to build the register settings */
		DelayRegister = (u32) DelayNss << XSPIPS_DR_NSS_SHIFT;
		DelayRegister |= (u32) DelayBtwn << XSPIPS_DR_BTWN_SHIFT;
		DelayRegister |= (u32) DelayAfter << XSPIPS_DR_AFTER_SHIFT;
		DelayRegister |= (u32) DelayInit;

		XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,
				XSPIPS_DR_OFFSET, DelayRegister);

		Status = (s32)XST_SUCCESS;
	}
	return Status;
}
Exemple #3
0
/**
*
* 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;
}
/**
*
* 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 an 3-bit mask with a 1 in the bit position of the
*		slave being selected. Only one slave can be selected.
*
* @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.
*
******************************************************************************/
int XSpiPs_SetSlaveSelect(XSpiPs *InstancePtr, u8 SlaveSel)
{
	u32 ConfigReg;

	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) {
		return XST_DEVICE_BUSY;
	}

	/*
	 * Set the bit position to low using SlaveSel. Update the Instance
	 * structure member.
	 */
	InstancePtr->SlaveSelect = ((~(1 << 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 |= InstancePtr->SlaveSelect;
	XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET,
			 ConfigReg);

	return XST_SUCCESS;
}
/**
*
* 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;
}
Exemple #6
0
/**
*
* 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;
}
Exemple #7
0
/**
*
* 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);

}
Exemple #8
0
/***************************************************************************//**
 * @brief spi_init
*******************************************************************************/
int32_t spi_init(uint32_t device_id,
				 uint8_t  clk_pha,
				 uint8_t  clk_pol)
{

	uint32_t base_addr	 = 0;
	uint32_t control_val = 0;
#ifdef _XPARAMETERS_PS_H_
	uint8_t  byte		 = 0;

	spi_config = XSpiPs_LookupConfig(device_id);
	base_addr = spi_config->BaseAddress;
	XSpiPs_CfgInitialize(&spi_instance, spi_config, base_addr);

	control_val = XSPIPS_CR_SSFORCE_MASK |
				  XSPIPS_CR_SSCTRL_MASK |
				  4 << XSPIPS_CR_PRESC_SHIFT |
				  (clk_pha ? XSPIPS_CR_CPHA_MASK : 0) |
				  (clk_pol ? XSPIPS_CR_CPOL_MASK : 0) |
				  XSPIPS_CR_MSTREN_MASK;

	XSpiPs_WriteReg(base_addr, XSPIPS_CR_OFFSET, control_val);

	for(byte = 0; byte < 128; byte++)
	{
		XSpiPs_ReadReg(base_addr, XSPIPS_RXD_OFFSET);
	}
#else
	XSpi_Initialize(&spi_instance, device_id);
	XSpi_Stop(&spi_instance);
	spi_config = XSpi_LookupConfig(device_id);
	base_addr = spi_config->BaseAddress;
	XSpi_CfgInitialize(&spi_instance, spi_config, base_addr);
	control_val = XSP_MASTER_OPTION |
				  XSP_CLK_PHASE_1_OPTION |
				  XSP_MANUAL_SSELECT_OPTION;
	XSpi_SetOptions(&spi_instance, control_val);
	XSpi_Start(&spi_instance);
	XSpi_IntrGlobalDisable(&spi_instance);
	XSpi_SetSlaveSelect(&spi_instance, 1);
#endif
	return SUCCESS;
}
Exemple #9
0
/**
*
* Resets the spi module
*
* @param    BaseAddress is the base address of the device.
*
* @return	None
*
* @note		None.
*
******************************************************************************/
void XSpiPs_ResetHw(u32 BaseAddress)
{
	u32 Check;
	/*
	 * Disable Interrupts
	 */
	XSpiPs_WriteReg(BaseAddress, XSPIPS_IDR_OFFSET,
			XSPIPS_IXR_DISABLE_ALL_MASK);

	/*
	 * Disable device
	 */
	XSpiPs_WriteReg(BaseAddress, XSPIPS_ER_OFFSET,
				0U);
	/*
	 * Write default value to RX and TX threshold registers
	 * RX threshold should be set to 1 here as the corresponding
	 * status bit is used to clear the FIFO next
	 */
	XSpiPs_WriteReg(BaseAddress, XSPIPS_TXWR_OFFSET,
			(XSPIPS_TXWR_RESET_VALUE & XSPIPS_TXWR_MASK));
	XSpiPs_WriteReg(BaseAddress, XSPIPS_RXWR_OFFSET,
			(XSPIPS_RXWR_RESET_VALUE & XSPIPS_RXWR_MASK));

	/*
	 * Clear RXFIFO
	 */
	Check = (XSpiPs_ReadReg(BaseAddress,XSPIPS_SR_OFFSET) &
		XSPIPS_IXR_RXNEMPTY_MASK);
	while (Check != 0U) {
		(void)XSpiPs_ReadReg(BaseAddress, XSPIPS_RXD_OFFSET);
		Check = (XSpiPs_ReadReg(BaseAddress,XSPIPS_SR_OFFSET) &
			XSPIPS_IXR_RXNEMPTY_MASK);
	}

	/*
	 * Clear status register by writing 1 to the write to clear bits
	 */
	XSpiPs_WriteReg(BaseAddress, XSPIPS_SR_OFFSET,
				XSPIPS_IXR_WR_TO_CLR_MASK);

	/*
	 * Write default value to configuration register
	 * De-select all slaves
	 */
	XSpiPs_WriteReg(BaseAddress, XSPIPS_CR_OFFSET,
				XSPIPS_CR_RESET_STATE |
				XSPIPS_CR_SSCTRL_MASK);

}
/**
*
* This function sets the clock prescaler for an SPI device. 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	Prescaler is the value that determine how much the clock should
*		be divided by. Use the XSPIPS_CLK_PRESCALE_* constants defined
*		in xspips.h for this setting.
*
* @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_SetClkPrescaler(XSpiPs *InstancePtr, u8 Prescaler)
{
	u32 ConfigReg;
	s32 Status;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid((Prescaler > 0U) && (Prescaler <= XSPIPS_CR_PRESC_MAXIMUM));

	/*
	 * Do not allow the prescaler to be changed while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy == TRUE) {
		Status = (s32)XST_DEVICE_BUSY;
	} else {

		/*
		 * Read the Config register, mask out the interesting bits, and set
		 * them with the shifted value passed into the function. Write the
		 * results back to the Config register.
		 */
		ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress,
					 XSPIPS_CR_OFFSET);

		ConfigReg &= (u32)(~XSPIPS_CR_PRESC_MASK);
		ConfigReg |= (u32) ((u32)Prescaler & (u32)XSPIPS_CR_PRESC_MAXIMUM) <<
			XSPIPS_CR_PRESC_SHIFT;

		XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,
				XSPIPS_CR_OFFSET,
				ConfigReg);

		Status = (s32)XST_SUCCESS;
	}
	return Status;
}
/**
*
* 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;
}
Exemple #12
0
/**
*
* 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);
    }

}
Exemple #13
0
/**
* 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;
}
Exemple #14
0
/**
*
* 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;
}
Exemple #15
0
/***************************************************************************//**
 * @brief spi_read
*******************************************************************************/
int32_t spi_read(struct spi_device *spi,
				 uint8_t *data,
				 uint8_t bytes_number)
{
	uint32_t cnt		 = 0;
#ifdef _XPARAMETERS_PS_H_
	uint32_t base_addr	 = 0;
	uint32_t control_val = 0;
	uint32_t status	  	 = 0;

	base_addr = spi_config->BaseAddress;
	control_val = XSpiPs_ReadReg(base_addr, XSPIPS_CR_OFFSET);

	XSpiPs_WriteReg(base_addr, XSPIPS_CR_OFFSET,
					control_val & ~((spi->id_no == 0 ? 1 : 2) << XSPIPS_CR_SSCTRL_SHIFT));

	XSpiPs_WriteReg(base_addr, XSPIPS_TXWR_OFFSET, 0x01);

	XSpiPs_WriteReg(base_addr, XSPIPS_SR_OFFSET, XSPIPS_IXR_TXOW_MASK);
	XSpiPs_WriteReg(base_addr, XSPIPS_IER_OFFSET, XSPIPS_IXR_TXOW_MASK);

	while(cnt < bytes_number)
	{
		XSpiPs_WriteReg(base_addr, XSPIPS_TXD_OFFSET, data[cnt]);
		cnt++;
	}

	XSpiPs_WriteReg(base_addr, XSPIPS_ER_OFFSET, XSPIPS_ER_ENABLE_MASK);

	do
	{
		status = XSpiPs_ReadReg(base_addr, XSPIPS_SR_OFFSET);
	}
	while((status & XSPIPS_IXR_TXOW_MASK) == 0x0);

	XSpiPs_WriteReg(base_addr, XSPIPS_SR_OFFSET, XSPIPS_IXR_TXOW_MASK);

	XSpiPs_WriteReg(base_addr, XSPIPS_CR_OFFSET, control_val);

	cnt = 0;
	while(cnt < bytes_number)
	{
		data[cnt] = XSpiPs_ReadReg(base_addr, XSPIPS_RXD_OFFSET);
		cnt++;
	}

	XSpiPs_WriteReg(base_addr, XSPIPS_ER_OFFSET, 0x0);
#else
#ifdef XPAR_AXI_SPI_0_DEVICE_ID
	uint8_t send_buffer[20];

	for(cnt = 0; cnt < bytes_number; cnt++)
	{
		send_buffer[cnt] = data[cnt];
	}

	XSpi_Transfer(&spi_instance, send_buffer, data, bytes_number);
#else
	Xil_Out32((spi_instance.BaseAddr + 0x60), 0x1e6);
	Xil_Out32((spi_instance.BaseAddr + 0x70), 0x000);
	while(cnt < bytes_number)
	{
		Xil_Out32((spi_instance.BaseAddr + 0x68), data[cnt]);
		Xil_Out32((spi_instance.BaseAddr + 0x60), 0x096);
		do {usleep(100);}
		while ((Xil_In32((spi_instance.BaseAddr + 0x64)) & 0x4) == 0x0);
		Xil_Out32((spi_instance.BaseAddr + 0x60), 0x186);
		data[cnt] = Xil_In32(spi_instance.BaseAddr + 0x6c);
		cnt++;
	}
	Xil_Out32((spi_instance.BaseAddr + 0x70), 0x001);
	Xil_Out32((spi_instance.BaseAddr + 0x60), 0x180);
#endif
#endif
	return SUCCESS;
}