简体   繁体   English

stm32 hal 库警告与 C++14 及更高版本

[英]stm32 hal library warning with C++14 & above

I posted the same question in the STM32 community forum as well, but didn't receive an answer.我也在 STM32 社区论坛上发布了同样的问题,但没有得到答复。

I am using stm32 HAL library in a project with C++14 enabled.我在启用 C++14 的项目中使用 stm32 HAL 库。 It issues me the following warning which I can't get rid of.它向我发出以下警告,我无法摆脱。

../platform/stm32/l4/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h:735:57: ../platform/stm32/l4/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_rcc.h:735:57:

warning: conversion to void will not access object of type 'volatile uint32_t {aka volatile long unsigned int}' UNUSED(tmpreg);警告:转换为 void 将无法访问类型为 'volatile uint32_t {aka volatile long unsigned int}' 的对象 UNUSED(tmpreg); \\ \\

This happens, when a call to __GPIOX_CLK_ENABLE() or __HAL_RCC_GPIOX_CLK_ENABLE is called.当调用 __GPIOX_CLK_ENABLE() 或 __HAL_RCC_GPIOX_CLK_ENABLE 时会发生这种情况。

Has anyone been able to get rid of the above warning leaving the HAL source code intact.有没有人能够摆脱上述警告而保持 HAL 源代码完好无损。

Or any ideas as what is possible to be done.或任何可能的想法。

The current warning level is -Wall.当前警告级别为 -Wall。

I've experienced the above issue with both l4 & f4 series code.我在 l4 和 f4 系列代码中都遇到过上述问题。

An Example code:示例代码:

int main(void)
{
    HAL_Init();

    __GPIOB_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.Pin = GPIO_PIN_7;

    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

    for (;;)
    {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
        HAL_Delay(500);
    }
}

The culprit is __GPIOB_CLK_ENABLE() , which gets expanded to the following(in ST drivers).罪魁祸首是__GPIOB_CLK_ENABLE() ,它扩展到以下内容(在 ST 驱动程序中)。

#define __HAL_RCC_GPIOB_CLK_ENABLE()           do { \
                                                 __IO uint32_t tmpreg; \
                                                 SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN); \
                                                 /* Delay after an RCC peripheral clock enabling */ \
                                                 tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN); \
                                                 UNUSED(tmpreg); \
                                               } while(0)

My original question is intended to find out a solution, leaving the underlying ST driver intact.我最初的问题旨在找出解决方案,同时保持底层 ST 驱动程序完好无损。 One possible solution would be to use the direct register access without going through the library provided convenient macro.一种可能的解决方案是使用直接寄存器访问,而无需通过库提供的方便宏。

Thank you in advance.先感谢您。

The problem is -std=c++14 changing the semantics of a volatile expression cast to (void) , and introducing an apparently* unconditional warning for it, and a coder at ST trying to make "triple sure" that a register read would take place.问题是-std=c++14volatile表达式的语义转换为(void) ,并为其引入了一个明显* 的无条件警告,并且 ST 的编码器试图“三重确保”读取寄存器发生。

The definition of the UNUSED() macro is UNUSED()宏的定义是

#define UNUSED(x) ((void)(x))

and __IO is defined as __IO被定义为

#define     __IO    volatile

Then the expansion of __HAL_RCC_GPIOB_CLK_ENABLE() would be那么__HAL_RCC_GPIOB_CLK_ENABLE()的扩展将是

do {
    volatile uint32_t tmpreg;
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
    /* Delay after an RCC peripheral clock enabling */
    tmpreg = RCC->AHB2ENR & RCC_AHB2ENR_GPIOBEN;
    ((void)(tmpreg));
} while(0)

The delay and read-back of the register is recommended by various STM32 errata saying寄存器的延迟和回读是各种STM32勘误表推荐的

A delay between an RCC peripheral clock enable and the effective peripheral enabling should be taken into account in order to manage the peripheral read/write to registers.应考虑 RCC 外设时钟使能和有效外设使能之间的延迟,以便管理对寄存器的外设读/写。

[...] [...]

insert a dummy read operation from the corresponding register just after enabling the peripheral clock.在启用外设时钟后立即从相应的寄存器插入一个虚拟读操作。

As all peripheral registers are of course declared as volatile , a simple expression containing just the register in question would force a readback with the necessary wait states via the same peripheral bus, so this would suffice:由于所有外围寄存器当然都被声明为volatile ,一个只包含相关寄存器的简单表达式将通过相同的外围总线强制回读具有必要的等待状态,所以这就足够了:

do {
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
    /* Delay after an RCC peripheral clock enabling */
    RCC->AHB2ENR;
} while(0)

