1、ARM与FPGA介绍
1、运行方式
- FPGA :FPGA(现场可编程门阵列)允许用户根据需求定制硬件电路,优化特定应用的性能。与固定硬件不同,FPGA 可以根据需要重新配置,适合处理高并行性任务、实时处理和低延迟操作。
- ARM 处理器:是一种通用的计算平台,提供强大的处理能力,适合执行操作系统、应用程序和控制逻辑。它支持丰富的开发工具和生态系统,可以实现复杂的算法和功能。
2、性能
- FPGA 在执行并行计算时可以显著提高性能。例如,图像处理、信号处理、等任务在 FPGA 上可以通过并行化实现大幅度的加速。
- FPGA 可以实现极低的延迟,适合对实时性有严格要求的应用。通过将关键任务在 FPGA 上实现,可以提高系统响应速度,减少 ARM 处理器的负担。
3、系统集成
- ARM + FPGA 的架构可以非常适合于 异构计算系统,通过硬件和软件的结合来优化系统的各个部分。ARM 可以处理复杂的控制任务、文件操作与GUI等,而 FPGA 则可以处理计算密集型或需要高速并行计算的任务。
4、应用广泛
- 嵌入式系统、自动驾驶、5G、人工智能等领域,ARM + FPGA 架构可以满足高性能、低延迟和高并行的需求,适应未来技术发展的趋势。
2、实战任务
ARM端通过I/O端口输出高低电平组合,形成不同的编码,FPGA则通过读取ARM端I/O引脚的状态来控制对应的RGB灯。具体来说,当ARM端的ABC端口输出000时,FPGA端的LED2红色亮起,同时LED1的红色灯也会亮;当ARM端的ABC端口输出001时,FPGA端的LED2绿色亮起,同时LED1的绿色灯也亮;直到ARM端的ABC端口输出110时,FPGA端的LED3蓝色亮起,LED1的蓝色灯也同步亮起。
3、系统框图
根据实际任务要求,我们需要将ARM处理器输出的电平信号进行编码转换,随后通过FPGA引脚读取这些编码状态,并根据不同的状态输出相应的结果。这里我们需要三个I/O与FPGA进行数据交互,同时ARM端需要三个I/O来控制LED1的RGB灯,FPGA端需要六个引脚来控制LED2和LED3的RGB灯。
4、时序图
根据功能分析,该模块的输入为 A B C 三个信号,输出为 X 是一个 6bit 信号代表输出的 六 种状态,对应RGB的不同位置和颜色如图下所示:
5、程序编写
FPGA端:
verilog
module arm_fpga (
input A, // 输入 A
input B, // 输入 B
input C, // 输入 C
output reg [5:0] X // 6位输出
);
always @(*) begin
case ({A, B, C}) // 拼接输入信号
3'b000: X = 6'b11_1110; // 输出 x0
3'b001: X = 6'b11_1101; // 输出 x1
3'b010: X = 6'b11_1011; // 输出 x2
3'b011: X = 6'b11_0111; // 输出 x3
3'b100: X = 6'b10_1111; // 输出 x4
3'b101: X = 6'b01_1111; // 输出 x5
default : X = 6'b11_1110; // 默认情况,输出 x0
endcase
end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
程序注释:
- 第 8 - 18 行:位拼接,是使用花括号 {} 来实现,将三个一位信号,拼接成一个 3bit 信号来使用。因为我们是共阳的RGB灯需要低电平才能点亮,根据ARM端的I/O变化来控制RGB灯进行不同颜色的切换。
6、仿真编写
verilog
`timescale 1ns / 1ns // 定义时间单位和精度为 1 纳秒
module arm_fpga_mod();
// 输入和输出信号定义
reg A; // 输入 A
reg B; // 输入 B
reg C; // 输入 C
wire X; // 输出 X
initial begin // 初始块开始
A = 1'b0; // 设置输入 A 为 0
B = 1'b0; // 设置输入 B 为 0
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b0; // 设置输入 B 为 0
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b1; // 设置输入 B 为 1
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b0; // 设置输入 A 为 0
B = 1'b1; // 设置输入 B 为 1
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b0; // 设置输入 B 为 0
C = 1'b0; // 设置输入 C 为 0
#200; // 延迟 200 纳秒
A = 1'b1; // 设置输入 A 为 1
B = 1'b0; // 设置输入 B 为 0
C = 1'b1; // 设置输入 C 为 1
#200; // 延迟 200 纳秒
$stop; // 停止仿真
end
// 例化
arm_fpga u_arm_fpga (
.A(A), // 将输入 A 连接到FPGA的J12引脚
.B(B), // 将输入 B 连接到FPGA的J11引脚
.C(C), // 将输入 C 连接到FPGA的k11引脚
.X(X) // 将输出 X 连接到RGB输出
);
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
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
程序注释:
- 第 12 - 45 行:根据我们设计的时序图来,输出是不是按照我们设计的逻辑。
7、ARM程序编写
7.1、RGB与FPGA通讯接口驱动
C
#include "gpio.h"
/*
- Function : Init_GPIO()
- Description : 初始化GPIO引脚
- Input : 无
- Output : 无
- Return : 无
- Other : 无
*/
void Init_GPIO(void)
{
//ARM端RGB
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
gpio_bit_write(GPIOB, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8,SET);
//FPGA与ARMI/O通信引脚
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2);
gpio_bit_write(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2,RESET);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
7.2、应用程序
c
#include "app.h"
//函数声明
void ARM_FPGA(bit_status A,bit_status B,bit_status C);
void ARM_FPGA(bit_status A,bit_status B,bit_status C);
/*
- Function : APP_Run
- Description : 执行与FPGA的I/O口进行单向数据交换的功能。
该函数允许FPGA读取RAM的I/O状态,并据此输出数据。
- Input : 无
- Output : 无
- Return : 无
- Other : 无
*/
void APP_Run(void)
{
APP_ARM_FPGA(RESET,RESET,RESET);
APP_ARM_RGB(RESET,SET,SET);
delay_1ms(1000);
APP_ARM_FPGA(RESET,RESET,SET);
APP_ARM_RGB(SET,RESET,SET);
delay_1ms(1000);
APP_ARM_FPGA(RESET,SET,RESET);
APP_ARM_RGB(SET,SET,RESET);
delay_1ms(1000);
APP_ARM_FPGA(RESET,SET,SET);
APP_ARM_RGB(RESET,SET,SET);
delay_1ms(1000);
APP_ARM_FPGA(SET,RESET,RESET);
APP_ARM_RGB(SET,RESET,SET);
delay_1ms(1000); // 红色 绿色
APP_ARM_FPGA(SET,RESET,SET);
APP_ARM_RGB(SET,SET,RESET);
delay_1ms(1000); //绿色
}
/*
- Function : APP_ARM_FPGA
- Description : 设置与FPGA通信的GPIO口状态。
- Input : A GPIOA_PIN_0的状态
B GPIOA_PIN_1的状态
C GPIOA_PIN_2的状态
\arg : RESET: 清除端口引脚(低电平)
SET: 设置端口引脚(高电平)
- Output : 无
- Return : 无
- Other : 无
*/
void APP_ARM_FPGA(bit_status A,bit_status B,bit_status C)
{
gpio_bit_write(GPIOA, GPIO_PIN_0, A);// 设置GPIOA_PIN_0的状态
gpio_bit_write(GPIOA, GPIO_PIN_1, B);// 设置GPIOA_PIN_1的状态
gpio_bit_write(GPIOA, GPIO_PIN_2, C);// 设置GPIOA_PIN_2的状态
}
/*
- Function : APP_ARM_RGB
- Description : 控制RGB LED的状态,通过设置GPIO引脚状态来控制RGB颜色的显示。
该函数根据输入的状态分别设置红、绿、蓝三个颜色通道的引脚状态。
- Input : R GPIOB_PIN_6的状态(控制红色通道)
G GPIOB_PIN_7的状态(控制绿色通道)
B GPIOB_PIN_8的状态(控制蓝色通道)
\arg : RESET: 点亮对应颜色
SET: 熄灭对应颜色
- Output : 无
- Return : 无
- Other : 无
*/
void APP_ARM_RGB(bit_status R,bit_status G,bit_status B)
{
gpio_bit_write(GPIOB, GPIO_PIN_7, R); // 设置GPIOB_PIN_6的状态(红色通道)
gpio_bit_write(GPIOB, GPIO_PIN_6, G); // 设置GPIOB_PIN_7的状态(绿色通道)
gpio_bit_write(GPIOB, GPIO_PIN_8, B); // 设置GPIOB_PIN_8的状态(蓝色通道)
}
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
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
7.3、主函数
c
#include "app.h"
#include "Init.h"
/*
- Function : main
- Description : 主函数
- Other : 无
*/
int main(void)
{
Init_Driver();//外设初始化函数
delay_1ms(1850);//等待FPGA启动
while(1)
{
APP_Run(); //应用运行函数
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
接下来打开 Modelsim 软件对代码进行仿真,需要添加文件如下图所示:
运行仿真一段时间后,仿真的波形如下图所示:
通过观察发现,仿真出来的波形与我们时序的波形一致。
8、I/O 引脚绑定
进行 I/O 约束,这里只需要对ARM交互的引脚进行约束,管脚分配如下表所示:
信号 | 方向 | 引脚 | 端口作用 | 电平标准 |
---|---|---|---|---|
PA0 | input | J12 | A | LVCMOS33 |
PA1 | input | J11 | B | LVCMOS33 |
PA2 | input | K11 | C | LVCMOS33 |
X[0] | output | R9 | LED2R | LVCMOS33 |
X[1] | output | C10 | LED2G | LVCMOS33 |
X[2] | output | R7 | LED2B | LVCMOS33 |
X[3] | output | N6 | LED3R | LVCMOS33 |
X[4] | output | T10 | LED3G | LVCMOS33 |
X[5] | output | P7 | LED3B | LVCMOS33 |
Gowin 软件中 I/O Constraints 界面如下图所示:
10、程序下载
连接开发板的下载器,将码流文件下载到开发板后,及可看到RGB灯循环闪烁