PRIMASK在STM32F4上

huangapple go评论67阅读模式
英文:

PRIMASK on STM32F4

问题

我有一些用于STM32F4的旧代码,其中关键部分如下所示:

uint32_t primask;
primask = __get_PRIMASK();
__disable_irq();

/* ... 临界代码 ... */

__set_PRIMASK(primask);

我在这篇文章中读到,恢复关键部分后的中断掩码的正确方式是:

if (!primask) {
     __enable_irq();
}

旧代码"似乎有效",但我找不到类似的示例,对可能的副作用感到担忧。关于PRIMASK寄存器,文档相当模糊。以下是摘录:

PRIMASK在STM32F4上

这里有两个问题让我感到担忧:

  1. 位1-31被"保留",可以安全地假定它们为零吗?如果不是,我们应该写成 if ((primask & 1) == 0)
  2. 在位0写入0被标记为"无效"。这似乎不是真的(实际上恢复了以前的中断掩码),但这解释了为什么建议退出关键部分的方式是使用 __enable_irq()

我该如何解释"无效"?

使用 __set_PRIMASK() 离开关键部分有什么缺点吗?

注意:为了提供准确的翻译,我保留了原文中的代码部分。

英文:

I have some old code for STM32F4 in which a critical section looks like

uint32_t primask;
primask = __get_PRIMASK();
__disable_irq();

/* ... Critical code ... */

__set_PRIMASK(primask);

I read in this article that the right way to restore interrupt mask after a critical section is instead:

if (!primask) {
     __enable_irq();
}

The old code "seems to works", but I couldn't find any similar example, and am concerned about possible side effects. The documentation is quite ambiguous about PRIMASK register. Here an excerpt:

PRIMASK在STM32F4上

There are two things here that concern me:

  1. Bits 1-31 are "reserved", is it safe to assume that they are zeroes? If not, we should rather write if ((primask & 1) == 0).
  2. Writing 0 in Bit 0 is labeled as "No effect". It does not seem to be true (indeed previos interrupt mask is restored), but it does explain why the suggested way to leave the critical section is by __enable_irq().

How should I interpret that "No effect"?

Are there any drawbacks in using __set_PRIMASK() to leave a critical section?

答案1

得分: 1

__set_PRIMASK(value) 使用一个 32 位指令 (MSR)。

if(!value){__enable_irq();} 可能使用三个 16 位指令 (CMP, IT, CPSIE)。

在旧架构中,也许只有第二个选项可用,但如果两者都可用,那么结果始终相同。

在我看来,__set_PRIMASK__get_PRIMASK 搭配起来更好。

我认为当ST手册说“没有影响”时,他们是指在那里放一个零不会改变中断的通常处理方式。正如您已经测试过的那样,写入零会使寄存器中的值变为零。

您应该参考ARMv7M体系结构参考手册以获取权威的文档。

在该文档中,您还会发现明确指出PRIMASK是一个“一位寄存器”。您不需要担心屏蔽其他位。

英文:

These two methods are completely equivalent.

__set_PRIMASK(value) uses one 32-bit instruction (MSR).

if(!value){__enable_irq();} probably uses three 16-bit instructions (CMP,IT,CPSIE).

On older architectures maybe only the second option was available, but if both are available then the result is always identical.

In my opinion __set_PRIMASK looks better paired with __get_PRIMASK.

I think that when the ST manual says "no effect" they mean having a zero there causes no change in the usual handling of interrupts. As you have tested, writing a zero will have the effect of making the value in the register be zero.

You should refer to the ARMv7M Architecture Reference Manual for the authoritative documentation.

You will also find in that document that it says explicitly that PRIMASK is a "one bit register". You don't need to worry about masking off the other bits.

答案2

得分: 1

Cortex M4 是 ARMv7-M,所以适用 ARM 的架构参考手册。

这里

第 519页

PRIMASK在STM32F4上

明确表示为 "1 位寄存器"。这可以理解为 "其他位未实现"。

PRIMASK 值为 0 表示没有屏蔽。没有效果 = 无屏蔽。
PRIMASK 值为 1 表示屏蔽了具有可配置优先级的中断。

现在来解答你的主要问题 - 写入 vs 读-修改的答案是,你确实可以通过新值来设置它,但原因可能不是你所期望的。你设置该值不是通过向该寄存器写入数据。当你设置 PRIMASK 时,实际上从不写入该寄存器。你执行指令 __asm volatile("cpsid i"); 来将 PRIMASK 设置为 1,执行 __asm volatile("cpsie i"); 来将 PRIMASK 设置为 0。这是一条专门用于此目的的特殊指令。你可以将其直接粘贴到你的 C/C++ 代码中。来自文档的同一页:

PRIMASK在STM32F4上

英文:

Cortex M4 is ARMv7-M, so Architecture Reference Manual from ARM applies.

Here

Page 519

PRIMASK在STM32F4上

It explicitly says "1-bit register". Which can be understood as "other bits are not implemented".

PRIMASK value 0 means no masking happens. No effect = No masking.
PRIMASK value 1 means interrupts with configurable priority are masked.

Now for the greatest part: your main question - to write vs to read-modify - the answer is you can definitely set it straight with new value, but not for the reason you probably expect. You set the value not by writing to that register. When you set PRIMASK, you never actually write to that register. You execute instruction __asm volatile("cpsid i"); to set PRIMASK to 1, and you execute __asm volatile("cpsie i"); to set PRIMASK to 0. This is a special instruction that exists specifically to do this. You can paste it right into your C/C++. From the same page of the document:

PRIMASK在STM32F4上

huangapple
  • 本文由 发表于 2023年2月23日 22:26:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定