/** * * This function gets the options for the SPI device. The options control how * the device behaves relative to the SPI bus. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * * @return * * 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 * XSP_*_OPTIONS in the file xspi.h. * * @note None. * ******************************************************************************/ u32 XSpi_GetOptions(XSpi *InstancePtr) { u32 OptionsFlag = 0; u32 ControlReg; u32 Index; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Get the control register to determine which options are currently * set. */ ControlReg = XSpi_GetControlReg(InstancePtr); /* * Loop through the options table to determine which options are set. */ for (Index = 0; Index < XSP_NUM_OPTIONS; Index++) { if (ControlReg & OptionsTable[Index].Mask) { OptionsFlag |= OptionsTable[Index].Option; } } return OptionsFlag; }
/** * * This function stops the SPI device by disabling interrupts and disabling the * device itself. Interrupts are disabled only within the device itself. If * desired, the caller is responsible for disabling interrupts in the interrupt * controller and disconnecting the interrupt handler from the interrupt * controller. * * In interrupt mode, if the device is in progress of transferring data on the * SPI bus, this function returns a status indicating the device is busy. The * user will be notified via the status handler when the transfer is complete, * and at that time can again try to stop the device. As a master, we do not * allow the device to be stopped while a transfer is in progress because the * slave may be left in a bad state. As a slave, we do not allow the device to be * stopped while a transfer is in progress because the master is not done with * its transfer yet. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * * @return * - XST_SUCCESS if the device is successfully started. * - XST_DEVICE_BUSY if a transfer is in progress and cannot be * stopped. * * @note * * This function makes use of internal resources that are shared between the * XSpi_Stop() and XSpi_SetOptions() functions. So if one task might be setting * device options while another is trying to stop the device, the user is * is required to provide protection of this shared data (typically using a * semaphore). * ******************************************************************************/ int XSpi_Stop(XSpi *InstancePtr) { u32 ControlReg; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Do not allow the user to stop the device while a transfer is in * progress. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Disable the device. First disable the interrupts since there is * a critical section here because this register is also modified during * interrupt context. The device is likely disabled already since there * is no transfer in progress, but we do it again just to be sure. */ XSpi_IntrGlobalDisable(InstancePtr); ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg & ~XSP_CR_ENABLE_MASK); InstancePtr->IsStarted = 0; return XST_SUCCESS; }
/** * * 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 XSpi instance to be worked on. * @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 XSP_*_OPTIONS in the file xspi.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. * - XST_SPI_SLAVE_ONLY if the caller attempted to configure a * slave-only device as a master. * * @note * * This function makes use of internal resources that are shared between the * XSpi_Stop() and XSpi_SetOptions() functions. So if one task might be setting * device options while another is trying to stop the device, the user is * required to provide protection of this shared data (typically using a * semaphore). * ******************************************************************************/ int XSpi_SetOptions(XSpi *InstancePtr, u32 Options) { u32 ControlReg; u32 Index; 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. * No need to worry about a critical section here since even if the Isr * changes the busy flag just after we read it, the function will return * busy and the caller can retry when notified that their current * transfer is done. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Do not allow master option to be set if the device is slave only. */ if ((Options & XSP_MASTER_OPTION) && (InstancePtr->SlaveOnly)) { return XST_SPI_SLAVE_ONLY; } ControlReg = XSpi_GetControlReg(InstancePtr); /* * 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 = 0; Index < XSP_NUM_OPTIONS; Index++) { if (Options & OptionsTable[Index].Option) { /* *Turn it ON. */ ControlReg |= OptionsTable[Index].Mask; } else { /* *Turn it OFF. */ ControlReg &= ~OptionsTable[Index].Mask; } } /* * Now write the control register. Leave it to the upper layers * to restart the device. */ XSpi_SetControlReg(InstancePtr, ControlReg); return XST_SUCCESS; }
/** * * This function enables interrupts for the SPI device. If the Spi driver is used * in interrupt mode, it is up to the user to connect the SPI interrupt handler * to the interrupt controller before this function is called. If the Spi driver * is used in polled mode the user has to disable the Global Interrupts after * this function is called. If the device is configured with FIFOs, the FIFOs are * reset at this time. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * * @return * - XST_SUCCESS if the device is successfully started * - XST_DEVICE_IS_STARTED if the device was already started. * * @note None. * ******************************************************************************/ int XSpi_Start(XSpi *InstancePtr) { u32 ControlReg; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * If it is already started, return a status indicating so. */ if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { return XST_DEVICE_IS_STARTED; } /* * Enable the interrupts. */ XSpi_IntrEnable(InstancePtr, XSP_INTR_DFT_MASK); /* * Indicate that the device is started before we enable the transmitter * or receiver or interrupts. */ InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; /* * Reset the transmit and receive FIFOs if present. There is a critical * section here since this register is also modified during interrupt * context. So we wait until after the r/m/w of the control register to * enable the Global Interrupt Enable. */ ControlReg = XSpi_GetControlReg(InstancePtr); ControlReg |= XSP_CR_TXFIFO_RESET_MASK | XSP_CR_RXFIFO_RESET_MASK | XSP_CR_ENABLE_MASK; XSpi_SetControlReg(InstancePtr, ControlReg); /* * Enable the Global Interrupt Enable just after we start. */ XSpi_IntrGlobalEnable(InstancePtr); return XST_SUCCESS; }
/* * * Runs an internal loopback test on the SPI device. This is done as a master * with a enough data to fill the FIFOs if FIFOs are present. If the device is * configured as a slave-only, this function returns successfully even though * no loopback test is performed. * * This function does not restore the device context after performing the test * as it assumes the device will be reset after the call. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * * @return * - XST_SUCCESS if loopback was performed successfully or not * performed at all if device is slave-only. * - XST_LOOPBACK_ERROR if loopback failed. * * @note None. * ******************************************************************************/ static int LoopbackTest(XSpi *InstancePtr) { u32 StatusReg; u32 ControlReg; u32 Index; u32 Data; u32 RxData; u32 NumSent = 0; u32 NumRecvd = 0; u8 DataWidth; /* * Cannot run as a slave-only because we need to be master in order to * initiate a transfer. Still return success, though. */ if (InstancePtr->SlaveOnly) { return XST_SUCCESS; } /* * Setup the control register to enable master mode and the loopback so * that data can be sent and received. */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_LOOPBACK_MASK | XSP_CR_MASTER_MODE_MASK); /* * We do not need interrupts for this loopback test. */ XSpi_IntrGlobalDisable(InstancePtr); DataWidth = InstancePtr->DataWidth; /* * Send data up to the maximum size of the transmit register, which is * one byte without FIFOs. We send data 4 times just to exercise the * device through more than one iteration. */ for (Index = 0; Index < 4; Index++) { Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = XSP_WORD_TESTBYTE; } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data + Index); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ do { StatusReg = XSpi_IntrGetStatus(InstancePtr); } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * Receive and verify the data just transmitted. */ StatusReg = XSpi_GetStatusReg(InstancePtr); while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { RxData = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); if (DataWidth == XSP_DATAWIDTH_BYTE) { if((u8)RxData != Index) { return XST_LOOPBACK_ERROR; } } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { if((u16)RxData != (u16)(Index + XSP_HALF_WORD_TESTBYTE)) { return XST_LOOPBACK_ERROR; } } else if (DataWidth == XSP_DATAWIDTH_WORD) { if(RxData != (u32)(Index + XSP_WORD_TESTBYTE)) { return XST_LOOPBACK_ERROR; } } NumRecvd += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); } /* * One final check to make sure the total number of bytes sent equals * the total number of bytes received. */ if (NumSent != NumRecvd) { return XST_LOOPBACK_ERROR; } return XST_SUCCESS; }
/** * * Runs a self-test on the driver/device. The self-test is destructive in that * a reset of the device is performed in order to check the reset values of * the registers and to get the device into a known state. A simple loopback * test is also performed to verify that transmit and receive are working * properly. The device is changed to master mode for the loopback test, since * only a master can initiate a data transfer. * * Upon successful return from the self-test, the device is reset. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * * @return * - XST_SUCCESS if successful. * - XST_REGISTER_ERROR indicates a register did not read or write * correctly. * - XST_LOOPBACK_ERROR if a loopback error occurred. * * @note None. * ******************************************************************************/ int XSpi_SelfTest(XSpi *InstancePtr) { int Result; u32 Register; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Return Success if XIP Mode */ if((InstancePtr->XipMode) == 1) { return XST_SUCCESS; } /* * Reset the SPI device to leave it in a known good state. */ XSpi_Reset(InstancePtr); if(InstancePtr->XipMode) { Register = XSpi_GetControlReg(InstancePtr); if (Register != XSP_CR_RESET_STATE) { return XST_REGISTER_ERROR; } Register = XSpi_GetStatusReg(InstancePtr); if ((Register & XSP_SR_RESET_STATE) != XSP_SR_RESET_STATE) { return XST_REGISTER_ERROR; } } /* * All the SPI registers should be in their default state right now. */ Register = XSpi_GetControlReg(InstancePtr); if (Register != XSP_CR_RESET_STATE) { return XST_REGISTER_ERROR; } Register = XSpi_GetStatusReg(InstancePtr); if ((Register & XSP_SR_RESET_STATE) != XSP_SR_RESET_STATE) { return XST_REGISTER_ERROR; } /* * Each supported slave select bit should be set to 1. */ Register = XSpi_GetSlaveSelectReg(InstancePtr); if (Register != InstancePtr->SlaveSelectMask) { return XST_REGISTER_ERROR; } /* * If configured with FIFOs, the occupancy values should be 0. */ if (InstancePtr->HasFifos) { Register = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_TFO_OFFSET); if (Register != 0) { return XST_REGISTER_ERROR; } Register = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_RFO_OFFSET); if (Register != 0) { return XST_REGISTER_ERROR; } } /* * Run loopback test only in case of standard SPI mode. */ if (InstancePtr->SpiMode != XSP_STANDARD_MODE) { return XST_SUCCESS; } /* * Run an internal loopback test on the SPI. */ Result = LoopbackTest(InstancePtr); if (Result != XST_SUCCESS) { return Result; } /* * Reset the SPI device to leave it in a known good state. */ XSpi_Reset(InstancePtr); return XST_SUCCESS; }
/* * Change LO frequency in integer mode * frequency must be multiple of 40 (MHz) */ int trf3795changeFreqInt(XSpi *InstancePtr, u32 freq) { u32 StatusReg; u32 ControlReg; u32 Index; u32 Delay; u32 Data; u32 NumSent = 0; u32 NumRecvd = 0; u32 RxData[] = {0,0,0}; u32 reg1Val, reg2Val, reg6Val; u8 DataWidth; u8 j; int ctr; u8 loDivSel, loDiv; u8 pllDiv; u8 pllDivSel; u8 prscSel; u16 rDiv; u16 nInt; // Calculate parameter and register values freq = freq/2; // Output frequency is doubled if(freq>2400) { loDiv = 1; loDivSel = 0; } else if(freq>1200) { loDiv = 2; loDivSel = 1; } else if(freq>600) { loDiv = 4; loDivSel = 2; } else if(freq>300) { loDiv = 8; loDivSel = 3; } pllDiv = (u8)ceil((double)loDiv*freq/3000.0); //xil_printf("Pll Div %d\r\n", pllDiv); rDiv = 1; nInt = (u16)(loDiv*freq*rDiv/(10*pllDiv)); if(pllDiv==1) pllDivSel = 0; else if(pllDiv==2) pllDivSel = 1; else if(pllDiv==4) pllDivSel = 2; else { xil_printf("Invalid PLL_DIV!\r\n"); return XST_FAILURE; } if(nInt>=72) prscSel = 1; else prscSel = 0; //xil_printf("NInt %d\r\n", nInt); //xil_printf("prscSel %d\r\n", prscSel); //xil_printf("loDiv %d\r\n", loDiv); reg1Val = XSP_REG1_WRITE_CF + (rDiv<<5); reg2Val = XSP_REG2_WRITE_CF + (nInt<<5) + (pllDivSel<<21) + (prscSel<<23); reg6Val = XSP_REG6_WRITE_CF + (loDivSel<<23); u32 write_trf_register[] = {reg1Val,reg6Val,reg2Val}; u32 reg_list = {1,2,6}; //xil_printf("reg1: %x", reg1Val); //xil_printf("reg2: %x", reg2Val); //xil_printf("reg6: %x", reg6Val); /* * Setup the control reogister to enable master mode and * to send least significant bit 1st */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK | XSP_CR_LSB_FIRST); //xil_printf("ctrl reg setup done\r\n"); /* * Set the slave select zero bit to active - low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); /* * We do not need interrupts for now */ XSpi_IntrGlobalDisable(InstancePtr); DataWidth = InstancePtr->DataWidth; /*****************************************************************************/ /* * perform a write to a TRF3765 register */ for (Index = 0; Index < 3; Index++) { // for loop write to three registers Data = 0; xil_printf("start transfer %d\r\n", Index); /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); //xil_printf("got status reg\r\n"); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // no loop, do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = write_trf_register[Index]; // choose the register index 0 to 7 ************ //xil_printf("selected register \r\n"); } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); //xil_printf("wrote data \r\n"); NumSent += (DataWidth >> 3); //xil_printf("Numsent %d\r\n", NumSent); StatusReg = XSpi_GetStatusReg(InstancePtr); //xil_printf("status reg %d \r\n", StatusReg); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ //xil_printf("start for loop\r\n"); //xil_printf("status reg %d\r\n", XSpi_IntrGetStatus(InstancePtr)); ctr = 0; do { StatusReg = XSpi_IntrGetStatus(InstancePtr); if(ctr > SPI_TIMEOUT) break; ctr++; } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); //xil_printf("done with while loop \r\n"); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * To create a latch enable pulse and extra read clock pulse, * set the slave select one SS(1) bit low */ XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFD); // creates read pulse and clock for (Delay = 0; Delay < 10; Delay++) // more delay makes wider pulses {} XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes read pulse and clock /* * To create a latch enable pulse, * set the slave select one SS(0) bit low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); // drives the latch enable // for (Delay = 0; Delay < 10; Delay++) // more delay makes pulse wider // {} // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes the latch enable /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); //xil_printf("Done transfer %d\r\n", Index); } XSpi_Reset(InstancePtr); return XST_SUCCESS; }
/* * Enables the fractional mode of the LO * LO must be initialized first */ int trf3795EnableInt(XSpi *InstancePtr) { u32 StatusReg; u32 ControlReg; u32 Index; u32 Delay; u32 Data; u32 NumSent = 0; u32 NumRecvd = 0; u32 RxData[] = {0,0,0}; u8 DataWidth; u8 j; int ctr; u32 write_trf_register[] = {XSP_REG0_WRITE,XSP_REG1_WRITE,XSP_REG2_WRITE,XSP_REG3_WRITE, XSP_REG4_WRITE,XSP_REG5_WRITE,XSP_REG6_WRITE,XSP_REG7_WRITE}; /* * Setup the control reogister to enable master mode and * to send least significant bit 1st */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK | XSP_CR_LSB_FIRST); /* * Set the slave select zero bit to active - low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); /* * We do not need interrupts for now */ XSpi_IntrGlobalDisable(InstancePtr); DataWidth = InstancePtr->DataWidth; /*****************************************************************************/ /* * perform a write to a TRF3765 register */ for (Index = 0; Index < 8; Index++) { // for loop write to all eight registers Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // no loop, do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = write_trf_register[Index]; // choose the register index 0 to 7 ************ } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ do { StatusReg = XSpi_IntrGetStatus(InstancePtr); if(ctr > SPI_TIMEOUT) break; ctr++; } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * To create a latch enable pulse and extra read clock pulse, * set the slave select one SS(1) bit low */ XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFD); // creates read pulse and clock for (Delay = 0; Delay < 10; Delay++) // more delay makes wider pulses {} XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes read pulse and clock /* * To create a latch enable pulse, * set the slave select one SS(0) bit low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); // drives the latch enable // for (Delay = 0; Delay < 10; Delay++) // more delay makes pulse wider // {} // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes the latch enable /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); } XSpi_Reset(InstancePtr); return XST_SUCCESS; }
/* Write to and read back the RF board TRF3795 * * ******************************************************************************/ static int trf3795WriteAndRead(XSpi *InstancePtr) { u32 StatusReg; u32 ControlReg; u32 Index; u32 Delay; u32 Data; u32 NumSent = 0; u32 NumRecvd = 0; u32 RxData[] = {0,0,0}; u8 DataWidth; u8 j; int ctr = 0; u32 write_trf_register[] = {XSP_REG0_WRITE,XSP_REG1_WRITE,XSP_REG2_WRITE_ENC,XSP_REG3_WRITE, XSP_REG4_WRITE,XSP_REG5_WRITE,XSP_REG6_WRITE, XSP_REG7_WRITE}; u32 read_trf_register[] = {XSP_REG0_READBACK,XSP_REG1_READBACK,XSP_REG2_READBACK,XSP_REG3_READBACK, XSP_REG4_READBACK,XSP_REG5_READBACK,XSP_REG6_READBACK,XSP_REG7_READBACK,XSP_REG7_READBACK}; /* * Setup the control register to enable master mode and * to send least significant bit 1st */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK | XSP_CR_LSB_FIRST); /* * Set the slave select zero bit to active - low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); /* * We do not need interrupts for now */ XSpi_IntrGlobalDisable(InstancePtr); DataWidth = InstancePtr->DataWidth; /*****************************************************************************/ /* * perform a write to a TRF3765 register */ for (Index = 0; Index < 8; Index++) { // for loop write to all eight registers Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // no loop, do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = write_trf_register[Index]; // choose the register index 0 to 7 ************ } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ //xil_printf("status reg %d \r\n", StatusReg); //xil_printf("intr status reg %d \r\n", XSpi_IntrGetStatus(InstancePtr)); ctr = 0; do { StatusReg = XSpi_IntrGetStatus(InstancePtr); if(ctr > SPI_TIMEOUT) break; ctr++; } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * To create a latch enable pulse and extra read clock pulse, * set the slave select one SS(1) bit low */ XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFD); // creates read pulse and clock for (Delay = 0; Delay < 10; Delay++) // more delay makes wider pulses {} XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes read pulse and clock /* * To create a latch enable pulse, * set the slave select one SS(0) bit low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); // drives the latch enable // for (Delay = 0; Delay < 10; Delay++) // more delay makes pulse wider // {} // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes the latch enable /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); // } // end of the for loop /*****************************************************************************/ /* * To Read-back from the Internal Register Banks, Register 0 must be programmed * with a specific command that sets the TRF3765 into read-back mode and * specifies the register to be read */ // for (Index = 0; Index < 1; Index++) { // Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = read_trf_register[Index]; // index of the register to readback here ********************* } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); // | XSP_CR_CLK_PHASE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ ctr = 0; do { StatusReg = XSpi_IntrGetStatus(InstancePtr); if(ctr > SPI_TIMEOUT) break; ctr++; } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); for (Delay = 0; Delay < 10; Delay++) // add delay {} /* * To create a latch enable pulse and extra read clock pulse, * set the slave select one SS(1) bit low */ XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFD); // creates read pulse and clock for (Delay = 0; Delay < 10; Delay++) // more delay makes wider pulses {} XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes read pulse and clock for (Delay = 0; Delay < 10; Delay++) // add delay {} /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); // } // end of the for loop /* ************* Now read-back the specific register ********************************* */ // for (Index = 0; Index < 1; Index++) { // Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = XSP_ZERO_WRITE; // just leave the data bits at zero during read-back } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data + Index); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK | XSP_CR_CLK_PHASE_MASK); // clock data in on the second edge (falling) /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ ctr = 0; do { StatusReg = XSpi_IntrGetStatus(InstancePtr); if(ctr > SPI_TIMEOUT) break; ctr++; } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * Receive and verify the data just transmitted. */ StatusReg = XSpi_GetStatusReg(InstancePtr); while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { for (j = 0; j < 3; j++) { RxData[j] = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); NumRecvd += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } xil_printf("\r%08x\n\r", RxData[2]); } /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); } // end of the for loop /* * One final check to make sure the total number of bytes sent equals * the total number of bytes received. */ // if (NumSent != NumRecvd) { // return XST_LOOPBACK_ERROR; // } xil_printf("\n\rTRF3765 Register Access Done\n\r"); return XST_SUCCESS; }
int trf3795ReadBackRegs(XSpi *InstancePtr) { u32 StatusReg; u32 ControlReg; u32 Index; u32 Delay; u32 Data; u32 NumSent = 0; u32 NumRecvd = 0; u32 RxData[] = {0,0,0}; u8 DataWidth; u8 j; u32 read_trf_register[] = {XSP_REG0_READBACK,XSP_REG1_READBACK,XSP_REG2_READBACK,XSP_REG3_READBACK, XSP_REG4_READBACK,XSP_REG5_READBACK,XSP_REG6_READBACK,XSP_REG7_READBACK}; ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK | XSP_CR_LSB_FIRST); xil_printf("ctrl reg setup done\r\n"); /* * Set the slave select zero bit to active - low */ // XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFE); /* * We do not need interrupts for now */ XSpi_IntrGlobalDisable(InstancePtr); DataWidth = InstancePtr->DataWidth; StatusReg = XSpi_GetStatusReg(InstancePtr); for(Index=0; Index<8; Index++) { if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = read_trf_register[Index]; // index of the register to readback here ********************* } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); // | XSP_CR_CLK_PHASE_MASK); /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ //xil_printf("enter first tx while loop \r\n"); do { StatusReg = XSpi_IntrGetStatus(InstancePtr); } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); for (Delay = 0; Delay < 10; Delay++) // add delay {} /* * To create a latch enable pulse and extra read clock pulse, * set the slave select one SS(1) bit low */ XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFD); // creates read pulse and clock for (Delay = 0; Delay < 10; Delay++) // more delay makes wider pulses {} XSpi_SetSlaveSelectReg(InstancePtr, 0xFFFF); // removes read pulse and clock for (Delay = 0; Delay < 10; Delay++) // add delay {} /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); // } // end of the for loop /* ************* Now read-back the specific register ********************************* */ // for (Index = 0; Index < 1; Index++) { // Data = 0; /* * Fill the transmit register. */ StatusReg = XSpi_GetStatusReg(InstancePtr); // while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) { // do just a single transfer for now if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = 0; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = XSP_HALF_WORD_TESTBYTE; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = XSP_ZERO_WRITE; // just leave the data bits at zero during read-back } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data + Index); NumSent += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); // } /* * Start the transfer by not inhibiting the transmitter and * enabling the device. */ ControlReg = XSpi_GetControlReg(InstancePtr) & (~XSP_CR_TRANS_INHIBIT_MASK); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK | XSP_CR_CLK_PHASE_MASK); // clock data in on the second edge (falling) /* * Wait for the transfer to be done by polling the transmit * empty status bit. */ //xil_printf("Enter tx empty while loop\r\n"); do { StatusReg = XSpi_IntrGetStatus(InstancePtr); } while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0); XSpi_IntrClear(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * Receive and verify the data just transmitted. */ StatusReg = XSpi_GetStatusReg(InstancePtr); //xil_printf("Enter rx empty while loop\r\n"); while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { for (j = 0; j < 3; j++) { RxData[j] = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); NumRecvd += (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } xil_printf("\r%08x\n\r", RxData[2]); } /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter and disabling the device. */ ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); } // end of the for loop xil_printf("\n\rTRF3765 Register Access Done\n\r"); return XST_SUCCESS; }
/** * * Transfers the specified data on the SPI bus. If the SPI device is configured * to be a master, this function initiates bus communication and sends/receives * the data to/from the selected SPI slave. If the SPI device is configured to * be a slave, this function prepares the data to be sent/received when selected * by a master. For every byte sent, a byte is received. * * This function/driver operates in interrupt mode and polled mode. * - In interrupt mode this function is non-blocking and the transfer is * initiated by this function and completed by the interrupt service routine. * - In polled mode this function is blocking and the control exits this * function only after all the requested data is transferred. * * 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> * XSpi_Transfer(InstancePtr, SendBuf, RecvBuf, ByteCount) * The caller wishes to send and receive, and provides two different * buffers for send and receive. * * XSpi_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. * * XSpi_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. * * XSpi_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> * In interrupt mode, though this function takes a buffer as an argument, the * driver can only transfer a limited number of bytes at time. It transfers only * one byte at a time if there are no FIFOs, or it can transfer the number of * bytes up to the size of the FIFO if FIFOs exist. * - In interrupt mode a call to this function only starts the transfer, the * subsequent transfer 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. * - In polled mode this function is blocking and the control exits this * function only after all the requested data is transferred. * * As a master, the SetSlaveSelect function must be called prior to this * function. * * @param InstancePtr is a pointer to the XSpi instance to be worked on. * @param SendBufPtr is a pointer to a buffer of data which is to be sent. * This buffer must not be NULL. * @param RecvBufPtr is a pointer to a buffer which will be filled with * received data. This argument can be NULL if the caller does not * wish to receive data. * @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 * driver for transfer. Otherwise, returns: * - XST_DEVICE_IS_STOPPED if the device must be started before * transferring data. * - XST_DEVICE_BUSY indicates that a data transfer is already in * progress. This is determined by the driver. * - XST_SPI_NO_SLAVE indicates the device is configured as a * master and a slave has not yet been selected. * * @notes * * 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. * ******************************************************************************/ int XSpi_Transfer(XSpi *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, unsigned int ByteCount) { u32 ControlReg; u32 GlobalIntrReg; u32 StatusReg; u32 Data = 0; u8 DataWidth; /* * The RecvBufPtr argument can be NULL. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SendBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); if (InstancePtr->IsStarted != XIL_COMPONENT_IS_STARTED) { return XST_DEVICE_IS_STOPPED; } /* * Make sure there is not a transfer already in progress. No need to * worry about a critical section here. Even if the Isr changes the bus * flag just after we read it, a busy error is returned and the caller * can retry when it gets the status handler callback indicating the * transfer is done. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * Save the Global Interrupt Enable Register. */ GlobalIntrReg = XSpi_IsIntrGlobalEnabled(InstancePtr); /* * Enter a critical section from here to the end of the function since * state is modified, an interrupt is enabled, and the control register * is modified (r/m/w). */ XSpi_IntrGlobalDisable(InstancePtr); ControlReg = XSpi_GetControlReg(InstancePtr); /* * If configured as a master, be sure there is a slave select bit set * in the slave select register. If no slaves have been selected, the * value of the register will equal the mask. When the device is in * loopback mode, however, no slave selects need be set. */ if (ControlReg & XSP_CR_MASTER_MODE_MASK) { if ((ControlReg & XSP_CR_LOOPBACK_MASK) == 0) { if (InstancePtr->SlaveSelectReg == InstancePtr->SlaveSelectMask) { if (GlobalIntrReg == TRUE) { /* Interrupt Mode of operation */ XSpi_IntrGlobalEnable(InstancePtr); } return XST_SPI_NO_SLAVE; } } } /* * Set the slave select register to select the device on the SPI before * starting the transfer of data. */ XSpi_SetSlaveSelectReg(InstancePtr, InstancePtr->SlaveSelectReg); /* * Set the busy flag, which will be cleared when the transfer * is completely done. */ InstancePtr->IsBusy = TRUE; /* * Set up buffer pointers. */ InstancePtr->SendBufferPtr = SendBufPtr; InstancePtr->RecvBufferPtr = RecvBufPtr; InstancePtr->RequestedBytes = ByteCount; InstancePtr->RemainingBytes = ByteCount; DataWidth = InstancePtr->DataWidth; /* * Fill the DTR/FIFO with as many bytes as it will take (or as many as * we have to send). We use the tx full status bit to know if the device * can take more data. By doing this, the driver does not need to know * the size of the FIFO or that there even is a FIFO. The downside is * that the status register must be read each loop iteration. */ StatusReg = XSpi_GetStatusReg(InstancePtr); while (((StatusReg & XSP_SR_TX_FULL_MASK) == 0) && (InstancePtr->RemainingBytes > 0)) { if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ Data = *InstancePtr->SendBufferPtr; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word (16 bit). */ Data = *(u16 *)InstancePtr->SendBufferPtr; } else if (DataWidth == XSP_DATAWIDTH_WORD){ /* * Data Transfer Width is Word (32 bit). */ Data = *(u32 *)InstancePtr->SendBufferPtr; } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); InstancePtr->SendBufferPtr += (DataWidth >> 3); InstancePtr->RemainingBytes -= (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } /* * Start the transfer by no longer inhibiting the transmitter and * enabling the device. For a master, this will in fact start the * transfer, but for a slave it only prepares the device for a transfer * that must be initiated by a master. */ ControlReg = XSpi_GetControlReg(InstancePtr); ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr, ControlReg); /* * If the interrupts are enabled as indicated by Global Interrupt * Enable Register, then enable the transmit empty interrupt to operate * in Interrupt mode of operation. */ if (GlobalIntrReg == TRUE) { /* Interrupt Mode of operation */ /* * Enable the transmit empty interrupt, which we use to * determine progress on the transmission. */ XSpi_IntrEnable(InstancePtr, XSP_INTR_TX_EMPTY_MASK); /* * End critical section. */ XSpi_IntrGlobalEnable(InstancePtr); } else { /* Polled mode of operation */ /* * If interrupts are not enabled, poll the status register to * Transmit/Receive SPI data. */ while(ByteCount > 0) { /* * Wait for the transfer to be done by polling the * Transmit empty status bit */ do { StatusReg = XSpi_GetStatusReg(InstancePtr); } while ((StatusReg & XSP_SR_TX_EMPTY_MASK) == 0); /* * A transmit has just completed. Process received data * and check for more data to transmit. Always inhibit * the transmitter while the transmit register/FIFO is * being filled, or make sure it is stopped if we're * done. */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_TRANS_INHIBIT_MASK); /* * First get the data received as a result of the * transmit that just completed. We get all the data * available by reading the status register to determine * when the Receive register/FIFO is empty. 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). */ StatusReg = XSpi_GetStatusReg(InstancePtr); while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) { Data = XSpi_ReadReg(InstancePtr->BaseAddr, XSP_DRR_OFFSET); if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte (8 bit). */ if(InstancePtr->RecvBufferPtr != NULL) { *InstancePtr->RecvBufferPtr++ = (u8)Data; } } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half Word * (16 bit). */ if (InstancePtr->RecvBufferPtr != NULL){ *(u16 *)InstancePtr->RecvBufferPtr = (u16)Data; InstancePtr->RecvBufferPtr += 2; } } else if (DataWidth == XSP_DATAWIDTH_WORD) { /* * Data Transfer Width is Word (32 bit). */ if (InstancePtr->RecvBufferPtr != NULL){ *(u32 *)InstancePtr->RecvBufferPtr = Data; InstancePtr->RecvBufferPtr += 4; } } InstancePtr->Stats.BytesTransferred += (DataWidth >> 3); ByteCount -= (DataWidth >> 3); StatusReg = XSpi_GetStatusReg(InstancePtr); } if (InstancePtr->RemainingBytes > 0) { /* * Fill the DTR/FIFO with as many bytes as it * will take (or as many as we have to send). * We use the Tx full status bit to know if the * device can take more data. * By doing this, the driver does not need to * know the size of the FIFO or that there even * is a FIFO. * The downside is that the status must be read * each loop iteration. */ StatusReg = XSpi_GetStatusReg(InstancePtr); while(((StatusReg & XSP_SR_TX_FULL_MASK)== 0) && (InstancePtr->RemainingBytes > 0)) { if (DataWidth == XSP_DATAWIDTH_BYTE) { /* * Data Transfer Width is Byte * (8 bit). */ Data = *InstancePtr-> SendBufferPtr; } else if (DataWidth == XSP_DATAWIDTH_HALF_WORD) { /* * Data Transfer Width is Half * Word (16 bit). */ Data = *(u16 *)InstancePtr-> SendBufferPtr; } else if (DataWidth == XSP_DATAWIDTH_WORD) { /* * Data Transfer Width is Word * (32 bit). */ Data = *(u32 *)InstancePtr-> SendBufferPtr; } XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET, Data); InstancePtr->SendBufferPtr += (DataWidth >> 3); InstancePtr->RemainingBytes -= (DataWidth >> 3); StatusReg = XSpi_GetStatusReg( InstancePtr); } /* * Start the transfer by not inhibiting the * transmitter any longer. */ ControlReg = XSpi_GetControlReg(InstancePtr); ControlReg &= ~XSP_CR_TRANS_INHIBIT_MASK; XSpi_SetControlReg(InstancePtr, ControlReg); } } /* * Stop the transfer (hold off automatic sending) by inhibiting * the transmitter. */ ControlReg = XSpi_GetControlReg(InstancePtr); XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_TRANS_INHIBIT_MASK); /* * Select the slave on the SPI bus when the transfer is * complete, this is necessary for some SPI devices, * such as serial EEPROMs work correctly as chip enable * may be connected to slave select */ XSpi_SetSlaveSelectReg(InstancePtr, InstancePtr->SlaveSelectMask); InstancePtr->IsBusy = FALSE; }