FC2カウンター FPGAの部屋 Dynamic Function eXchange
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Vitis でソフトウェアを起動する Vivado ML 2021.1 の DFX ではデバッグできない?

Vivado ML 2021.1 でデバッグできない4”の続き。

前回は、DFX の設定されていない DFX_filter_test2 プロジェクトと DFX の入っている DFX_filter_test_211 プロジェクトの dbg_hub の接続の違いを比べて、Debug 設定ではなく、直接 System_ILA を Add IP して接続し、今までと違いがあるか?を調べたが、DFX の入っているプロジェクトでは、デバッグできなかった。今回は、IDA さんに DFX でのデバッグのやり方を教えていただいたので、そのやり方でデバッグをやってみよう。

IDA さんに DFX でのデバッグのやり方を教えていただいた。ありがとうございます。

さて自分のプロジェクトでやってみよう。

DFX_filter_test のDFX モジュールの filter を書き換えた。
ILA_40_210905.png

filter DFX 部分を展開する。
ILA_41_210905.png

lap_filter_axis RM を示す。
ILA_42_210905.png

sobel_filter_axis RM を示す。
ILA_43_210905.png

これで、一度、論理合成、インプリメンテーション、ビットストリームの生成を行ったが、エラーになってしまった。それは、 filter PBlock の領域で RM のリソースを賄えないというエラーだったので、 filter PBlock の領域を広げた。
ILA_47_210905.png

こうすると、論理合成、インプリメンテーション、ビットストリームの生成を行って成功した。
ILA_44_210905.png

ハードウェアをエクスポートし、 Vitis でプラットフォームをアップデートした。
DFX filter_test をデバッグモードで起動した。
ILA_45_210905.png

Vivado で PROGRAM AND DEBUG -> Open Hardware Manager -> Open Target をクリックし、Auto Connect を選択して、ZYBO Z7-20 に接続したところ、 ILA ダッシュボードが表示されなかった。
ILA_46_210905.png

やはりだめか。。。
何が悪いのだろうか? IDA さんのは Vitis を使ってない? Vivado だけでやっているから?

(追加)
Implemented Design を示す。
Device 画面で茶色が debug_hub、黄色が RM 内の debug bridge、薄紫色が System_ila_0 だ。
ILA_48_210905.png
  1. 2021年09月05日 04:39 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

Zynq の PCAP を使用して DFX する4(Vivado でデバッグできない)

Zynq の PCAP を使用して DFX する3(xdevcfg_polled_example.c をマージする1)”の続き。

前回は、 xdevcfg_polled_example.c を”画像フィルタを DFX する14(DFX_filter_test プロジェクト7)”の DFX_filter_test.c にマージして DFXできたようなのだが、カメラが動作しなくなった。今回は、カメラが動作しない原因を Vivado で Debug を設定し、System ILA IP を実装して確かめてみようとしたが失敗した。

Vivado のブロック・デザインで、 Debug を設定し、System ILA IP を実装した。
PCAP_29_210827.png

Vitis 2021.1 でデバックモードで起動する。
PCAP_21_210826.png

デバックモードの画面の内 xsct の画面を使用する。
まずは、カレントディレクトリを表示する。
pwd
ホーム・ディレクトリにいることが分かった。
PCAP_22_210826.png

ホーム・ディレクトリに lap_filter_axis_partial.bin をコピーした。(”Zynq の PCAP を使用して DFX する2(.bin ファイルの生成)”参照)
PCAP_23_210826.png

lap_filter_axis_partial.bin をメモリにダウンロードした。
dow -data lap_filter_axis_partial.bin 0x11000000
PCAP_24_210826.png

ログを示す。

xsct% pwd
/home/masaaki
xsct% dow -data lap_filter_axis_partial.bin 0x11000000

  0%    0MB   0.0MB/s  ??:?? ETA
 38%    0MB   0.3MB/s  ??:?? ETA
 94%    0MB   0.4MB/s  ??:?? ETA
100%    0MB   0.4MB/s  00:01    
Successfully downloaded /home/masaaki/lap_filter_axis_partial.bin
xsct% 


Resume ボタンをクリックして、ソフトウェアを走らせる。
PCAP_25_210826.png

gtkterm に ”Press the key.”が表示された。
カメラ画像が表示された。
PCAP_27_210826.jpg

この時点で、 Vivado で PROGRAM AND DEBUG -> Open Hardware Manager -> Open Target -> Auto Connect を選択する。
ILA ダッシュボードが表示されるはずが表示されない。。。
PCAP_30_210827.png

DFX ではこの方法でのデバッグはできないのかな?
  1. 2021年08月27日 04:26 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

Zynq の PCAP を使用して DFX する3(xdevcfg_polled_example.c をマージする1)

”Zynq の PCAP を使用して DFX する3(embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/)”の続き。

前回は、”embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/”に良いサンプルがあったので、その内の xdevcfg_selftest_example.c と xdevcfg_polled_example.c をやってみた。今回は、その内の xdevcfg_polled_example.c を”画像フィルタを DFX する14(DFX_filter_test プロジェクト7)”の DFX_filter_test.c にマージして DFX してみよう。

