问题描述
void __attribute__ ((interrupt ("TIM4_IRQHandler"))) myhandler()
{
puts("hi");
TIM4->EGR |= TIM_EGR_UG; // send an update even to reset timer and apply settings
TIM4->SR &= ~0x01; // clear UIF
TIM4->DIER |= 0x01; // UIE
}
我设置了计时器:
RCC_APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC=7999;
TIM4->ARR=1000;
TIM4->EGR |= TIM_EGR_UG; // send an update even to reset timer and apply settings
TIM4->EGR |= (TIM_EGR_TG | TIM_EGR_UG);
TIM4->DIER |= 0x01; // UIE enable interrupt
TIM4->CR1 |= TIM_CR1_CEN;
我的计时器似乎没有启动。我认为我实际上并未启用它。我有吗?
我在许多示例代码命令中都看到了
NVIC_EnableIRQ(USART1_IRQn);
NVIC_EnableIRQ()中实际发生了什么?
我似乎错过了关键的一步。
更新2020-09-23 ,感谢此问题的答复者。技巧是将NVIC_ISER寄存器中的中断号位置1。正如我在下面指出的那样,这在STM32F101xx参考手册中似乎没有提到,因此我可能永远无法独自解决这个问题。不是说我有阅读数据表的真正技能。
无论如何,哦,喜悦,我设法使中断开始工作!您可以在此处查看代码:https://github.com/blippy/rpi/tree/master/stm32/bare/04-timer-interrupt
解决方法
即使您精疲力尽,您仍可能想要使用CMSIS头文件,这些头文件提供非常基本的ARM Cortex元素(例如NVIC_EnableIRQ
)的声明和内联版本。
您可以在https://github.com/ARM-software/CMSIS_5/blob/develop/CMSIS/Core/Include/core_cm3.h#L1508处找到NVIC_EnableIRQ
其定义为:
#define NVIC_EnableIRQ __NVIC_EnableIRQ
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
__COMPILER_BARRIER();
NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
__COMPILER_BARRIER();
}
}
如果需要,可以忽略__COMPILER_BARRIER()
。以前的版本没有使用它。
该定义适用于Cortex M-3芯片。与其他Cortex版本不同。
,带库仍被认为是裸机。没有操作系统,但是无论如何,这是您希望在此级别上学习的好地方。有人必须为他人编写库。
我打算在这里做一个完整的示例(实际上只需要很少的代码即可完成此操作),但是将从我的使用Timer1的开发板上的代码中提取。
显然,您需要ARM文档(cortex-m3的技术参考手册和armv7-m的体系结构参考手册)以及这部分的数据表和参考手册(两家公司都不需要程序员手册)。
您几乎没有提供与使零件正常工作相关的信息。您永远不要直接陷入中断,它们是高级主题,在最终使中断成为内核之前,您应该尽可能地进行调查。
我更喜欢让uart工作,然后在翻转,计数等操作时使用它来监视计时器寄存器。然后查看/确认已触发状态寄存器,了解/确认如何清除它(有时只是清除读取)。
然后将其启用到NVIC中,并通过轮询查看NVIC已看到它,并且可以清除它。
您没有显示向量表,这是使中断处理程序正常工作的关键。更少的核心启动。
08000000 <_start>:
8000000: 20005000
8000004: 080000b9
8000008: 080000bf
800000c: 080000bf
...
80000a0: 080000bf
80000a4: 080000d1
80000a8: 080000bf
...
080000b8 <reset>:
80000b8: f000 f818 bl 80000ec <notmain>
80000bc: e7ff b.n 80000be <hang>
...
080000be <hang>:
80000be: e7fe b.n 80000be <hang>
...
080000d0 <tim1_handler>:
第一个单词加载堆栈指针,其余为向量,指向处理程序的地址或一个(由我来查找)。
在这种情况下,st参考手册显示中断25在地址0x000000A4处为TIM1_UP。哪个镜像到0x080000A4,这就是处理程序在我的二进制文件中的位置,如果不是,则有两件事,您可以使用VTOR查找对齐的空间,有时会为此创建sram或其他一些闪存空间并将其指向,但是向量表处理程序必须具有正确的指针,否则中断处理程序将无法运行。
volatile unsigned int counter;
void tim1_handler ( void )
{
counter++;
PUT32(TIM1_SR,0);
}
volatile
不一定是在中断处理程序和前台任务之间共享变量的正确方法,它恰好适用于此编译器/代码,您可以进行研究,甚至更好地检查编译器输出(反汇编二进制文件)以确认这不是问题。
ra=GET32(RCC_APB2ENR);
ra|=1<<11; //TIM1
PUT32(RCC_APB2ENR,ra);
...
counter=0;
PUT32(TIM1_CR1,0x00001);
PUT32(TIM1_DIER,0x00001);
PUT32(NVIC_ISER0,0x02000000);
for(rc=0;rc<10;)
{
if(counter>=1221)
{
counter=0;
toggle_led();
rc++;
}
}
PUT32(TIM1_CR1,0x00000);
PUT32(TIM1_DIER,0x00000);
tim1的最小初始化和运行时。
请注意,NVIC_ISER0是位25,该位被设置为使能中断25至中断。
在尝试此代码之前,我轮询了计时器状态寄存器以查看其工作方式,与文档进行比较,并根据文档清除中断。然后,借助NVIC_ICPR0确认的知识,1,2寄存器将其中断25。此外,某些供应商提供的某些芯片可能在外设和NVIC之间没有其他门。
然后使用NVIC_ISER0将其发布到内核。
如果您不采取这些可能的步骤,也许您已经采取了这种措施,那么只会使任务变得更糟,并且需要更长的时间(是的,有时候您会很幸运)。
TIM4在向量表中看起来像是中断30,偏移量/地址0x000000B8。 NVIC_ISER0(0xE000E100)覆盖了前32个中断,因此该寄存器中有30个中断。如果您反汇编正在使用库生成的代码,那么我们可以看到正在发生的事情,或者可以在库源代码中查找它(就像有人已经为您所做的那样)。
然后,当然,您的计时器4代码需要正确地初始化计时器,并引发中断,我没有检查。
有些例子,您需要继续看下去。
最小值是
- 表格中的向量
- 设置中断设置允许寄存器中的位
- 启用中断以离开外围设备
- 触发中断
不一定按此顺序。