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 的裸机开发示例很难找到。

埃德

  • 德州仪器 TMS320DM6466
  • Code Composer Studio v5.5
4

1 回答 1

3

Note that this answer is only applicable to Cortex series ARM processors

I see you reached a solution for this a while back, hopefully this will be useful to anyone with a similar problem in the future.

There are many ways to set up interrupt vectors, they vary a lot between hardware and some platforms may require extra steps. The solution below is generally viable on ARM Cortex micro controllers and is compiler agnostic.

#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()
{

}

...

If you just need to add a single entry to the table you could use the following:

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

At the end of the day setting up the table is the easy part, all you are doing is loading a table of function pointers to a specific location, the hard part is setting the right bits in the right registers to enable the interrupts and clear up after them properly.

Further be aware that the interrupt functions typically need to be declared with a compiler specific keyword or pragma to make sure that the compiler generates correct code. This is because function call and return handling is often different when calling an interrupt vector to when calling a normal function.

Note that ARMv7 architecture supports remapping the vector table which can be very useful, this approach adds constraints to the alignment of the table though which in turn requires compiler/linker specific directives.

于 2015-07-30T14:09:13.943 回答