さて、 xdevcfg_polled_example.c を DFX_filter_test.c にマージした。
PCAP_20_210826.png

デバックモードで起動する。
PCAP_21_210826.png

デバックモードの画面の内 xsct の画面を使用する。
まずは、カレントディレクトリを表示する。
pwd
ホーム・ディレクトリにいることが分かった。
PCAP_22_210826.png

ホーム・ディレクトリに lap_filter_axis_partial.bin をコピーした。(”Zynq の PCAP を使用して DFX する2(.bin ファイルの生成)”参照)
PCAP_23_210826.png

lap_filter_axis_partial.bin をメモリにダウンロードした。
dow -data lap_filter_axis_partial.bin 0x11000000
PCAP_24_210826.png

ログを示す。

xsct% pwd
/home/masaaki
xsct% dow -data lap_filter_axis_partial.bin 0x11000000

  0%    0MB   0.0MB/s  ??:?? ETA
 38%    0MB   0.3MB/s  ??:?? ETA
 94%    0MB   0.4MB/s  ??:?? ETA
100%    0MB   0.4MB/s  00:01    
Successfully downloaded /home/masaaki/lap_filter_axis_partial.bin
xsct% 


Resume ボタンをクリックして、ソフトウェアを走らせる。
PCAP_25_210826.png

gtkterm に ”Press the key.”が表示された。
カメラ画像が表示された。
PCAP_27_210826.jpg

Enter キーを押すと、”Download the partial bit file of the Laplacian filter and press the key.”が表示された。
Enter キーを押すと、 ”Press the key.”が表示された。
表示画像はラプラシアン・フィルタのようだが、止まっていて、カメラの前で手を振っても画像に反映されない。
PCAP_28_210826.jpg

DFX は成功したようだが?まだ不可解な部分がある。
もしかして、PS の FCLK_RESET0_N が 0 で全体をリセットしたのか?

DFX_filter_test.c を貼っておく。なお、全部貼ると長いので、 cam_reg_set() を除いたコードを貼っておく。 cam_reg_set() については、”画像フィルタを DFX する13(DFX_filter_test プロジェクト6)”を参照のこと。

// DFX_filter_test.c
// 2021/08/08 by marsee
// 2021/08/09 : Stop the operation of DMA2axis IP on the video side and restart it.
// 2021/08/26 : PCAP partial configuration (Quoted from the following URL)
//              https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/devcfg/examples/xdevcfg_polled_example.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "xil_io.h"
#include "xparameters.h"
#include "xdevcfg.h"

#include "xvflip_dma_write.h"
#include "xdma2axis.h"
#include "xthrough_axis.h"
#include "xlap_filter_axis_hw.h"
#include "xsobel_filter_axis_hw.h"

#define CAMERA_DATA_DMA_ADDR    0x10000000

#define HORIZONTAL_PIXELS   800
#define VERTICAL_LINES      600

#define XLAP_FILTER_AXIS_BASEADDR   0x40000000
#define XSOBEL_FILTER_AXIS_BASEADDR 0x40000000

/************************** Constant Definitions *****************************/
/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are only defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define DCFG_DEVICE_ID      XPAR_XDCFG_0_DEVICE_ID

/*
 * The BIT_STREAM_LOCATION is a dummy address and BIT_STREAM_SIZE_WORDS is a
 * dummy size. This has to replaced with the actual location/size of the bitstream.
 *
 * The 2 LSBs of the Source/Destination address when equal to 2�b01 indicate
 * the last DMA command of an overall transfer.
 * The 2 LSBs of the BIT_STREAM_LOCATION in this example is set to 2b01
 * indicating that this is the last DMA transfer (and the only one).
 */
#define BIT_STREAM_LOCATION 0x11000001  /* Bitstream location */
#define BIT_STREAM_SIZE_WORDS   0x20000     /* Size in Words (32 bit)*/

/*
 * SLCR registers
 */
#define SLCR_LOCK   0xF8000004 /**< SLCR Write Protection Lock */
#define SLCR_UNLOCK 0xF8000008 /**< SLCR Write Protection Unlock */
#define SLCR_LVL_SHFTR_EN 0xF8000900 /**< SLCR Level Shifters Enable */
#define SLCR_PCAP_CLK_CTRL XPAR_PS7_SLCR_0_S_AXI_BASEADDR + 0x168 /**< SLCR
                    * PCAP clock control register address
                    */

#define SLCR_PCAP_CLK_CTRL_EN_MASK 0x1
#define SLCR_LOCK_VAL   0x767B
#define SLCR_UNLOCK_VAL 0xDF0D

int cam_reg_set(volatile unsigned *axi_iic, unsigned int device_addr);
int XDcfgPolledExample(XDcfg *DcfgInstPtr, u16 DeviceId);

XDcfg DcfgInstance;     /* Device Configuration Interface Instance */