the rest is presumably an overengineered workaround for some buggy compilers, but I'm yet to see one so broken that an expression with a volatile type would be optimized out.其余的可能是一些有缺陷的编译器的过度设计的解决方法,但我还没有看到一个如此破碎以至于具有 volatile 类型的表达式会被优化掉的方法。

There is that edge case however, with a volatile variable cast to (void) , where the semantics have apparently changed in C++14.然而,存在一种边缘情况,将 volatile 变量强制转换为(void) ,其中语义在 C++14 中明显发生了变化。

Let's take this simple example让我们以这个简单的例子

void x() {
    volatile int t;
    t=1;
    ((void)(t));
}

Arm gcc 7.2.1 invoked with -O3 -mcpu=cortex-m4 -mthumb -Wall -x c++ -std=c++11 would compile it to使用-O3 -mcpu=cortex-m4 -mthumb -Wall -x c++ -std=c++11调用的 Arm gcc 7.2.1会将其编译为

x():
  sub sp, sp, #8
  movs r3, #1
  str r3, [sp, #4]
  ldr r3, [sp, #4]
  add sp, sp, #8
  bx lr

and the same code compiled with -std=c++14 is使用-std=c++14编译的相同代码

x():
  sub sp, sp, #8
  movs r3, #1
  str r3, [sp, #4]
  add sp, sp, #8
  bx lr

... and a warning: ...和警告:

<source>: In function 'void x()':
<source>:5:13: warning: conversion to void will not access object of type 'volatile int'
     ((void)(t));
            ~^~

Also notice the missing ldr instruction in the second case.还要注意第二种情况下缺少的ldr指令。 The variable is not accessed after the write with C++14.使用 C++14 写入后不会访问该变量。

My original question is intended to find out a solution, leaving the underlying ST driver intact.我最初的问题旨在找出解决方案,同时保持底层 ST 驱动程序完好无损。 One possible solution would be to use the direct register access without going through the library provided convenient macro.一种可能的解决方案是使用直接寄存器访问,而无需通过库提供的方便宏。

I'd suggest go ahead and avoid the library, IMHO HAL is better treated as a collection of examples or implementation suggestions.我建议继续并避免使用库,恕我直言 HAL 最好将其视为示例或实施建议的集合。

*I couldn't find a way to disable it. *我找不到禁用它的方法。 That doesn't mean there is none.这并不意味着没有。

There is code you can commit to your own repository to work around the issue and still compile the code with c++14.您可以将代码提交到自己的存储库以解决该问题,并且仍然使用 c++14 编译代码。

/* Workaround for the broken UNUSED macro */
#include "stm32f3xx_hal_def.h"
#undef UNUSED
#define UNUSED(x) ((void)((uint32_t)(x)))

This needs to be added before any of the HAL headers are included.这需要在包含任何 HAL 标头之前添加。 For me it was convenient to place into the stm32f3xx_hal_conf.h file right after the module enable macros (ie #define HAL_WWDG_MODULE_ENABLED line) but before the actual HAL headers are included.对我来说,在模块启用宏之后(即#define HAL_WWDG_MODULE_ENABLED行)但在包含实际 HAL 标头之前放入stm32f3xx_hal_conf.h文件很方便。 I updated all my sources to #include "stm32f3xx_hal_conf.h" instead of individual HAL headers.我将所有源更新为#include "stm32f3xx_hal_conf.h"而不是单个 HAL 标头。

This works because based on @berendi's excellent research the warning comes form the volatile designation.这是有效的,因为基于@berendi 的出色研究,警告来自volatile名称。 By casting the value to something that's not volatile first, the new clause in the C++14 standard is eluded.通过首先将值转换为非 volatile 的值,C++14 标准中的新子句就被忽略了。

As @oliv mentioned in reply to @berendi's answer, the root cause appears to be a bug in GCC, which has been fixed in more recent versions.正如@oliv 在回复@berendi 的回答时提到的那样,根本原因似乎是 GCC 中的一个错误,该错误已在较新的版本中得到修复。 The warning went away for me when I upgraded to the "Version 9-2019-q4-major" toolchain (GCC 9.2).当我升级到“版本 9-2019-q4-major”工具链 (GCC 9.2) 时,警告消失了。

Also, for the STM32G0 series, ST changed the definition of UNUSED to:另外,对于STM32G0系列,ST将UNUSED的定义改为:

#define UNUSED(X) (void)X      /* To avoid gcc/g++ warnings */

which makes the warning go away for earlier versions of the compiler.这使得早期版本的编译器的警告消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM