使用C ++ 14& amp; stm32 hal库警告上述

时间:2018-03-02 01:04:24

标签: c++ embedded c++14 stm32

我也在STM32社区论坛中发布了相同的question,但没有得到答案。

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

  

../平台/ STM32 / L4 / STM32L4xx_HAL_Driver /公司/ 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和amp; 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);
    }
}

罪魁祸首是__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)

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

提前谢谢。

3 个答案:

答案 0 :(得分:6)

问题是-std=c++14volatile表达式的语义更改为(void),并为其引入了明显的*无条件警告,并且ST中的编码人员试图制作&# 34;三重确定"注册读取将会发生。

UNUSED()宏的定义是

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

__IO定义为

#define     __IO    volatile

然后__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)

各种STM32勘误表

建议延迟和回读寄存器
  

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

     

[...]

     

刚刚从相应的寄存器中插入一个虚拟读操作   启用外设时钟。

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

do {
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
    /* Delay after an RCC peripheral clock enabling */
    RCC->AHB2ENR;
} while(0)
对于一些有问题的编译器来说,其余部分可能是一个过度设计的解决方法,但是我还没有看到一个如此破碎,以至于一个易失性类型的表达式会被优化掉。

然而,有一个边缘情况,其中一个volatile变量强制转换为(void),其中语义在C ++ 14中显然发生了变化。

让我们来看看这个简单的例子

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会将其编译为

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

the same code compiled with -std=c++14

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

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

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

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

  

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

我建议继续前进并避开图书馆,恕我直言HAL最好被视为一系列示例或实施建议。

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

答案 1 :(得分:3)

您可以将代码提交到您自己的存储库以解决此问题,并仍使用c ++ 14编译代码。

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

这需要在包含任何HAL标头之前添加。对我来说,在模块启用宏(即stm32f3xx_hal_conf.h行)之后但在包含实际HAL头之前放入#define HAL_WWDG_MODULE_ENABLED文件很方便。 我将所有来源更新为#include "stm32f3xx_hal_conf.h",而不是单个HAL标题。

这是有效的,因为基于@ berendi的出色研究,警告来自volatile。通过将值转换为首先不易变的东西,C ++ 14标准中的新子句就不复存在了。

答案 2 :(得分:0)

正如@oliv在回复@berendi的答复中提到的那样,根本原因似乎是GCC中的错误,该错误已在较新的版本中修复。当我升级到“版本9-2019-q4-major”工具链(GCC 9.2)时,警告对我消失了。

此外,对于STM32G0系列,ST将UNUSED的定义更改为:

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

这使警告不再针对早期版本的编译器。