赛灵思的Zynq-7000器件的ARM内核带有两个SPI外设,由于我们开发中要用到SPI总线控制外设,本文拟用创龙TLZ7x-EasyEVM评估板实现对ARM Cortex-A9的SPI外设模块的测试,首先介绍下Zynq-7000器件SPI外设的主要特性:
1、SPI外设模块可以工作在主模式、从模式或者多主模式。
2、四线总线,包括MOSI, MISO, SCLK, and SS信号,通过MIO布线连接时SPI控制器最高支持50MHz的SCLK时钟频率,通过EMIO布线到PL侧连接时SPI控制器最高支持25MHz的SCLK时钟频率。
3、支持128个字节的读FIFO和128个字节的写FIFO,每个FIFO宽度为8个比特,可以编程FIFO状态或中断的门限。
4、主模式支持:
a、手动或者自动开始发送数据。
b、手动或者自动地选择从(SS)模式。
c、从机片选信号可以直接连接从机设备或者外部扩展(如经译码器)后连接从机设备。
d、可编程SS and MOSI 信号的延时。
5、从机模式:可编程开始检测模式。
6、多主模式:如果控制器不使能,驱动IO缓冲为3态;如果检测到多个主设备,可以产生一个模式失败中断。
7、可编程时钟的相位和极性 (CPHA, CPOL)。
8、可编程中断或者轮询设备状态。
SPI外设模块的框图如下:
经查创龙TLZ7x-EasyEVM评估板上并没有什么SPI外设,核心板有个QSPI FLASH是接到Zynq的QSPI外设模块的,和SPI不是用一个外设,因为TLZ7x-EasyEVM评估板可以扩展的IO非常多,这里我们直接把SPI信号经EMIO布线到PL侧的扩展IO上,这样可以直观地用示波器或者逻辑分析仪来观察测试,软件上用PS侧的SPI外设模块工作在主模式下进行数据传输,具体实验步骤如下:
1、实验基于创龙提供的第一张光盘Demo\All-Programmable-SoC-demos\tl-emio-gpio-led-demo下DEMO来修改,首先要学习下用户手册目录下的《3-1-1-基于TcL脚本生成Vivado工程及编译.pdf》文档,按照其步骤生成一个Vivado工程,如cd C:/tl-emio-gpio-led-demo/hw/src/scripts目录,然后执行vivado -mode batch -source tl_emio_gpio_led_project.tcl -tclargstlz7x-easyevm xc7z020clg400-2 ,注意该脚本只能运行于vivado2007.4版本。Tcl脚本执行完成后,在工程源码" hw \src\runs"目录下生成对应开发平台的Vivado工程。
2、进入Vivado工程所在的hw \src\runs路径,双击tl_emio_gpio_led.xpr文件打开工程。然后再工程界面左侧点击"IPINTEGRATOR -> Open Block Design",打开块图后双击processing_system7_0重新配置Zynq处理器IP, 点击MIOConfiguration -> SPI 0,IO配置为EMIO按OK,具体如下所示:
在Diagram窗口中可以看到 ZYNQ7 Processing System多了一个SPI_0端口, 将光标移动到该端口并选中该端口,然后点击鼠标右键,在弹出的列表中选择 “MakeExternal”,这样就把SPI_0信号输出了,具体如下所示:
3、在Sources窗口中展开Design Sources,然后右键点击tl_emio_gpio_led_wrapper下的tl_emio_gpio_led.bd,在弹出的菜单中选择Generate Output Products,在弹出的对话框中选择Generate,然后等待Generate完成后点击“OK”。然后同样右键点击tl_emio_gpio_led_wrapper下的tl_emio_gpio_led.bd,在弹出的菜单中选择Create HDL Wrapper…创建顶层 HDL Wrapper。
4、在左侧Flow Navigator导航栏中找到 RTL ANALYSIS 点击该选项中的Open Elaborated Design,在弹出的对话框中点击OK;运行完点主界面Windows -> IO Ports, 修改SPI信号电平为LVCMOS33,然后修改SPI信号的脚位为V20、W20、R16、R17,最后按快捷键Ctrl+S保存管脚约束, 具体如下图示:
5、点击左侧Flow Navigator导航栏中PROGRAM AND DEBUG ->Generate Bitstream对设计进行综合、 实现、并生成 Bitstream文件。
6、在菜单栏中选择 File -> Export -> Export hardware。在弹出的对话框中,勾选“Include bitstream”,然后点击OK”按钮。硬件导出完成后,在菜单栏选择File -> Launch SDK,启动SDK开发环境。
7、在SDK软件菜单栏中选择File -> New -> ApplicationProject, 新建一个 SDK应用工程,工程名为spi_test,使用Hello World模板。
8、修改工程中helloworld.c代码,使用PS的SPI驱动连续发送数据,同时对读回的数据进行检查,具体代码如下:
#include<stdio.h>
#include"platform.h"
#include"xil_printf.h"
#include"sleep.h"
#include"xspips.h" /* SPIdevice driver */
#defineSPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
static XSpiPsSpiInstance;
unsigned charReadBuffer[1024];
unsigned charWriteBuffer[1024];
int main()
{
int Status;
int i;
int err;
XSpiPs_Config *SpiConfig;
init_platform();
xil_printf("Spi test demo\n\r");
/*
*Initialize the SPI driver so that it's ready to use
*/
SpiConfig =XSpiPs_LookupConfig(SPI_DEVICE_ID);
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status =XSpiPs_CfgInitialize(&SpiInstance, SpiConfig,
SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
*Perform a self-test to check hardware build
*/
Status =XSpiPs_SelfTest(&SpiInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
*Set the Spi device as a master. External loopback is required.
*/
XSpiPs_SetOptions(&SpiInstance,XSPIPS_MASTER_OPTION |
XSPIPS_FORCE_SSELECT_OPTION);
XSpiPs_SetClkPrescaler(&SpiInstance,XSPIPS_CLK_PRESCALE_128);
//XSpiPs_Enable(&SpiInstance);
/*
*Assert the slave device select
*/
XSpiPs_SetSlaveSelect(&SpiInstance,0x1);
/*
*initial write data.
*/
for(i=0; i<1024; i++)
{
WriteBuffer = i%256;
}
err = 0;
while(1)
{
XSpiPs_PolledTransfer(&SpiInstance, WriteBuffer, ReadBuffer, 1024);
for(i=0; i<1024; i++)
{
if(ReadBuffer!=(i%256))
{
err++;
}
}
sleep(1);
memset(ReadBuffer, 0x0, 1024);
if(err != 0)
{
xil_printf("Spi receiveerror!\n\r");
err = 0;
}
}
cleanup_platform();
return 0;
}
9、首先在评估板的J4扩展口上用杜邦线或者跳线帽把SPI的MOSI和MISO线连起来实现硬件回环的效果,然后用JTAG下载线连接到评估板的JTAG接口上后上电,然后再SDK软件界面选择Xilinx -> Program FPGA先把PL逻辑下载到Zynq芯片,然后在Project Explorer中右键点spi_test工程并选择Debug As -> Launch onHardware(System Debugger)下载软件程序,可以看到SPI发送和读回数据一致,当把硬件回环的杜邦线或者跳线帽去掉时,读回的数据全为0或者乱码,err变量对错误结果进行计数,测试过程及结果的视频如下: