FC2カウンター FPGAの部屋 axi_timerを使う1
FC2ブログ

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

FPGAの部屋

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

axi_timerを使う1

AXIバスのEDKでキャラクタ・ディスプレイ・コントローラのカスタムIPを作る8”でやった表示を0.2秒ごとに書きたいと思い、axi_timerを使ってみることにした。

axi_timerのデータシートはこちら以前にxps_timerのことを書いたことがあった。ほとんど同じだと思う。
今回は、Auto Reload/Hold Timerのビットを1にして、Downカウントにしようと思う。それから、InterruptもONにしたい。
手順を下に示す。timer0をgenerateモードで使用する。

1.XPAR_AXI_TIMER_0_BASEADDR+0x4アドレス(Load Registger, TLR0)に、ロードする値をWriteする。50MHzなので、0.2秒では10000000、16進に直すと0x00989680

2.XPAR_AXI_TIMER_0_BASEADDRアドレス(Control/Status Register, TCSR0)に、10ビット目のENALL、5ビット目のLOAD0を1にして、Writeする (0x00000420)。

3.XPAR_AXI_TIMER_0_BASEADDR+8アドレス(Timer/Counter Register, TCR0)を見ると、0x00989680ガロードされている。

4.XPAR_AXI_TIMER_0_BASEADDRアドレス(Control/Status Register, TCSR0)に、10ビット目のENALL、7ビット目のENT0、6ビット目のEINT0、4ビット目のARHT0、1ビット目のUDT0を1にする。(0x000004D2) GenerateモードでDWONカウント、割り込みあり、オートロードあり。

5.割り込みハンドラを使って、割り込みが来たら、色を替えたキャラクタを表示する。

これをCプログラムにしたのが、下のコードとなる。

/* * axi_timer_test.c * *  Created on: 2011/08/12 *      Author: Masaaki */

#include "xbasic_types.h"
#include "xio.h"
#include "mb_interface.h"
#include "xparameters.h"

#define AXI_TIMER_0_TCSR0    XPAR_AXI_TIMER_0_BASEADDR    // Control/Status Register 0
#define AXI_TIMER_0_TLR0    XPAR_AXI_TIMER_0_BASEADDR+0x4    // Load Register 0
#define AXI_TIMER_0_TCR0    XPAR_AXI_TIMER_0_BASEADDR+0x8    // Timer/Counter Register 0
#define AXI_TIMER_0_TCSR1    XPAR_AXI_TIMER_0_BASEADDR+0x10    // Control/Status Register 1
#define AXI_TIMER_0_TLR1    XPAR_AXI_TIMER_0_BASEADDR+0x14    // Load Register 1
#define AXI_TIMER_0_TCR1    XPAR_AXI_TIMER_0_BASEADDR+0x18    // Timer/Counter Register 1

int interrupt = 0;

void axi_timer_init(){
    *(volatile *)(AXI_TIMER_0_TLR0) = 0x00989680// 0.2秒
    *(volatile *)(AXI_TIMER_0_TCSR0) = 0x00000420// TLR0へロード
    *(volatile *)(AXI_TIMER_0_TCSR0) = 0x000004D2; // GenerateモードでDWONカウント、割り込みあり、オートロードあり
}

void timer_int_handler(void * arg) {
    interrupt = 1;
}

void write_data(unsigned int address, unsigned int data)
{
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR) = address;
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR+4) = data;
}

int read_data(unsigned int address)
{
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR) = address;
    return(*(volatile *)(XPAR_CHARDISPC_0_BASEADDR+4));
}

int main()
{
    unsigned int addr;
    unsigned int color, char_code, data;

    axi_timer_init(); // axi_timerの初期化

    // 割り込みハンドラ登録、割り込み許可
    microblaze_register_handler(timer_int_handler, (void *) 0);
    microblaze_enable_interrupts();

    for(addr=0, color=1, char_code=0x21; addr < 100*75; addr++, color++, char_code++){
        data = (color & 0x7)<<7 | char_code;
        write_data(addr, data);
        if (char_code == 0x7e) // キャラクタの~
            char_code = 0x20// キャラクタの!
        if ((color & 0x7) == 7)
            color = 0;

        // axi_timter割り込み待ち
        interrupt = 0;
        while(interrupt==0);
    }

    return 0;
}


これを実行すると、while(interrupt==0);から進まない。割り込みがかかっていないようだ。

