1 /**
2   ******************************************************************************
3   * @file    stm32l4xx_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) 2017 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 "stm32l4xx_hal.h"
47 
48 /** @addtogroup STM32L4xx_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   /* check whether or not non-default generating polynomial has been
125    * picked up by user */
126   assert_param(IS_DEFAULT_POLYNOMIAL(hcrc->Init.DefaultPolynomialUse));
127   if (hcrc->Init.DefaultPolynomialUse == DEFAULT_POLYNOMIAL_ENABLE)
128   {
129     /* initialize peripheral with default generating polynomial */
130     WRITE_REG(hcrc->Instance->POL, DEFAULT_CRC32_POLY);
131     MODIFY_REG(hcrc->Instance->CR, CRC_CR_POLYSIZE, CRC_POLYLENGTH_32B);
132   }
133   else
134   {
135     /* initialize CRC peripheral with generating polynomial defined by user */
136     if (HAL_CRCEx_Polynomial_Set(hcrc, hcrc->Init.GeneratingPolynomial, hcrc->Init.CRCLength) != HAL_OK)
137     {
138       return HAL_ERROR;
139     }
140   }
141 
142   /* check whether or not non-default CRC initial value has been
143    * picked up by user */
144   assert_param(IS_DEFAULT_INIT_VALUE(hcrc->Init.DefaultInitValueUse));
145   if (hcrc->Init.DefaultInitValueUse == DEFAULT_INIT_VALUE_ENABLE)
146   {
147     WRITE_REG(hcrc->Instance->INIT, DEFAULT_CRC_INITVALUE);
148   }
149   else
150   {
151     WRITE_REG(hcrc->Instance->INIT, hcrc->Init.InitValue);
152   }
153 
154 
155   /* set input data inversion mode */
156   assert_param(IS_CRC_INPUTDATA_INVERSION_MODE(hcrc->Init.InputDataInversionMode));
157   MODIFY_REG(hcrc->Instance->CR, CRC_CR_REV_IN, hcrc->Init.InputDataInversionMode);
158 
159   /* set output data inversion mode */
160   assert_param(IS_CRC_OUTPUTDATA_INVERSION_MODE(hcrc->Init.OutputDataInversionMode));
161   MODIFY_REG(hcrc->Instance->CR, CRC_CR_REV_OUT, hcrc->Init.OutputDataInversionMode);
162 
163   /* makes sure the input data format (bytes, halfwords or words stream)
164    * is properly specified by user */
165   assert_param(IS_CRC_INPUTDATA_FORMAT(hcrc->InputDataFormat));
166 
167   /* Change CRC peripheral state */
168   hcrc->State = HAL_CRC_STATE_READY;
169 
170   /* Return function status */
171   return HAL_OK;
172 }
173 
174 /**
175   * @brief  DeInitialize the CRC peripheral.
176   * @param  hcrc CRC handle
177   * @retval HAL status
178   */
HAL_CRC_DeInit(CRC_HandleTypeDef * hcrc)179 HAL_StatusTypeDef HAL_CRC_DeInit(CRC_HandleTypeDef *hcrc)
180 {
181   /* Check the CRC handle allocation */
182   if (hcrc == NULL)
183   {
184     return HAL_ERROR;
185   }
186 
187   /* Check the parameters */
188   assert_param(IS_CRC_ALL_INSTANCE(hcrc->Instance));
189 
190   /* Check the CRC peripheral state */
191   if (hcrc->State == HAL_CRC_STATE_BUSY)
192   {
193     return HAL_BUSY;
194   }
195 
196   /* Change CRC peripheral state */
197   hcrc->State = HAL_CRC_STATE_BUSY;
198 
199   /* Reset CRC calculation unit */
200   __HAL_CRC_DR_RESET(hcrc);
201 
202 #if defined(CRC_IDR32BITSLENGTH_SUPPORT)
203   /* Reset IDR register content */
204   __HAL_CRC_SET_IDR(hcrc, 0);
205 
206 #else
207   /* Reset IDR register content */
208   CLEAR_BIT(hcrc->Instance->IDR, CRC_IDR_IDR);
209 
210 #endif /* CRC_IDR32BITSLENGTH_SUPPORT */
211   /* DeInit the low level hardware */
212   HAL_CRC_MspDeInit(hcrc);
213 
214   /* Change CRC peripheral state */
215   hcrc->State = HAL_CRC_STATE_RESET;
216 
217   /* Process unlocked */
218   __HAL_UNLOCK(hcrc);
219 
220   /* Return function status */
221   return HAL_OK;
222 }
223 
224 /**
225   * @brief  Initializes the CRC MSP.
226   * @param  hcrc CRC handle
227   * @retval None
228   */
HAL_CRC_MspInit(CRC_HandleTypeDef * hcrc)229 __weak void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
230 {
231   /* Prevent unused argument(s) compilation warning */
232   UNUSED(hcrc);
233 
234   /* NOTE : This function should not be modified, when the callback is needed,
235             the HAL_CRC_MspInit can be implemented in the user file
236    */
237 }
238 
239 /**
240   * @brief  DeInitialize the CRC MSP.
241   * @param  hcrc CRC handle
242   * @retval None
243   */
HAL_CRC_MspDeInit(CRC_HandleTypeDef * hcrc)244 __weak void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc)
245 {
246   /* Prevent unused argument(s) compilation warning */
247   UNUSED(hcrc);
248 
249   /* NOTE : This function should not be modified, when the callback is needed,
250             the HAL_CRC_MspDeInit can be implemented in the user file
251    */
252 }
253 
254 /**
255   * @}
256   */
257 
258 /** @defgroup CRC_Exported_Functions_Group2 Peripheral Control functions
259   *  @brief    management functions.
260   *
261 @verbatim
262  ===============================================================================
263                       ##### Peripheral Control functions #####
264  ===============================================================================
265     [..]  This section provides functions allowing to:
266       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
267           using combination of the previous CRC value and the new one.
268 
269        [..]  or
270 
271       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
272           independently of the previous CRC value.
273 
274 @endverbatim
275   * @{
276   */
277 
278 /**
279   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
280   *         starting with the previously computed CRC as initialization value.
281   * @param  hcrc CRC handle
282   * @param  pBuffer pointer to the input data buffer, exact input data format is
283   *         provided by hcrc->InputDataFormat.
284   * @param  BufferLength input data buffer length (number of bytes if pBuffer
285   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
286   *         number of words if pBuffer type is * uint32_t).
287   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
288   *        Input buffer pointers with other types simply need to be cast in uint32_t
289   *        and the API will internally adjust its input data processing based on the
290   *        handle field hcrc->InputDataFormat.
291   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
292   */
HAL_CRC_Accumulate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)293 uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
294 {
295   uint32_t index;      /* CRC input data buffer index */
296   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
297 
298   /* Change CRC peripheral state */
299   hcrc->State = HAL_CRC_STATE_BUSY;
300 
301   switch (hcrc->InputDataFormat)
302   {
303     case CRC_INPUTDATA_FORMAT_WORDS:
304       /* Enter Data to the CRC calculator */
305       for (index = 0U; index < BufferLength; index++)
306       {
307         hcrc->Instance->DR = pBuffer[index];
308       }
309       temp = hcrc->Instance->DR;
310       break;
311 
312     case CRC_INPUTDATA_FORMAT_BYTES:
313       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
314       break;
315 
316     case CRC_INPUTDATA_FORMAT_HALFWORDS:
317       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
318       break;
319     default:
320       break;
321   }
322 
323   /* Change CRC peripheral state */
324   hcrc->State = HAL_CRC_STATE_READY;
325 
326   /* Return the CRC computed value */
327   return temp;
328 }
329 
330 /**
331   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
332   *         starting with hcrc->Instance->INIT as initialization value.
333   * @param  hcrc CRC handle
334   * @param  pBuffer pointer to the input data buffer, exact input data format is
335   *         provided by hcrc->InputDataFormat.
336   * @param  BufferLength input data buffer length (number of bytes if pBuffer
337   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
338   *         number of words if pBuffer type is * uint32_t).
339   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
340   *        Input buffer pointers with other types simply need to be cast in uint32_t
341   *        and the API will internally adjust its input data processing based on the
342   *        handle field hcrc->InputDataFormat.
343   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
344   */
HAL_CRC_Calculate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)345 uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
346 {
347   uint32_t index;      /* CRC input data buffer index */
348   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
349 
350   /* Change CRC peripheral state */
351   hcrc->State = HAL_CRC_STATE_BUSY;
352 
353   /* Reset CRC Calculation Unit (hcrc->Instance->INIT is
354   *  written in hcrc->Instance->DR) */
355   __HAL_CRC_DR_RESET(hcrc);
356 
357   switch (hcrc->InputDataFormat)
358   {
359     case CRC_INPUTDATA_FORMAT_WORDS:
360       /* Enter 32-bit input data to the CRC calculator */
361       for (index = 0U; index < BufferLength; index++)
362       {
363         hcrc->Instance->DR = pBuffer[index];
364       }
365       temp = hcrc->Instance->DR;
366       break;
367 
368     case CRC_INPUTDATA_FORMAT_BYTES:
369       /* Specific 8-bit input data handling  */
370       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
371       break;
372 
373     case CRC_INPUTDATA_FORMAT_HALFWORDS:
374       /* Specific 16-bit input data handling  */
375       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
376       break;
377 
378     default:
379       break;
380   }
381 
382   /* Change CRC peripheral state */
383   hcrc->State = HAL_CRC_STATE_READY;
384 
385   /* Return the CRC computed value */
386   return temp;
387 }
388 
389 /**
390   * @}
391   */
392 
393 /** @defgroup CRC_Exported_Functions_Group3 Peripheral State functions
394   *  @brief    Peripheral State functions.
395   *
396 @verbatim
397  ===============================================================================
398                       ##### Peripheral State functions #####
399  ===============================================================================
400     [..]
401     This subsection permits to get in run-time the status of the peripheral.
402 
403 @endverbatim
404   * @{
405   */
406 
407 /**
408   * @brief  Return the CRC handle state.
409   * @param  hcrc CRC handle
410   * @retval HAL state
411   */
HAL_CRC_GetState(const CRC_HandleTypeDef * hcrc)412 HAL_CRC_StateTypeDef HAL_CRC_GetState(const CRC_HandleTypeDef *hcrc)
413 {
414   /* Return CRC handle state */
415   return hcrc->State;
416 }
417 
418 /**
419   * @}
420   */
421 
422 /**
423   * @}
424   */
425 
426 /** @addtogroup CRC_Private_Functions
427   * @{
428   */
429 
430 /**
431   * @brief  Enter 8-bit input data to the CRC calculator.
432   *         Specific data handling to optimize processing time.
433   * @param  hcrc CRC handle
434   * @param  pBuffer pointer to the input data buffer
435   * @param  BufferLength input data buffer length
436   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
437   */
CRC_Handle_8(CRC_HandleTypeDef * hcrc,uint8_t pBuffer[],uint32_t BufferLength)438 static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
439 {
440   uint32_t i; /* input data buffer index */
441   uint16_t data;
442   __IO uint16_t *pReg;
443 
444   /* Processing time optimization: 4 bytes are entered in a row with a single word write,
445    * last bytes must be carefully fed to the CRC calculator to ensure a correct type
446    * handling by the peripheral */
447   for (i = 0U; i < (BufferLength / 4U); i++)
448   {
449     hcrc->Instance->DR = ((uint32_t)pBuffer[4U * i] << 24U) | \
450                          ((uint32_t)pBuffer[(4U * i) + 1U] << 16U) | \
451                          ((uint32_t)pBuffer[(4U * i) + 2U] << 8U)  | \
452                          (uint32_t)pBuffer[(4U * i) + 3U];
453   }
454   /* last bytes specific handling */
455   if ((BufferLength % 4U) != 0U)
456   {
457     if ((BufferLength % 4U) == 1U)
458     {
459       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i];         /* Derogation MisraC2012 R.11.5 */
460     }
461     if ((BufferLength % 4U) == 2U)
462     {
463       data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
464       pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
465       *pReg = data;
466     }
467     if ((BufferLength % 4U) == 3U)
468     {
469       data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
470       pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
471       *pReg = data;
472 
473       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[(4U * i) + 2U];  /* Derogation MisraC2012 R.11.5 */
474     }
475   }
476 
477   /* Return the CRC computed value */
478   return hcrc->Instance->DR;
479 }
480 
481 /**
482   * @brief  Enter 16-bit input data to the CRC calculator.
483   *         Specific data handling to optimize processing time.
484   * @param  hcrc CRC handle
485   * @param  pBuffer pointer to the input data buffer
486   * @param  BufferLength input data buffer length
487   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
488   */
CRC_Handle_16(CRC_HandleTypeDef * hcrc,uint16_t pBuffer[],uint32_t BufferLength)489 static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength)
490 {
491   uint32_t i;  /* input data buffer index */
492   __IO uint16_t *pReg;
493 
494   /* Processing time optimization: 2 HalfWords are entered in a row with a single word write,
495    * in case of odd length, last HalfWord must be carefully fed to the CRC calculator to ensure
496    * a correct type handling by the peripheral */
497   for (i = 0U; i < (BufferLength / 2U); i++)
498   {
499     hcrc->Instance->DR = ((uint32_t)pBuffer[2U * i] << 16U) | (uint32_t)pBuffer[(2U * i) + 1U];
500   }
501   if ((BufferLength % 2U) != 0U)
502   {
503     pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                 /* Derogation MisraC2012 R.11.5 */
504     *pReg = pBuffer[2U * i];
505   }
506 
507   /* Return the CRC computed value */
508   return hcrc->Instance->DR;
509 }
510 
511 /**
512   * @}
513   */
514 
515 #endif /* HAL_CRC_MODULE_ENABLED */
516 /**
517   * @}
518   */
519 
520 /**
521   * @}
522   */
523