一、概述
zynq自带两个SPI的硬核,SPI控制相关寄存器,ug585上有相关说明,其中SPI0的base address是0xe0006000,SPI1的base address是0xe0007000。
二、应用举例
SPI可以配置为master、multi master 和 slave 等模式,注意TX_FIFO和RX_FIFO实际有效数据位宽是8bit,即每次发送的数据是8bit,如果实际一次SPI操作位宽不是8bit,可通过手动控制CS来更改一次SPI拉低之后发送的数据量。
比如AD9361,其SPI一次是发送24bit数据,standalone使用SPI0进行SPI读写的模块如下:
main函数文件
#include "spips.h"
int main(void)
{
int i =0;
unsigned int reg_value;
SpiPs_Init(SPI_DEVICE_ID);
AD9361_WR(0x6a,0x5a);
reg_value = AD9361_RD(0x6a);
if(reg_value == 0x5a)
xil_printf("spi test OK!\r\n");
else
xil_printf("spi test Error!\r\n");
return 0;
}
unsigned int AD9361_WR(unsigned int reg_addr,unsigned int value)
{
u8 spi_wr_Buf[3];
int i =0;
spi_wr_Buf[0] = 0x80 | (reg_addr >> 8);
spi_wr_Buf[1] = reg_addr ;
spi_wr_Buf[2] = value;
// for(i=0;i<3;i++)
// xil_printf("%x\r\n",spi_wr_Buf[i]);
XSpiPs_SetSlaveSelect(&SpiInstance, SLAVE0_SELECT);
SpiPs_Send(spi_wr_Buf,3);
XSpiPs_SetSlaveSelect(&SpiInstance, NONE_SELECT);
SpiPs_Read(spi_wr_Buf,3);
return 0;
}
unsigned int AD9361_RD(unsigned int reg_addr)
{
unsigned int value;
int i =0;
u8 spi_rd_Buf[3];
spi_rd_Buf[0] = 0x00 | (reg_addr >> 8);
spi_rd_Buf[1] = reg_addr ;
spi_rd_Buf[2] = 0x00;
// for(i=0;i<3;i++)
// xil_printf("%x\r\n",spi_rd_Buf[i]);
XSpiPs_SetSlaveSelect(&SpiInstance, SLAVE0_SELECT);
SpiPs_Send(spi_rd_Buf,3);
XSpiPs_SetSlaveSelect(&SpiInstance, NONE_SELECT);
SpiPs_Read(spi_rd_Buf,3);
value = spi_rd_Buf[2];
return value;
}
spips.c文件:
//spips.c
#include "spips.h"
int SpiPs_Init(u16 SpiDeviceId)
{
int Status;
u8 *BufferPtr;
XSpiPs_Config *SpiConfig;
/*
* Initialize the SPI driver so that it's ready to use
*/
SpiConfig = XSpiPs_LookupConfig(SpiDeviceId);
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status = XSpiPs_CfgInitialize((&SpiInstance), SpiConfig,
SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* The SPI device is a slave by default and the clock phase
* have to be set according to its master. In this example, CPOL is set
* to quiescent high and CPHA is set to 1.
*/
XSpiPs_SetSlaveSelect(&SpiInstance, NONE_SELECT);
Status = XSpiPs_SetOptions((&SpiInstance), (XSPIPS_FORCE_SSELECT_OPTION) | \
(XSPIPS_CLK_PHASE_1_OPTION) | (0) | XSPIPS_MASTER_OPTION);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XSpiPs_SetClkPrescaler(&SpiInstance, XSPIPS_CLK_PRESCALE_8);
/*
* Enable the device.
*/
XSpiPs_Enable((&SpiInstance));
return XST_SUCCESS;
}
void SpiPs_Read(u8 *ReadBuffer,int ByteCount)
{
int Count;
u32 StatusReg;
do{
StatusReg = XSpiPs_ReadReg(SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
}while(!(StatusReg & XSPIPS_IXR_RXNEMPTY_MASK));
/*
* Reading the Rx Buffer
*/
for(Count = 0; Count < ByteCount; Count++){
ReadBuffer[Count] = SpiPs_RecvByte(
SpiInstance.Config.BaseAddress);
// xil_printf("%x\r\n",ReadBuffer[Count]);
}
}
void SpiPs_Send(u8 *SendBuffer, int ByteCount)
{
u32 StatusReg;
int TransCount = 0;
/*
* Fill the TXFIFO with as many bytes as it will take (or as
* many as we have to send).
*/
while ((ByteCount > 0) &&
(TransCount < XSPIPS_FIFO_DEPTH)) {
SpiPs_SendByte(SpiInstance.Config.BaseAddress,
*SendBuffer);
SendBuffer++;
++TransCount;
ByteCount--;
}
/*
* Wait for the transfer to finish by polling Tx fifo status.
*/
do {
StatusReg = XSpiPs_ReadReg(
SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
} while ((StatusReg & XSPIPS_IXR_TXOW_MASK) == 0);
}
spips.h文件:
//spips.h 对Xilinx的spi裸机驱动进行封装
#ifndef SRC_SPIPS_H_
#define SRC_SPIPS_H_
#include "xparameters.h" /* SDK generated parameters */
#include "xspips.h" /* SPI device driver */
#include "xil_printf.h"
void SpiPs_Read (u8 *ReadBuffer, int ByteCount);
void SpiPs_Send (u8 *SendBuffer, int ByteCount);
int SpiPs_Init (u16 SpiDeviceId);
#define SPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
#define SpiPs_RecvByte(BaseAddress) (u8)XSpiPs_In32((BaseAddress) + XSPIPS_RXD_OFFSET)
#define SpiPs_SendByte(BaseAddress, Data) XSpiPs_Out32((BaseAddress) + XSPIPS_TXD_OFFSET, (Data))
XSpiPs SpiInstance;
#define SLAVE0_SELECT 0
#define SLAVE1_SELECT 1
#define SLAVE2_SELECT 2
#define NONE_SELECT 0xf
extern unsigned int AD9361_WR(unsigned int reg_addr,unsigned int value);
extern unsigned int AD9361_RD(unsigned int reg_addr);
#endif /* SRC_SPIPS_H_ */