FC2カウンター FPGAの部屋 Clocking Wizard の Dynamic Reconfiguration mode を使ってみよう2
fc2ブログ

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

FPGAの部屋

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

Clocking Wizard の Dynamic Reconfiguration mode を使ってみよう2

Clocking Wizard の Dynamic Reconfiguration mode を使ってみよう1”の続き。

PLL の出力周波数をソフトウェアで動的に変更する機能の Clocking Wizard の Dynamic Reconfiguration mode を使ってみようということで、Adom Taylor さんの”MicroZed Chronicles: Dynamic Clocking”を参照して、やってみたが、ブロック・デザインに手を加えて、カウンタのカウント数で周波数をカウントしている。ただし、出力周波数は設定とは少し異なっていた。今回は、clk_wiz_0 の s_axi_lite に System ILA を挿入して、XClk_Wiz_SetRate(&ClkWiz_Dynamic, 10); のアクセスを調べて、設定周波数ピッタリになるように設定を行ってみよう。

ブロック・デザインの clk_wiz_0 の s_axi_lite の配線を右クリックし、右クリックメニューから Debug を選択して、System ILA を挿入した。
Dynamic_Clocking_10_230526.png

論理合成、インプリメンテーション、ビットストリームの生成を行った。
ハードウェアをエクスポートした。

Vitis で DC_wrapper プラットフォームを右クリックし、Update Hardware Specification を選択して、ハードウェアの仕様をアップデートした。
Vitis の Explorer の Dynamic_Clocking_system をクリックし、トンカチボタンをクリックして、ビルドを行って成功した。
Vitis の Explorer の Dynamic_Clocking_system を右クリックし、右クリックメニューから Dubug As -> 1 Launch Hardware を選択してデバック・モードで起動した。
Dynamic_Clocking_11_230526.png

Vivado で Flow Navigator で PROGRAM AND DEBUG -> Open Hardware Manager -> Open Target をクリックし、Auto Connect を選択した。
ILA ダッシュボードが表示された。
Trigger Setup で AWVALID を選択して、Value を R にして、トリガをかけた。
Dynamic_Clocking_12_230526.png

Vitis で Step Over 実行していって、XClk_Wiz_SetRate(&ClkWiz_Dynamic, 10); でトリガがかかった。(実際はその前の行でもトリガがかかったが、もう一度かけなおした)
Dynamic_Clocking_13_230526.png

ILA ダッシュボードの波形を示す。
Dynamic_Clocking_14_230526.png

最初に 0x200 番地に 0x801 を書いて、次に、0x208 番地に 0x49 を書いている。
Clocking Wizard LogiCORE IP Product Guide (PG065)”によると

0x200 番地 ― Clock Configuration Register 0
Bit[25:16] = CLKFBOUT_FRAC Multiply = 0
Bit[15:8] = CLKFBOUT_MULT = 8
Bit[7:0] = DIVCLK_DIVIDE = 1

0x208 番地 - Clock Configuration Register 2
Bit[7:0] = CLKOUT0_DIVIDE = 0x49 (10進で 73)
 Integer part of clkout0 divide value
 For example, for 2.250, this value is 2 = 0x2
Bit[17:8] = CLKOUT0_FRAC Divide = 0
 Fractional part of clkout0 divide value
 For example, for 2.250, this value is 250 = 0xFA


Dynamic Reconfiguration mode における VCO Frequency は以下の式で表せるということだ。(”Clocking Wizard LogiCORE IP Product Guide (PG065)”を参照)
VCO Frequency = (Input Clock Frequency) * (CLKFBOUT_MULT)/DIVCLK_DIVIDE
よって
VCO Frequency = 100 MHz * 8 *1 = 800 MHz
出力周波数 = VCO Frequency / CLKOUT0_DIVIDE.CLKOUT0_FRAC Divide
出力周波数 = 800 MHz / 73.0 ≒ 10.959 MHz となって、この数値はおおむね正しい。

次に、10 MHz にしようとすると CLKOUT0_DIVIDE.CLKOUT0_FRAC Divide = 80.0 とすれば良いので、
CLKOUT0_DIVIDE = 0x50 (10進数で 80)、CLKOUT0_FRAC Divide = 0 とすればよい。つまり、

XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x50);


とすれば良いはずだ。

25 MHz は

XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x20);


20 MHz は

XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x28);


と書き換えて、実行すると、その周波数にほとんど一致した。
Dynamic_Clocking_16_230526.png

XClk_Wiz_SetRate() は周波数がぴったりとは行かないので、その場合は、自分で値を設定した方が良いようだ。

最後に現在の Dynamic_Clocking.c を貼っておく。

// Dynamic_Clocking.c
// 2023/05/18 by marsee
// Referred to "MicroZed Chronicles: Dynamic Clocking"
// https://www.adiuvoengineering.com/post/microzed-chronicles-dynamic-clocking
// 2023/05/27 : Modified by marsee

#include <stdio.h>
#include "xclk_wiz.h"
#include "xgpio.h"
#include "xparameters.h"

XClk_Wiz ClkWiz_Dynamic;
XClk_Wiz_Config *CfgPtr_Dynamic;
XGpio gpio_0, gpio_1;

