FC2カウンター FPGAの部屋 2011年10月03日
FC2ブログ

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

FPGAの部屋

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

xps_timerとxps_intcの使い方1(ソースコード・デバックができない)

Spartan-3A Starter KitでEDKを使ってカメラ表示25(LCD、Rotary EncoderカスタムIPの追加3)”の続きなんだが、その前に、今回はxps_timerとxps_intcの使い方を探ってみよう。

前回、”axi_timerを使う1”、”axi_timerを使う2(割り込みを使用した)”でaxi_timerの使い方を学んだ。
それより前では、”XPS_TIMERをテスト”でXMDを使って、xps_timerをテストしてみた。今回は、インタラプト・コントローラ(xps_intc) 付きの xps_timer に付いて、使い方を探ってみようと思う。

まずは、Project Navigator のProcessesウインドウのExport Hardware Design To SDK with Bitstream をダブルクリックして、SDKを立ち上げる。
SDKが立ち上がった。
Spa3A_SKit_OV7670_109_111001.png

試しに本番のlcd_rot_contプロジェクトを作ってみたが、今回は、xps_timer_testプロジェクトを作成する。これは、XilinxのCプロジェクトだ。
そこに、xps_timer_test.c を新規作成した。
Spa3A_SKit_OV7670_110_111002.png

今回は、ハードウェアを直接アクセスして制御してみようと思う。
axi_timerを使う2(割り込みを使用した)”のCコードをベースに、GPIOで接続されたLEDを点滅してみることにする。

参照データシート
”LogiCORE IP XPS Interrupt Controller (v2.01a)
LogiCORE IP XPS Timer/Counter (v1.02a)
XPS General Purpose Input/Output (GPIO) (v2.00a)

次に、XPSの設定を下に貼っておく。最初はxps_intcから。
Spa3A_SKit_OV7670_111_111002.png

ここで、Number of Interrupt Inputs が2になっているが、XPSのPortsタブで見ると、Iが1つしかないのが謎だ?
Spa3A_SKit_OV7670_112_111002.png

xps_timerの設定を下に示す。
Spa3A_SKit_OV7670_113_111002.png

xps_gpioの設定を下に示す。
Spa3A_SKit_OV7670_114_111002.png

Spa3A_SKit_OV7670_115_111002.png

・SDKでXilinx ToolsメニューからProgram FPGAを選択した。Program FPGAダイアログが開くので、Programボタンをクリックしてビットファイルをダウンロードした。

・elfファイルで、右クリックして、右クリックメニューからDebug As -> Lanunch on Hardware を選択する。すると、No source available for "" が出てソースコード・デバックできない。。。(EDKのバージョンは13.2)
Spa3A_SKit_OV7670_116_111003.png

デバック時にソースコード・デバックできないのは痛い。

今回のトラブルには関係ないが、タイマーの便利な使用方法。”11.1 EDK - Microblaze のプロセッサ実行サイクルを計算する方法”タイマーで実行サイクルを計算する方法。

バグっているのが確実だが、現在のCソースを貼っておく。

/* xps_timer_test.c * *  Created on: 2011/10/02 *      Author: Masaaki *  *  65MHzクロック */

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

// XPS_INTC define
#define XPS_INTC_0_ISR        XPAR_XPS_INTC_0_BASEADDR        // Interrupt Status Register
#define XPS_INTC_0_IPR        XPAR_XPS_INTC_0_BASEADDR+0x4    // Interrupt Pending Register
#define XPS_INTC_0_IER        XPAR_XPS_INTC_0_BASEADDR+0x8    // Interrupt Enable Register
#define XPS_INTC_0_IAR        XPAR_XPS_INTC_0_BASEADDR+0xC    // Interrupt Acknowledge Register
#define XPS_INTC_0_SIE        XPAR_XPS_INTC_0_BASEADDR+0x10    // Set Interrupt Enable Bits
#define XPS_INTC_0_CIE        XPAR_XPS_INTC_0_BASEADDR+0x14    // Clear Interrupt Enable Bits
#define XPS_INTC_0_IVR        XPAR_XPS_INTC_0_BASEADDR+0x18    // Interrupt Vector Register
#define XPS_INTC_0_MER        XPAR_XPS_INTC_0_BASEADDR+0x1C    // Master Enable Register

