扯皮时间

没有便宜只有更便宜

买了900多的zynq板子,亏得月底吃土,其实实验用FPGA有的时候用不到这么多功能。这个时候怎么办?在淘宝和钟sir的蛊惑下选择了高云的片子,一片20,不比自行车香,这个时候正好看到之前我们实验室上古遗老画的小板子,于是拿来把玩一番。

通病

国产片子的通病自然是资料少品控差,网上高云片子的教程基本上是很难找到,还有就是板子的开发环境比较简陋,不过凑合着也够用,而且操作简单报错清晰,勉强算是及格线以上

入门

本人作为一个FPGA萌新,基本上只用过赛灵思的片子,主要还是zynq,高云片子的逻辑单元之类的和那些高性能的FPGA肯定比不起来,但是它的基本操作倒是和赛灵思的片子基本一样,而且麻雀虽小,五脏俱全,算是FPGA入门的不二之选(指不愿意花钱)

第一节:IDE安装与verilog小实验

这里给出的是商业版的链接,因为教育版的库特别少,基本上算是没有,商业版烦就烦在需要去申请license,不过高云的客服非常友好,基本上申请就有,是在没有就要把自己的mac地址发给高云,ipconfig/all命令跑一下就行了。

  • 安装后打开gowin,就是对标赛灵思的vivado,新建工程
  • 选择芯片,Device Version非常重要,影响最后烧录

  • 建立工程文档,一个.v和一个.cst(一个verilog HDL文件和约束文件)

  • 写一个简单的点灯的程序,注意调用系统内部时钟程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module Gowin_OSC (oscout);
output oscout;
OSC osc_inst (
.OSCOUT(oscout)
);
defparam osc_inst.FREQ_DIV = 42; //5M,0.2us;GW1N-4:50,GW1N-4B:42
//defparam osc_inst.DEVICE = "GW1N-4B";
endmodule //Gowin_OSC

module top_hdl(
//Outputs
output reg led
);
//wire
wire gclk;
Gowin_OSC uut(
.oscout(gclk)
);
//reg
reg [21:0]clk_cnt = 0;
//初始化
initial begin
led = 0;
end

always @(posedge gclk)
begin
clk_cnt <= clk_cnt + 22'b1;
if(clk_cnt%5000000 == 0)
begin
led <= ~led;
end
end
endmodule
  • 添加约束文件
1
2
IO_LOC "led" 21;
IO_PORT "led" PULL_MODE=UP DRIVE=8;
  • 直接跑一下,生成比特流文件.fs后缀
  • 下载到SRAM
  • 可以看到小灯闪烁
  • 来玩一下数码管,修改一下verilog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
module Gowin_OSC (oscout);

output oscout;

OSC osc_inst (
.OSCOUT(oscout)
);

defparam osc_inst.FREQ_DIV = 42; //5M,0.2us;GW1N-4:50,GW1N-4B:42
//defparam osc_inst.DEVICE = "GW1N-4B";

endmodule //Gowin_OSC

//数码管扫描周期为2ms,计数10000次
//数码管走马灯周期为0.5s,计数2.5*10^6次
//外部Led闪烁周期为1s,计数5*10^6次
module SegmentDisplay(
seg,sel,switch,button,led_inside,led_outside
);
wire clk;
Gowin_OSC uut(
.oscout(clk)
);
output reg [7:0]seg;//segment select
output reg [3:0]sel;//sel select
output reg [3:0]led_inside;
output reg [8:0]led_outside = 9'b10000_0000;
input [3:0]switch;
input [3:0]button;
reg [21:0]clk_cnt = 0;
reg[1:0] segment_cnt = 2'b00;
//定义数码管缓存区及初始化
reg[7:0] segment_buff[15:0]; //段选缓存
reg[3:0] sel_buff[4:0]; //位选缓存
reg[3:0] segment_var[3:0]; //数码管变量
reg clk_segment = 1'b0;
reg[8:0] sequence_buff = 9'b100100110;

parameter Num0 = 8'b1011_1111,
Num1 = 8'b1000_0110,
Num2 = 8'b1101_1011,
Num3 = 8'b1100_1111,
Num4 = 8'b1110_0110,
Num5 = 8'b1110_1101,
Num6 = 8'b1111_1101,
Num7 = 8'b1000_0111,
Num8 = 8'b1111_1111,
Num9 = 8'b1110_1111,
NumA = 8'b1111_0111,
Numb = 8'b1111_1100,
NumC = 8'b1011_1001,
Numd = 8'b1101_1110,
NumE = 8'b1111_1001,
NumF = 8'b1111_0001;
parameter NUM = 500_0000;

//初始化
initial begin
segment_var[0] = 4'd0;
segment_var[1] = 4'd1;
segment_var[2] = 4'd2;
segment_var[3] = 4'd3;
end

