本文主要介绍使用ZYNQ硬核通过编程实现SPI通信,为控制外设提供参考!
软件:Vivado2018.2
硬件:PYNQ-Z2(理论上来说,只要含Zynq-7000 SoC的开发板都可以)
理论:熟悉SPI通信协议与时序
硬件回环连接,由MOSI发,MISO接收,数据暂存在FIFO模块中!
第一部分
PL部分,新建Vivado工程,新建Block Design,添加zynq7 Processing System,点击自动连线。完成后如图所示
双击ZYNQ7,添加SPI_0接口,本次只用到SPI_0。如图所示
手动连线,将SPI_0的四个管脚引出,其中MISO为Input,其余三个为Output。完成后如图所示
下面Creat HDL Wrapper,然后进行Run Synthesis,综合完成后在弹出的窗口里选择中间选项。如图所示
接下来要对四个引出的管脚进行约束,先点击Schematic,然后点击I/O Ports,扩大下面的窗口,找到我们连接的四个管脚,如图
参考你所用的开发板的Schematic,找到对应的管脚编号,并在表中对应填写,电平标准都选择LVCOM18即可。如图,填写完成后保存,自动生成XDC约束文件。
上述完成后,点击Generate Bitstream,时间较长,等待完成。完成后导出hdf文件,然后Launch SDK。如图所示
第二部分
PS部分,进入SDK后,新建工程。如图所示
在helloworld.c文件中原代码删除,替换为如下代码,保存。
#include "xparameters.h"
#include "xspips.h"
#include "xil_printf.h"
#include "sleep.h"
XSpiPs Spi0, Spi1;
#define SpiPs_RecvByte(BaseAddress) \
(u8)XSpiPs_In32((BaseAddress) + XSPIPS_RXD_OFFSET)
#define SpiPs_SendByte(BaseAddress, Data) \
XSpiPs_Out32((BaseAddress) + XSPIPS_TXD_OFFSET, (Data))
int spi0_init();
void spi0_one_write();
void SpiRead(int ByteCount);
void SpiWrite(u8 *Sendbuffer, int ByteCount);
unsigned char ReadBuffer[1024];
unsigned char WriteBuffer[1024]={1,2,3,4,5,6,7,8,9,0};
int main(void) {
int Status;
int i,j;
int value;
xil_printf("SPI Selftest Example \r\n");
Status = spi0_init();
if (Status != XST_SUCCESS) {
xil_printf("SPI Selftest Example Failed\r\n");
return XST_FAILURE;
}
for (i = 0; i < 6; i++)
{
SpiWrite(WriteBuffer,10);
SpiRead(10);
//xil_printf("read back \n");
for (j = 0; j < 10; j++ )
{
xil_printf("%d,",ReadBuffer[j]);
}
xil_printf("\n");
memset(ReadBuffer, 0x00, 1024);
sleep(1);
}
xil_printf("Successfully ran SPI Selftest Example\r\n");
return XST_SUCCESS;
}
void SpiRead(int ByteCount)
{
int Count;
u32 StatusReg;
StatusReg = XSpiPs_ReadReg(Spi0.Config.BaseAddress,
XSPIPS_SR_OFFSET);
/*
* Polling the Rx Buffer for Data
*/
do{
StatusReg = XSpiPs_ReadReg(Spi0.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(
Spi0.Config.BaseAddress);
}
}
void SpiWrite(u8 *Sendbuffer, int ByteCount)
{
u32 StatusReg;
int TransCount = 0;
StatusReg = XSpiPs_ReadReg(Spi0.Config.BaseAddress,
XSPIPS_SR_OFFSET);
while ((ByteCount > 0) &&
(TransCount < XSPIPS_FIFO_DEPTH)) {
SpiPs_SendByte(Spi0.Config.BaseAddress,
*Sendbuffer);
Sendbuffer++;
++TransCount;
ByteCount--;
}
/*
* Wait for the transfer to finish by polling Tx fifo status.
*/
do {
StatusReg = XSpiPs_ReadReg(
Spi0.Config.BaseAddress,
XSPIPS_SR_OFFSET);
} while ((StatusReg & XSPIPS_IXR_TXOW_MASK) == 0);
}
int spi0_init() {
int Status;
XSpiPs_Config *SpiConfig;
/*
* Initialize the SPI device.
*/
SpiConfig = XSpiPs_LookupConfig(XPAR_XSPIPS_0_DEVICE_ID);
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status = XSpiPs_CfgInitialize(&Spi0, SpiConfig, SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Perform a self-test to check hardware build.
*/
Status = XSpiPs_SelfTest(&Spi0);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
xil_printf("%s self test succ\r\n", __func__);
Status = XSpiPs_SetOptions(&Spi0, XSPIPS_MASTER_OPTION);
if (Status != XST_SUCCESS) {
xil_printf("%s XSpiPs_SetOptions fail\n", __func__);
return XST_FAILURE;
}
Status = XSpiPs_SetClkPrescaler(&Spi0, XSPIPS_CLK_PRESCALE_64);
if (Status != XST_SUCCESS) {
xil_printf("%s XSpiPs_SetClkPrescaler fail\n", __func__);
return XST_FAILURE;
}
XSpiPs_Enable(&Spi0);
xil_printf("spi 0 config finish\n");
return XST_SUCCESS;
}
下面板上测试,回环连接后,开发板上电,通过SDK自带串口,与开发板进行连接。如图所示
串口连接成功后,首先Program FPGA,然后Run As--->Launch On Hardware。如图所示
然后在窗口中就能看到串口打印的数据了,至此,例程结束。
本文是在参考前辈的文章基础上,亲自验证可行,对没有详细说明的地方贴了图,感谢分享,也希望可以帮到更多人!
前辈文章链接:ZYNQ SPI测试