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相关的详细信息通常在编程手册中提及,而不是在参考手册中提及。