如何使用 CMSIS API 将无符号整数转换为枚举

How to cast unsigned integer to enum using CMSIS API

我在我的 ARM Cortex-M C 程序中使用 CMSIS API CPU。
CMSIS 将 NVIC_DisableIRQ 函数定义为

__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn);

IRQn_Type是一个typedef enum,像

typedef enum IRQn
{

  NonMaskableInt_IRQn           = -14,     /*  2 Non Maskable Interrupt */
  HardFault_IRQn                = -13,     /*  3 HardFault Interrupt */
  .....
  Interrupt0_IRQn               =   0,
  Interrupt1_IRQn               =   1,
  Interrupt2_IRQn               =   2,
} IRQn_Type;

所以,鉴于我想打电话给 NVIC_DisableIRQ,因为

NVIC_DisableIRQ( (IRQn_Type )(SCB->ICSR -16);

MISRA 检查失败

note 9034: cannot assign 'unsigned32' to different essential type 'enum (IRQn)' [MISRA 2012 Rule 10.3, required]

我理解 MISRA 抱怨的原因,但这是一个切实可行的解决方案吗? 我发现是创建巨大的 switch/case ,还有其他可用的 solutions/hacks 吗?

假设 SCB->ICSR -16 导致 uint32_t 结果,那么您不能将其分配给 enum 变量 (10.3),也不允许将其转换为 enum (10.5)。这是因为枚举具有 implementation-defined 大小和符号。

我想可能有各种肮脏的技巧来躲避 MISRA,但这违背了这些规则的相当合理的理由,归结为:不要在你的代码中使用带符号的操作数以使其在各种情况下失控微妙而严厉的方式。例如更改默认编译器枚举类型导致所有中断改变行为 - 即 不好 - 可能很危险。

问题的根源在于 enum 类型和需要 enum 的 CMSIS 函数 __NVIC_DisableIRQ。如果那个写法不同,我们就可以使用无符号类型。很奇怪,草率的 non-MISRA 兼容库仍在 2020 年推出。

我建议您放弃该函数并编写自定义函数。这些函数中的大多数只是简单的 single-line 汇编程序指令或寄存器写入的包装器,因此如果您可以访问函数实现,可能并不需要太多努力。

请注意,MISRA-C (10.5) 允许从枚举类型转换为无符号类型,因此如果您基于 uint32_t 创建 API,您仍然可以传递枚举值通过铸造它们。