stm32 NVIC_EnableIRQ() 裸机等效?

Posted

技术标签:

【中文标题】stm32 NVIC_EnableIRQ() 裸机等效?【英文标题】:stm32 NVIC_EnableIRQ() bare metal equivalent? 【发布时间】:2021-01-07 11:13:48 【问题描述】:

我正在使用蓝色药丸,并试图找出中断。我有一个中断处理程序:

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() 中实际发生了什么?

我在 Google 上四处搜索,但找不到与我类似的实际裸机代码。

我似乎错过了一个关键步骤。

2020 年 9 月 23 日更新感谢回答此问题的人。诀窍是在 NVIC_ISER 寄存器中设置中断号位。正如我在下面指出的,STM32F101xx 参考手册中似乎没有提到这一点,所以我可能永远无法自己解决这个问题;并不是说我在阅读数据表方面有任何真正的技能。

无论如何,天哪,我设法让中断工作!你可以在这里看到代码:https://github.com/blippy/rpi/tree/master/stm32/bare/04-timer-interrupt

【问题讨论】:

Cortex内核相关的细节一般在《编程手册》中提到,而不是在《参考手册》中。 在此处找到 NVIC 寄存器的描述:booksite.elsevier.com/9780124080829/downloads/APP-06.pdf 【参考方案1】:

即使您使用裸机,您可能仍希望使用 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 版本则不同。

【讨论】:

【参考方案2】:

库仍然被认为是裸机。没有操作系统,但无论如何,你有在这个级别学习的愿望很好。必须有人为其他人编写库。

我打算在这里做一个完整的例子,(它真的需要很少的代码来做到这一点),但会从我的代码中获取这个使用 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>:

第一个字加载堆栈指针,其余的是向量,处理程序的地址或与一个或一个(我会让你查一下)。

在这种情况下,参考手册显示中断 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 代码需要正确初始化定时器并触发中断,我没有检查。

有例子,你需要继续看。

最小值是

    表格中的向量 设置中断设置启用寄存器中的位 启用中断以离开外设 触发中断

不一定按这个顺序。

【讨论】:

啊哈!好的,这给了我足够的线索让它发挥作用。我在数据表中看不到 NVIC_ISER0,所以我有点困惑。尽管如此,地址似乎是 0xE000E100 - 这是我通过谷歌搜索得到的。我只需要使用我尝试设置的中断号来设置该位。我会更新我原来的问题。非常感谢。

以上是关于stm32 NVIC_EnableIRQ() 裸机等效?的主要内容,如果未能解决你的问题,请参考以下文章

[STM32F4裸机]STM32F4HAL库开发

STM32F1 - 在裸机上使用主 SPI

ARM(IMX6U)裸机模仿STM32驱动开发实验

stm32裸机实现mqtt遇到的问题和需要注意的地方

STM32F405 裸机 SPI 从机 - MISO 数据有时会混乱

一个stm32程序带有ucos实时操作系统,那还算是裸机程序吗?