7

RTOS または Linux OS を使用しないベアメタル環境で、C またはインライン アセンブリを使用して ARM9 割り込みベクトル テーブルをセットアップする方法の例を教えてください。

具体的には、インライン アセンブリまたは C を使用して、C でコーディングされた IRQ 割り込みハンドラー ISR に分岐を設定するにはどうすればよいですか?

/// timer1 64-bit mode interrupt handler connected to TINT2 interrupt=#34
/// \todo I think I need to ACK it once I get working
interrupt void interruptHandlerTimer1(void) {
    printf("\n [* ISR *] \n");
    // ACK TINT2 interrupt #34
    AINTC ->IRQ1 = 1 << (34 - 32);
}
void main(void) {

    TIMER1 ->TCR = 0x00000000;
    // TGCR: TIMMODE=0 64-bit GP, TIM34RS=TIM12RS=1
    TIM0ER1 ->TGCR = 0x00000003;
    TIMER1 ->TIM34 = 0x00000000;
    TIMER1 ->TIM12 = 0x00000000;
    TIMER1 ->PRD34 = 0x00000000;
    TIMER1 ->PRD12 = 0x0000ffff;
    // TCR: inc until period match, then reset
    TIMER1 ->TCR = (2 << 6);

    // This is wrong.
    // I think I need to insert opcode or assembly to branch to interruptHandlerTimer1 ?
    // AINTC ->EABASE located @ 0x00000000
    uint32_t** ptrEabase = (uint32_t**) (AINTC ->EABASE);
    ptrEabase[34] = (uint32_t*) (interruptHandlerTimer1);

    // Set INT34 TINT2 to IRQ priority 2
    AINTC ->INTPRI4 = 0x00000200;
    // Enable INT34
    AINTC ->EINT1 = (1 << (34 - 32));

    // Enable IRQ in CPSR
    // "TMS32DM644x ARM Subsystem", 3.3 Processor Status registers
    asm("    ;Enable IRQ in CPSR");
    asm("    mrs     r0, cpsr");
    asm("    bic     r0, r0, #0x80");
    asm("    msr     cpsr_c, r0");

    // I expected to see " [* ISR *] " print
    // when TIMER1->TIM12 reaches 0x0000ffff
    while (1) {
        printf("%08x %08x\r\n", TIMER1 ->TIM34, TIMER1 ->TIM12);
    }
}

割り込みエントリ テーブル

ヒントや方向性を事前に感謝します。

ARM9 のベアメタル開発の例を見つけるのは非常に困難です。

エド

  • TI TMS320DM6466
  • コード コンポーザー スタジオ v5.5
4

1 に答える 1

3

この回答は、Cortex シリーズ ARM プロセッサにのみ適用されることに注意してください。

しばらく前にこれに対する解決策に達したようですが、これが将来同様の問題を抱えている人に役立つことを願っています.

割り込みベクトルを設定するには多くの方法があります。それらはハードウェア間で大きく異なり、一部のプラットフォームでは追加の手順が必要になる場合があります。以下のソリューションは、通常、ARM Cortex マイクロ コントローラーで実行可能であり、コンパイラに依存しません。

#include <string.h>

//Size of vector table, note yours is probably 16 entries
#define VECTOR_TABLE_ENTRIES 4
//Base address in MCU memory of vector table (by default 0x0 for ARM9)
#define HARDWARE_VECTOR_TABLE_ADDRESS 0x00000000

typedef void(*isr_vector)(void);

void myIsr1();
void myIsr2();
void myIsr3();
void myIsr4();

static isr_vector s_vector_table[VECTOR_TABLE_ENTRIES] =
{
    myIsr1,
    myIsr2,
    myIsr3,
    myIsr4
};

/**
 * Load interrupt vector to correct area in system memory, call on startup
 */
void load_vector_table()
{
    memcpy(HARDWARE_VECTOR_TABLE_ADDRESS, s_vector_table, sizeof(isr_vector));
}

void myIsr1()
{

}

...

テーブルに単一のエントリを追加する必要がある場合は、次を使用できます。

void set_vector_table_entry(int index, isr_vector vector)
{
    *(HARDWARE_VECTOR_TABLE_ADDRESS + (sizeof(isr_vector) * index)) = vector;
}

結局のところ、テーブルのセットアップは簡単な部分です。関数ポインターのテーブルを特定の場所にロードするだけです。難しい部分は、適切なレジスターに適切なビットを設定して、割り込みを有効にしてクリアすることです。それらを適切に追跡します。

さらに、割り込み関数は通常、コンパイラ固有のキーワードまたはプラグマを使用して宣言し、コンパイラが正しいコードを生成するようにする必要があることに注意してください。これは、通常の関数呼び出し時と割り込みベクタ呼び出し時では、関数呼び出しとリターンの扱いが異なることが多いためです。

ARMv7 アーキテクチャは、非常に便利なベクトル テーブルの再マッピングをサポートしていることに注意してください。このアプローチでは、テーブルのアラインメントに制約が追加されますが、コンパイラ/リンカー固有のディレクティブが必要になります。

于 2015-07-30T14:09:13.943 に答える