// XPS_TIMER define
#define XPS_TIMER_0_TCSR0    XPAR_XPS_TIMER_0_BASEADDR    // Control/Status Register 0
#define XPS_TIMER_0_TLR0    XPAR_XPS_TIMER_0_BASEADDR+0x4    // Load Register 0
#define XPS_TIMER_0_TCR0    XPAR_XPS_TIMER_0_BASEADDR+0x8    // Timer/Counter Register 0
#define XPS_TIMER_0_TCSR1    XPAR_XPS_TIMER_0_BASEADDR+0x10    // Control/Status Register 1
#define XPS_TIMER_0_TLR1    XPAR_XPS_TIMER_0_BASEADDR+0x14    // Load Register 1
#define XPS_TIMER_0_TCR1    XPAR_XPS_TIMER_0_BASEADDR+0x18    // Timer/Counter Register 1

// XPS_GPIO_LEDS_8BIT define
#define XPS_GPIO_LEDS_8BIT_DATA    XPAR_LEDS_8BIT_BASEADDR        // データ
#define XPS_GPIO_LEDS_8BIT_TRI    XPAR_LEDS_8BIT_BASEADDR+0x4    // 0 - Output, 1 - Input

#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 xps_intc_init() {
    *(volatile unsigned int *)(XPS_INTC_0_IER) = 0x80000000;    // int0 enable
    *(volatile unsigned int *)(XPS_INTC_0_MER) = 0x1;        // IRQ Enable
}

void xps_timer_init(){
    *(volatile unsigned int *)(XPS_TIMER_0_TLR0) = 62500000// 1秒 1000,000,000ns/16ns = 62,500,000
    // *(volatile *)(XPS_TIMER_0_TLR0) = 0x00989680; // 0.2秒
    *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード
    *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
}

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

int main()
{
    unsigned char i;

    *(volatile unsigned int *)(XPS_GPIO_LEDS_8BIT_TRI) = 0;    // 出力設定
    *(volatile unsigned int *)(XPS_GPIO_LEDS_8BIT_DATA) = 1;
    xps_intc_init();    // xps_intc の初期化
    xps_timer_init(); // xps_timerの初期化
    //*(volatile unsigned char *)(XPS_GPIO_LEDS_8BIT_TRI) = 0;    // 出力設定

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

    i = 1;
    while(1){
        *(volatile unsigned char *)(XPS_GPIO_LEDS_8BIT_DATA) = i;

        // xps_timter割り込み待ち
        interrupt = 0;
        while(interrupt==0);
        
        // 割り込み待ちループから抜け出す
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER | TIMER_INTERRUPT;    // 割り込みクリア
        *(volatile unsigned int *)(XPS_INTC_0_IAR) = 0x80000000;    // int0 clear

        *(volatile unsigned int *)(XPS_TIMER_0_TLR0) = 62500000// 1秒 1000,000,000ns/16ns = 62,500,000
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード、割り込みクリア
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
    }

    return 0;
}



(2011/10/06:追記)
K林さんに間違いを指摘して頂いて、コードを修正しましたが、まだ割り込みがかかっていないようです。何でしょうか?現在のコードを貼っておきます。

/* * xps_timer_test.c * *  Created on: 2011/10/02 *      Author: Masaaki *  *  65MHzクロック */

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

// XPS_INTC define
#define XPS_INTC_0_ISR        XPAR_XPS_INTC_0_BASEADDR        // Interrupt Status Register
#define XPS_INTC_0_IPR        XPAR_XPS_INTC_0_BASEADDR+0x4    // Interrupt Pending Register
#define XPS_INTC_0_IER        XPAR_XPS_INTC_0_BASEADDR+0x8    // Interrupt Enable Register
#define XPS_INTC_0_IAR        XPAR_XPS_INTC_0_BASEADDR+0xC    // Interrupt Acknowledge Register
#define XPS_INTC_0_SIE        XPAR_XPS_INTC_0_BASEADDR+0x10    // Set Interrupt Enable Bits
#define XPS_INTC_0_CIE        XPAR_XPS_INTC_0_BASEADDR+0x14    // Clear Interrupt Enable Bits
#define XPS_INTC_0_IVR        XPAR_XPS_INTC_0_BASEADDR+0x18    // Interrupt Vector Register
#define XPS_INTC_0_MER        XPAR_XPS_INTC_0_BASEADDR+0x1C    // Master Enable Register