void cam_i2c_init(volatile uint32_t *ov5642_axi_iic) {
    ov5642_axi_iic[64] = 0x2; // reset tx fifo ,address is 0x100, i2c_control_reg
    ov5642_axi_iic[64] = 0x1; // enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
    // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile uint32_t *ov5642_axi_iic, uint32_t device_addr, uint32_t write_addr, uint32_t write_data){
    ov5642_axi_iic[66] = 0x100 | (device_addr & 0xfe); // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    ov5642_axi_iic[66] = (write_addr >> 8) & 0xff;  // address upper byte
    ov5642_axi_iic[66] = write_addr & 0xff;           // address lower byte
    ov5642_axi_iic[66] = 0x200 | (write_data & 0xff);      // data
    cam_i2x_write_sync();
}

int main(){
    XVflip_dma_write XVfilp_dma_write_ap;
    XDma2axis XDma2axis_ap;
    XThrough_axis XTh_axis_ap;
    int inbyte_in;
    int Status;

    XVflip_dma_write_Initialize(&XVfilp_dma_write_ap, 0);
    XDma2axis_Initialize(&XDma2axis_ap, 0);
    XThrough_axis_Initialize(&XTh_axis_ap, 0);

    XVflip_dma_write_Set_fb0_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XVflip_dma_write_Set_fb1_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XVflip_dma_write_Set_fb2_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XDma2axis_Set_x_size(&XDma2axis_ap, HORIZONTAL_PIXELS);
    XDma2axis_Set_y_size(&XDma2axis_ap, VERTICAL_LINES);
    XDma2axis_Set_in_V(&XDma2axis_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XThrough_axis_Set_x_size(&XTh_axis_ap, (u32)HORIZONTAL_PIXELS);
    XThrough_axis_Set_y_size(&XTh_axis_ap, (u32)VERTICAL_LINES);

    // vflip_dma_write start
    XVflip_dma_write_Start(&XVfilp_dma_write_ap);
    XVflip_dma_write_EnableAutoRestart(&XVfilp_dma_write_ap);

    // CMOS Camera initialize, ov5642
    cam_i2c_init((volatile uint32_t *)XPAR_AXI_IIC_0_BASEADDR);
    cam_reg_set((volatile uint32_t *)(XPAR_AXI_IIC_0_BASEADDR), (uint32_t)0x78); // OV5642 register set
    Xil_Out32(XPAR_MT9D111_INF_AXIS_0_BASEADDR, CAMERA_DATA_DMA_ADDR); // ov5642 AXI4-Stream Start
    Xil_Out32((XPAR_MT9D111_INF_AXIS_0_BASEADDR+4), 0);

    // bitmap_disp_cont_axis start
    Xil_Out32(XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR, CAMERA_DATA_DMA_ADDR); // dummy address, start

    // through_axis start
    XThrough_axis_Start(&XTh_axis_ap);
    XThrough_axis_EnableAutoRestart(&XTh_axis_ap);

    // DMA2axis start
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    printf("Press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    // Display Stopped
    XDma2axis_DisableAutoRestart(&XDma2axis_ap);
    XThrough_axis_DisableAutoRestart(&XTh_axis_ap);
    while(XDma2axis_IsIdle(&XDma2axis_ap)==0);
    while(XThrough_axis_IsIdle(&XTh_axis_ap)==0);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 1); // 1: Turn decoupling on

    printf("Download the partial bit file of the Laplacian filter and press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    Status = XDcfgPolledExample(&DcfgInstance, DCFG_DEVICE_ID);
    //Status = XST_SUCCESS;
    if (Status != XST_SUCCESS) {
        xil_printf("Dcfg Polled Example Test Failed\r\n");
        return XST_FAILURE;
    }

    xil_printf("Successfully ran Dcfg Polled Example Test\r\n");

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 0); // 0: Turn decoupling off

    // laplacian filter start
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR+XLAP_FILTER_AXIS_CONTROL_ADDR_ROW_DATA, (u32)VERTICAL_LINES);
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR+XLAP_FILTER_AXIS_CONTROL_ADDR_COL_DATA, (u32)HORIZONTAL_PIXELS);
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR, (u32)0x81);

    // DMA2axis resumes
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    printf("Press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    // Display Stopped
    XDma2axis_DisableAutoRestart(&XDma2axis_ap);
    XThrough_axis_DisableAutoRestart(&XTh_axis_ap);
    while(XDma2axis_IsIdle(&XDma2axis_ap)==0);
    while(XThrough_axis_IsIdle(&XTh_axis_ap)==0);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 1); // 1: Turn decoupling on

    printf("Download the partial bit file of the Sobel filter and press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 0); // 0: Turn decoupling off

    // sobel filter start
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR+XSOBEL_FILTER_AXIS_CONTROL_ADDR_ROW_DATA, (u32)VERTICAL_LINES);
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR+XSOBEL_FILTER_AXIS_CONTROL_ADDR_COL_DATA, (u32)HORIZONTAL_PIXELS);
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR, (u32)0x81);

    // DMA2axis resumes
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    return(0);
}

