3. S32K中断向量表重映射与外部中断

S32K中断向量表重映射与外部中断 学习卡片

任务说明

本案例在 S32K1xx(以 S32K144 为例)上完成两件事:把中断向量表从 Flash 重定位到 RAM(VTOR 指向 RAM 中的向量表副本),并配置 PTB2 为下降沿触发的外部中断,在中断服务函数中翻转 LED。验证方式:给 PTB2 一个下降沿(按键按下),观察 LED 状态翻转。

关键点

  • 向量表重映射:先把 Flash 中的向量表整体拷贝到 RAM,再写 SCB->VTOR 指向 RAM 副本。RAM 向量表需按 512 字节对齐(Cortex-M4 要求)。
  • PTB2 对应 PORTB 的 PORTB_IRQn(IRQ 号 43),需在 RAM 向量表中把该表项指向自定义 ISR。
  • 下降沿触发:PORT 配置 PORT_PCR_IRQC(0xA)(下降沿中断),并使能 NVIC 对应中断。
  • LED 使用 PTD0(S32K144 EVB 板载 RGB 的蓝/绿通道之一,按实际板卡调整引脚)。
Flash 向量表 0x0000_0000 (复位默认) RAM 向量表副本 0x2000_0000 (512B对齐) [43] = PORTB_IRQHandler 其余表项 = Flash 原值 SCB->VTOR 重映射后 = 0x2000_0000 异常/中断查表走 RAM 可运行时动态改 ISR 拷贝 VTOR 指向 PTB2 下降沿 → PORTB_IRQHandler → 翻转 LED

完整代码(main.c)

#include "S32K144.h"

#define VECTOR_TABLE_SIZE   (48u * 4u)          /* 前 48 个表项足够覆盖 PORTB_IRQn(43) */
#define RAM_VECTOR_BASE     0x20000000u         /* 512B 对齐 */

extern uint32_t __Vectors[];                    /* 链接脚本提供的 Flash 向量表起始 */

void PORTB_IRQHandler(void);

/* 把 Flash 向量表拷到 RAM,并把 PORTB 表项替换为自定义 ISR */
void RemapVectorTable(void)
{
    uint32_t *ramVec = (uint32_t *)RAM_VECTOR_BASE;
    for (uint32_t i = 0; i < VECTOR_TABLE_SIZE / 4u; i++) {
        ramVec[i] = __Vectors[i];
    }
    ramVec[16 + 43] = (uint32_t)PORTB_IRQHandler;   /* 16 为系统异常数,43 为 PORTB_IRQn */
    SCB->VTOR = RAM_VECTOR_BASE;                    /* 重映射 */
    __DSB();
    __ISB();
}

/* PTB2 下降沿中断:翻转 PTD0 上的 LED */
void PORTB_IRQHandler(void)
{
    if (PORTB->ISFR & (1u << 2)) {                 /* 确认是 PTB2 触发 */
        PORTB->ISFR = (1u << 2);                   /* 写 1 清标志 */
        PTD->PTOR ^= (1u << 0);                    /* 翻转 LED */
    }
}

void LED_Init(void)
{
    PCC->PCC_PORTD |= PCC_PCC_PORTD_CGC_MASK;
    PORTD->PCR[0] = PORT_PCR_MUX(1);                /* PTD0 作 GPIO */
    PTD->PDDR |= (1u << 0);                        /* 输出 */
    PTD->PSOR  = (1u << 0);                        /* 初始灭 */
}

void PTB2_EXTI_Init(void)
{
    PCC->PCC_PORTB |= PCC_PCC_PORTB_CGC_MASK;
    PORTB->PCR[2] = PORT_PCR_MUX(1)                 /* GPIO */
                  | PORT_PCR_IRQC(0xA)              /* 下降沿中断 */
                  | PORT_PCR_PE_MASK                /* 使能上拉 */
                  | PORT_PCR_PS_MASK;
    NVIC_EnableIRQ(PORTB_IRQn);
}

int main(void)
{
    RemapVectorTable();
    LED_Init();
    PTB2_EXTI_Init();

    for (;;) { __asm volatile ("wfi"); }
}

运行与验证

  1. 用 S32 Design Studio 新建 S32K144 工程,把上述 main.c 替换默认文件;确认链接脚本中 __Vectors 符号存在(S32DS 默认提供)。
  2. 编译、下载到目标板,复位运行。
  3. 用杜邦线把 PTB2 短接到 GND 再松开,制造一个下降沿;或按下接在 PTB2 上的按键。
  4. 观察 PTD0 上的 LED:每次下降沿应翻转一次状态。若 LED 不翻转,检查 PTB2 是否已上拉、NVIC 是否使能、SCB->VTOR 是否等于 0x20000000。

常见问题

  • RAM 向量表未按 512 字节对齐会导致 VTOR 写入被硬件忽略或行为异常,务必使用对齐地址。
  • 若只拷贝前 48 项,需保证后续不会触发编号更大的中断;否则应拷贝完整向量表。
  • ISR 中必须清 ISFR 对应位,否则中断会反复进入。