3

In STM32Cube_FW_F7_V1.3.0 and still in STM32Cube_FW_F7_V1.11.0

I get the following warning when the compiling the stm32f7 HAL library with -Os or -O2.
Note: -O1 compiles without warnings.

[Warning] dereferencing type-punned pointer will break strict-aliasing rules 

The warning is justified. The code appears to work correctly. However, I would like to treat warnings as errors.

Question: How can the code be changed to remove the warning without breaking the crc module?

Note: I could not find a solution to this anywhere online.

This is one of the lines that causes the warning

 *(__IO uint16_t*) (&hcrc->Instance->DR) = (uint16_t)(((uint16_t)(pBuffer[4*i])<<8) | (uint16_t)(pBuffer[4*i+1]));

I believe this is a little tricky and intimidating to change because it is dealing with a hardware crc register.

This is ST Micro's licence, which states I'm required to include when distributing source code, it is not relevant to the question

  /******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

Relevant Code:

#define     __IO    volatile             /*!< Defines 'read / write' permissions */

typedef struct
{
  __IO uint32_t  DR;          /*!< CRC Data register,                           Address offset: 0x00 */
  __IO uint8_t   IDR;         /*!< CRC Independent data register,               Address offset: 0x04 */
  uint8_t        RESERVED0;   /*!< Reserved, 0x05                                                    */
  uint16_t       RESERVED1;   /*!< Reserved, 0x06                                                    */
  __IO uint32_t  CR;          /*!< CRC Control register,                        Address offset: 0x08 */
  uint32_t       RESERVED2;   /*!< Reserved,                                                    0x0C */
  __IO uint32_t  INIT;        /*!< Initial CRC value register,                  Address offset: 0x10 */
  __IO uint32_t  POL;         /*!< CRC polynomial register,                     Address offset: 0x14 */
} CRC_TypeDef;


/**             
  * @brief  Enter 8-bit input data to the CRC calculator.
  *         Specific data handling to optimize processing time.  
  * @param  hcrc: CRC handle
  * @param  pBuffer: pointer to the input data buffer
  * @param  BufferLength: input data buffer length
  * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
  */
static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
{
  uint32_t i = 0; /* input data buffer index */

   /* Processing time optimization: 4 bytes are entered in a row with a single word write,
    * last bytes must be carefully fed to the CRC calculator to ensure a correct type
    * handling by the IP */
   for(i = 0; i < (BufferLength/4); i++)
   {
     hcrc->Instance->DR = (uint32_t)(((uint32_t)(pBuffer[4*i])<<24) | ((uint32_t)(pBuffer[4*i+1])<<16) | ((uint32_t)(pBuffer[4*i+2])<<8) | (uint32_t)(pBuffer[4*i+3]));
   }
   /* last bytes specific handling */
   if((BufferLength%4) != 0)
   {
     if(BufferLength%4 == 1)
     {
       *(__IO uint8_t*) (&hcrc->Instance->DR) = pBuffer[4*i];
     }
     if(BufferLength%4 == 2)
     {
       //the following line gives the warning (rightfully) '[Warning] dereferencing type-punned pointer will break strict-aliasing rules'
       *(__IO uint16_t*) (&hcrc->Instance->DR) = (uint16_t)(((uint16_t)(pBuffer[4*i])<<8) | (uint16_t)(pBuffer[4*i+1]));
     }
     if(BufferLength%4 == 3)
     {
       //the following line gives the warning (rightfully) '[Warning] dereferencing type-punned pointer will break strict-aliasing rules'
       *(__IO uint16_t*) (&hcrc->Instance->DR) = (uint16_t)(((uint16_t)(pBuffer[4*i])<<8) | (uint16_t)(pBuffer[4*i+1]));
       *(__IO uint8_t*) (&hcrc->Instance->DR) = pBuffer[4*i+2];       
     }
   }

  /* Return the CRC computed value */ 
  return hcrc->Instance->DR;
}

The warning also appears in the 16 bit CRC function as well

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
iamJP
  • 386
  • 1
  • 12

1 Answers1

2

Use an anonymous union to avoid c type punning.

Change the definition of CRC_TypeDef in the header file to use an anonymous union.

typedef struct
{
  union
  {
    __IO uint32_t  DR;          /*!< CRC Data register 32 bit access,            Address offset: 0x00 */
    __IO uint16_t  DR16;        /*!< CRC Data register 16 bit access,            Address offset: 0x00 */
    __IO uint8_t   DR8;         /*!< CRC Data register 8 bit access,             Address offset: 0x00 */
  };
  __IO uint8_t   IDR;         /*!< CRC Independent data register,               Address offset: 0x04 */
  uint8_t        RESERVED0;   /*!< Reserved, 0x05                                                    */
  uint16_t       RESERVED1;   /*!< Reserved, 0x06                                                    */
  __IO uint32_t  CR;          /*!< CRC Control register,                        Address offset: 0x08 */
  uint32_t       RESERVED2;   /*!< Reserved,                                                    0x0C */
  __IO uint32_t  INIT;        /*!< Initial CRC value register,                  Address offset: 0x10 */
  __IO uint32_t  POL;         /*!< CRC polynomial register,                     Address offset: 0x14 */
} CRC_TypeDef;