/*****************************************************************************/
/**
* This function downloads the Non secure bit stream to the FPGA fabric
* using the Device Configuration Interface.
*
* @param    DcfgInstPtr is a pointer to the instance of XDcfg driver.
* @param    DeviceId is the unique device id of the device.
*
* @return
*       - XST_SUCCESS if successful
*       - XST_FAILURE if unsuccessful
*
* @note     None
*
****************************************************************************/
int XDcfgPolledExample(XDcfg *DcfgInstPtr, u16 DeviceId)
{
    int Status;
    u32 IntrStsReg = 0;
    u32 StatusReg;
    u32 PartialCfg = 0;

    XDcfg_Config *ConfigPtr;

    /*
     * Initialize the Device Configuration Interface driver.
     */
    ConfigPtr = XDcfg_LookupConfig(DeviceId);

    /*
     * This is where the virtual address would be used, this example
     * uses physical address.
     */
    Status = XDcfg_CfgInitialize(DcfgInstPtr, ConfigPtr,
                    ConfigPtr->BaseAddr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }


    Status = XDcfg_SelfTest(DcfgInstPtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Check first time configuration or partial reconfiguration
     */
    IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
    if (IntrStsReg & XDCFG_IXR_DMA_DONE_MASK) {
        PartialCfg = 1;
    }

    /*
     * Enable the pcap clock.
     */
    StatusReg = Xil_In32(SLCR_PCAP_CLK_CTRL);
    if (!(StatusReg & SLCR_PCAP_CLK_CTRL_EN_MASK)) {
        Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
        Xil_Out32(SLCR_PCAP_CLK_CTRL,
                (StatusReg | SLCR_PCAP_CLK_CTRL_EN_MASK));
        Xil_Out32(SLCR_UNLOCK, SLCR_LOCK_VAL);
    }

    /*
     * Disable the level-shifters from PS to PL.
     */
    if (!PartialCfg) {
        Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
        Xil_Out32(SLCR_LVL_SHFTR_EN, 0xA);
        Xil_Out32(SLCR_LOCK, SLCR_LOCK_VAL);
    }

    /*
     * Select PCAP interface for partial reconfiguration
     */
    if (PartialCfg) {
        XDcfg_EnablePCAP(DcfgInstPtr);
        XDcfg_SetControlRegister(DcfgInstPtr, XDCFG_CTRL_PCAP_PR_MASK);
    }

    /*
     * Clear the interrupt status bits
     */
    XDcfg_IntrClear(DcfgInstPtr, (XDCFG_IXR_PCFG_DONE_MASK |
                    XDCFG_IXR_D_P_DONE_MASK |
                    XDCFG_IXR_DMA_DONE_MASK));

    /* Check if DMA command queue is full */
    StatusReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr,
                XDCFG_STATUS_OFFSET);
    if ((StatusReg & XDCFG_STATUS_DMA_CMD_Q_F_MASK) ==
            XDCFG_STATUS_DMA_CMD_Q_F_MASK) {
        return XST_FAILURE;
    }

    /*
     * Download bitstream in non secure mode
     */
    XDcfg_Transfer(DcfgInstPtr, (u8 *)BIT_STREAM_LOCATION,
            BIT_STREAM_SIZE_WORDS,
            (u8 *)XDCFG_DMA_INVALID_ADDRESS,
            0, XDCFG_NON_SECURE_PCAP_WRITE);

    /* Poll IXR_DMA_DONE */
    IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
    while ((IntrStsReg & XDCFG_IXR_DMA_DONE_MASK) !=
            XDCFG_IXR_DMA_DONE_MASK) {
        IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
    }

    if (PartialCfg) {
        /* Poll IXR_D_P_DONE */
        while ((IntrStsReg & XDCFG_IXR_D_P_DONE_MASK) !=
                XDCFG_IXR_D_P_DONE_MASK) {
            IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
        }
    } else {
        /* Poll IXR_PCFG_DONE */
        while ((IntrStsReg & XDCFG_IXR_PCFG_DONE_MASK) !=
                XDCFG_IXR_PCFG_DONE_MASK) {
            IntrStsReg = XDcfg_IntrGetStatus(DcfgInstPtr);
        }
        /*
         * Enable the level-shifters from PS to PL.
         */
        Xil_Out32(SLCR_UNLOCK, SLCR_UNLOCK_VAL);
        Xil_Out32(SLCR_LVL_SHFTR_EN, 0xF);
        Xil_Out32(SLCR_LOCK, SLCR_LOCK_VAL);
    }

    return XST_SUCCESS;
}


BIT_STREAM_LOCATION だが、その説明のDeepL 翻訳結果を貼っておく。

Source/Destinationアドレスの2LSBが2b01に等しい場合は、全体の転送の最後のDMAコマンドを示します。
この例のBIT_STREAM_LOCATIONの2つのLSBは2b01に設定され、これが最後のDMA転送(そして唯一の転送)であることを示しています。

  1. 2021年08月26日 05:14 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

Zynq の PCAP を使用して DFX する3(embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/)

Zynq の PCAP を使用して DFX する2(.bin ファイルの生成)”の続き。

