这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 上一修订版 两侧同时换到之后的修订记录 | ||
基于spi总线的arm与fpga通信实验 [2019/11/29 10:18] zhangzheng 创建 |
基于spi总线的arm与fpga通信实验 [2020/07/02 18:38] zgf [三、 实验原理] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | [[http://www.cnblogs.com/xiaomagee/p/5507488.html]] | + | | **银杏科技有限公司旗下技术文档发布平台** |||| |
+ | |技术支持电话|**0379-69926675-801**||| | ||
+ | |技术支持邮件|Gingko@vip.163.com||| | ||
+ | |技术论坛|http://www.eeschool.org||| | ||
+ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
+ | | V1.0 | 2020-07-02 | gingko | 初次建立 | | ||
+ | |||
+ | ===== 实验十三:SPI通信实验——基于SPI总线的ARM与FPGA通信 ===== | ||
+ | ==== 一、 实验目的与意义 ==== | ||
+ | |||
+ | - 掌握SPI通信协议及实现方法。 | ||
+ | - 掌握QuartusII的使用方法。 | ||
+ | ==== 二、 实验设备及平台 ==== | ||
+ | |||
+ | - iCore4 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&id=551864196684|点击购买]]。 | ||
+ | - Blaster(或相同功能)仿真器[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]。 | ||
+ | - JLINK(或相同功能)仿真器。 | ||
+ | - Micro USB线缆。 | ||
+ | - Keil MDK 开发平台。 | ||
+ | - Quartus开发平台。 | ||
+ | - 电脑一台。 | ||
+ | ==== 三、 实验原理 ==== | ||
+ | === 1.SPI简介 === | ||
+ | * SPI是串行外设接口(Serial PeripheralInterface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议。SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。 | ||
+ | * SPI硬件接口: | ||
+ | * MISO :主设备数据输入,从设备数据输出 | ||
+ | * MOSI :主设备数据输出,从设备数据输入 | ||
+ | * SCLK :时钟信号,由主设备产生 | ||
+ | * CS :从设备片选信号,由主设备控制 | ||
+ | === 2.SPI功能说明 === | ||
+ | |||
+ | * SPI时钟极性和相位: | ||
+ | * CPOL决定时钟空闲时的稳定电平,对主/从都有效 | ||
+ | * CPOL=0:空闲时低电平 | ||
+ | * CPOL=1:空闲时高电平 | ||
+ | * CPHA决定数据采样时刻 | ||
+ | * CPHA=0:第一个时钟延开始采样MSBit | ||
+ | * CPHA=1:第二个时钟延开始采样MSBit | ||
+ | * SPI总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。如图13-1所示 | ||
+ | |||
+ | {{ :icore4:icore4_fpga_13_1.png?direct |图13-1}} | ||
+ | === 3.SPI通信指令表 === | ||
+ | |||
+ | |指令名称 |字节1 |字节2 |字节3 |字节4| | ||
+ | |器件ID |01h| | ||
+ | |写数据长度| 02h| A15~A8| A7~A0| | ||
+ | |写数据 | 04h| A15~A8 |A7~A0| 数据(直至写完所有数据)| | ||
+ | |读数据长度| 05h| A15~A8| A7~A0| | ||
+ | |读数据 | 07h|A15~A8 |A7~A0| 数据(直至读完所有数据)| | ||
+ | |读错误信息| 08h| | ||
+ | |||
+ | * ARM与FPGA通信采用的是半双工式通信,FPGA通过识别指令完成与ARM的交互。 | ||
+ | * 器件ID指令为01h,接下来为两字节的伪指令,第四字节仍为伪指令读取ID标志。 | ||
+ | * 写数据长度指令02h,接下来两个字节为写数据的长度,先发高字节,后发低字节,接下来为一个字节的伪指令00h。 | ||
+ | * 写数据指令为04h,接下来为两字节的地址指令,后为要写入的数据,数据写入完毕以伪指令00h结束数据传输。 | ||
+ | * 读数据长度指令05h,接下来两个字节为写数据的长度,先发高字节,后发低字节,接下来为一个字节的伪指令00h。 | ||
+ | * 读数据指令为07h,接下来为两字节的地址指令,其后为伪指令00h开始读取数据进行数据传输,第五字节以后为要读取的数据。 | ||
+ | * 读错误信息指令08h,FPGA接收数据是否出错,先发送两个字节的伪指令,第四字节仍为伪指令读取错误标志信息。 | ||
+ | === 4、本实验实现方式 === | ||
+ | * 通过FPGA建立的SPI模块对外提供的SCLK、CS、MOSI、MISO接口与STM32的SPI相连接,Commix串口精灵与STM32通过串口连接,实现三者之间的通信。本实验中,Commix串口精灵向STM32发送数据,STM32的RXD端口接收数据,然后,通过TXD端口把数据发送至FPGA,STM32起到一个桥梁作用。程序运行后,FPGA定时向STM32发送数据,经过STM32发送至串口精灵显示出来。下图为实验原理图。 | ||
+ | {{ :icore4:icore4_fpga_13_2.png?direct&700 |实验原理图}} | ||
+ | ==== 四、 代码讲解 ==== | ||
+ | * 本实验基于ARM+FPGA构架,通过ARM首先发送查询ID指令,然后依次通过指令设置写数据的长度、写数据地址、读数据的长度、读数据的地址,然后对比写入数据和读出数据是否一致判断数据是否写入成功,从而基于SPI总线实现ARM与FPGA之间的通信。 | ||
+ | * 实现ARM与FPGA通信,对FPGA而言,其关键就在于SPI时序的模拟,实现SPI数据的接收与发送,实现数据与传输信号之间的串并转换。FPGA首先接收ARM指令,然后解析指令,存储相应的信息与数据,并根据指令需求将相应的指令数据放到SIMO总线上,等待ARM读取,从而实现两者之间的数据交互。SPI时序的硬件语言描述如下: | ||
+ | <code verilog> | ||
+ | ////////////////按字节接收SPI发送过来的数据////////////// | ||
+ | ///////接收模块/////// | ||
+ | reg[3:0]i; | ||
+ | reg[7:0]data_in; | ||
+ | reg [39:0]temp_data,data; | ||
+ | |||
+ | always@(posedge spi_clk or negedge rst_n) | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | i <= 4'd0; | ||
+ | temp_data <= 40'd0; | ||
+ | data <= 40'd0; | ||
+ | data_in <= 8'd0; | ||
+ | end | ||
+ | else case(i) //从高位开始接收数据,每8个spi_clk时钟接收一个Byte | ||
+ | 4'd0: | ||
+ | begin | ||
+ | i <= i + 1'd1; | ||
+ | data_in <= {data_in[6:0],spi_mosi}; | ||
+ | temp_data <= {temp_data[31:0],data_in}; | ||
+ | if(data_in == 8'd13) | ||
+ | begin | ||
+ | data <= temp_data; | ||
+ | end | ||
+ | else | ||
+ | begin | ||
+ | data <= data; | ||
+ | end | ||
+ | end | ||
+ | 4'd1,4'd2,4'd3,4'd4,4'd5,4'd6: | ||
+ | begin | ||
+ | i <= i + 1'd1; | ||
+ | data_in <= {data_in[6:0],spi_mosi}; | ||
+ | end | ||
+ | 4'd7:begin | ||
+ | i <= 4'd0; | ||
+ | data_in <= {data_in[6:0],spi_mosi}; | ||
+ | end | ||
+ | default: i <= 4'd0; | ||
+ | endcase | ||
+ | |||
+ | /*对比接收数据*/ | ||
+ | reg [2:0]led; | ||
+ | |||
+ | always@(posedge clk_25m or negedge rst_n) | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | led <= 3'b101; | ||
+ | end | ||
+ | else if (data == ledr) | ||
+ | led <= 3'b011; //红灯亮 | ||
+ | else if (data == ledg) | ||
+ | led <= 3'b101; //绿灯亮 | ||
+ | else if (data == ledb) | ||
+ | led <= 3'b110; //蓝灯亮 | ||
+ | |||
+ | assign {led_red,led_green,led_blue} = led; | ||
+ | |||
+ | //--------------------------delay----------------------------// | ||
+ | reg spi_clk_r; | ||
+ | always@(posedge clk_25m or negedge rst_n) | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | spi_clk_r <= 1'd1; | ||
+ | end | ||
+ | else | ||
+ | spi_clk_r <= spi_clk; | ||
+ | |||
+ | //--------------------------spi_miso----------------------------// | ||
+ | /*发送模块*/ | ||
+ | reg [39:0]data_out; | ||
+ | reg [5:0]j; | ||
+ | reg spi_out; | ||
+ | always@(negedge spi_clk_r or negedge rst_n) | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | data_out <= hello; | ||
+ | spi_out <= 1'd0; | ||
+ | j <= 6'd0; | ||
+ | end | ||
+ | else case(j) //连续40个spi_clk_r时钟发送“hello”字符串 | ||
+ | 6'd0: | ||
+ | begin | ||
+ | {spi_out,data_out[39:1]} <= data_out; | ||
+ | j <= j + 1'd1; | ||
+ | end | ||
+ | 6'd39: | ||
+ | begin | ||
+ | {spi_out,data_out[39:1]} <= data_out; | ||
+ | data_out <= hello; | ||
+ | j <= 6'd0; | ||
+ | end | ||
+ | default: | ||
+ | begin | ||
+ | {spi_out,data_out[39:1]} <= data_out; | ||
+ | j <= j + 1'd1; | ||
+ | end | ||
+ | endcase | ||
+ | </code> | ||
+ | ==== 五、 实验步骤 ==== | ||
+ | |||
+ | 1、把仿真器与iCore4的SWD调试口连接(直接相连或者通过转换器相连)。\\ | ||
+ | 2、将USB-Blaster与iCore4的JTAG调试口相连。\\ | ||
+ | 3、将跳线帽插在USB_UART。\\ | ||
+ | 4、把iCore4(USB_UART)通过Micro USB线与计算机相连,为iCore4供电。如图13-2所示:\\ | ||
+ | 图13-2 | ||
+ | 5、打开串口精灵,找到对应口打开,如下图。\\ | ||
+ | {{ :icore4:icore4_fpga_13_3.png?direct |图13-3}} | ||
+ | 6、打开KeilMDK开发环境,并打开实验工程。\\ | ||
+ | 7、将ARM程序下载至iCore4。\\ | ||
+ | 8、打开QuartusII开发环境,并打开实验工程。\\ | ||
+ | 9、将FPGA程序下载至iCore4\\ | ||
+ | 10、输入串口命令,观察实验现象。\\ | ||
+ | ==== 六、 实验现象 ==== | ||
+ | * 在Commix上发送命令后,对应的ARM和FPGA的LED灯亮,同时接收显示:hello | ||
+ | |||
+ | |串口命令发送格式 |ARM_LED现象 |FPGA_LED灯现象| | ||
+ | |LEDR\CR\LF |红灯亮 |红灯亮| | ||
+ | |LEDG\CR\LF |绿灯亮 |绿灯亮| | ||
+ | |LEDB\CR\LF |蓝灯亮 |蓝灯亮| | ||
+ |