一、工程设计概述
许多应用都需要通过主机上的通用接口和主机进行通信,传统的 RS232 必须通过 RS232接口连接,但如今绝大多数的个人电脑都不再有 RS232 接口,这对于某些工程开发十分的不方便。因此,C5G、DE1-SOC H版本、DE23-Lite、C5P/OSK/TSP等板子设计有UART 转 USB 电路的接口,使得用户可以直接通过 USB 接口与主机进行串口通信。
本文将为用户展示如何使用主机上的 PUTTY terminal 通过 USB 接口向 FPGA 发送和接收指令,控制 FPGA 开发板上的 LED。
在 FPGA 端是通过UART(RS-232 Serial Port) IP来进行数据收发。案例功能框图如下:

UART 通信相关知识请参考 1-串行通信基础知识。
本案例要求串口通信的起始位1位,数据位为8位, 停止位1位,无校验位,波特率115200bps。

接下来将在UART(RS-232 Serial Port) IP 中进行串口相关设置。
二、UART控制器:UART(RS-232 Serial Port)Intel FPGA IP简介
Quartus Prime软件中集成了UART控制器:UART(RS-232 Serial Port)Intel FPGA IP。

UART(RS-232 Serial Port)Intel FPGA IP用于在Intel FPGA上的嵌入式系统与外部设备之间进行串行字符流通信。该IP实现了RS-232协议,并提供可调节的波特率、校验位、停止位和数据位。该IP提供Avalon Memory-Mapped从设备接口,允许Avalon-MM主设备(如Nios II和Nios V处理器)通过读或写控制寄存器和数据寄存器来与UART IP核进行通信。
该IP设置界面:

更多Uart IP相关描述请参考:Chapter 9 UART Core from https://www.intel.com/content/www/us/en/docs/programmable/683130/25-3/uart-core.html
三、C5G 串口硬件
C5G开发板板载串口IC是 FT232R, 该IC的PC端驱动:https://ftdichip.com/drivers/vcp-drivers/, 关于驱动的安装步骤可以参考:3-基于FPGA开发板OSK/TSP/C5P的串口通信设计 (CP2102N)

该IC与FPGA 之间硬件连接简化图如下:

四、硬件工程设计------Quartus 工程设计
Quartus 版本: Quartus Prime 17.1 Lite。
在Quartus中使用Platform Designer(以前称为QSYS)创建包含Nios II处理器和RS-232 Serial Port IP的系统,以下是Quartus工程中Qsys系统的框架(注意Nios II IP选择Nios II/e,如果选择Nios II/f会要求有Quartus license才行):