前回は、ソフトウェアから DFX を制御したいということで、”Partial Reconfiguration by PCAP: bitstream size not an integer of words?”を参考にして、パーシャル・ビット・ファイルから bin ファイルを生成した。今回は、”embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/”に良いサンプルがあったので、その内の xdevcfg_selftest_example.c と xdevcfg_polled_example.c をやってみる。

embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/”という良いサンプルがあった。
PCAP_19_210825.png

とりあえず、 xdevcfg_selftest_example.c を実行してみよう。
画像フィルタを DFX する14(DFX_filter_test プロジェクト7)”で使用した Vitis 2021.1 のワークスペースを利用する。
当初の予定は独自のコードを作って試してみようということだったので、 DcfgSelTestExample というアプリケーション・プロジェクトを作成した。
DcfgSelTestExample_system -> DcfgSelTestExample -> src に xdevcfg_selftest_example.c ファイルを新規作成し、”embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/xdevcfg_selftest_example.c”のコードをコピー&ペーストした。
PCAP_13_210825.png

ビルドして、Run ボタンをクリックして、実行したところ、gtkterm に成功の表示が出た。
PCAP_14_210825.png

xdevcdg.h を示す。
PCAP_15_210825.png

XDcfg_SelfTest() を示す。
PCAP_16_210825.png

次に”embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/xdevcfg_polled_example.c”をやってみる。
xdevcfg_polled_example.c は PCAP 経由でビット・ファイルをコンフィギュレーションするサンプルのようだ。これを修正すれば、私の用途に使えそうだ。

xdevcfg_polled_example アプリケーション・プロジェクトを作成した。
xdevcfg_polled_example_system -> xdevcfg_polled_example -> src に xdevcfg_polled_example.c ファイルを新規作成して、”embeddedsw/XilinxProcessorIPLib/drivers/devcfg/examples/xdevcfg_polled_example.c”からコピー&ペーストした。
PCAP_17_210825.png

ビルドしてから Run すると、成功した。
PCAP_18_210825.png
  1. 2021年08月25日 05:00 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

Zynq の PCAP を使用して DFX する2(.bin ファイルの生成)

Zynq の PCAP を使用して DFX する1(情報収集)”の続き。

前回は、ソフトウェアから DFX を制御したいということで、Zynq 系で使用できるプロセッサ コンフィギュレーション アクセス ポート (PCAP)について情報収集を行った。今回は、その内の”Partial Reconfiguration by PCAP: bitstream size not an integer of words?”を参考にして、パーシャル・ビット・ファイルから bin ファイルを生成する。

XDcfg_TransferBitfile() を使用して DFX するためには bit ファイルから bin ファイルを生成する必要あるそうだ。(”How to use PCAP to config the PL in zynq”参照)

bin ファイルの生成方法は Vivado の TCL コンソールで write_cfgmem コマンドを使うことだそうだ。(”Partial Reconfiguration by PCAP: bitstream size not an integer of words?”参照)

最初に child_0_impl_1 の DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit を lap_filter_axis_partial.bin に変換する。
PCAP_7_210824.png

Vivado の TCL コンソールで cd コマンドを使用した。
cd /media/masaaki/Ubuntu_Disk/HDL/ZYBO_Z7-20/DFX_filter_test_211/DFX_filter_test_211.runs/child_0_impl_1

write_cfgmem コマンドを使用して bin ファイルを生成した。
write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit "up 0x0 DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit" lap_filter_axis_partial.bin
PCAP_8_210824.png

write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit "up 0x0 DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit" lap_filter_axis_partial.bin
Command: write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit {up 0x0 DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit} lap_filter_axis_partial.bin
Creating config memory files...
INFO: [Writecfgmem 68-23] Start address provided has been multiplied by a factor of 4 due to the use of interface SMAPX32.
Creating bitstream load up from address 0x00000000
Loading bitfile DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit
WARNING: [Writecfgmem 68-32] Bitfile DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit is a Dynamic Function eXchange bitfile. It is not possible to validate that this bitfile is compatible with the SMAPX32 interface.
Memory size is calculated to be 512 KB
Writing file ./lap_filter_axis_partial.bin
Writing log file ./lap_filter_axis_partial.prm
===================================
Configuration Memory information
===================================
File Format        BIN
Interface          SMAPX32
Size               512K
Start Address      0x00000000
End Address        0x0007FFFF

Addr1         Addr2         Date                    File(s)
0x00000000    0x00072863    Aug 21 07:14:31 2021    DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit
1 Infos, 1 Warnings, 0 Critical Warnings and 0 Errors encountered.
write_cfgmem completed successfully


lap_filter_axis_partial.bin が生成された。
PCAP_9_210824.png


child1_impl_1 の DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit を sobel_filter_axis_partial.bin に変換する。
PCAP_10_210824.png

Vivado の TCL コンソールで cd コマンドを使用した。
cd /media/masaaki/Ubuntu_Disk/HDL/ZYBO_Z7-20/DFX_filter_test_211/DFX_filter_test_211.runs/child_1_impl_1

write_cfgmem コマンドを使用して bin ファイルを生成した。
write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit "up 0x0 DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit" sobel_filter_axis_partial.bin
PCAP_11_210824.png

