本帖最后由 L-MCU 于 2024-6-28 17:21 编辑
1、VTF与SysTick介绍 CH32L103内置可编程快速中断控制器(PFIC–Programmable Fast Interrupt Controller),特有免表VTF(Vector Table Free)中断响应机制,4路可编程直达中断向量地址。关于免表中断,可不经过中断向量表的查表过程,直达中断函数入口。关于免表中断的具体介绍,可看QingKeV4微处理器手册。 CH32L103内核自带了一个64位加减计数器(SysTick),支持HCLK或者HCLK/8作为时基,具有较高优先级,校准后可用于时间基准。
2、VTF与SysTick应用 开启免表中断(VTF)后,可以缩短中断延迟时间。关于中断延迟(响应)时间,即从中断触发条件产生到中断函数执行的时间。通过SysTick中断可以验证开启VTF后会缩短中断延迟时间。 CH32L103的SysTick进入中断的条件为:当计数寄存器的值与比较寄存器的值相同时,触发中断。测试程序配置SysTick计数模式为向上计数,选择HCLK作为时基,当计数器值与比较寄存器值相同时,会触发中断,此时SysTick计数器会重新从0开始计数,在中断第一时间读取计数器的值。通过对开启VTF和不开启VTF计数器值的比较,当开启VTF后计数器值变小,说明中断延迟时间被缩短。 具体测试程序如下: /********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2023/07/08
* Description : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*
*@Note
*VTF IRQ interrupt routine:
*This example is used to demonstrate VTF IRQ
*/
#include "debug.h"
/* Global define */
/* Global Variable */
uint32_t time=0;
void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fn Systick_Init
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Initializes Systick.
*
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
void SYSTICK_Init_Config(u64 ticks)
{
SysTick->SR = 0;
SysTick->CNT = 0;
SysTick->CMP = ticks;
SysTick->CTLR =0x0F;
NVIC_SetPriority(SysTicK_IRQn, 0);
NVIC_EnableIRQ(SysTicK_IRQn);
SetVTFIRQ((u32)SysTick_Handler,SysTicK_IRQn,0,ENABLE);
}
/*********************************************************************
* @fn main
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Main program.
*
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
int main(void)
{
SystemCoreClockUpdate();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
printf("Interrupt VTF Test\r\n");
SYSTICK_Init_Config(SystemCoreClock-1);
while(1)
{
}
}
/*********************************************************************
* @fn SysTick_Handler
*
* @brief This function handles SysTick exception.
*
* @return none
*/
void SysTick_Handler(void)
{
printf("CNT:%d\r\n",(u32)SysTick->CNT);
SysTick->CTLR=0;
SysTick->SR=0;
}
关于SysTick的配置,程序中: (1)首先对系统计数状态寄存器(STK_SR)以及系统计数寄存器(STK_CNT)置0,清除对应标志位,以及将计数器值置0,从0开始向上计数。 (2)其次对系统计数比较寄存器寄存器(STK_CMP)进行赋值,此处赋值为SystemCoreClock-1,SystemCoreClock的大小为96M,则需要计数96M次,即96000000次。 (3)最后对系统计数控制寄存器(STK_CTLR)进行配置并进行中断使能以及开启免表中断。系统计数控制寄存器(STK_CTLR)赋值为0x0F,即配置启动系统计数器STK,使能计数器中断,选择HCLK做时基,向上计数到比较值后重新从0开始计数。 关于SysTick时基,可选择HCLK或HCLK/8作为时基。以测试例程为例,选择HCLK作为时基,HCLK大小一般为系统主频大小,具体看配置,此处为系统主频大小96MHz,则SysTick计数一次的时间为1/96MHz。比较寄存器值设置为96M-1,从0开始计数,则计数96M次。因此进一次SysTick中断的时间为1s进一次中断。 关于系统计数控制寄存器(STK_CTLR),具体如下: 根据例程: 当不开启免表中断时,进入中断后,打印计数器的值为22,如下图 当开启免表中断时,进入中断后,打印计数器的值为20,如下图 由结果可知,开启免表中断后,中断延迟时间还是缩短一些的。
3、软件中断 通过配置系统计数控制寄存器(STK_CTLR)的位31置1,可以配置触发软件中断,如下图 关于软件中断的触发以及对应标志位的清除函数如下: /*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n", SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
printf("This is printf example\r\n");
NVIC_EnableIRQ(Software_IRQn);
while(1)
{
SysTick->CTLR |= (1<<31);
Delay_Ms(1000);
}
}
void SW_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void SW_Handler(void)
{
SysTick->CTLR &= ~(1<<31);
printf("Enter INT\r\n");
}
程序中,首先使能开启软件中断,然后在while循环中每隔1s将位31置1进入软件中断,软件中断中将该位清0。
附件为测试所用例程,有需要可以下载看一下。
|