PS端UpSample函数实现
PS端UpSample函数实现
目的
- 在PS端dingyi一个函数,实现对PL端的
UpSample
模块的调用,完成对输入数据的上采样操作 UpSample
模块的功能是将输入的13x13x128的数据上采样为26x26x128的数据,保持通道数不变UpSample
模块在YOLO网络中只有一层,位于第19层
步骤
-
在PS端定义函数
upsample_task
- 在状态机中判断
i==11
时调用该函数 - 在该函数中分为三个步骤:
- 发送数据给PL端
- 发送
UpSample
命令给PL端 - 接收PL端返回的数据
- 在状态机中判断
-
发送数据给PL端
- 使用DMA写操作,将
layer18
的输出数据(13x13x128)发送给PL端 - 发送地址为
0x3000000
,发送长度为0x548(1352字节) - 发送前需要发送
ZeroPointIn
命令,将ZeroPointIn
设置为0(因为不需要减去ZeroPoint
)
- 使用DMA写操作,将
-
发送
UpSample
命令给PL端- 使用
FUTURE_WRITE
操作,将0x00000001
写入0x40000000
地址(对应计算器2的命令寄存器) - 这个命令会触发PL端的
UpSample
模块开始工作
- 使用
-
接收PL端返回的数据
- 使用DMA读操作,从PL端读取上采样后的数据(26x26x128)
- 读取地址为
0x3100000
,读取长度为0x1520
(5408字节) - 由于输入通道数为128,需要分16次循环读取,每次读取8个通道的数据
- 每次循环后,更新发送地址和接收地址
由于输入数据有128个通道,而每次只能发送8个通道的数据,所以需要循环16次执行第二步中的三个子步骤,并且每次更新发送和接收的地址
例子
- 假设layer18的输出数据为:
通道 | 数据 |
---|---|
0 | [1, 2, 3, …, 169] |
1 | [170, 171, 172, …, 338] |
… | … |
127 | [21506, 21507, 21508, …, 21674] |
- 则发送给PL端的数据为:
地址 | 数据 |
---|---|
0x3000000 | [1, 2, 3, …, 169] |
0x3000054 | [170, 171, 172, …, 338] |
… | … |
0x30004FC | [21506, 21507, 21508, …, 21674] |
- PL端接收到数据后,根据UpSample命令,将每个元素复制四次,形成26x26的矩阵,例如:
输入 | 输出 |
---|---|
[1, 2, …, 13] | [1, 1, 2, 2, …, 12, 12, 13, 13] |
… | … |
[157, …, 169] | [157, 157, …, 168, 168, 169, 169] |
- PL端将上采样后的数据放到AXI接口上,等待PS端读取,例如:
地址 | 数据 |
---|---|
0x3100000 | [1, 1, …, 13, 13] |
… | … |
0x310151C | [21662, …,21674] |
- PS端从PL端读取数据,每次读取8个通道的数据,共16次循环,例如:
循环次数 | 发送地址 | 接收地址 | 数据长度 |
---|---|---|---|
i=0 | 0x3000000 | 0x3100000 | 0x1520 |
i=1 | 0x3000548 | 0x3101520 | 0x1520 |
… | … | … | … |
i=15 | 0x3004FC8 | 0x3114F20 | 0x1520 |
流程(a):
graph TD
A[修改 PL 端代码] --> B[生成bit文件]
B --> C[定义 PS 端函数]
C --> D[判断当前层]
D -->|是| E[调用 UpSample 函数]
D -->|否| F[执行状态机操作]
E --> G[发送数据给 PL 端]
G --> H[发送 UpSample 命令]
H --> I[接收 PL 端数据]
I --> J[存储到 layer 19 缓存]
J --> K[验证结果]
流程(b):
sequenceDiagram
participant PS
participant PL
Note over PS: 初始化参数和地址
loop i = 0 to 15
PS->>PL: 发送第 i 组数据 (8 个通道, 13x13)
PS->>PL: 发送 Zero point 命令 (Zero point in = 0)
PS->>PL: 发送 UpSample 命令
PL->>PS: 返回第 i 组数据 (8 个通道, 26x26)
end
Note over PS: 检查结果并导出 bit 文件
- PL 端的 UpSample 模块代码:在 PL 端编写 UpSample 模块,该模块可以接收 PS 端发送的 13x13 的数据,并将其上采样为 26x26 的数据,然后通过 AXI 接口输出。修改一些参数和频率,以及生成比特文件
- PS 端的 UpSample 函数代码:在 PS 端编写 UpSample 函数,该函数可以将输入的 128 个通道的 13x13 的数据分成 16 组,每组 8 个通道,然后依次发送给 PL 端的 UpSample 模块,并接收返回的 26x26 的数据。设置一些地址和长度,以及发送 Zero point 命令
- PS 端的 UpSample 函数调试:在 VITIS 中设置调试选项,下载比特文件,运行程序,并检查结果。比较 PS 端接收到的数据和期望的数据之间的差异
代码框架:
void upsample_task() {
// 定义配置参数
int input_channel = 128;
int output_channel = 128;
int input_size = 13;
int output_size = 26;
// 定义发送和接收地址
int tx_addr = TX_BASE_ADDR; // 假设 TX_BASE_ADDR 是 0x3000000
int rx_addr = RX_BASE_ADDR; // 假设 RX_BASE_ADDR 是 0x3100000
// 定义发送和接收长度
int tx_len = input_size * input_size * 8; // 每次发送8个通道的数据
int rx_len = output_size * output_size * 8; // 每次接收8个通道的数据
// 定义命令和中断信号
int upsample_cmd = 0x00000001; // 表示执行UpSample操作
int zero_point_in_cmd = 0x00000000; // 表示Zero point in为0
int interrupt_sig; // 表示中断信号
// 使用 for 循环处理所有通道的数据
for (int i = 0; i < input_channel / 8; i++) {
// 发送数据给 PL 端
dma_write(tx_addr, tx_len, input_data); // 假设 input_data 是 PS 端的输入数据
// 发送命令给 PL 端
axi_lite_write(0x43C00000, upsample_cmd); // 假设 0x43C00000 是 PL 端的命令地址
axi_lite_write(0x43C00004, zero_point_in_cmd); // 假设 0x43C00004 是 PL 端的 Zero point in 地址
// 接收数据从 PL 端
dma_read(rx_addr, rx_len, output_data); // 假设 output_data 是 PS 端的输出数据
// 接收中断信号从 PL 端
axi_lite_read(0x43C00008, interrupt_sig); // 假设 0x43C00008 是 PL 端的中断信号地址
// 更新发送和接收地址
tx_addr += tx_len;
rx_addr += rx_len;
}
}