write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit "up 0x0 DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit" sobel_filter_axis_partial.bin
Command: write_cfgmem -format BIN -interface SMAPx32 -disablebitswap -loadbit {up 0x0 DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit} sobel_filter_axis_partial.bin
Creating config memory files...
INFO: [Writecfgmem 68-23] Start address provided has been multiplied by a factor of 4 due to the use of interface SMAPX32.
Creating bitstream load up from address 0x00000000
Loading bitfile DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit
WARNING: [Writecfgmem 68-32] Bitfile DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit is a Dynamic Function eXchange bitfile. It is not possible to validate that this bitfile is compatible with the SMAPX32 interface.
Memory size is calculated to be 512 KB
Writing file ./sobel_filter_axis_partial.bin
Writing log file ./sobel_filter_axis_partial.prm
===================================
Configuration Memory information
===================================
File Format        BIN
Interface          SMAPX32
Size               512K
Start Address      0x00000000
End Address        0x0007FFFF

Addr1         Addr2         Date                    File(s)
0x00000000    0x00072863    Aug 21 07:14:37 2021    DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit
1 Infos, 1 Warnings, 0 Critical Warnings and 0 Errors encountered.
write_cfgmem completed successfully


sobel_filter_axis_partial.bin が生成された。
PCAP_12_210824.png
  1. 2021年08月24日 05:24 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

Zynq の PCAP を使用して DFX する1(情報収集)

いままで、DFX をやってきたが、Vivado で RM をリコンフィギュレーションしてきた。この辺りでソフトウェアから DFX を制御したいということで、Zynq 系で使用できるプロセッサ コンフィギュレーション アクセス ポート (PCAP)について情報収集していこう。

PCAP でのコンフィギュレーションについては、”Zynq-7000 SoC テクニカル リファレンス マニュアル UG585 (v1.10) 2015 年 2 月 23 日”の 192 ページからの”6.4 デバイス ブートおよび PL コンフ ィギュレーシ ョ ン”に書いてあった。

Zynq-7000 SoC テクニカル リファレンス マニュアル UG585 (v1.10) 2015 年 2 月 23 日”の 192 ページからの”6.4 デバイス ブートおよび PL コンフ ィギュレーシ ョ ン”から図と文章を引用する。

”6.4.1 PS ソフ トウェアによる PL 制御”を引用する。
PCAP_1_210823.png

”PS ソフ トウェアによる PL 初期化”から引用する。
1. [PCFG_PROG_B] 信号を High にする。
2. [PCFG_PROG_B] 信号を Low にする。
3. [PCAP_INIT] ステータスがリセットされているかポーリングする。
4. [PCFG_PROG_B] 信号を High にする。
5. [PCAP_INIT] ステータスがセットされているかポーリングする。

”6.4.3 PL への PCAP ブリッジ”から引用する。
PCAP ブリ ッジ (AXI-PCAP ブリッジまたは PCAP インターフェイス と も呼ぶ) は、ビットストリームによ る PL コンフィギュレーション、 ブート イメージおよびビットストリームの復号化、 ファイルの認証に使用できます。
PCAP_2_210823.png

DMA 転送を開始するには、 4 つの DMA レジ スタに次の順序で書き込みます。
1. ソース アドレス レジスタ devcfg.DMA_SRC_ADDR
2. デスティネーション アドレス レジスタ devcfg.DMA_DST_ADDR
3. ソース長レジスタ devcfg.DMA_SRC_LEN
4. デスティネーション長レジスタ devcfg.DMA_DEST_LEN (このレジスタへの書き込みにより DMA 転送が開始)

”6.4.4 PCAP データパス コンフィギュレーション”
PCAP でコンフィギュレーションする時のブロック図”図 6-18 : 非セキュアおよびセキュア PL ビ ッ ト ス ト リーム パスの図”を引用する。
PCAP_3_210823.png

”PL の初期化およびコンフィギュレーション レジスタ”
”表 6-23 : PL の制御およびステータス レジスタ ビット”を引用する。
PCAP_4_210823.png
PCAP_5_210823.png
PCAP_6_210823.png

PCAP の資料は Xilinx Forum にもある。
How to use PCAP to config the PL in zynq
Zynq Z0720 PCAP Readback

アプリケーションノートも 2 つ参考になりそうだ。
Zynq-7000 All Programmable SoC デバイスにおけるハー ドウェア アクセラレーターのパーシャル リコンフィギュレーション
xapp1159.zip

Zynq‐7000 AP SoC プロセ ッサにおける Vivado Design Suite を使用したハー ドウェア アクセ ラレータのパーシ ャル リコンフィギュレーション
xapp1231-partial-refonfig-hw-axxelerator-vivado.zip

ライセンスのためブログに書けないが、そのものズバリなので、”Zynq‐7000 AP SoC プロセ ッサにおける Vivado Design Suite を使用したハー ドウェア アクセ ラレータのパーシ ャル リコンフィギュレーション”をやってみよう。