//switch/button有一个按下,led熄灭,否则,led点亮
always @ (posedge clk)
begin
if((switch[0]==1)&&(button[0]==1)) led_inside[0]<=1;
else led_inside[0]<=0;
if((switch[1]==1)&&(button[1]==1)) led_inside[1]<=1;
else led_inside[1]<=0;
if((switch[2]==1)&&(button[2]==1)) led_inside[2]<=1;
else led_inside[2]<=0;
if((switch[3]==1)&&(button[3]==1)) led_inside[3]<=1;
else led_inside[3]<=0;
end

//clk change, led toggle
always@(posedge clk)
begin
clk_cnt <= clk_cnt + 22'b1;
if(clk_cnt%5000 == 0) begin
clk_segment <= ~clk_segment;
end
if(clk_cnt == (NUM/2)) begin
led_outside <= {led_outside[0],led_outside[8:1]};
clk_cnt <= 0;
if(segment_var[0] == 9) segment_var[0]<=4'b0;
else segment_var[0] <= segment_var[0]+4'b1;
if(segment_var[1] == 9) segment_var[1]<=4'b0;
else segment_var[1] <= segment_var[1]+4'b1;
if(segment_var[2] == 9) segment_var[2]<=4'b0;
else segment_var[2] <= segment_var[2]+4'b1;
if(segment_var[3] == 9) segment_var[3]<=4'b0;
else segment_var[3] <= segment_var[3]+4'b1;
end
end

//数码管更新
always@(posedge clk_segment)
begin
seg <= segment_buff[segment_var[segment_cnt]];
sel <= sel_buff[segment_cnt];
end

//数码管计数变量更新
always@(posedge clk_segment)
begin
if(segment_cnt <3) segment_cnt <= segment_cnt + 2'b1;
else segment_cnt <= 2'b0;
end

//写缓存区
always@(posedge clk)
begin
sel_buff[0] <= 4'b1110;
sel_buff[1] <= 4'b1101;
sel_buff[2] <= 4'b1011;
sel_buff[3] <= 4'b0111;
segment_buff[0] <= Num0;
segment_buff[1] <= Num1;
segment_buff[2] <= Num2;
segment_buff[3] <= Num3;
segment_buff[4] <= Num4;
segment_buff[5] <= Num5;
segment_buff[6] <= Num6;
segment_buff[7] <= Num7;
segment_buff[8] <= Num8;
segment_buff[9] <= Num9;
segment_buff[10] <= NumA;
segment_buff[11] <= Numb;
segment_buff[12] <= NumC;
segment_buff[13] <= Numd;
segment_buff[14] <= NumE;
segment_buff[15] <= NumF;
end

endmodule

  • 修改约束文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//Copyright (C)2014-2020 Gowin Semiconductor Corporation.
//All rights reserved.
//File Title: Physical Constraints file
//GOWIN Version: 1.9.7 Beta
//Part Number: GW1N-LV9QN48C6/I5
//Device: GW1N-9
//Created Time: Mon 11 09 15:22:42 2020

IO_LOC "led_inside[3]" 21;
IO_PORT "led_inside[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_inside[2]" 23;
IO_PORT "led_inside[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_inside[1]" 27;
IO_PORT "led_inside[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_inside[0]" 29;
IO_PORT "led_inside[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;

IO_LOC "led_outside[8]" 19;
IO_PORT "led_outside[8]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[7]" 18;
IO_PORT "led_outside[7]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[6]" 17;
IO_PORT "led_outside[6]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[5]" 16;
IO_PORT "led_outside[5]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[4]" 15;
IO_PORT "led_outside[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[3]" 14;
IO_PORT "led_outside[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[2]" 13;
IO_PORT "led_outside[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[1]" 11;
IO_PORT "led_outside[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "led_outside[0]" 10;
IO_PORT "led_outside[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "sel[3]" 47;
IO_PORT "sel[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "sel[2]" 46;
IO_PORT "sel[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "sel[1]" 45;
IO_PORT "sel[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "sel[0]" 44;
IO_PORT "sel[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[7]" 34;
IO_PORT "seg[7]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[6]" 35;
IO_PORT "seg[6]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[5]" 38;
IO_PORT "seg[5]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[4]" 39;
IO_PORT "seg[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[3]" 40;
IO_PORT "seg[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[2]" 41;
IO_PORT "seg[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[1]" 42;
IO_PORT "seg[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "seg[0]" 43;
IO_PORT "seg[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "button[3]" 20;
IO_PORT "button[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "button[2]" 22;
IO_PORT "button[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "button[1]" 24;
IO_PORT "button[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "button[0]" 28;
IO_PORT "button[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "switch[3]" 30;
IO_PORT "switch[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "switch[2]" 31;
IO_PORT "switch[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "switch[1]" 32;
IO_PORT "switch[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "switch[0]" 33;
IO_PORT "switch[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;

  • 一样烧录,可以看到有意思的东西