1 /**
2   ******************************************************************************
3   * @file    stm32f0xx_hal_crc.c
4   * @author  MCD Application Team
5   * @brief   CRC HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the Cyclic Redundancy Check (CRC) peripheral:
8   *           + Initialization and de-initialization functions
9   *           + Peripheral Control functions
10   *           + Peripheral State functions
11   *
12   ******************************************************************************
13   * @attention
14   *
15   * Copyright (c) 2016 STMicroelectronics.
16   * All rights reserved.
17   *
18   * This software is licensed under terms that can be found in the LICENSE file
19   * in the root directory of this software component.
20   * If no LICENSE file comes with this software, it is provided AS-IS.
21   *
22   ******************************************************************************
23   @verbatim
24  ===============================================================================
25                      ##### How to use this driver #####
26  ===============================================================================
27     [..]
28          (+) Enable CRC AHB clock using __HAL_RCC_CRC_CLK_ENABLE();
29          (+) Initialize CRC calculator
30              (++) specify generating polynomial (peripheral default or non-default one)
31              (++) specify initialization value (peripheral default or non-default one)
32              (++) specify input data format
33              (++) specify input or output data inversion mode if any
34          (+) Use HAL_CRC_Accumulate() function to compute the CRC value of the
35              input data buffer starting with the previously computed CRC as
36              initialization value
37          (+) Use HAL_CRC_Calculate() function to compute the CRC value of the
38              input data buffer starting with the defined initialization value
39              (default or non-default) to initiate CRC calculation
40 
41   @endverbatim
42   ******************************************************************************
43   */
44 
45 /* Includes ------------------------------------------------------------------*/
46 #include "stm32f0xx_hal.h"
47 
48 /** @addtogroup STM32F0xx_HAL_Driver
49   * @{
50   */
51 
52 /** @defgroup CRC CRC
53   * @brief CRC HAL module driver.
54   * @{
55   */
56 
57 #ifdef HAL_CRC_MODULE_ENABLED
58 
59 /* Private typedef -----------------------------------------------------------*/
60 /* Private define ------------------------------------------------------------*/
61 /* Private macro -------------------------------------------------------------*/
62 /* Private variables ---------------------------------------------------------*/
63 /* Private function prototypes -----------------------------------------------*/
64 /** @defgroup CRC_Private_Functions CRC Private Functions
65   * @{
66   */
67 static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength);
68 static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength);
69 /**
70   * @}
71   */
72 
73 /* Exported functions --------------------------------------------------------*/
74 
75 /** @defgroup CRC_Exported_Functions CRC Exported Functions
76   * @{
77   */
78 
79 /** @defgroup CRC_Exported_Functions_Group1 Initialization and de-initialization functions
80   *  @brief    Initialization and Configuration functions.
81   *
82 @verbatim
83  ===============================================================================
84             ##### Initialization and de-initialization functions #####
85  ===============================================================================
86     [..]  This section provides functions allowing to:
87       (+) Initialize the CRC according to the specified parameters
88           in the CRC_InitTypeDef and create the associated handle
89       (+) DeInitialize the CRC peripheral
90       (+) Initialize the CRC MSP (MCU Specific Package)
91       (+) DeInitialize the CRC MSP
92 
93 @endverbatim
94   * @{
95   */
96 
97 /**
98   * @brief  Initialize the CRC according to the specified
99   *         parameters in the CRC_InitTypeDef and create the associated handle.
100   * @param  hcrc CRC handle
101   * @retval HAL status
102   */
HAL_CRC_Init(CRC_HandleTypeDef * hcrc)103 HAL_StatusTypeDef HAL_CRC_Init(CRC_HandleTypeDef *hcrc)
104 {
105   /* Check the CRC handle allocation */
106   if (hcrc == NULL)
107   {
108     return HAL_ERROR;
109   }
110 
111   /* Check the parameters */
112   assert_param(IS_CRC_ALL_INSTANCE(hcrc->Instance));
113 
114   if (hcrc->State == HAL_CRC_STATE_RESET)
115   {
116     /* Allocate lock resource and initialize it */
117     hcrc->Lock = HAL_UNLOCKED;
118     /* Init the low level hardware */
119     HAL_CRC_MspInit(hcrc);
120   }
121 
122   hcrc->State = HAL_CRC_STATE_BUSY;
123 
124 #if defined(CRC_POL_POL)
125   /* check whether or not non-default generating polynomial has been
126    * picked up by user */
127   assert_param(IS_DEFAULT_POLYNOMIAL(hcrc->Init.DefaultPolynomialUse));
128   if (hcrc->Init.DefaultPolynomialUse == DEFAULT_POLYNOMIAL_ENABLE)
129   {
130     /* initialize peripheral with default generating polynomial */
131     WRITE_REG(hcrc->Instance->POL, DEFAULT_CRC32_POLY);
132     MODIFY_REG(hcrc->Instance->CR, CRC_CR_POLYSIZE, CRC_POLYLENGTH_32B);
133   }
134   else
135   {
136     /* initialize CRC peripheral with generating polynomial defined by user */
137     if (HAL_CRCEx_Polynomial_Set(hcrc, hcrc->Init.GeneratingPolynomial, hcrc->Init.CRCLength) != HAL_OK)
138     {
139       return HAL_ERROR;
140     }
141   }
142 #endif /* CRC_POL_POL */
143 
144   /* check whether or not non-default CRC initial value has been
145    * picked up by user */
146   assert_param(IS_DEFAULT_INIT_VALUE(hcrc->Init.DefaultInitValueUse));
147   if (hcrc->Init.DefaultInitValueUse == DEFAULT_INIT_VALUE_ENABLE)
148   {
149     WRITE_REG(hcrc->Instance->INIT, DEFAULT_CRC_INITVALUE);
150   }
151   else
152   {
153     WRITE_REG(hcrc->Instance->INIT, hcrc->Init.InitValue);
154   }
155 
156 
157   /* set input data inversion mode */
158   assert_param(IS_CRC_INPUTDATA_INVERSION_MODE(hcrc->Init.InputDataInversionMode));
159   MODIFY_REG(hcrc->Instance->CR, CRC_CR_REV_IN, hcrc->Init.InputDataInversionMode);
160 
161   /* set output data inversion mode */
162   assert_param(IS_CRC_OUTPUTDATA_INVERSION_MODE(hcrc->Init.OutputDataInversionMode));
163   MODIFY_REG(hcrc->Instance->CR, CRC_CR_REV_OUT, hcrc->Init.OutputDataInversionMode);
164 
165   /* makes sure the input data format (bytes, halfwords or words stream)
166    * is properly specified by user */
167   assert_param(IS_CRC_INPUTDATA_FORMAT(hcrc->InputDataFormat));
168 
169   /* Change CRC peripheral state */
170   hcrc->State = HAL_CRC_STATE_READY;
171 
172   /* Return function status */
173   return HAL_OK;
174 }
175 
176 /**
177   * @brief  DeInitialize the CRC peripheral.
178   * @param  hcrc CRC handle
179   * @retval HAL status
180   */
HAL_CRC_DeInit(CRC_HandleTypeDef * hcrc)181 HAL_StatusTypeDef HAL_CRC_DeInit(CRC_HandleTypeDef *hcrc)
182 {
183   /* Check the CRC handle allocation */
184   if (hcrc == NULL)
185   {
186     return HAL_ERROR;
187   }
188 
189   /* Check the parameters */
190   assert_param(IS_CRC_ALL_INSTANCE(hcrc->Instance));
191 
192   /* Check the CRC peripheral state */
193   if (hcrc->State == HAL_CRC_STATE_BUSY)
194   {
195     return HAL_BUSY;
196   }
197 
198   /* Change CRC peripheral state */
199   hcrc->State = HAL_CRC_STATE_BUSY;
200 
201   /* Reset CRC calculation unit */
202   __HAL_CRC_DR_RESET(hcrc);
203 
204   /* Reset IDR register content */
205   __HAL_CRC_SET_IDR(hcrc, 0);
206 
207   /* DeInit the low level hardware */
208   HAL_CRC_MspDeInit(hcrc);
209 
210   /* Change CRC peripheral state */
211   hcrc->State = HAL_CRC_STATE_RESET;
212 
213   /* Process unlocked */
214   __HAL_UNLOCK(hcrc);
215 
216   /* Return function status */
217   return HAL_OK;
218 }
219 
220 /**
221   * @brief  Initializes the CRC MSP.
222   * @param  hcrc CRC handle
223   * @retval None
224   */
HAL_CRC_MspInit(CRC_HandleTypeDef * hcrc)225 __weak void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
226 {
227   /* Prevent unused argument(s) compilation warning */
228   UNUSED(hcrc);
229 
230   /* NOTE : This function should not be modified, when the callback is needed,
231             the HAL_CRC_MspInit can be implemented in the user file
232    */
233 }
234 
235 /**
236   * @brief  DeInitialize the CRC MSP.
237   * @param  hcrc CRC handle
238   * @retval None
239   */
HAL_CRC_MspDeInit(CRC_HandleTypeDef * hcrc)240 __weak void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc)
241 {
242   /* Prevent unused argument(s) compilation warning */
243   UNUSED(hcrc);
244 
245   /* NOTE : This function should not be modified, when the callback is needed,
246             the HAL_CRC_MspDeInit can be implemented in the user file
247    */
248 }
249 
250 /**
251   * @}
252   */
253 
254 /** @defgroup CRC_Exported_Functions_Group2 Peripheral Control functions
255   *  @brief    management functions.
256   *
257 @verbatim
258  ===============================================================================
259                       ##### Peripheral Control functions #####
260  ===============================================================================
261     [..]  This section provides functions allowing to:
262       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
263           using combination of the previous CRC value and the new one.
264 
265        [..]  or
266 
267       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
268           independently of the previous CRC value.
269 
270 @endverbatim
271   * @{
272   */
273 
274 /**
275   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
276   *         starting with the previously computed CRC as initialization value.
277   * @param  hcrc CRC handle
278   * @param  pBuffer pointer to the input data buffer, exact input data format is
279   *         provided by hcrc->InputDataFormat.
280   * @param  BufferLength input data buffer length (number of bytes if pBuffer
281   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
282   *         number of words if pBuffer type is * uint32_t).
283   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
284   *        Input buffer pointers with other types simply need to be cast in uint32_t
285   *        and the API will internally adjust its input data processing based on the
286   *        handle field hcrc->InputDataFormat.
287   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
288   */
HAL_CRC_Accumulate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)289 uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
290 {
291   uint32_t index;      /* CRC input data buffer index */
292   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
293 
294   /* Change CRC peripheral state */
295   hcrc->State = HAL_CRC_STATE_BUSY;
296 
297   switch (hcrc->InputDataFormat)
298   {
299     case CRC_INPUTDATA_FORMAT_WORDS:
300       /* Enter Data to the CRC calculator */
301       for (index = 0U; index < BufferLength; index++)
302       {
303         hcrc->Instance->DR = pBuffer[index];
304       }
305       temp = hcrc->Instance->DR;
306       break;
307 
308     case CRC_INPUTDATA_FORMAT_BYTES:
309       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
310       break;
311 
312     case CRC_INPUTDATA_FORMAT_HALFWORDS:
313       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
314       break;
315     default:
316       break;
317   }
318 
319   /* Change CRC peripheral state */
320   hcrc->State = HAL_CRC_STATE_READY;
321 
322   /* Return the CRC computed value */
323   return temp;
324 }
325 
326 /**
327   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
328   *         starting with hcrc->Instance->INIT as initialization value.
329   * @param  hcrc CRC handle
330   * @param  pBuffer pointer to the input data buffer, exact input data format is
331   *         provided by hcrc->InputDataFormat.
332   * @param  BufferLength input data buffer length (number of bytes if pBuffer
333   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
334   *         number of words if pBuffer type is * uint32_t).
335   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
336   *        Input buffer pointers with other types simply need to be cast in uint32_t
337   *        and the API will internally adjust its input data processing based on the
338   *        handle field hcrc->InputDataFormat.
339   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
340   */
HAL_CRC_Calculate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)341 uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
342 {
343   uint32_t index;      /* CRC input data buffer index */
344   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
345 
346   /* Change CRC peripheral state */
347   hcrc->State = HAL_CRC_STATE_BUSY;
348 
349   /* Reset CRC Calculation Unit (hcrc->Instance->INIT is
350   *  written in hcrc->Instance->DR) */
351   __HAL_CRC_DR_RESET(hcrc);
352 
353   switch (hcrc->InputDataFormat)
354   {
355     case CRC_INPUTDATA_FORMAT_WORDS:
356       /* Enter 32-bit input data to the CRC calculator */
357       for (index = 0U; index < BufferLength; index++)
358       {
359         hcrc->Instance->DR = pBuffer[index];
360       }
361       temp = hcrc->Instance->DR;
362       break;
363 
364     case CRC_INPUTDATA_FORMAT_BYTES:
365       /* Specific 8-bit input data handling  */
366       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
367       break;
368 
369     case CRC_INPUTDATA_FORMAT_HALFWORDS:
370       /* Specific 16-bit input data handling  */
371       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
372       break;
373 
374     default:
375       break;
376   }
377 
378   /* Change CRC peripheral state */
379   hcrc->State = HAL_CRC_STATE_READY;
380 
381   /* Return the CRC computed value */
382   return temp;
383 }
384 
385 /**
386   * @}
387   */
388 
389 /** @defgroup CRC_Exported_Functions_Group3 Peripheral State functions
390   *  @brief    Peripheral State functions.
391   *
392 @verbatim
393  ===============================================================================
394                       ##### Peripheral State functions #####
395  ===============================================================================
396     [..]
397     This subsection permits to get in run-time the status of the peripheral.
398 
399 @endverbatim
400   * @{
401   */
402 
403 /**
404   * @brief  Return the CRC handle state.
405   * @param  hcrc CRC handle
406   * @retval HAL state
407   */
HAL_CRC_GetState(CRC_HandleTypeDef * hcrc)408 HAL_CRC_StateTypeDef HAL_CRC_GetState(CRC_HandleTypeDef *hcrc)
409 {
410   /* Return CRC handle state */
411   return hcrc->State;
412 }
413 
414 /**
415   * @}
416   */
417 
418 /**
419   * @}
420   */
421 
422 /** @addtogroup CRC_Private_Functions
423   * @{
424   */
425 
426 /**
427   * @brief  Enter 8-bit input data to the CRC calculator.
428   *         Specific data handling to optimize processing time.
429   * @param  hcrc CRC handle
430   * @param  pBuffer pointer to the input data buffer
431   * @param  BufferLength input data buffer length
432   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
433   */
CRC_Handle_8(CRC_HandleTypeDef * hcrc,uint8_t pBuffer[],uint32_t BufferLength)434 static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
435 {
436   uint32_t i; /* input data buffer index */
437   uint16_t data;
438   __IO uint16_t *pReg;
439 
440   /* Processing time optimization: 4 bytes are entered in a row with a single word write,
441    * last bytes must be carefully fed to the CRC calculator to ensure a correct type
442    * handling by the peripheral */
443   for (i = 0U; i < (BufferLength / 4U); i++)
444   {
445     hcrc->Instance->DR = ((uint32_t)pBuffer[4U * i] << 24U) | \
446                          ((uint32_t)pBuffer[(4U * i) + 1U] << 16U) | \
447                          ((uint32_t)pBuffer[(4U * i) + 2U] << 8U)  | \
448                          (uint32_t)pBuffer[(4U * i) + 3U];
449   }
450   /* last bytes specific handling */
451   if ((BufferLength % 4U) != 0U)
452   {
453     if ((BufferLength % 4U) == 1U)
454     {
455       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i];         /* Derogation MisraC2012 R.11.5 */
456     }
457     if ((BufferLength % 4U) == 2U)
458     {
459       data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
460       pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
461       *pReg = data;
462     }
463     if ((BufferLength % 4U) == 3U)
464     {
465       data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
466       pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
467       *pReg = data;
468 
469       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[(4U * i) + 2U];  /* Derogation MisraC2012 R.11.5 */
470     }
471   }
472 
473   /* Return the CRC computed value */
474   return hcrc->Instance->DR;
475 }
476 
477 /**
478   * @brief  Enter 16-bit input data to the CRC calculator.
479   *         Specific data handling to optimize processing time.
480   * @param  hcrc CRC handle
481   * @param  pBuffer pointer to the input data buffer
482   * @param  BufferLength input data buffer length
483   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
484   */
CRC_Handle_16(CRC_HandleTypeDef * hcrc,uint16_t pBuffer[],uint32_t BufferLength)485 static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength)
486 {
487   uint32_t i;  /* input data buffer index */
488   __IO uint16_t *pReg;
489 
490   /* Processing time optimization: 2 HalfWords are entered in a row with a single word write,
491    * in case of odd length, last HalfWord must be carefully fed to the CRC calculator to ensure
492    * a correct type handling by the peripheral */
493   for (i = 0U; i < (BufferLength / 2U); i++)
494   {
495     hcrc->Instance->DR = ((uint32_t)pBuffer[2U * i] << 16U) | (uint32_t)pBuffer[(2U * i) + 1U];
496   }
497   if ((BufferLength % 2U) != 0U)
498   {
499     pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                 /* Derogation MisraC2012 R.11.5 */
500     *pReg = pBuffer[2U * i];
501   }
502 
503   /* Return the CRC computed value */
504   return hcrc->Instance->DR;
505 }
506 
507 /**
508   * @}
509   */
510 
511 #endif /* HAL_CRC_MODULE_ENABLED */
512 /**
513   * @}
514   */
515 
516 /**
517   * @}
518   */
519