(追加)
、”Zynq‐7000 AP SoC プロセ ッサにおける Vivado Design Suite を使用したハー ドウェア アクセ ラレータのパーシ ャル リコンフィギュレーション”の 14 ページの”デバイス コンフィギュレーションおよびブート フロー”から引用。

1 つのコ ンフィ ギュレーシ ョン エンジンがフル コンフィ ギュ レーション とパーシャル コンフィギュ レーシ ョ ンの両方を管理し ます。パーシャル ビット ストリームにはコンフィギュ レーション フ レームのア ド レス情報が含まれている ため、 これを PL へロードする際に、 リコンフィギャラブル モジュールの物理的な位置を把握し ている必要はあ り ません。


18 ページから引用。

PCAP イ ン ターフ ェ イ ス経由でパーシャル ビット ストリームを転送する前に、is_partial_bitstream デバイス属性が 1 に設定 されている必要があります。 DevC デバイス ノード上での書き込みファイル動作によ り 、 パーシャル ビット ストリームが転送されます。


is_partial_bitstream デバイス属性は Linux の devcfg の属性のようです。(”Partial reconfiguration in linux”参照)

パーシャル・リコンフィギュレーションの資料
Partial Reconfiguration: XDcfg
Partial Reconfiguration by PCAP: bitstream size not an integer of words?
Partial Reconfiguration: Measuring Zynq PCAP Reconfiguration Time
  1. 2021年08月23日 03:38 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0

画像フィルタを DFX する14(DFX_filter_test プロジェクト7)

画像フィルタを DFX する13(DFX_filter_test プロジェクト6)”の続き。

前回は、通過 IP 、ラプラシアン・フィルタ IP 、ソーベル・フィルタ IP の 3 個の IP を DFX で切り替えるべく Vivado 2021.1 の DFX_filter_test プロジェクトに追加するということで、 Vitis 2021.1 を起動して、プラットフォームとアプリケーション・プロジェクトを作成し、ソースコードを作成した。それをビルドして実機で確認することができた。今回は、そのプロジェクトで DFX として、ラプラシアン・フィルタとソーベル・フィルタを切り替えて動作させてみよう。

DFX_filter_test.c を書き換えて、ラプラシアン・フィルタとソーベル・フィルタのパーシャル・ビット・ファイルをコンフィギュレーションできるようにした。更に、 xlap_filter_axis_hw.h と xsobel_filter_axis_hw.h をインポートした。
DFX2_122_210822.png

ここに、OV5642 のレジスタをセットするための関数 cam_reg_set() を除いたコードを貼っておく。 cam_reg_set() については、”画像フィルタを DFX する13(DFX_filter_test プロジェクト6)”を参照のこと。

// DFX_filter_test.c
// 2021/08/08 by marsee
// 2021/08/09 : Stop the operation of DMA2axis IP on the video side and restart it.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "xil_io.h"
#include "xparameters.h"

#include "xvflip_dma_write.h"
#include "xdma2axis.h"
#include "xthrough_axis.h"
#include "xlap_filter_axis_hw.h"
#include "xsobel_filter_axis_hw.h"

#define CAMERA_DATA_DMA_ADDR    0x10000000

#define HORIZONTAL_PIXELS   800
#define VERTICAL_LINES      600

#define XLAP_FILTER_AXIS_BASEADDR   0x40000000
#define XSOBEL_FILTER_AXIS_BASEADDR 0x40000000

int cam_reg_set(volatile unsigned *axi_iic, unsigned int device_addr);

void cam_i2c_init(volatile uint32_t *ov5642_axi_iic) {
    ov5642_axi_iic[64] = 0x2; // reset tx fifo ,address is 0x100, i2c_control_reg
    ov5642_axi_iic[64] = 0x1; // enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
    // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile uint32_t *ov5642_axi_iic, uint32_t device_addr, uint32_t write_addr, uint32_t write_data){
    ov5642_axi_iic[66] = 0x100 | (device_addr & 0xfe); // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    ov5642_axi_iic[66] = (write_addr >> 8) & 0xff;  // address upper byte
    ov5642_axi_iic[66] = write_addr & 0xff;           // address lower byte
    ov5642_axi_iic[66] = 0x200 | (write_data & 0xff);      // data
    cam_i2x_write_sync();
}

