用户工具

站点工具


icore3_fpga_15

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
icore3_fpga_15 [2019/12/23 17:44]
zhangzheng 创建
icore3_fpga_15 [2022/03/18 15:43] (当前版本)
sean
行 1: 行 1:
-[[http://www.cnblogs.com/xiaomagee/p/5464908.html]]+|  **银杏科技有限公司旗下技术文档发布平台** ​ |||| 
 +|技术支持电话|**0379-69926675-801**||| 
 +|技术支持邮件|Gingko@vip.163.com||| 
 +^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^ 
 +|  V1.0  |  2020-03-03 ​ |  gingko ​ |  初次建立 ​ |  
 + 
 +\\ 
 +===== 实验十五:基于UART的ARM和FPGA通信实验 ===== 
 + 
 +==== 一、实验目的与意义 ==== 
 + 
 +  - 了解以UART协议的定义及时序要求。 
 +  - 掌握串口通信的方法。 
 +  - 学习FPGA模拟时序实现UART通信的设计方法。 
 +==== 二、实验设备及平台 ==== 
 + 
 +  - iCore3 双核心板( FPGA型号为EP4CE10F17,ARM型号为STM32F407IGT6)。[[https://item.taobao.com/item.htm?​id=524229438677|点击购买]] 
 +  - Blaster(或相同功能的)仿真器。[[https:​//item.taobao.com/​item.htm?​id=554869837940|点击购买]] 
 +  - Micro USB线缆。 
 +  - QuartusII开发软件(本实验中使用的是13.1版本)。 
 +==== 三、实验原理 ==== 
 + 
 +  * UART(通用异步收发器)是一种通用串行数据总线,用于异步通信,可实现全双工传输和接收,是做硬件开发时常用的一种硬件接口。USART(通用同步异步收发器)在UART的基础上增加了同步功能,即USART是UART的增强型,异步通信的时候和UART没有区别。 
 +  * STM32F407的手册中有讲,任何USART双向通信均需要至少两个引脚:接收数据输入引脚(RX)和发送数据输出引脚(TX)。其中,如果使能了发送器但没发送数据的时候,TX引脚是处于高电平的。  
 +  * 本实验是基于ARM和FPGA的,STM32F407本身带有USART外设。FPGA通过模拟USART的时序建立USART模块。对外提供的RXD和TXD接口与STM32 的TXD、RXD串口I/​O相连接,实现和STM32F407的串口通信功能。STM32同时与Commix串口精灵连接,从而实现三者之间的数据传递。 
 +  * 本实验中,Commix串口精灵向STM32发送数据,STM32的RXD端口接收数据,然后通过和FPGA相连的TXD端口把数据发送至FPGA,STM32起到一个桥梁的作用。程序运行后,FPGA定时向STM32发送数据, STM32再将数据发送至Commix串口精灵。下图是本实验系统框图: 
 +{{ :​icore3:​icore3_fpga_15_1.png?​direct |}} 
 +  * UART作为串行传输总线,通过RX、TX双线连接ARM和FPGA。ARM只需配置好USART外设,实现串行传输功能即可;而FPGA本身不具有串行通信外设,需要模拟UART的接收和发送时序实现和ARM的串口通信功能。本实验主要讲解如何通过对串口传输时序的理解,用逻辑语言在FPGA上实现串口功能。 
 +  * 以8位字长的串口发送数据帧为例,下图是是传输时序图,从图中可以看到,初始状态时,传输线上为高电平,在持续一个波特的低电平之后,是发送的有效数据。之后是至少一个波特高电平的停止位。 
 +{{ :​icore3:​icore3_fpga_15_2.png?​direct |}} 
 +  * 由时序图得知,对于FPGA来说,在RX端口,可以通过启动位的电平判断有无数据传输进行。如果检测到RX端口有低电平,表示有串口数据传输过来,而低电平持续一个波特之后的数据才是传输的有效数据。FPGA可以采集一个波特率低电平之后的值,从而实现数据的接受。同理,如果FPGA要发送数据,则首先要拉低一个波特的低电平,之后开始传输数据。 
 +  * 这里有一个奇偶校验位,这是一种简单的检错方式。串口通过校验位判断是否通信收到干扰或者传输数据是否同步。加入传输说句是1001,对于偶校验,校验位为0,保证逻辑高的位数是偶数。如果是奇校验,校验位为1,保证逻辑高位数为奇数。当然,也可以不设置校验位。 
 +  * 那么,一个波特持续多长时间呢?这个跟串口传输的速率有关。以9600波特率为例,1秒传输9600个二进制位,每个二进制位持续时钟周期数为(1/​9600)*25M≈2604(本实验开发板的驱动时钟周期为25M)。 
 +  * 有了以上信息,就可以控制串口的发送了,流程如下:​ 
 +    * 1、发送端先拉低2604个时钟周期。 
 +    * 2、由发送字节的二进制位控制发送端口的电平高低,每个二进制位持续2604个时钟周期。 
 +    * 3、待发送完一个字节,发送一个奇偶校验位。电平持续2604个时钟周期。 
 +    * 4、将输出端口拉高至少2604个时钟周期的高电平,表示一个字节发送完毕。 
 +  * 知道了发送流程,那么接收流程也就清楚了。检测接收端口电平,如果出现低电平,开始计数,计满2604个时钟周期之后,将持续接收的八位二进制数据保存,即为接收数据。这里要注意,时钟的上升沿要保持在数据稳定的区间,以保证接收数据的准确性。 
 +==== 四、代码讲解 ==== 
 + 
 +  * 明白串口传输的收发过程之后,就可以通过代码实现了。首先,接收和发送可以划分成独立的两个模块。其次,串口波特率有9600bps、19200bps、38400bps、57600bps、115200bps等不同的波特率。那么,还要加一个波特率控制模块。 
 +  * 先讲一下波特率控制模块,这个模块本质上是对系统时钟做分频处理。通过计数,将25MHz的系统时钟分频成9600Hz、19200Hz等的周期信号。部分代码如下: 
 +<code verilog>​ 
 + always @(posedge CLK_25M or negedge rst_n) 
 + if (!rst_n) 
 + cnt <= 12'​d0;​ 
 + else if(cnt == Baud) 
 + cnt <= 12'​d0;​ 
 + else cnt = cnt + 1'​d1;​ 
 + 
 + always @(posedge CLK_25M or negedge rst_n) 
 + if (!rst_n) 
 + BPS_CLK_r <= 1'​d0;​ 
 + else if (cnt <= Baud >> 1) //​相当于Baud/​2 
 + BPS_CLK_r <= 1'​d0;​ //​作为接收数据时的中间采样点,​或发送数据时的位分界点 
 + else 
 + BPS_CLK_r <= 1'​d1;​  
 +</​code>​ 
 +  * 其次是数据接收模块,可以采用case语句,以对波特计数的变量J控制二进制位的采集。首先判断起始位,检测到起始位之后,对接下来的8个二进制数据依次接收,对校验位接收。最后是停止位检测,并将变量J归零。代码如下: 
 +<code verilog>​ 
 + always@(posedge BPS_CLK or negedge rst_n) 
 + if(!rst_n) 
 + begin 
 + j <= 4'​d0;​ 
 + data_in <= 8'​d0;​ 
 + data_inr <= 40'​d0;​ 
 + receive_data <= 40'​d0;​ 
 + end 
 + else case(j) 
 + 4'​d0: ​                               //​判断起始标志 
 + begin 
 + if(!RX) ​           
 + begin 
 + data_in <= 8'​d0;​ 
 + j <= j+ 1'​d1;​ 
 + end 
 + else j <= j; 
 + end 
 + 4'​d1,​4'​d2,​4'​d3,​4'​d4,​4'​d5,​4'​d6,​4'​d7,​4'​d8:​ //​接收数据 
 + begin 
 + j <= j + 1'​d1;​ 
 + data_in <= {RX,​data_in[7:​1]};​ 
 + end 
 + 4'​d9: ​                    //​接收校验位 
 + begin 
 + receive_data <= {receive_data[31:​0],​data_in};​ 
 + j <= j + 1'​d1;​ 
 + end 
 + 4'​d10:​ //​接收停止位 
 + begin 
 + j <= 1'​d0;​ 
 + if(receive_data[7:​0] == 8'​b00001010) 
 + begin 
 +  ​   data_inr <= receive_data;​ 
 + end 
 + end 
 + default: j <= 4'​d0;​ 
 + endcase  
 +</​code>​ 
 +  * 知道了数据的接收流程,那么数据发送的过程也就清楚了。与接收过程类似,先拉低一个波特的低电平,然后开始发送数据。然后发送一个校验位和1个停止位。整个过程是顺序执行的,那么,可以用case语句,结合计数器实现发送数据的控制,具体实现过程参考如下代码: 
 +<code verilog>​ 
 + always @(posedge BPS_CLK or negedge rst_n) 
 + if (!rst_n) 
 +     begin 
 + i <= 14'​d0;​ 
 + TX_r <= 1'​d1;​ //​空闲状态为1 
 + cnt <= 4'​d0;​ 
 + data_out <= 8'​d0;​ 
 + GINGKO <= {8'​d71,​8'​d73,​8'​d78,​8'​d71,​8'​d75,​8'​d79,​8'​d13,​8'​d10};​ 
 +     end 
 + else //​开始发送DATA 
 +     case(i) 
 + 14'​d0:​ begin //​先发送起始位0 
 + i <= i + 1'​d1;​ 
 + {data_out,​GINGKO[63:​8]} <= GINGKO; 
 + TX_r <= 1'​d0;​  
 +        end 
 + 14'​d1,​14'​d2,​14'​d3,​14'​d4,​14'​d5,​14'​d6,​14'​d7,​14'​d8:​ //​TX_r将DATA数据发送出去 
 +        ​begin 
 + i <= i + 1'​d1;​ 
 + {data_out[6:​0],​TX_r} <= data_out; //​串口发送时,​低位在先 
 +        ​end  
 + 14'​d9:​ begin //​1位奇偶校验位和1位停止位 
 + i <= i + 1'​d1;​ 
 + TX_r <= 1'​d1; ​                                      
 + end 
 + 14'​d10:​ begin //​1位停止位 
 + if(cnt == 4'​d7) 
 +     begin 
 + i <= i + 1'​d1;​ 
 + cnt <= 4'​d0;​ 
 +     end 
 + else  
 +     begin 
 + i <= 14'​d0;​ 
 + cnt <= cnt + 1'​d1;​ 
 +     end 
 + end 
 + 14'​d9600:​ begin //​定时约为1s  
 + i <= 14'​d0;​ 
 + GINGKO <= {8'​d71,​8'​d73,​8'​d78,​8'​d71,​8'​d75,​8'​d79,​8'​d13,​8'​d10};​ 
 + end 
 + default:​ i <= i + 1'​d1; ​ //​i为其他无效数值时,​直接转到退出TXD模块状态 
 + endcase 
 +</​code>​ 
 +  * 为了便于观察验证通信的正确性,还可以将接收数据进行对比,并通过LED将不同对比结果呈现出来,便于观察和判断。代码较为简单,可以参考例程的源码。 
 +==== 五、操作流程和测试结果 ==== 
 + 
 +=== 1.操作步骤: === 
 + 
 +  * 1)把仿真器与iCore3的SWD调试口连接(直接相连或者通过转换器相连);  
 +  * 2)将USB-Blaster与iCore3的JTAG调试口相连; 
 +  * 3)将跳线帽插在USB UART; 
 +  * 4)把iCore3(USB_UART)通过Micro USB线与计算机连接,为iCore3供电; 
 +  * 5)打开Commix串口精灵,找到对应的端口打开; 
 +  * 6)打开Quartus II开发环境,并打开实验工程;  
 +  * 7)烧写FPGA程序到iCore3上; 
 +  * 8)打开Keil MDK开发环境,并打开实验工程;  
 +  * 9)烧写ARM程序到iCore3上; 
 +  * 10)输入串口命令,观察实验现象。 
 + 
 +=== 2.测试结果: === 
 + 
 +  * 发送串口命令,输入命令后对应的ARM灯和FPGA灯亮,同时,串口精灵上定时接收显示:GINGKO\CR。 
 + 
 +|串口发送命令格式| ​ ARM_LED现象 |FPGA_LED现象| 
 +|LEDR\CR\LF| 红灯亮 |红灯亮| 
 +|LEDG\CR\LF| 绿灯亮 |绿灯亮| 
 +|LEDB\CR\LF| 蓝灯亮 |蓝灯亮| 
 +==== 六、拓展实验: ==== 
 + 
 +  - 尝试改变传输波特率。 
 +  - 在FPGA上构建另一个串口模块,通过杜邦线连接相对应引脚,实现FPGA自身两个串口模块的通信功能。 
 +  - 在实验二基础上自定义波特率进行通信。 
icore3_fpga_15.1577094247.txt.gz · 最后更改: 2019/12/23 17:44 由 zhangzheng