次に割り込みをやめて、AXI_TIMER_0_TCSR0をReadして、T0INが1になるの待つ。そうなったら、一文字Writeして、T0INに1をWriteしてT0INをクリアするという手順でやってみた。今回は、TimerのControl/Statusレジスタのビットの割り当てをデファインして、ORして設定するという手順を取ることにした。そのCコードを下に示す。microblaze_register_handler()、microblaze_enable_interrupts()は行っているが、割り込みルーチンtimer_int_handler()を使用していないので、関係がなくなっている。

/* * axi_timer_test.c * *  Created on: 2011/08/12 *      Author: Masaaki */
#include "xbasic_types.h"
#include "xio.h"
#include "mb_interface.h"
#include "xparameters.h"

#define AXI_TIMER_0_TCSR0    XPAR_AXI_TIMER_0_BASEADDR    // Control/Status Register 0
#define AXI_TIMER_0_TLR0    XPAR_AXI_TIMER_0_BASEADDR+0x4    // Load Register 0
#define AXI_TIMER_0_TCR0    XPAR_AXI_TIMER_0_BASEADDR+0x8    // Timer/Counter Register 0
#define AXI_TIMER_0_TCSR1    XPAR_AXI_TIMER_0_BASEADDR+0x10    // Control/Status Register 1
#define AXI_TIMER_0_TLR1    XPAR_AXI_TIMER_0_BASEADDR+0x14    // Load Register 1
#define AXI_TIMER_0_TCR1    XPAR_AXI_TIMER_0_BASEADDR+0x18    // Timer/Counter Register 1

#define ENABLE_ALL_TIMERS                (0x1<<10)
#define ENABLE_PULSE_WIDTH_MODULATION    (0x1<<9)
#define TIMER_INTERRUPT                    (0x1<<8)
#define ENABLE_TIMER                    (0x1<<7)
#define ENABLE_INTERRUPT                (0x1<<6)
#define LOAD_TIMER                        (0x1<<5)
#define AUTO_RELOAD_HOLD_TIMER            (0x1<<4)
#define ENABLE_EXT_CAPTURE_TRIG            (0x1<<3)
#define ENABLE_EXT_GENERATE_SIG            (0x1<<2)
#define DOWN_UP_COUNT_TIMER                (0x1<<1)
#define TIMER_MODE_CAP_GENE                (0x1)

int interrupt = 0;

void axi_timer_init(){
    *(volatile *)(AXI_TIMER_0_TLR0) = 0x004C4B40; // 0.1秒
    // *(volatile *)(AXI_TIMER_0_TLR0) = 0x00989680; // 0.2秒
    *(volatile *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード
    *(volatile *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | AUTO_RELOAD_HOLD_TIMER | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり、オートロードあり
}

void timer_int_handler(void * arg) {
    interrupt = 1;
}

void write_data(unsigned int address, unsigned int data)
{
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR) = address;
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR+4) = data;
}

int read_data(unsigned int address)
{
    *(volatile *)(XPAR_CHARDISPC_0_BASEADDR) = address;
    return(*(volatile *)(XPAR_CHARDISPC_0_BASEADDR+4));
}

int main()
{
    unsigned int addr;
    unsigned int color, char_code, data;
    unsigned int temp;

    axi_timer_init(); // axi_timerの初期化

    // 割り込みハンドラ登録、割り込み許可
    microblaze_register_handler(timer_int_handler, (void *) 0);
    microblaze_enable_interrupts();

    for(addr=0, color=1, char_code=0x21; addr < 100*75; addr++, color++, char_code++){
        data = (color & 0x7)<<7 | char_code;
        write_data(addr, data);
        if (char_code == 0x7e) // キャラクタの~
            char_code = 0x20// キャラクタの!
        if ((color & 0x7) == 7)
            color = 0;

        // axi_timter割り込み待ち
        // interrupt = 0;
        // while(interrupt==0);
        do{
            temp = *(volatile *)(AXI_TIMER_0_TCSR0);
        }while((temp & TIMER_INTERRUPT)==0);
        *(volatile *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | AUTO_RELOAD_HOLD_TIMER | DOWN_UP_COUNT_TIMER | TIMER_INTERRUPT;
    }

    return 0;
}


0.2秒に1回では、SVGAではキャラクタを書くのがあまりに遅いので、0.1秒単位に変更した。割り込み使わなければうまくいきました。
SP605_AXI_CDC_41_110813.jpg
  1. 2011年08月13日 20:28 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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