#define XCLK_WIZARD_DEVICE_ID       XPAR_CLK_WIZ_0_DEVICE_ID
#define XCLK_US_WIZ_RECONFIG_OFFSET 0x0000025C
#define CLK_LOCK            1

int main(){
    u32 count, locked;
    int Status;

    CfgPtr_Dynamic = XClk_Wiz_LookupConfig(XCLK_WIZARD_DEVICE_ID);
    XClk_Wiz_CfgInitialize(&ClkWiz_Dynamic, CfgPtr_Dynamic, CfgPtr_Dynamic->BaseAddr);
    XGpio_Initialize(&gpio_0, XPAR_AXI_GPIO_0_DEVICE_ID);
    XGpio_Initialize(&gpio_1, XPAR_AXI_GPIO_1_DEVICE_ID);

    printf("freq = 40 MHz\n");
    XGpio_DiscreteWrite(&gpio_1, 1, 1); // counter SCLR = 1, CE = 0
    usleep(1000);
    XGpio_DiscreteWrite(&gpio_1, 1, 2); // counter SCLR = 0, CE = 1
    sleep(1);
    XGpio_DiscreteWrite(&gpio_1, 1, 0); // counter SCLR = 0, CE = 0
    count = XGpio_DiscreteRead(&gpio_0, 1);
    locked = XGpio_DiscreteRead(&gpio_0, 2);
    printf("count = %d, locked = %d\n\n", count, locked);

    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, XCLK_WIZ_REG25_OFFSET, 0);
    //XClk_Wiz_SetRate(&ClkWiz_Dynamic, 10);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x50);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr,
                       XCLK_US_WIZ_RECONFIG_OFFSET,
                       (XCLK_WIZ_RECONFIG_LOAD | XCLK_WIZ_RECONFIG_SADDR));
    Status = XClk_Wiz_WaitForLock(&ClkWiz_Dynamic);
    printf("freq = 10 MHz, XClk_Wiz_SetRate\n");
    XGpio_DiscreteWrite(&gpio_1, 1, 1); // counter SCLR = 1, CE = 0
    usleep(1000);
    XGpio_DiscreteWrite(&gpio_1, 1, 2); // counter SCLR = 0, CE = 1
    sleep(1);
    XGpio_DiscreteWrite(&gpio_1, 1, 0); // counter SCLR = 0, CE = 0
    count = XGpio_DiscreteRead(&gpio_0, 1);
    locked = XGpio_DiscreteRead(&gpio_0, 2);
    printf("count = %d, locked = %d\n\n", count, locked);

    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, XCLK_WIZ_REG25_OFFSET, 0);
    //XClk_Wiz_SetRate(&ClkWiz_Dynamic, 25);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x20);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr,
                       XCLK_US_WIZ_RECONFIG_OFFSET,
                       (XCLK_WIZ_RECONFIG_LOAD | XCLK_WIZ_RECONFIG_SADDR));
    Status = XClk_Wiz_WaitForLock(&ClkWiz_Dynamic);
    printf("freq = 25 MHz\n");
    XGpio_DiscreteWrite(&gpio_1, 1, 1); // counter SCLR = 1, CE = 0
    usleep(1000);
    XGpio_DiscreteWrite(&gpio_1, 1, 2); // counter SCLR = 0, CE = 1
    sleep(1);
    XGpio_DiscreteWrite(&gpio_1, 1, 0); // counter SCLR = 0, CE = 0
    count = XGpio_DiscreteRead(&gpio_0, 1);
    locked = XGpio_DiscreteRead(&gpio_0, 2);
    printf("count = %d, locked = %d\n\n", count, locked);

    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, XCLK_WIZ_REG25_OFFSET, 0);
    //XClk_Wiz_SetRateHz(&ClkWiz_Dynamic, 20000000);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x200, 0x0801);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr, 0x208, 0x28);
    XClk_Wiz_WriteReg(CfgPtr_Dynamic->BaseAddr,
                       XCLK_US_WIZ_RECONFIG_OFFSET,
                       (XCLK_WIZ_RECONFIG_LOAD | XCLK_WIZ_RECONFIG_SADDR));
    Status = XClk_Wiz_WaitForLock(&ClkWiz_Dynamic);
    printf("freq = 20 MHz, XClk_Wiz_SetRateHz(&ClkWiz_Dynamic, 20000000);\n");
    XGpio_DiscreteWrite(&gpio_1, 1, 1); // counter SCLR = 1, CE = 0
    usleep(1000);
    XGpio_DiscreteWrite(&gpio_1, 1, 2); // counter SCLR = 0, CE = 1
    sleep(1);
    XGpio_DiscreteWrite(&gpio_1, 1, 0); // counter SCLR = 0, CE = 0
    count = XGpio_DiscreteRead(&gpio_0, 1);
    locked = XGpio_DiscreteRead(&gpio_0, 2);
    printf("count = %d, locked = %d\n\n", count, locked);

    return(0);
}

  1. 2023年05月27日 21:07 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/5946-cb8dca59
この記事にトラックバックする(FC2ブログユーザー)