1 /**
2   ******************************************************************************
3   * @file    stm32u5xx_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) 2021 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 "stm32u5xx_hal.h"
47 
48 /** @addtogroup STM32U5xx_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   /* Reset IDR register content */
203   CLEAR_BIT(hcrc->Instance->IDR, CRC_IDR_IDR);
204 
205   /* DeInit the low level hardware */
206   HAL_CRC_MspDeInit(hcrc);
207 
208   /* Change CRC peripheral state */
209   hcrc->State = HAL_CRC_STATE_RESET;
210 
211   /* Process unlocked */
212   __HAL_UNLOCK(hcrc);
213 
214   /* Return function status */
215   return HAL_OK;
216 }
217 
218 /**
219   * @brief  Initializes the CRC MSP.
220   * @param  hcrc CRC handle
221   * @retval None
222   */
HAL_CRC_MspInit(CRC_HandleTypeDef * hcrc)223 __weak void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
224 {
225   /* Prevent unused argument(s) compilation warning */
226   UNUSED(hcrc);
227 
228   /* NOTE : This function should not be modified, when the callback is needed,
229             the HAL_CRC_MspInit can be implemented in the user file
230    */
231 }
232 
233 /**
234   * @brief  DeInitialize the CRC MSP.
235   * @param  hcrc CRC handle
236   * @retval None
237   */
HAL_CRC_MspDeInit(CRC_HandleTypeDef * hcrc)238 __weak void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc)
239 {
240   /* Prevent unused argument(s) compilation warning */
241   UNUSED(hcrc);
242 
243   /* NOTE : This function should not be modified, when the callback is needed,
244             the HAL_CRC_MspDeInit can be implemented in the user file
245    */
246 }
247 
248 /**
249   * @}
250   */
251 
252 /** @defgroup CRC_Exported_Functions_Group2 Peripheral Control functions
253   *  @brief    management functions.
254   *
255 @verbatim
256  ===============================================================================
257                       ##### Peripheral Control functions #####
258  ===============================================================================
259     [..]  This section provides functions allowing to:
260       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
261           using combination of the previous CRC value and the new one.
262 
263        [..]  or
264 
265       (+) compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
266           independently of the previous CRC value.
267 
268 @endverbatim
269   * @{
270   */
271 
272 /**
273   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
274   *         starting with the previously computed CRC as initialization value.
275   * @param  hcrc CRC handle
276   * @param  pBuffer pointer to the input data buffer, exact input data format is
277   *         provided by hcrc->InputDataFormat.
278   * @param  BufferLength input data buffer length (number of bytes if pBuffer
279   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
280   *         number of words if pBuffer type is * uint32_t).
281   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
282   *        Input buffer pointers with other types simply need to be cast in uint32_t
283   *        and the API will internally adjust its input data processing based on the
284   *        handle field hcrc->InputDataFormat.
285   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
286   */
HAL_CRC_Accumulate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)287 uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
288 {
289   uint32_t index;      /* CRC input data buffer index */
290   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
291 
292   /* Change CRC peripheral state */
293   hcrc->State = HAL_CRC_STATE_BUSY;
294 
295   switch (hcrc->InputDataFormat)
296   {
297     case CRC_INPUTDATA_FORMAT_WORDS:
298       /* Enter Data to the CRC calculator */
299       for (index = 0U; index < BufferLength; index++)
300       {
301         hcrc->Instance->DR = pBuffer[index];
302       }
303       temp = hcrc->Instance->DR;
304       break;
305 
306     case CRC_INPUTDATA_FORMAT_BYTES:
307       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
308       break;
309 
310     case CRC_INPUTDATA_FORMAT_HALFWORDS:
311       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
312       break;
313     default:
314       break;
315   }
316 
317   /* Change CRC peripheral state */
318   hcrc->State = HAL_CRC_STATE_READY;
319 
320   /* Return the CRC computed value */
321   return temp;
322 }
323 
324 /**
325   * @brief  Compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer
326   *         starting with hcrc->Instance->INIT as initialization value.
327   * @param  hcrc CRC handle
328   * @param  pBuffer pointer to the input data buffer, exact input data format is
329   *         provided by hcrc->InputDataFormat.
330   * @param  BufferLength input data buffer length (number of bytes if pBuffer
331   *         type is * uint8_t, number of half-words if pBuffer type is * uint16_t,
332   *         number of words if pBuffer type is * uint32_t).
333   * @note  By default, the API expects a uint32_t pointer as input buffer parameter.
334   *        Input buffer pointers with other types simply need to be cast in uint32_t
335   *        and the API will internally adjust its input data processing based on the
336   *        handle field hcrc->InputDataFormat.
337   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
338   */
HAL_CRC_Calculate(CRC_HandleTypeDef * hcrc,uint32_t pBuffer[],uint32_t BufferLength)339 uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
340 {
341   uint32_t index;      /* CRC input data buffer index */
342   uint32_t temp = 0U;  /* CRC output (read from hcrc->Instance->DR register) */
343 
344   /* Change CRC peripheral state */
345   hcrc->State = HAL_CRC_STATE_BUSY;
346 
347   /* Reset CRC Calculation Unit (hcrc->Instance->INIT is
348   *  written in hcrc->Instance->DR) */
349   __HAL_CRC_DR_RESET(hcrc);
350 
351   switch (hcrc->InputDataFormat)
352   {
353     case CRC_INPUTDATA_FORMAT_WORDS:
354       /* Enter 32-bit input data to the CRC calculator */
355       for (index = 0U; index < BufferLength; index++)
356       {
357         hcrc->Instance->DR = pBuffer[index];
358       }
359       temp = hcrc->Instance->DR;
360       break;
361 
362     case CRC_INPUTDATA_FORMAT_BYTES:
363       /* Specific 8-bit input data handling  */
364       temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
365       break;
366 
367     case CRC_INPUTDATA_FORMAT_HALFWORDS:
368       /* Specific 16-bit input data handling  */
369       temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength);    /* Derogation MisraC2012 R.11.5 */
370       break;
371 
372     default:
373       break;
374   }
375 
376   /* Change CRC peripheral state */
377   hcrc->State = HAL_CRC_STATE_READY;
378 
379   /* Return the CRC computed value */
380   return temp;
381 }
382 
383 /**
384   * @}
385   */
386 
387 /** @defgroup CRC_Exported_Functions_Group3 Peripheral State functions
388   *  @brief    Peripheral State functions.
389   *
390 @verbatim
391  ===============================================================================
392                       ##### Peripheral State functions #####
393  ===============================================================================
394     [..]
395     This subsection permits to get in run-time the status of the peripheral.
396 
397 @endverbatim
398   * @{
399   */
400 
401 /**
402   * @brief  Return the CRC handle state.
403   * @param  hcrc CRC handle
404   * @retval HAL state
405   */
HAL_CRC_GetState(CRC_HandleTypeDef * hcrc)406 HAL_CRC_StateTypeDef HAL_CRC_GetState(CRC_HandleTypeDef *hcrc)
407 {
408   /* Return CRC handle state */
409   return hcrc->State;
410 }
411 
412 /**
413   * @}
414   */
415 
416 /**
417   * @}
418   */
419 
420 /** @addtogroup CRC_Private_Functions
421   * @{
422   */
423 
424 /**
425   * @brief  Enter 8-bit input data to the CRC calculator.
426   *         Specific data handling to optimize processing time.
427   * @param  hcrc CRC handle
428   * @param  pBuffer pointer to the input data buffer
429   * @param  BufferLength input data buffer length
430   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
431   */
CRC_Handle_8(CRC_HandleTypeDef * hcrc,uint8_t pBuffer[],uint32_t BufferLength)432 static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
433 {
434   uint32_t i; /* input data buffer index */
435   uint16_t data;
436   __IO uint16_t *pReg;
437 
438   /* Processing time optimization: 4 bytes are entered in a row with a single word write,
439    * last bytes must be carefully fed to the CRC calculator to ensure a correct type
440    * handling by the peripheral */
441   for (i = 0U; i < (BufferLength / 4U); i++)
442   {
443     hcrc->Instance->DR = ((uint32_t)pBuffer[4U * i] << 24U) | \
444                          ((uint32_t)pBuffer[(4U * i) + 1U] << 16U) | \
445                          ((uint32_t)pBuffer[(4U * i) + 2U] << 8U)  | \
446                          (uint32_t)pBuffer[(4U * i) + 3U];
447   }
448   /* last bytes specific handling */
449   if ((BufferLength % 4U) != 0U)
450   {
451     if ((BufferLength % 4U) == 1U)
452     {
453       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i];         /* Derogation MisraC2012 R.11.5 */
454     }
455     if ((BufferLength % 4U) == 2U)
456     {
457       data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
458       pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
459       *pReg = data;
460     }
461     if ((BufferLength % 4U) == 3U)
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       *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[(4U * i) + 2U];  /* Derogation MisraC2012 R.11.5 */
468     }
469   }
470 
471   /* Return the CRC computed value */
472   return hcrc->Instance->DR;
473 }
474 
475 /**
476   * @brief  Enter 16-bit input data to the CRC calculator.
477   *         Specific data handling to optimize processing time.
478   * @param  hcrc CRC handle
479   * @param  pBuffer pointer to the input data buffer
480   * @param  BufferLength input data buffer length
481   * @retval uint32_t CRC (returned value LSBs for CRC shorter than 32 bits)
482   */
CRC_Handle_16(CRC_HandleTypeDef * hcrc,uint16_t pBuffer[],uint32_t BufferLength)483 static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength)
484 {
485   uint32_t i;  /* input data buffer index */
486   __IO uint16_t *pReg;
487 
488   /* Processing time optimization: 2 HalfWords are entered in a row with a single word write,
489    * in case of odd length, last HalfWord must be carefully fed to the CRC calculator to ensure
490    * a correct type handling by the peripheral */
491   for (i = 0U; i < (BufferLength / 2U); i++)
492   {
493     hcrc->Instance->DR = ((uint32_t)pBuffer[2U * i] << 16U) | (uint32_t)pBuffer[(2U * i) + 1U];
494   }
495   if ((BufferLength % 2U) != 0U)
496   {
497     pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                 /* Derogation MisraC2012 R.11.5 */
498     *pReg = pBuffer[2U * i];
499   }
500 
501   /* Return the CRC computed value */
502   return hcrc->Instance->DR;
503 }
504 
505 /**
506   * @}
507   */
508 
509 #endif /* HAL_CRC_MODULE_ENABLED */
510 /**
511   * @}
512   */
513 
514 /**
515   * @}
516   */
517