int main(){
    XVflip_dma_write XVfilp_dma_write_ap;
    XDma2axis XDma2axis_ap;
    XThrough_axis XTh_axis_ap;
    int inbyte_in;

    XVflip_dma_write_Initialize(&XVfilp_dma_write_ap, 0);
    XDma2axis_Initialize(&XDma2axis_ap, 0);
    XThrough_axis_Initialize(&XTh_axis_ap, 0);

    XVflip_dma_write_Set_fb0_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XVflip_dma_write_Set_fb1_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XVflip_dma_write_Set_fb2_V(&XVfilp_dma_write_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XDma2axis_Set_x_size(&XDma2axis_ap, HORIZONTAL_PIXELS);
    XDma2axis_Set_y_size(&XDma2axis_ap, VERTICAL_LINES);
    XDma2axis_Set_in_V(&XDma2axis_ap, (u32)CAMERA_DATA_DMA_ADDR);
    XThrough_axis_Set_x_size(&XTh_axis_ap, (u32)HORIZONTAL_PIXELS);
    XThrough_axis_Set_y_size(&XTh_axis_ap, (u32)VERTICAL_LINES);

    // vflip_dma_write start
    XVflip_dma_write_Start(&XVfilp_dma_write_ap);
    XVflip_dma_write_EnableAutoRestart(&XVfilp_dma_write_ap);

    // CMOS Camera initialize, ov5642
    cam_i2c_init((volatile uint32_t *)XPAR_AXI_IIC_0_BASEADDR);
    cam_reg_set((volatile uint32_t *)(XPAR_AXI_IIC_0_BASEADDR), (uint32_t)0x78); // OV5642 register set
    Xil_Out32(XPAR_MT9D111_INF_AXIS_0_BASEADDR, CAMERA_DATA_DMA_ADDR); // ov5642 AXI4-Stream Start
    Xil_Out32((XPAR_MT9D111_INF_AXIS_0_BASEADDR+4), 0);

    // bitmap_disp_cont_axis start
    Xil_Out32(XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR, CAMERA_DATA_DMA_ADDR); // dummy address, start

    // through_axis start
    XThrough_axis_Start(&XTh_axis_ap);
    XThrough_axis_EnableAutoRestart(&XTh_axis_ap);

    // DMA2axis start
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    printf("Press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    // Display Stopped
    XDma2axis_DisableAutoRestart(&XDma2axis_ap);
    while(XDma2axis_IsIdle(&XDma2axis_ap)==0);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 1); // 1: Turn decoupling on

    printf("Download the partial bit file of the Laplacian filter and press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 0); // 0: Turn decoupling off

    // laplacian filter start
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR+XLAP_FILTER_AXIS_CONTROL_ADDR_ROW_DATA, (u32)VERTICAL_LINES);
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR+XLAP_FILTER_AXIS_CONTROL_ADDR_COL_DATA, (u32)HORIZONTAL_PIXELS);
    Xil_Out32(XLAP_FILTER_AXIS_BASEADDR, (u32)0x81);

    // DMA2axis resumes
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    printf("Press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    // Display Stopped
    XDma2axis_DisableAutoRestart(&XDma2axis_ap);
    while(XDma2axis_IsIdle(&XDma2axis_ap)==0);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 1); // 1: Turn decoupling on

    printf("Download the partial bit file of the Sobel filter and press the key.");
    fflush(stdout);
    inbyte_in = inbyte();
    printf("\n"); fflush(stdout);

    Xil_Out32(XPAR_DFX_DECOUPLER_0_BASEADDR, 0); // 0: Turn decoupling off

    // sobel filter start
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR+XSOBEL_FILTER_AXIS_CONTROL_ADDR_ROW_DATA, (u32)VERTICAL_LINES);
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR+XSOBEL_FILTER_AXIS_CONTROL_ADDR_COL_DATA, (u32)HORIZONTAL_PIXELS);
    Xil_Out32(XSOBEL_FILTER_AXIS_BASEADDR, (u32)0x81);

    // DMA2axis resumes
    XDma2axis_Start(&XDma2axis_ap);
    XDma2axis_EnableAutoRestart(&XDma2axis_ap);

    return(0);
}


Vitis の Explorer 画面で DFX_filter_test_system を選択し、Run ボタンをクリックする。
gtkterm の画面に”Press the key”と表示された。
この状態では通常のカメラ画像が表示されている。
DFX2_123_210822.jpg

gtkterm 画面で何かのキーを押した。
”Download the partial bit file of the Laplacian filter and press the key.”が表示された。
DFX2_117_210821.png

Vivado で PROGRAM AND DEBUG -> Open Hardware Manager -> Open Target -> Auto Connect を選択する。
HARDWARE MANAGER が表示された。
Program device をクリックする。
DFX2_121_210821.png

DFX_filter_test_i_filter_lap_filter_axis_inst_0_partial.bit を指定してコンフィギュレーションした。
DFX2_118_210821.png

gtkterm で何かキーを押すと、ラプラシアン・フィルタ画像がディスプレイに表示された。
ただしスタート位置が間違っている。
DFX2_124_210822.jpg

もう一度、何かキーを押すと、”Download the partial bit file of the Sobel filter and press the key.”が表示された。
DFX2_119_210821.png

Vivado で DFX_filter_test_i_filter_sobel_filter_axis_inst_0_partial.bit をコンフィギュレーションした。
DFX2_120_210819.png

何かキーを押すと、ソーベル・フィルタの画面がディスプレイに表示された。
これもスタート位置が間違っている。
DFX2_125_210822.jpg

これで、手動での DFX はうまく行ったと思う。
ディスプレイ表示にはバグというかビットマップ・ディスプレイ・コントローラの仕様による不具合はあったが。。。
  1. 2021年08月22日 07:41 |
  2. Dynamic Function eXchange
  3. | トラックバック:0
  4. | コメント:0
»