Quartus工程的top文件如下:
module UART_USB_LED(
///////// CLOCK /////////
input CLOCK_50_B3B,
///////// LED /////////
output [ 3: 0] LED, //LED is High-Active
///////// Uart to USB /////////
output UART_TX,
input UART_RX
);
//=======================================================
// Structural coding
//=======================================================
uart_test u0 (
.clk_clk (CLOCK_50_B3B), // clk.clk
.reset_reset_n (1'b1), // reset.reset_n
.led_external_connection_export (LED), // led_external_connection.export
.uart_rxd (UART_RX), // uart.rxd
.uart_txd (UART_TX) // .txd
);
endmodule
FPGA引脚分配如下:

五、软件工程设计------Nios II 程序设计
在嵌入式系统开发中,硬件平台的多样性给软件开发带来了巨大挑战。Intel(Altera)的Nios II处理器通过其硬件抽象层(Hardware Abstraction Layer, HAL) 有效解决了这一问题,为开发者提供了统一的编程接口,极大地简化了嵌入式软件开发流程。关于HAL更多说明请参考:Nios II 处理器的硬件抽象层(HAL)
在Nios II IDE中创建software工程,编写代码使用fprintf和getc等标准C库函数来访问UART(这种访问方式依赖于HAL系统库,其底层由HAL设备驱动完成寄存器读写)。
这段代码是一个基于Nios II处理器的嵌入式程序,通过UART与计算机通信,控制LED灯。
cs
#include ".\terasic_lib\terasic_includes.h"
#include ".\terasic_lib\LED.h"
#include ".\terasic_lib\debug.h"
int main(void)
{
FILE* fp;
char promot;
LED_AllOn();
usleep(500*1000);
LED_AllOff();
printf("---------C5P UART TO USB demo --------\r\n");
printf("before you send the command\r\n");
printf("you must ensure uart to usb driver has been installed on you computer\r\n");
printf("and ensure a usb cable is connected between c5p and your computer\r\n");
printf("please execute putty and setup parameter correctly\r\n");
printf("ensure that you open the correct common port\r\n");
printf("the baud rate should be 115200\r\n");
printf("the data bits should be 8\r\n");
printf("no verify bit and 1 stop bit\r\n");
printf("you can send character to control the led state\r\n");
printf("send 0-3 to toggle the related led \r\n");
printf("send a or A to turn on all leds and n or N to turn off all \r\n");
fp=fopen("/dev/uart","r++");
if(fp == NULL)
{
// UART设备打开失败处理
printf("ERROR: Cannot open UART device /dev/uart\r\n");
return -1;
}
else if(fp)
{
fprintf(fp,"you can send character to control the led state\r\n");
fprintf(fp,"send 0-3 to toggle the related led\r\n");
fprintf(fp,"send a or A to turn on all leds and n or N to turn off all\r\n");
}
while(1)
{
promot=getc(fp);
if(promot>='0'&&promot<='3')
{
printf("%c sent\r\n",promot);
LED_toggle_count((promot-'0'));
fprintf(fp,"LED %c state toggle\r\n",promot);
}
else if(promot=='n'||promot=='N')
{
LED_AllOff( );
fprintf(fp,"All LED off\r\n");
printf("%c sent \r\n",promot);
}
else if(promot=='a'||promot=='A')
{
LED_AllOn( );
fprintf(fp," All LED on\r\n");
printf("%c sent \r\n",promot);
}
else
{
fprintf(fp,"you send wrong command\r\n");
printf("you send wrong command\r\n");
}
}
fclose(fp);
return 0;
}
这段代码的流程图如下:

关于LED_AllOff、LED_AllOn和LED_toggle_count函数,则是通过调用HAL里面提供的PIO宏定义 IOWR_ALTERA_AVALON_PIO_DATA直接读写寄存器:
cs
#include "terasic_includes.h"
#include "LED.h"
void LED_AllOff(void){
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0x0); //0:unlight, 1:light
}
void LED_toggle_count(alt_u8 led_count)
{
alt_32 bit_mask=0x01<<led_count; // check 0~3
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, bit_mask);// light the related led
}
void LED_AllOn(void)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xF); //0:unlight, 1:light
}
六、测试步骤
**1.**连接串口J11 到PC;
-
用USB Blaster线缆连接开发板J10和PC;
-
连接12V电源到开发板,开启电源开关;

- 打开Quartus工程,点击Start Compilation生成sof文件,然后点击Programmer 将sof配置文件下载到开发板:

- 打开Nios II 工程,右击UART_USB_LED_bsp工程选择Nios II------generate BSP,然后右击UART_USB_LED工程选择Build Project 产生新的elf文件后,继续右击UART_USB_LED工程选择Run As------Nios II Hardware:

如若遇到以下报错时,请将下图所示的两个复选框选中,再点击Refresh Connections ------Apply------Run就可以了。
Connected system ID hash not found on target at expected base address.
Connected system timestamp not found on target at expected base address.

- 打开PuTTY串口终端,按照如下截图配置串口:

- 然后点击Session,点选Serial,然后点击Open:

- 在PuTTY端下发0、1、2、3、4、a、n等命令看串口和Nios II 窗口各打印什么信息:

也可以直接双击运行UART_USB_LED\demo_batch\test.bat文件将sof和elf下载到FPGA 开发板:

然后打开PuTTY下发命令,得到结果一样:

七、源码免费下载
通过网盘分享的文件:weixin_C5G_UART_USB_LED.rar
链接:https://pan.baidu.com/s/12c6BpsdWtMI5PoHm63MJEA提取码: tera
往期阅读:
2-基于FPGA开发板DE23-Lite的串口通信设计 (FT2232H)
3-基于FPGA开发板OSK/TSP/C5P的串口通信设计 (CP2102N)