0%

ZYNQ嵌入式之常用接口(基于PYNQ-Z2开发板)

本节主要介绍了SPI与CSI2接口协议。

SPI接口

1.SPI接口协议的基本概念

  • SPI(Serial Peripheral interface),串行外设接口,SPI协议主要作为主控芯片去配置外围芯片的接口协议

  • SPI是一种高速的、全双工、同步、串行、主从结构通信总线

  • SPI需要至少4根线,分别是MISO(主机输入从机输出)、MOSI(主机输出从机输入)、SCLK(时钟)、CS(片选)【或者叫SS】

    image-20231022171636889
  • 通信过程:

    • SPI总线在进行数据传送时,先传送高位,后传送低位

    • SPI协议规定一个SPI设备不能在数据通信过程中仅仅只充当发送或接收方。故在每个clk周期内,SPI设备都会发送并接收一个bit大小的数据,即SPI只有主模式和从模式之分,没有读和写的说法,因为实质上每次SPI是主从设备在交换数据,也就是说,你发送一个数据必然会收到一个数据(SPI设备在进行通信的过程中,主设备与从设备之间会产生一个数据链路回环)

    • 时钟通过时钟极性(CPOL)和时钟相位(CPHA)控制两个SPI设备间何时进行数据交换何时对接收到的数据进行采样,来保证数据在两个设备之间是同步传输的

      • CPOL表示SCLK空闲时的状态
        • CPOL=0,空闲时SCLK为低电平
        • CPOL=1,空闲时SCLK为高电平
      • CPOL表示采样时刻
        • CPHA=0,每个周期的第一个时钟沿采样
        • CPHA=0,每个周期的第二个时钟沿采样
    • SPI工作的四种不同模式:

      • CPOL=0,CPHA=0:

        image-20231022173756537
      • CPOL=0,CPHA=1:

        image-20231022174251122
      • CPOL=1,CPHA=0:

        image-20231022174504083
      • CPOL=1,CPHA=1:

        image-20231022174328058
      CPOL/CPHA的设定 第一位数据的输出 其他位的输出 数据采样
      CPOL=0,CPHA=0 在第一个SCLK上升沿之前 SCLK下降沿 SCLK上升沿
      CPOL=0,CPHA=1 第一个SCLK下降沿 SCLK下降沿 SCLK上升沿
      CPOL=1,CPHA=0 在第一个SCLK下升沿之前 SCLK上升沿 SCLK下降沿
      CPOL=1,CPHA=1 第一个SCLK上降沿 SCLK上升沿 SCLK下降沿

2.ZYNQ SPI数据回环实验

2.1 vivado相关配置

  • 在hello world实验的基础上加上SPI控制器的配置,如下:

    image-20231023113419498

  • 对SPI接口引出如下引脚:

    image-20231023113554218
  • 最终block结构如下:

    image-20231023113649187
  • 引脚约束如下:

    image-20231023113307224

  • 生成bit stream后导出硬件

2.2 Vitis代码编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "xparameters.h"
#include "xspips.h"
#include "xil_printf.h"
#include "sleep.h"
XSpiPs Spi0;

#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 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;

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;
}

2.3 实验结果

image-20231023113132477

CSI2接口

Reference

欢迎来到ssy的世界