本帖最后由 FPGA课程 于 2024-9-26 09:55 编辑
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述SPI总线接口简单,SPI的时钟可以到100M以上,SPI总线可以用于多种场合串行通信,比如存储器,温度传感器,压力传感器,模拟转换器,实时时钟,显示器以及任何支持串行模式的SD卡。一些ADC比如AD7606也可以用SPI接口实现通信。
实验目的: 1:熟悉掌握SPI通信协议 2:熟悉SPI控制器的硬件资源 3:通过VITIS-SDK实现对SPI控制器的使用 2系统框图
3SPI总线协议介绍技术性能: SPI接口是Motorola 首先提出的全双工三线同步串行外围接口,采用主从模式(MasterSlave)架构;支持多slave模式应用,一般仅支持单Master。时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后(MSBfirst);SPI接口有2根单向数据线,为全双工通信,目前应用中的数据速率可达几Mbps的水平。总线结构如下图所示。
接口定义: SPI接口共有4根信号线,分别是:设备选择线、时钟线、串行输出数据线、串行输入数据线。 (1)MOSI:主器件数据输出,从器件数据输入 (2)MISO:主器件数据输入,从器件数据输出 (3)SCLK:时钟信号,由主器件产生 (4)/SS:从器件使能信号,由主器件控制 时钟极性和时钟相位: SPI数据的传输是在串行同步时钟信号(Serial Clock,SCK)的控制下进行的。主机的时钟发生器一方面控制主机的移位寄存器,另一方面通过从机的SCK信号线来控制从机的移位寄存器,从而保证主机与从机的数据交换是同步进行的。 SPI串行同步时钟可以设置为不同的极性(Clock Polarity ,CPOL)与相位(Clock Phase ,CPHA)。 时钟的极性(CPOL)用来决定在总线空闲时,同步时钟(SCK)信号线上的电位是高电平还是低电平。当时钟极性为0时(CPOL=0),SCK信号线在空闲时为低电平;当时钟极性为1时(CPOL=1),SCK信号线在空闲时为高电平; 时钟的相位(CPHA)用来决定何时进行信号采样。 当时钟相位为1时(CPHA=1),在SCK信号线的第二个跳变沿进行采样;这里的跳变沿究竟是上升沿还是下降沿?取决于时钟的极性。当时钟极性为0时,取下降沿;当时钟极性为1时,取上升沿;如下图:
CPHA=1 的SPI时序当时钟相位为0时(CPHA=0),在SCK信号线的第一个跳变沿进行采样。跳变沿同样与时钟极性有关:当时钟极性为0时,取上升沿;当时钟极性为1时,取下降沿;如下图:
CPHA=0 的SPI时序
数据传输 在一个SPI时钟周期内,会完成如下操作: 1)主机通过MOSI线发送1位数据,从机通过该线读取这1位数据; 2)从机通过MISO线发送1位数据,主机通过该线读取这1位数据。 这是通过移位寄存器来实现的。如下图所示,主机和从机各有一个移位寄存器,且二者连接成环。随着时钟脉冲,数据按照从高位到低位的方式依次移出主机寄存器和从机寄存器,并且依次移入从机寄存器和主机寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。
4ZYNQ SPI控制器介绍
4.1SPI控制器介绍SPI控制器通过APB总线接入到ARM,SPI控制器部分包含了数据的SPI控制器、SPI中断、发送模块、发送FIFO、接收模块、接收FIFO,并且支持SPI Master模式,以及SPI Slave模式,对于SPI的SLAVE模式还有SLAVE 同步默默。SPI的信号接口可以定义为MIO也可以定于到FPGA的EMIO,对于MIO速度可以到50M,对于EMIO速度为25M.
以下介绍SPI控制器的重要功能模块。 1:SPI的SS选通信号当SPI作为Master模式的时候,SPI的可以通过3个SS信号实现1~3个外设或者通过3-8译码可以实现1~8个外设选通。SS选通支持手动模式和自动模式,默认是自动模式,在自动模式下每次发送数据会自动设置SS。如果手动模式则需要手动取消SS的片选。我们演示demo就是自动模式。 2:SPI控制器的FIFOSPI控制器的RxFIFO和TxFIFO深度各是128字节。 往已经满的RxFIFO中送入数据,会导致溢出标志置1,新的数据不会添加进入FIFO。可以通过软件写1清除[RX_OVERFLOW]位。 往已经满的TxFIFO写入数据,这个数据会被忽略。当TxFIFO已经写满,TX_FIFO_full标志会置1,直到数据被读出,当FIFO非满后TX_FIFO_full标志会置0。如果TxFIFO读空产生向下溢出, TX_FIFO_underflow位置1。 3:SPI控制器的时钟SPI_REF_CLK时钟在主机模式提供控制器的工作时钟,并且是SCLK的波特率分频器的参考时钟。在主模式下, SCLK使用波特率分频器从SPI_REF_CLK分频而来。 波特率分频器支持4~256分频(4,8,16,... 256分频)。 在从机模式下使用输入的SCL时钟驱动MISO信号和对MOSI以及SS信号采样,数据最终需要和SPI_REF_CLK时钟同步到SPI的控制器。 4:控制器的中断下图中RXFIFO和TXFIFO的最多可以保存128个数据。可以通过设置TX FIFO或者RX FIFO的Threshold寄存器设置TX FIFO的将满中断以及RX FIFO的将空中断中FIFO的数据量。
以下这种图表示了中断相关寄存器的设置关系。
4.2 SPI控制器的寄存器XSPIPS_CR寄存器XSPIPS_CR_OFFSET (0x00U) Field Name | Bits | Type | Reset Value | Description | 保留 | 31:18 | RO | 0x0 | 保留 | Modefail_gen_en | 17 | WR | 0x1 | 模式失败生成启动 1:使能,当总线冲突导致模式设置失败 0:禁用 | MANSTRT
| 16 | WO | 0x0 | Master启动命令 1:使能 0:禁用 | Man_start_en | 15 | WR | 0x0 | 手动启动使能 1:使能 0:禁用 | Manual_CS | 14 | WR | 0x0 | 手动CS 1:手动模式 0:自动模式 | CS | 13:10 | WR | 0x0 | 外设选择 xxx0:Slave0选通 xx01:Slave1选通 x010:Slave2选通 0111:保留 1111:没有Slave选通 | PERI_SEL | 9 | WR | 0x0 | 外设译码选择 1:支持3-8译码 0:支持1~3个外设 | REF_CLK | 8 |
| 0x0 | 参考时钟 1:不支持 0:使用SPI REFERENCE CLOCK | 保留 | 7:6 | RO | 0x0 | 保留 | BAUD_RATE_DIV | 5:3 | WR | 0x0 | 分频器 只有Master模式才支持对spi_ref_clk分频 000:不支持 001:4分频 010:8分频 011:16分频 100:32分频 101:64分频 110:128分频 111:256分频 | CPHA | 2 | WR | 0x0 | 时钟相位 1:在SCLK第2个时钟沿采样 0:在SCLK第1个时钟沿采样 | CPOL | 1 | WR | 0x0 | 时钟极性 1:在SCLK上升沿采样 0:在SCLK下降沿采样 | MSTREN | 0 | WR | 0x0 | 模式选择 1:主机模式 0:从机模式 |
XSPIPS_SR寄存器XSPIPS_SR_OFFSET (0x04U) 中断状态寄存器,当相应的中断产生后,中断状态寄存器相应的位置1,写1清零 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:7 | RO | 0x0 | 31~7bit:保留 | TX_FIFO_underflow | 6 | WTC | 0x0 | TX FIFO下溢 1:溢出 0:未溢出 | RX_FIFO_full | 5 | WTC | 0x0 | RX FIFO满 1:满 0:未满 | RX_FIFO_not_empty | 4 | WTC | 0x0 | RX FIFO非空 1:FIFO数据大于等于THRESHOLD 0:FIFO数据小于THRESHOLD | TX_FIFO_full | 3 | WTC | 0x0 | TX FIFO满 1:满 0:未满 | TX_FIFO_not_full | 2 | WTC | 0x0 | TX FIFO将满 1:FIFO数据小于THRESHOLD 0:FIFO数据大于等于THRESHOLD | MODE_FAIL | 1 | WTC | 0x0 | SPI 模式错误 表示管脚 n_ss_in上的电压与SPI模式不一致。如果 n_ss_in在主机模式(多主机竞争)下为低电平,或者n_ss_in在从机模式下传输期间变为高电平,则设置 =1。这些条件将清除 spi_enable 位并禁用SPI。该位仅在系统复位时复位, 并且仅在读取该寄存器时清零。 ModeFail 中断,向该位写入1清除。 1:产生模式错误 0:没有错误 | RX_OVERFLOW | 0 | WTC | 0x0 | 接收溢出中断 1:溢出 0:未溢出 |
XSPIPS_IER寄存器XSPIPS_IER_OFFSET (0x08U) 中断使能寄存器,对应于之前的中断状态寄存器,设置1为使能相关中断 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:7 | RO | 0x0 | 保留 | TX_FIFO_underflow | 6 | WO | 0x0 | TX FIFO下溢中断使能 | RX_FIFO_full | 5 | WO | 0x0 | RX FIFO满中断使能 | RX_FIFO_not_empty | 4 | WO | 0x0 | RX FIFO非空中断使能 | TX_FIFO_full | 3 | WO | 0x0 | TX FIFO满中断使能 | TX_FIFO_not_full | 2 | WO | 0x0 | TX FIFO非满中断使能 | MODE_FAIL | 1 | WO | 0x0 | SPI 模式错误中断使能 | RX_OVERFLOW | 0 | WO | 0x0 | 接收溢出中断中断使能 |
XSPIPS_IDR寄存器XSPIPS_IDR_OFFSET (0x0CU) 中断禁用寄存器, 对应于之前的中断状态寄存器,设置1为禁用相关中断 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:7 | RO | 0x0 | 保留 | TX_FIFO_underflow | 6 | WO | 0x0 | TX FIFO下溢中断禁用 | RX_FIFO_full | 5 | WO | 0x0 | RX FIFO满中断禁用 | RX_FIFO_not_empty | 4 | WO | 0x0 | RX FIFO非空中断禁用 | TX_FIFO_full | 3 | WO | 0x0 | TX FIFO满中断禁用 | TX_FIFO_not_full | 2 | WO | 0x0 | TX FIFO非满中断禁用 | MODE_FAIL | 1 | WO | 0x0 | SPI 模式错误中断禁用 | RX_OVERFLOW | 0 | WO | 0x0 | 接收溢出中断禁用 |
XSPIPS_IMR寄存器XSPIPS_IMR_OFFSET (0x10U) 中断掩码寄存器, 对应于之前的中断状态寄存器、中断使能寄存器、中断禁用寄存器,1代表相关中断禁用 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:7 | RO | 0x0 | 保留 | TX_FIFO_underflow | 6 | RO | 0x0 | TX FIFO下溢中断掩码 | RX_FIFO_full | 5 | RO | 0x0 | RX FIFO满中断掩码 | RX_FIFO_not_empty | 4 | RO | 0x0 | RX FIFO非空中断掩码 | TX_FIFO_full | 3 | RO | 0x0 | TX FIFO满中断掩码 | TX_FIFO_not_full | 2 | RO | 0x0 | TX FIFO非满中断掩码 | MODE_FAIL | 1 | RO | 0x0 | SPI 模式错误中断掩码 | RX_OVERFLOW | 0 | RO | 0x0 | 接收溢出中断掩码 |
XSPIPS_ER寄存器XSPIPS_ER_OFFSET (0x14U) SPI使能寄存器 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:1 | RO | 0x0 | 保留 | SPI_EN | 0 | WR | 0x0 | 1:使能SPI 0:禁止SPI |
XSPIPS_DR寄存器XSPIPS_DR_OFFSET (0x18U) SPI的延迟寄存器用于控制选通到非选通、非选通到选通、当前WORD最后bit到下个WORD第1bit、选通到第一个Bit开始的延迟参数。 Field Name | Bits | Type | Reset Value | Description | d_nss | 31:24 | RW | 0x0 | 选通到取消选通延迟 Master模式,当cpha=0时,设置SPI REFERENCE CLOCK或ext_clk个周期的延迟。 | d_btwn | 23:16 | RW | 0x0 | 取消选通到选通的延迟 从取消选通到选通之间延迟SPI REFERENCE CLOCK或ext_clk个周期 | d_after | 15:8 | RW | 0x0 | 最后1Bit到下1bit间延迟 当前WORD的最后1Bit到下个WORD的第1bit间延迟SPI REFERENCE CLOCK或ext_clk个周期 | d_int | 7:0 | RW | 0x0 | nss低电平到第1bit的延迟 低电平到第1bit间延迟SPI REFERENCE CLOCK或ext_clk个周期 |
XSPIPS_TXD寄存器XSPIPS_TXD_OFFSET (0x1CU) SPI的发送数据寄存器 Field Name | Bits | Type | Reset Value | Description | TX_FIFO_data | 31:0 | WO | 0x0 | 7~0bit:数据寄存器写入这个寄存器的数据会写入FIFO |
XSPIPS_RXD寄存器XSPIPS_RXD_OFFSET (0x20U) SPI的接收数据寄存器 Field Name | Bits | Type | Reset Value | Description | RX_FIFO_data | 31:0 | RW | 0x0 | 7~0bit:从接收FIFO读出的数据 |
XSPIPS_SICR寄存器XSPIPS_SICR_OFFSET (0x24U) SPI的SLAVE启动对于总线时钟监测设置 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:8 | RW | 0x0 | 保留 | Slave_Idle_coun | 7:0 | rw | 0xff | 7~0bit:当外部主机输出的SCLK时钟稳定的输入Slave_Idle_coun个SPI参考时钟周期或者SPI被取消选择,则SPI SLAVE模式会检测到启动 |
XSPIPS_TXWR寄存器XSPIPS_TXWR_OFFSET (0x28U) XSPIPS_TXWR将满值 Field Name | Bits | Type | Reset Value | Description | Threshold_of_TX_FIFO | 31:0 | RW | 0x1 | 设置TX FIFO将满值 |
RX_thres_reg0寄存器RX_thres_reg0_OFFSET (0x2CU) 设置RX FIFO的将空值 Field Name | Bits | Type | Reset Value | Description | Threshold_of_RX_FIFO | 31:0 | RW | 0x1 | 设置RX FIFO将空值 |
Mod_id_reg0寄存器Mod_id_reg0 (0xFCU) 这个寄存器暂时不清楚作用 Field Name | Bits | Type | Reset Value | Description | 保留 | 31:25 | RO | 0x0 | 保留 | module_ID | 24:0 | RO | 0x90106 | 模块ID号 | 5硬件电路分析FEP-BASE-CARD是米联客设计开发用于支持一些基本的FPGA接口学习的模块,可以支持SPI动态驱动数码管实验、RTC实验、EEPROM实验、液晶屏实验、PL串口实验,以及通过CEP扩展到GPIO可以支持LVDS实验、GPIO验证、DVP摄像头连接 FEP-BASE-CARD分3.3V和1.8V版本,由于默认IO采用1.8V因此,这里仅介绍1.8V版本,我们本方案只需要短接MISO和MOSI就可以完成环路测试.
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
6搭建SOC系统工程详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。 6.1SOC系统工程
ZYNQ IP中设置SPI0
设置SPI的参考时钟,以及PL 50M时钟提供给ILA使用
ILA设置
6.2编译并导出平台文件以下步骤简写,有不清楚的看第一篇文章。 1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。 2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。 3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件 4:生成Bit文件。 5:导出到硬件: FileàExport HardwareàInclude bitstream 6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
7搭建Vitis-sdk工程创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。 7.1创建SDK Platform工程
右击soc_base编译,编译的时间可能会有点长 7.2创建APP工程
8spi polled模式程序分析
8.1SpiPs_Init(SPI_DEVICE_ID)函数
1:XSpiPs_LookupConfig(SpiDeviceId)函数
首先依然是通过查找配置程序来获取SPI控制器的硬件配置。我们跟踪这个程序,看看他获取的配置是什么。
右击参数打开参数定义
可以看到,这个数组里存放的是SPI设备ID、SPI控制器的基地址,SPI的时钟。
可以继续右击这些参数定位到这些参数的定义
在xparameters.h中找到如下定义,可以看到spi的基地址和SPI时钟
2:XSpiPs_CfgInitialize((&SpiInstance), SpiConfig,SpiConfig->BaseAddress)函数
2.1: XSpiPs *InstancePtr XSpiPs结构体定义了包括SPI数据收发缓存指针、还剩下的数据量未传输、忙状态,主机或从机模式、回调函数、回调函数的参数。
2.2XSpiPs_Reset(InstancePtr)函数
2.3SPI配置寄存器
SPI的配置寄存器偏移地址:XSPIPS_CR_OFFSET = 0x00 设置XSPIPS_CR_RESET_STATE模式失败生成启用,这个资料没有详细说明大概的意思是用于多主机模式的系统中。以下是 SPI配置寄存器的功能说明
3:XSpiPs_SetOptions((&SpiInstance), XSPIPS_MASTER_OPTION)SPI默认是Slave模式,所以我们必须设置的是Master模式,我们来进入这个函数继续分析。
3.1XSpiPs_ReadReg(InstancePtr->Config.BaseAddress,XSPIPS_CR_OFFSET) 这个函数首先读取配置寄存器的值 3.2接下来是一个for循环
在这个for循环中,关键是通过传递进来的Options变量和OptionsTable查表比对,然后设置相应的功能位。我们这里传递进来的参数是: XSPIPS_MASTER_OPTION,用于设置SPI位主机模式; XSPIPS_FORCE_SSELECT_OPTION设置强制从机选择;
最后计算结果配置寄存器的低16bit 00xx_xx0x_xxxx_x001
可以得出CPOL=0 CPHA=0 SCK空闲低电平,第一个SCLK的跳变沿接收数据
3.3 XSpiPs_Disable(InstancePtr)函数 这段代码的意思是如果要切换SPI的CPOL-CPHA的模式,则先禁止SPI控制器,然后再写入
Enable/Disable寄存器的地址偏移XSPIPS_ER_OFFSET=0x14
3.3XSpiPs_Enable(SpiInstance)函数 作用和XSpiPs_Disable(InstancePtr)相反,使能SPI控制器 4:XSpiPs_SetClkPrescaler(&SpiInstance, XSPIPS_CLK_PRESCALE_64)函数这个函数设置SPI的时钟分频参数
参数XSPIPS_CLK_PRESCALE_64 =0x05,所以设置64分频
5:XSpiPs_SetSlaveSelect(&SpiInstance, 0x01)XSpiPs_SetSlaveSelect(XSpiPs *InstancePtr, u8 SlaveSel)函数用来设置被选择的从设备,通常来说,可以选择3个从设备,但是如果通过三八译码器,最多可以支持8个从设备的选择,一次只能选择一个从设备。
7.1XSpiPs_IsDecodeSSelect( InstancePtr )函数
以上代码中先通过XSpiPs_IsDecodeSSelect( InstancePtr )函数获取当前SPI 配置寄存器的值,然后对其中OptionsTable的值进行判断,以获取当然的Options值。(XSpiPs_GetOptions(InstancePtr)函数定义如下:
关于OptionsTable的介绍,在前面也介绍过,这里再次给出定义:
所以这段代码最终的目的时判单从设备选项是否已经设置了从设备选择方式,相关的寄存器功能如下:
我们这里没有用到三八译码方式,所以这一位为0,所以以上代码会执行else分支的部分,并且设置配置寄存器的 13~10位。
8.2SpiPs_Send(&SpiInstance,SendBuf,10)函数
这里为了完成数据的回传,把tx和rx短接。SPI控制器的发送和接收本质就是移位寄存器,每个SCK时钟移出或者移入1位数据。
所以对于发送移位寄存器:不管是发数据,还是收数据,SPI的发送移位控制器都会把发送寄存器里面的数据发出,接收控制器的移位寄存器都会把数据移位输入; 所以对于接收移位寄存器:不管是发数据,还是收数据,SPI的发送移位控制器都会把发送寄存器里面的数据发出,接收控制器的移位寄存器都会把数据移位输入; 接下来我们主要分析XSpiPs_PolledTransfer(IntcInstancePtr, SendBuffer, ReadBuf,ByteCount)函数。这个函数负责SPI数据的收发。因为上面我们也分析了,对于SPI不管是发送数据,还是接收数据,其实收发 过程都是在发生的。
以上代码中,在大while循环中完成所有SPI数的收发。在第一个被框选的代码中完成数的发送,在第二个框选的代码中完成数据的接收。下面我们对整个函数的流程做一个分析: 1:从设备选择是否是自动还是手动
这里也是通过XSpiPs_GetOptions函数判断,这个分析过程在前面代码已经分析过
2:XSpiPs_Enable(InstancePtr)
这个函数使能SPI控制器
3:数据发送3.3.1写数据到FIFO 这部分代码判断需要发送的数据是否小于SPI FIFO深度的大小,如果是则把数据都发送,直到达到SPI FIFO深度
SPI发送数据寄存器XSPIPS_TXD_OFFSET=0x1C
3.3.2自动模式还是主动模式 我们是自动模式,再初始化阶段已经完成了寄存器的配置
3.3.3等待数据发送完毕 通过读取状态寄存器,判单是否传输完毕
SPI状态寄存器的偏移地址XSPIPS_SR_OFFSET = 0x04
这里还有一个寄存器,TX阈值寄存器,这个寄存器的值和XSPIPS_IXR_TXOW_MASK位相关,当TX的FIFO数据量小于这个阈值XSPIPS_IXR_TXOW_MASK置1.后面的中断程序分析中,中断的触发和这个置的设置也有关系。默认是1,那么当TxFIFO的数据为0的时候XSPIPS_IXR_TXOW_MASK置1。当使能了中断传输就会触发中断。
4:数据接收以下代码中,通过判断TransCount值,直到发送了多少数据,那么RXFIFO就会接收多少数据。直接读SPI的RX数据寄存器。
SPI的RX数据寄存器地址偏移XSPIPS_RXD_OFFSET= 0x20
5:停止SPI传输当一次传输完毕后,如果手动模式需要手动设置XSPIPS_CR_SSCTRL_MASK相关位。我们这里是自动模式,所以if里面的代码不被执行。
6: XSpiPs_Disable(InstancePtr)函数停止SPI控制器
8.3SpiPs_Read(&SpiInstance,ReadBuf,10)函数
前面用SpiPs_Send实际上已经把数据接收到了RevBuf了,这次再次传输会再发送端继续传输RevBuf的值,并且接收到ReadBuffer。这就完成了本文需要演示的loop功能。 9spi interrupt模式程序分析前面我们已经详细分析了polled模式下的工作机制,对于中断模式,数据传输结束后触发中断。其他的内容都非常类似。而且大家学习米联客的代码,很多代码具备类似的结构。中断部分亦是如此。中断部分介绍有不少重复类似的分析过程,我们依然再次说明,已经熟悉我们代码结构的读者可以提高效率,跳过一部分分析代码。 9.1init_intr_sys函数- void init_intr_sys(void) {
- Init_Intr_System(&Intc);
- Init_SpiPs(&SpiInstance,SPI_DEVICE_ID);
- SpiPs_Setup_IntrSystem(&Intc, &SpiInstance, SPI_INTR_ID); Setup_Intr_Exception(&Intc);
- }
复制代码
此函数在程序文件spi_test.c中通过调用相关中断函数实现中断功能。为了实现多类型中断,用户必须根据以下方式设置中断。 9.2Init_Intr_System(&Intc)函数- int Init_Intr_System(XScuGic * IntcInstancePtr)
- {
- int Status;
- XScuGic_Config *IntcConfig;
- /*
- * Initialize the interrupt controller driver so that it is ready to
- * use.
- */
- IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
- if (NULL == IntcConfig) {
- return XST_FAILURE;
- }
- Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
- IntcConfig->CpuBaseAddress);
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
复制代码
1:XScuGic_LookupConfig(INTC_DEVICE_ID) 函数
右击XScuGic_ConfigTable查看参数定义:
可以继续右击以下参数查看其定义
可以看到这里定义了GIC中断控制器的基地址
2: XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress)
中断部分主要内容是回调函数的设置,以下回调函数相关参数定义如下:
以下代码对所有为定义的全局中断进行定义回调函数和回调参数。
StubHandler函数定义如下:
9.3Setup_Intr_Exception函数- void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
- {
- /* Enable interrupts from the hardware */
- Xil_ExceptionInit();
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
- (Xil_ExceptionHandler)XScuGic_InterruptHandler,
- (void *)IntcInstancePtr);
- Xil_ExceptionEnable();
- }
复制代码
这个函数中对设置全局中断回调函数,以及使能全局中断 1:Xil_ExceptionInit()函数这个函数目前说明都没做,只是未来保留兼容性,预留在这里。
2:Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,(void *)IntcInstancePtr)函数
2.1XIL_EXCEPTION_ID_INT定义
2.2: XExc_VectorTableEntry定义 任何的中断都可以理解位异常处理,这里定义了MPSOC或者ZYNQ支持的异常处理类型。
2.3XScuGic_InterruptHandler函数 可以看到这个函数会根据读取到的中断号调用相应的回调函数,这个回调函数会在具体的外设中断初始化中设置。
2.3中断异常回调函数
由于XIL_EXCEPTION_ID_INT=2所以Xil_ExceptionNullHandler在中断产生的时候会被调用。
3:Xil_ExceptionEnable()函数这条函数最终指向了汇编指令:
9.4Init_SpiPs (&SpiInstance,SPI_DEVICE_ID)函数
此函数内容部分和SPI Polled模式一样,这里不再重复。
9.5SpiPs_Setup_IntrSystem(&Intc, &SpiInstance, SPI_INTR_ID)函数此函数负责设置中断的回调函数,中断回调函数一般分2此,第一次是系统中断函数回调,每次控制器完成一次数据传输都会中断,第二次是用户的函数回调,全部数据传输完,系统中断函数里面回调用户回调函数。 这里函数XSpiPs_InterruptHandler就是系统中断函数,SpiHandler是用户回调函数。
1:XScuGic_Connect(IntcInstancePtr, SpiIntrId, (Xil_ExceptionHandler)XSpiPs_InterruptHandler, (void *)SpiInstancePtr)这个函数负责把对应中断号从回调函数,以及回调参数,连接到之前在Init_Intr_System(&Intc)函数中定义的回调函数。
2:XSpiPs_InterruptHandler(XSpiPs *InstancePtr)函数2.1清中断禁用中断 进入中断函数后需要立马清除中断,和禁用中断,否则可能再次产生中断。
2.2判断模式错误 如果传输发送错误,直接停止传输,并且调用用户回调函数
2.3数据传输
首先判断是否有数据已经发送完了,通过判断XSPIPS_IXR_TXOW_MASK位
接着一个while循环,完成数据的接收。读者如果对SPI传输还不明白的看看Polled模式介绍。SPI发送和接收是同时进行的。 2.3判断数据是否完成传输 以下代码中判断数据是否完成传输,如果已经传输结束,则禁用中断、释放SPI选通信号、停止SPI传输、调用用户回调函数。 否则重新使能中断。
2.4检查上溢和下溢错误 判断发送FIFO和接收FIFO是否存在下溢(读空)和上溢(写满)错误。
3:XSpiPs_SetStatusHandler(SpiInstancePtr, SpiInstancePtr,(XSpiPs_StatusHandler) SpiHandler)函数设置用户回调函数
4: SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount)通知已经完成传输,以及通知错误的情况。
10实验结果
10.1硬件准备本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF) MLK_H3_CZ08-7100-MZ7100FC 支持跳线帽修改 FEP 或者 FMC IO BANK 电压,默认设置 1.8V,本实验需要用到 FEP-BASE-CARD-1.8V,短接用于 MISO 和 MOSI 的短接帽。
10.2实验结果Polled模式
中断模式
通过在线逻辑分析仪观察数据
|