/** * 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. * ******************************************************************************/ int XSpiPs_PolledTransfer(XSpiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, unsigned ByteCount) { u32 StatusReg; u32 ConfigReg; u32 TransCount; /* * 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); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * 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)) { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); /* * Set the slave select value. */ ConfigReg &= ~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 > 0) || (InstancePtr->RequestedBytes > 0)) { TransCount = 0; /* * Fill the TXFIFO with as many bytes as it will take (or as * many as we have to send). */ while ((InstancePtr->RemainingBytes > 0) && (TransCount < XSPIPS_FIFO_DEPTH)) { XSpiPs_SendByte(InstancePtr->Config.BaseAddress, *InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr++; InstancePtr->RemainingBytes--; ++TransCount; } /* * If master mode and manual start mode, issue manual start * command to start the transfer. */ if (XSpiPs_IsManualStart(InstancePtr) && XSpiPs_IsMaster(InstancePtr)) { 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. */ do { StatusReg = XSpiPs_ReadReg( InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET); } while ((StatusReg & XSPIPS_IXR_TXOW_MASK) == 0); /* * 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) { u8 TempData; TempData = XSpiPs_RecvByte( InstancePtr->Config.BaseAddress); if (InstancePtr->RecvBufferPtr != NULL) { *InstancePtr->RecvBufferPtr++ = (u8) TempData; } InstancePtr->RequestedBytes--; --TransCount; } } /* * Clear the slave selects now, before terminating the transfer. */ if (XSpiPs_IsManualChipSelect(InstancePtr)) { 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); return XST_SUCCESS; }
/** * * 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. * ******************************************************************************/ int XSpiPs_Transfer(XSpiPs *InstancePtr, u8 *SendBufPtr, u8 *RecvBufPtr, unsigned ByteCount) { u32 ConfigReg; u8 TransCount = 0; /* * 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); /* * Check whether there is another transfer in progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } /* * 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)) { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); /* * Set the slave select value. */ ConfigReg &= ~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 > 0) && (TransCount < XSPIPS_FIFO_DEPTH)) { XSpiPs_SendByte(InstancePtr->Config.BaseAddress, *InstancePtr->SendBufferPtr); InstancePtr->SendBufferPtr++; 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) && XSpiPs_IsMaster(InstancePtr)) { ConfigReg = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); ConfigReg |= XSPIPS_CR_MANSTRT_MASK; XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET, ConfigReg); } return XST_SUCCESS; }
/***************************************************************************//** * @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; }
/** * * 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. * * Upon successful return from the self-test, the device is reset. * * @param InstancePtr is a pointer to the XSpiPs instance. * * @return * - XST_SUCCESS if successful * - XST_REGISTER_ERROR indicates a register did not read or write * correctly. * * @note None. * ******************************************************************************/ s32 XSpiPs_SelfTest(XSpiPs *InstancePtr) { s32 Status; u32 Register; u8 DelayTestNss; u8 DelayTestBtwn; u8 DelayTestAfter; u8 DelayTestInit; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Reset the SPI device to leave it in a known good state */ XSpiPs_Reset(InstancePtr); /* * All the SPI registers should be in their default state right now. */ Register = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET); if (Register != XSPIPS_CR_RESET_STATE) { return (s32)XST_REGISTER_ERROR; } Register = XSpiPs_ReadReg(InstancePtr->Config.BaseAddress, XSPIPS_SR_OFFSET); if (Register != XSPIPS_ISR_RESET_STATE) { return (s32)XST_REGISTER_ERROR; } DelayTestNss = 0x5AU; DelayTestBtwn = 0xA5U; DelayTestAfter = 0xAAU; DelayTestInit = 0x55U; /* * Write and read the delay register, just to be sure there is some * hardware out there. */ Status = XSpiPs_SetDelays(InstancePtr, DelayTestNss, DelayTestBtwn, DelayTestAfter, DelayTestInit); if (Status != (s32)XST_SUCCESS) { return Status; } XSpiPs_GetDelays(InstancePtr, &DelayTestNss, &DelayTestBtwn, &DelayTestAfter, &DelayTestInit); if ((0x5AU != DelayTestNss) || (0xA5U != DelayTestBtwn) || (0xAAU != DelayTestAfter) || (0x55U != DelayTestInit)) { return (s32)XST_REGISTER_ERROR; } Status = XSpiPs_SetDelays(InstancePtr, 0U, 0U, 0U, 0U); if (Status != (s32)XST_SUCCESS) { return Status; } /* * Reset the SPI device to leave it in a known good state */ XSpiPs_Reset(InstancePtr); return (s32)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 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; }