Use this new union in the CRC_Handle_8 and CRC_Handle_16 functions.

/**             
  * @brief  Enter 8-bit input data to the CRC calculator.
  *         Specific data handling to optimize processing time.  
  * @param  hcrc: CRC handle
  * @param  pBuffer: pointer to the input data buffer
  * @param  BufferLength: input data buffer length
  * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
  */
static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
{
  uint32_t i = 0; /* input data buffer index */

   /* Processing time optimization: 4 bytes are entered in a row with a single word write,
    * last bytes must be carefully fed to the CRC calculator to ensure a correct type
    * handling by the IP */
   for(i = 0; i < (BufferLength/4); i++)
   {
     hcrc->Instance->DR = (uint32_t)(((uint32_t)(pBuffer[4*i])<<24) | ((uint32_t)(pBuffer[4*i+1])<<16) | ((uint32_t)(pBuffer[4*i+2])<<8) | (uint32_t)(pBuffer[4*i+3]));
   }
   /* last bytes specific handling */
   if((BufferLength%4) != 0)
   {
     if(BufferLength%4 == 1)
     {
       hcrc->Instance->DR8 = pBuffer[4*i];
     }
     if(BufferLength%4 == 2)
     {
       hcrc->Instance->DR16 = (uint16_t)(((uint16_t)(pBuffer[4*i])<<8) | (uint16_t)(pBuffer[4*i+1]));
     }
     if(BufferLength%4 == 3)
     {
       hcrc->Instance->DR16 = (uint16_t)(((uint16_t)(pBuffer[4*i])<<8) | (uint16_t)(pBuffer[4*i+1]));
       hcrc->Instance->DR8 = pBuffer[4*i+2];       
     }
   }

  /* Return the CRC computed value */ 
  return hcrc->Instance->DR;
}

/**             
  * @brief  Enter 16-bit input data to the CRC calculator.
  *         Specific data handling to optimize processing time.  
  * @param  hcrc: CRC handle
  * @param  pBuffer: pointer to the input data buffer
  * @param  BufferLength: input data buffer length
  * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
  */  
static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength)
{
  uint32_t i = 0;  /* input data buffer index */

  /* Processing time optimization: 2 HalfWords are entered in a row with a single word write,
   * in case of odd length, last HalfWord must be carefully fed to the CRC calculator to ensure 
   * a correct type handling by the IP */
  for(i = 0; i < (BufferLength/2); i++)
  {
    hcrc->Instance->DR = (((uint32_t)(pBuffer[2*i])<<16) | (uint32_t)(pBuffer[2*i+1]));
  }
  if((BufferLength%2) != 0)
  {
    hcrc->Instance->DR16 = pBuffer[2*i];
  }

  /* Return the CRC computed value */ 
  return hcrc->Instance->DR;
}

Obligatory ST Micro License and disclaimer.

  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

Credit to Olaf who hinted to this answer in comments.

iamJP
  • 386
  • 1
  • 12
  • That might work (I didn't check the details), but it would be problematic if you update the HAL stuff and/or the header. Nevertheless, I'd go with the header-edit, but - as I commented at your original answer (FYI: 10k+ users still can see it) - I'd not use the bloatware HAL anyway. Specifically the CRC unit is very straight-forward to use. On a sidenote: I'd feed the data using a DMA channel, that should speed up the processing to the max possible throughput, which the CPU can't maintain due to loop-overhead. Plus it's free for anything else, e.g. interrupt handlers. – too honest for this site May 18 '18 at 16:55
  • Sidenote: there are other registers which should need this editing. One is the GPIO BSRR, another the SPI DR (not sure if the latter applies to the F7, though). Remeber anonymous unions are a C99 feature and some commercial compilers are stuck with C90. In that case a named union could be used instead. – too honest for this site May 18 '18 at 16:58
  • Thanks for the tip, but the BSRR compiles fine and we aren't using it anyway. I actually had to modify the SPI a good bit to even make it work in a rational way about a year ago. I think the CRC module was the only one trying to do an 16 bit write to a 32 bit register. I was worried about changing the code because the hardware can detect the difference between 32 and 16 and 8 bit writes. – iamJP May 22 '18 at 04:25