四畳半テクノポリス

コロナのストレスで気が狂い、D進した院生

C API for PYNQ : C++でDMAする

C API for PYNQでDMAをする

PYNQでFPGAとOS上のアプリケーション通信間で高速に通信するにはDMAが有効です。前回の記事でも述べたようにPythonのスレッド間通信は低速なのでFPGA側からDMAで送られてきたデータを処理しようとすると速度不足になりやすいです。 今回はPYNQでAXIStreamによるDMAができたのその記事を書こうと思います。 github.com

README.MDにサンプルコードがあるのですが、実行するための回路を生成するTCLもビットファイルも無いので、回路を動かすためにどうしたらいいかわかりづらいと思います。そこで回路を作って実行してみました。

回路作成

以下のブログの「PS に接続されたメモリのデータを PL から読み書きしてみる」の回路を丸々拝借します。 www.acri.c.titech.ac.jp

出来上がったものがこちら

f:id:toriten1024:20211224213502p:plain
ブロック図
そして注目すべきところが作ったaxi_dmaにたいしてAXI_LITEで接続しているアドレス部分。
f:id:toriten1024:20211224215315p:plain
アドレスエディタ

このアドレス部分をソースコード中のPYNQ_openDMA(&dma, アドレス);と一致させる必要があります。

ソースコード

丸々引用のコードです

#include <stdio.h>
#include <pynq_api.h>

int main() {
  PYNQ_loadBitstream("/home/xilinx/my_bitstream.bit");
  
  PYNQ_SHARED_MEMORY shared_memory_1, shared_memory_2;
  PYNQ_allocatedSharedMemory(&shared_memory_1, sizeof(int)*10, 1);
  PYNQ_allocatedSharedMemory(&shared_memory_2, sizeof(int)*10, 1);
  
  int * d1=(int*)shared_memory_1.pointer;
  int * d2=(int*)shared_memory_2.pointer;
  for (int i=0;i<10;i++) {
    d1[i]=i;
    d2[i]=0;
  }
  
  PYNQ_AXI_DMA dma;
  PYNQ_openDMA(&dma, 0x40400000);
  
  PYNQ_writeDMA(&dma, &shared_memory_1, 0, sizeof(int) * 10);
  PYNQ_readDMA(&dma, &shared_memory_2, 0, sizeof(int) * 10);

  PYNQ_waitForDMAComplete(&dma, AXI_DMA_WRITE);
  PYNQ_waitForDMAComplete(&dma, AXI_DMA_READ);

  for (int i=0;i<10;i++) {
    printf("%d %d %d\n", i, d1[i], d2[i]);
  }

  PYNQ_closeDMA(&dma);
  PYNQ_freeSharedMemory(&shared_memory_1);
  PYNQ_freeSharedMemory(&shared_memory_2);
  return 0;
}

以下のように実行すると数を二倍した結果を得られます。

$ g++ -o my_dma DMA.cpp -lpynq  -lcma -lpthread -O3
$./my_dma
0 0 0
1 1 2
2 2 4
3 3 6
4 4 8
5 5 10
6 6 12
7 7 14
8 8 16
9 9 18