/***************************************************************************//** * @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; }
/** * * 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; }
/** * * 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; }
/** * * 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); }
/***************************************************************************//** * @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; }
/** * * 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; }
/** * * 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); } }
/** * 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; }
/** * * 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; }
/***************************************************************************//** * @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; }