文章目录
零、 内容简介
- 体验SIPEED Tang Nano 20K的串口操作
- 体验SIPEED Tang Nano 20K的基础代码和烧录-点灯
- 使用idea编写chisel代码并烧录进20K实验
- 测试nesTang游戏例程
一、介绍
Tang Nano 20K 是采用高云半导体 GW2AR-18 QN88 的一款核心板,芯片内部具有 20736 个逻辑查找表(LUT4) 和 15552 个寄存器(FF),内部有两个 PLL,还带有多个 DSP 单元支持 18位 x 18位 的乘法运算来加速数字运算。板载 BL616 芯片来作为 FPGA JTAG 下载器和与 FPGA 通信的串口。板上默认使用 27MHz 晶振用于倍频出 HDMI 显示所需要的时钟,还额外搭载 MS5351 时钟发生芯片来随意生成多种所需要的时钟。
二、准备工作
安装IDE-GOWIN
-
前往 http://www.gowinsemi.com.cn/faq.aspx 下载 IDE
往下翻到教育版,暂时够用了
-
安装GOWIN
解压下载的文件后点击安装包安装
安装过程比较简单,一路确定和下一步就行
三、 使用
3.1 体验默认例程
3.1.1 基础操作
Tang Nano 20K默认固件内容是litex,也可点击链接手动下载
Ⅰ 初次通电
直接插上提供的typec-usb数据线即可连接通电
默认效果为流水灯
Ⅱ 串口通信
找到对应串口
打开串口调试工具
可以下载Mobaxterm
点击Session
选择Serial
进行如下设置
点击OK
进入后按下回车进入litex固件终端
单击键盘Tab键自动补全指令可以看到能直接使用的指令
测试以下leds指令
leds指令
leds指令格式是
leds
即需要在led的后面加一个值
输入
leds 62
可以看到led只亮了一个
3.1.2 切换终端
上面的 litex 相关的终端操作都是在 FPGA 上运行的,Tang Nano 20K 除了 GW2AR-18C FPGA 外,还有一个板载的 BL616 芯片,可以进入它的终端来进行其他操作。
和前面一样,在 Mobaxterm 中打开串口之后,可以使用组合键 Ctrl + x 然后 Ctrl + c,最后按下回车来进入 BL616 芯片终端。
体验两个主要命令pll_clk
和 choose
Ⅰ pll_clk
这个命令主要用来控制板子上的MS5351
精准时钟发生器
Ⅱ choose
这个命令用于选择BL616与FPGA的通信方式
有uart
和spi
两个模式
uart即为默认模式
spi模式为BL616 作为 FPGA 的 SPI 从机,接收 FPGA 发送过来的数据。
输入
choose uart
再按两次回车可回到litex终端
3.2 点灯实验
3.2.1 创建项目
打开安装好的GOWIN
文件 -> 新建 -> FPGA Design -> Project
设置工程名称,要求只用英文的下划线命名,存放路径中不要有中文字符或者空格等特殊符号。
然后在下面的芯片型号中选择 GW2AR-LV18QN88C8/I7,使用上面的筛选能够更快地选择到正确的型号。注意 Device 那一栏为 GW2AR-18C。
然后点击确定后就可以进行最终项目预览了。确认无误后就完成工程创建了。
3.2.2 编写代码
Ctrl + N
新建文件,选择Verilog
复制以下代码:
注意模块名字和文件名字相同!
module led(
input Clock,
output IO_voltage
);
/**********计时部分**********/
//parameter Clock_frequency = 27_000_000; // 时钟频率为27Mhz
parameter count_value = 13_499_999; // 计时 0.5S 所需要的计数次数
reg [23:0] count_value_reg ; // 计数器
reg count_value_flag; // IO 电平翻转标志
always @(posedge Clock) begin
if ( count_value_reg <= count_value ) begin //没有计数到 0.5S
count_value_reg <= count_value_reg + 1'b1; // 继续计数
count_value_flag <= 1'b0 ; // 不产生翻转标志
end
else begin //计数到 0.5S 了
count_value_reg <= 23'b0; // 清零计数器,为重新计数最准备
count_value_flag <= 1'b1 ; // 产生翻转标志
end
end
reg IO_voltage_reg = 1'b0; // 声明 IO 电平状态用于达到计时时间后的翻转,并赋予一个低电平初始态
/**********电平翻转部分**********/
always @(posedge Clock) begin
if ( count_value_flag ) // 电平翻转标志有效
IO_voltage_reg <= ~IO_voltage_reg; // IO 电平翻转
else // 电平翻转标志无效
IO_voltage_reg <= IO_voltage_reg; // IO 电平不变
end
/**********补充一行代码**********/
assign IO_voltage = IO_voltage_reg;
endmodule
3.2.3 综合,约束,布局布线
- 综合
双击Process -> Synthesize进行综合
- 约束
点击上图 Synthesize 上面的 FloorPlanner 来进行管脚约束。
直接点击OK
进入约束界面
查看原理图
可知道
晶振所输入的引脚为 PIN04
点击IO Constranins
按Ctrl + S
保存下约束,然后关闭界面
3. 布局布线
点击Place&Route让IDE通过约束算出最优解,自动帮我们把资源合理的分配在FPGA芯片上
3.2.4 烧录
将20k连接电脑
点击Progam Device
点击扫描
选择GW2AR-18C
有两种烧录模式
1.下载到SRAM
2.下载到FLASH
区别就是下载SRAM烧录后断电重上电就会清空该程序
FLASH烧录后的程序会保存下来再次上电仍然会运行
采取SRAM模式烧录
双击
点击program
烧录效果
3.3 使用chisel点灯
3.3.1 准备工作
这里使用IDEA写chisel代码
IDEA配置chisel环境参考:
https://blog.csdn.net/qq_52315804/article/details/132933899
3.3.2 创建一个chisel项目
进入,将以下代码覆盖:
name := "chisel_for_tang"
version := "0.1"
scalacOptions += "-Xsource:2.11"
scalaVersion := "2.12.10"
libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.1.2"
libraryDependencies += "edu.berkeley.cs" %% "chisel-iotesters" % "1.2.3"
3.3.3 编写代码
在main/src/scala里面创建一个led.scala
import chisel3._
import chisel3.core.{Input, Output, RegInit, when}
class led extends Module {
val io = IO(new Bundle {
val Clock = Input(Clock())
val IO_voltage = Output(Bool())
})
val count_value = 13499999.U // 计时 0.5S 所需要的计数次数
val count_value_reg = RegInit(0.U(24.W)) // 计数器
val count_value_flag = RegInit(false.B) // IO 电平翻转标志
val IO_voltage_reg = RegInit(false.B) // IO 电平状态用于达到计时时间后的翻转,并赋予一个低电平初始态
when(count_value_reg <= count_value) {
count_value_reg := count_value_reg + 1.U
count_value_flag := false.B
}.otherwise {
count_value_reg := 0.U
count_value_flag := true.B
}
when(count_value_flag) {
IO_voltage_reg := ~IO_voltage_reg
}
io.IO_voltage := IO_voltage_reg
}
object hello extends App{
println("execute chisel")
Driver.execute(args, () => new led)
}
然后重新加载一下
点击运行
中途出错:
在build.sbt添加一行:scalacOptions += "-Xsource:2.11"
再次刷新一下
问题解决
在target里即可找到led.v,复制代码或者文件放到上面创建好的项目里
需要略微修改一下代码
删除第三行的reset输入,在模块配置下面添加一个reset,设置值恒为0
reg reset = 1'b0;
完整代码如下:
module led( // @[:@3.2]
input clock, // @[:@4.4]
output io_IO_voltage // @[:@6.4]
);
reg reset = 1'b0;
reg [23:0] count_value_reg; // @[led.scala 11:32:@8.4]
reg [31:0] _RAND_0;
reg count_value_flag; // @[led.scala 12:33:@9.4]
reg [31:0] _RAND_1;
reg IO_voltage_reg; // @[led.scala 14:31:@10.4]
reg [31:0] _RAND_2;
wire _T_14; // @[led.scala 17:24:@11.4]
wire [24:0] _T_16; // @[led.scala 18:40:@13.6]
wire [23:0] _T_17; // @[led.scala 18:40:@14.6]
wire [23:0] _GEN_0; // @[led.scala 17:42:@12.4]
wire _GEN_1; // @[led.scala 17:42:@12.4]
wire _T_21; // @[led.scala 27:23:@23.6]
wire _GEN_2; // @[led.scala 26:26:@22.4]
assign _T_14 = count_value_reg <= 24'hcdfe5f; // @[led.scala 17:24:@11.4]
assign _T_16 = count_value_reg + 24'h1; // @[led.scala 18:40:@13.6]
assign _T_17 = _T_16[23:0]; // @[led.scala 18:40:@14.6]
assign _GEN_0 = _T_14 ? _T_17 : 24'h0; // @[led.scala 17:42:@12.4]
assign _GEN_1 = _T_14 ? 1'h0 : 1'h1; // @[led.scala 17:42:@12.4]
assign _T_21 = ~ IO_voltage_reg; // @[led.scala 27:23:@23.6]
assign _GEN_2 = count_value_flag ? _T_21 : IO_voltage_reg; // @[led.scala 26:26:@22.4]
assign io_IO_voltage = IO_voltage_reg; // @[led.scala 33:17:@29.4]
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE
integer initvar;
initial begin
`ifndef verilator
#0.002 begin end
`endif
`ifdef RANDOMIZE_REG_INIT
_RAND_0 = {1{$random}};
count_value_reg = _RAND_0[23:0];
`endif // RANDOMIZE_REG_INIT
`ifdef RANDOMIZE_REG_INIT
_RAND_1 = {1{$random}};
count_value_flag = _RAND_1[0:0];
`endif // RANDOMIZE_REG_INIT
`ifdef RANDOMIZE_REG_INIT
_RAND_2 = {1{$random}};
IO_voltage_reg = _RAND_2[0:0];
`endif // RANDOMIZE_REG_INIT
end
`endif // RANDOMIZE
always @(posedge clock) begin
if (reset) begin
count_value_reg <= 24'h0;
end else begin
if (_T_14) begin
count_value_reg <= _T_17;
end else begin
count_value_reg <= 24'h0;
end
end
if (reset) begin
count_value_flag <= 1'h0;
end else begin
if (_T_14) begin
count_value_flag <= 1'h0;
end else begin
count_value_flag <= 1'h1;
end
end
if (reset) begin
IO_voltage_reg <= 1'h0;
end else begin
if (count_value_flag) begin
IO_voltage_reg <= _T_21;
end
end
end
endmodule
3.3.4 综合、约束、布局布线
3.3.5 烧录
运行结果与verilog的代码一致
3.4 nesTang的使用
3.4.1 准备工作
- Tang nano 20k和游戏套件
- TF卡和读卡器
- GOWIN Programmer
- python
- balenaEtcher
3.4.2 具体步骤
Ⅰ 烧录FPGA部件
点击下载固件:tang_nano_20k_nestan.fs
推荐使用百度网盘
进入后不要全部下载,根据目录找到目标文件
然后就可下载
烧录
Ⅱ 制作游戏镜像
首先下载依赖固件
点击下载
同样可以从百度网盘下载
挑选游戏镜像
可以去fc游戏网挑选镜像
将下载好的镜像解压到和依赖固件一个文件夹内
然后在此文件夹内打开终端
输入代码
python nes2img.py -o games.img 1.nes 2.nes 3.nes
注意1.nes 2.nes 3.nes要改成自己下载的nes文件名字
然后烧录游戏镜像
打开 balenaEtcher
选择从文件中烧录
会弹出一个警告,此时点击继续。
选择TF卡的盘符
烧录成功后弹出TF卡
Ⅲ 组装板子
插卡
连接手柄,显示器和电源(注意电源不能是USB连电脑供电,功率不够,需要使用充电器)
通电后就能上电选择游戏进行游玩体验了
特点 | Tang | Cyclone |
---|---|---|
成本 | 相对较低 | 相对较高 |
性能 | 适用于小型项目和初学者 | 提供更高性能和资源 |
社区支持 | 社区支持较少,但逐渐增加 | 拥有广泛的社区支持 |
开发工具 | 提供多种开发工具和编程语言支持 | 使用Altera Quartus等主流工具链 |
开发环境易用性 | 友好的开发环境,适合初学者 | 适用于有一定经验的开发者 |
尺寸 | 小巧便携 | 尺寸较大 |
功耗 | 低功耗 | 功耗相对较高 |
图片 | ![]() | ![]() |