stm32 NVIC_EnableIRQ()裸金属等效物?
我在用蓝色药丸,试图找出干扰。我有一个中断处理程序:stm32 NVIC_EnableIRQ()裸金属等效物?,stm32,interrupt,bare-metal,Stm32,Interrupt,Bare Metal,我在用蓝色药丸,试图找出干扰。我有一个中断处理程序: 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; /
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寄存器中设置中断号的位。正如我在下面指出的,STM32F101xx参考手册中似乎没有提到这一点,因此我可能永远无法独自解决这一问题;并不是说我有阅读数据表的真正技能
不管怎么说,哦,乔伊,我设法让干扰正常工作了!您可以在这里看到代码:即使您使用裸机,您可能仍然希望使用头文件来提供声明和非常基本的ARM Cortex元素(如NVIC_EnableIRQ)的内联版本 您可以在以下网址找到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();
}
}
如果你想,你可以忽略编译障碍。以前的版本没有使用它
该定义适用于Cortex M-3芯片。其他Cortex版本则不同。即使您使用裸机,您可能仍然希望使用头文件来提供声明和非常基本的ARM Cortex元素(如NVIC_EnableIRQ)的内联版本 您可以在以下网址找到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();
}
}
如果你想,你可以忽略编译障碍。以前的版本没有使用它
该定义适用于Cortex M-3芯片。对于其他的Cortex版本,它是不同的。库仍然被认为是裸机。没有操作系统,但无论如何,你有在这个级别学习的愿望是很好的。必须有人为他人编写库 我打算在这里做一个完整的例子,它实际上只需要很少的代码就可以做到这一点,但将从我为这个使用timer1的电路板编写的代码中学习 显然,您需要cortex-m3的ARM文档技术参考手册和armv7-m的架构参考手册,以及本st部分的数据表和参考手册,这两家公司都不需要程序员手册 您几乎没有提供与使零件工作相关的信息。您永远不应该直接进入中断,它们是高级主题,您应该在最终使中断进入核心之前尽可能地轮询您的方式 我更喜欢让uart工作,然后使用它在滚动、计数等时观察计时器寄存器。然后查看/确认状态寄存器已触发,了解/确认如何清除它有时只是读取时清除 然后将其启用到NVIC中,通过轮询see,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>:
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_iSeries 0将其释放到核心
如果你不采取这些小步骤,也许你已经采取了,这只会使任务变得更糟,需要更长的时间。是的,有时你会很幸运
在向量表中,TIM4看起来是中断30,偏移量/地址0x000000B8。NVIC_ISER0 0xE000E100覆盖前32个中断,因此30个中断将在该寄存器中。如果您反汇编使用库生成的代码,那么我们可以看到发生了什么,或者像其他人为您所做的那样在库源代码中查找它
当然,你的定时器4代码需要正确地初始化定时器并触发中断,我没有检查
这里有一些例子,你需要继续寻找
最低限度是
表中的向量
在中断设置启用寄存器中设置位
启用中断以离开外围设备
打岔
不一定是这样的顺序。与库一起仍然被视为裸机。没有操作系统,但不管怎样,你有学习的欲望是件好事 n在这个级别。必须有人为他人编写库 我打算在这里做一个完整的例子,它实际上只需要很少的代码就可以做到这一点,但将从我为这个使用timer1的电路板编写的代码中学习 显然,您需要cortex-m3的ARM文档技术参考手册和armv7-m的架构参考手册,以及本st部分的数据表和参考手册,这两家公司都不需要程序员手册 您几乎没有提供与使零件工作相关的信息。您永远不应该直接进入中断,它们是高级主题,您应该在最终使中断进入核心之前尽可能地轮询您的方式 我更喜欢让uart工作,然后使用它在滚动、计数等时观察计时器寄存器。然后查看/确认状态寄存器已触发,了解/确认如何清除它有时只是读取时清除 然后将其启用到NVIC中,通过轮询see,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>:
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_iSeries 0将其释放到核心
如果你不采取这些小步骤,也许你已经采取了,这只会使任务变得更糟,需要更长的时间。是的,有时你会很幸运
在向量表中,TIM4看起来是中断30,偏移量/地址0x000000B8。NVIC_ISER0 0xE000E100覆盖前32个中断,因此30个中断将在该寄存器中。如果您反汇编使用库生成的代码,那么我们可以看到发生了什么,或者像其他人为您所做的那样在库源代码中查找它
当然,你的定时器4代码需要正确地初始化定时器并触发中断,我没有检查
这里有一些例子,你需要继续寻找
最低限度是
表中的向量
在中断设置启用寄存器中设置位
启用中断以离开外围设备
打岔
不一定按那个顺序。Aha!好吧,这给了我足够的线索让它发挥作用。我在数据表中看不到NVIC_ISER0,所以我有点困惑。尽管如此,似乎地址是0xE000E100——这是我通过谷歌搜索得到的。我只需要用我要设置的中断号来设置位。我将更新我的原始问题。非常感谢。啊哈!好吧,这给了我足够的线索让它发挥作用。我在数据表中看不到NVIC_ISER0,所以我有点困惑。尽管如此,似乎地址是0xE000E100——这是我通过谷歌搜索得到的。我只需要用我要设置的中断号来设置位。我将更新我的原始问题。非常感谢。与Cortex core相关的详细信息通常在编程手册中提及,而不是在参考手册中提及。与Cortex core相关的详细信息通常在编程手册中提及,而不是在参考手册中提及。