GD32VF103中断机制(向量中断)

目录

本文基于GD32VF103 MCU简单介绍RISCV的向量中断方式, 并在RV-STAR开发板上实现验证。

完整程序下载地址:https://www.jiawei.site/downloads/gd32/gd32_irq_vectored.zip

中断机制与Vectored模式简介

中断与异常

GD32VF103中断机制(非向量中断) 中的中断与异常

RISC-V标准向量中断

RISC-V中断入口有两种方式:

  • Direct(非向量模式):所有trap(中断+异常)统一跳到 mtvec.BASE 所指的入口。
  • Vectored(向量模式):如果是异常,统一跳到mtvec.BASE所指的入口,如果 是中断,根据中断类型不同,硬件会跳到 mtvec.BASE + 4×cause 的位置。

这两种模式由 mtvec 的低两位决定:

  • 00 = Direct
  • 01 = Vectored

GD32VF103 ECLIC

GD32VF103不支持RISC-V标准的向量中断模式,往mtvec.MODE写入01会被忽略。 取而代之地,引入了ECLIC(Enhanced Core Local Interrupt Controller, 改进型内核中断控制器),用于管理所有的中断源。往mtvec.MODE写入11 启用ECLIC,支持每个中断配置单独配置为向量或非向量处理方式。

ECLIC向量中断模式与RISC-V标准的向量中断模式类似,也有中断向量表, 不同的是RISC-V标准的向量表中存放的是一系列跳转指令,而ECLIC的向量 表存放的是中断处理函数的地址。

向量模式中断相关CSR

ECLIC模式下mcause, mepc和mstatus的作用和RISC-V标准基本一致; mie和mip在ECLIC中断模式下不起作用。

ECLIC增加了一些寄存器,其中的i是中断编号:

  • mtvt:中断向量表基地址
  • clicintip[i]:中断等待标志
  • clicintie[i]:中断使能
  • clicintattr[i]:中断属性,trig域指定电平或边沿触发; shv域指定使用向量/非向量处理方式

典型的中断处理流程

使用ECLIC的向量中断方式前,必须先配置中断向量表,向量表 基地址写入mtvt中,在中断发生时,硬件自动地从 mtvt + 4×cause地位置取对应中断处理函数的地址,并 跳转到中断处理函数中执行。

进入和退出中断处理函数的需要执行上下文保存和恢复。

实践:定时器中断

对本站文章从零开始创建GD32VF103 Makefile工程 的程序进行扩充,添加定时器中断的处理部分,每隔 1秒进入中断,在中断处理函数中切换控制LED的IO口 的电平状态实现LED亮灭循环。

entry.S

    .section .text

    .align 14
    .globl _vector_base

_vector_base:
    j _defaut_handler
    .align 2
    .word 0
    .word 0
    .word 0
    .word 0
    .word 0
    .word 0
    .word _timer_handler_entry
    .word 0
    .word 0

_defaut_handler:
    j _defaut_handler
    
_timer_handler_entry:
    SAVE_CONTEXT

    call timer_handler

    RESTORE_CONTEXT
    mret

_vector_base标签的值将会写入mtvecmtvt,发生异常时会 进入_defaut_handler;定时器中断的编号为7,所以在 _vector_base偏移4×7个字节处写入定时器中断入口的地址。 _timer_handler_entry为定时器中断入口,执行上下文 保存操作,并调用中断服务函数,在退出前执行上下文恢复。

main.c

#include <stdint.h>

#define RCU_APB2EN 0x40021018
#define GPIOA_CTL0 0x40010800
#define GPIOA_OCTL 0x4001080C

#define TIMER_FREQ ((uint32_t)8000000/4)
#define TIMER_CTRL_ADDR 0xd1000000
#define TIMER_MTIME 0x0
#define TIMER_MTIMECMP 0x8

#define ECLIC_ADDR_BASE 0xd2000000
#define ECLIC_CLICINTIE_OFFSET 0x1001
#define ECLIC_CLICINTATTR_OFFSET 0x1002

extern uint32_t _vector_base[];

void gpio_init()
{
    // enable GPIOA clock
    *(uint32_t *)RCU_APB2EN |= (uint32_t)1 << 2;

    // set PA1 as output push pull
    *(uint32_t *)GPIOA_CTL0 = *(uint32_t *)GPIOA_CTL0 & ((uint32_t)0xffffff0f) |
                              (uint32_t)1 << 4;

    // PA1 output low
    *(uint32_t *)GPIOA_OCTL &= (uint32_t)0xfffffffd;
}

void timer_init()
{
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4) = 0;
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME) = 0;
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIMECMP + 4) = 0;
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIMECMP) = TIMER_FREQ;
}

int main()
{
    gpio_init();
    timer_init();

    uint32_t base = (uint32_t)_vector_base;
    // ECLIC mode
    asm volatile("csrw mtvec, %0" :: "r"(base | 3));
    asm volatile("csrw mtvt, %0" :: "r"(base));

    // vectored mode
    *(volatile uint32_t *)(ECLIC_ADDR_BASE + ECLIC_CLICINTATTR_OFFSET +
            7 * 4) |= 0x1; 
    // level trigger mode
    *(volatile uint32_t *)(ECLIC_ADDR_BASE + ECLIC_CLICINTATTR_OFFSET +
            7 * 4) &= 0xfffffff9; 
    // enable timer interrupt
    *(volatile uint32_t *)(ECLIC_ADDR_BASE + ECLIC_CLICINTIE_OFFSET +
            7 * 4) |= 0x1;
    // enable global interrupt
    asm volatile("csrs mstatus, %0" :: "r"(1 << 3));

    while(1);

    return 0;
}

void timer_handler()
{
    // reset mtime
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4) = 0;
    *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME) = 0;
    
    // toggle PA1 output
    if(*(uint32_t *)GPIOA_OCTL & (uint32_t)0b10){
        *(uint32_t *)GPIOA_OCTL &= (uint32_t)0xfffffffd;
    } else{
        *(uint32_t *)GPIOA_OCTL |= (uint32_t)0b10;
    }
}

main函数执行了一些初始化操作,使用内联汇编设置mtvecmtvt,启用ECLIC并设置中断向量表;写定时器中断相关寄存器 clicintattrclicintie将中断设置为向量处理方式、电平 触发并启用该中断;内联汇编设置mstatus.MIE启用全局中断。

timer_handler是定时器中断服务函数,在中断触发时,重新 设置mtime值以清除中断悬起状态标志,并翻转控制LED的IO电平。

参考