// XPS_TIMER define
#define XPS_TIMER_0_TCSR0    XPAR_XPS_TIMER_0_BASEADDR    // Control/Status Register 0
#define XPS_TIMER_0_TLR0    XPAR_XPS_TIMER_0_BASEADDR+0x4    // Load Register 0
#define XPS_TIMER_0_TCR0    XPAR_XPS_TIMER_0_BASEADDR+0x8    // Timer/Counter Register 0
#define XPS_TIMER_0_TCSR1    XPAR_XPS_TIMER_0_BASEADDR+0x10    // Control/Status Register 1
#define XPS_TIMER_0_TLR1    XPAR_XPS_TIMER_0_BASEADDR+0x14    // Load Register 1
#define XPS_TIMER_0_TCR1    XPAR_XPS_TIMER_0_BASEADDR+0x18    // Timer/Counter Register 1

// XPS_GPIO_LEDS_8BIT define
#define XPS_GPIO_LEDS_8BIT_DATA    XPAR_LEDS_8BIT_BASEADDR        // データ
#define XPS_GPIO_LEDS_8BIT_TRI    XPAR_LEDS_8BIT_BASEADDR+0x4    // 0 - Output, 1 - Input

#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 xps_intc_init() {
    *(volatile unsigned int *)(XPS_INTC_0_IER) = 0x1;    // int0 enable
    *(volatile unsigned int *)(XPS_INTC_0_MER) = 0x3;    // IRQ Enable
}

void xps_timer_init(){
    *(volatile unsigned int *)(XPS_TIMER_0_TLR0) = 62500000// 1秒 1000,000,000ns/16ns = 62,500,000
    // *(volatile *)(XPS_TIMER_0_TLR0) = 0x00989680; // 0.2秒
    *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード
    *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
}

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

int main()
{
    unsigned int i;

    *(volatile unsigned int *)(XPS_GPIO_LEDS_8BIT_TRI) = 0;    // 出力設定
    *(volatile unsigned int *)(XPS_GPIO_LEDS_8BIT_DATA) = 1;
    xps_intc_init();    // xps_intc の初期化
    xps_timer_init(); // xps_timerの初期化
    // *(volatile unsigned char *)(XPS_GPIO_LEDS_8BIT_TRI) = 0;    // 出力設定

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

    for(i=10; i<256; i++){
        *(volatile unsigned int *)(XPS_GPIO_LEDS_8BIT_DATA) = i;

        // xps_timter割り込み待ち
        interrupt = 0;
        while (interrupt==0);
        
        // 割り込み待ちループから抜け出す
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER | TIMER_INTERRUPT;    // 割り込みクリア
        *(volatile unsigned int *)(XPS_INTC_0_IAR) = 0x1;    // int0 clear

        *(volatile unsigned int *)(XPS_TIMER_0_TLR0) = 62500000// 1秒 1000,000,000ns/16ns = 62,500,000
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード、割り込みクリア
        *(volatile unsigned int *)(XPS_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
    }

    return 0;
}



(2011/10/07:追記)
SP605で同じCコードでxps_timerのテストをしてみたのですが、問題なく動作しました。
Spartan-3A Starter Kitでは、どうしても、うまく行きません。もう1つ、新規でEDKのプロジェクトを作成してやって見ましたが、やはり、割り込みはかかってないみたいでした。
Spartan-3A Starter KitのEDKでxps_timer, xps_intcの割り込み動作がおかしいようなので、独自のタイマーを組み込んでみようと思っています。
  1. 2011年10月03日 21:05 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:5