使用C++ 14及更高版本的stm32 hal库警告

aep*_*aep 10 c++ embedded stm32 c++14

我也在STM32社区论坛上发布了同样的问题,但没有得到答案.

我在启用了C++ 14的项目中使用stm32 HAL库.它发出了我无法摆脱的以下警告.

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

警告:转换为void将不会访问类型为'volatile uint32_t {aka volatile long unsigned int}'UNUSED(tmpreg); \

当调用__GPIOX_CLK_ENABLE()或__HAL_RCC_GPIOX_CLK_ENABLE时,会发生这种情况.

有没有人能够摆脱上述警告,使HAL源代码完好无损.

或任何想法可以做什么.

目前的警告级别是-Wall.

我遇到了l4和f4系列代码的上述问题.

示例代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

罪魁祸首是__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)
Run Code Online (Sandbox Code Playgroud)

我原来的问题是为了找到一个解决方案,让底层ST驱动程序完好无损.一种可能的解决方案是使用直接寄存器访问,而无需通过库提供方便的宏.

先感谢您.

ber*_*ing 8

问题是-std=c++14改变了一个volatile表达式的语义(void),并为它引入了一个明显的*无条件警告,并且ST中的一个编码器试图使"三重确定"发生寄存器读取.

UNUSED()宏的定义是

#define UNUSED(x) ((void)(x))
Run Code Online (Sandbox Code Playgroud)

并被__IO定义为

#define     __IO    volatile
Run Code Online (Sandbox Code Playgroud)

然后扩展__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)
Run Code Online (Sandbox Code Playgroud)

各种STM32勘误表中建议延迟和回读寄存器

应考虑RCC外设时钟使能和有效外设使能之间的延迟,以便管理外设对寄存器的读/写.

[...]

在启用外设时钟后立即从相应寄存器插入虚拟读操作.

由于所有外设寄存器当然都被声明为volatile,只包含相关寄存器的简单表达式将通过相同的外设总线强制回读必要的等待状态,因此这就足够了:

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

对于一些有问题的编译器来说,其余的可能是一个过度设计的解决方法,但是我还没有看到一个如此破碎,以至于一个具有volatile类型的表达式会被优化掉.

然而,有一个边缘情况,带有一个volatile变量(void),其中语义在C++ 14中明显改变了.

我们来看一个这个简单的例子吧

void x() {
    volatile int t;
    t=1;
    ((void)(t));
}
Run Code Online (Sandbox Code Playgroud)

调用arm gcc 7.2.1-O3 -mcpu=cortex-m4 -mthumb -Wall -x c++ -std=c++11将其编译为

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

编译的相同代码-std=c++14

x():
  sub sp, sp, #8
  movs r3, #1
  str r3, [sp, #4]
  add sp, sp, #8
  bx lr
Run Code Online (Sandbox Code Playgroud)

......并发出警告:

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

另请注意ldr第二种情况下的缺失指令.使用C++ 14写入后,不会访问该变量.

我原来的问题是为了找到一个解决方案,让底层ST驱动程序完好无损.一种可能的解决方案是使用直接寄存器访问,而无需通过库提供方便的宏.

我建议继续并避免使用库,恕我直言HAL更好地作为一组示例或实施建议处理.

*我找不到禁用它的方法.这并不意味着没有.

  • 这不是 C++14 特性,而是 GCC 错误!我填补了一个错误,gcc 不评估括号中的丢弃值表达式,而 [\[expr\]/11.1](https://timsong-cpp.github.io/cppwp/n4140/expr#11.1) 明确指定该表达式应被评估。 (2认同)