Subversion Repositories DashDisplay

Rev

Rev 61 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
77 mjames 1
/**
2
  ******************************************************************************
3
  * @file    stm32l1xx_hal_rcc_ex.c
4
  * @author  MCD Application Team
5
  * @brief   Extended RCC HAL module driver.
6
  *          This file provides firmware functions to manage the following
7
  *          functionalities RCC extension peripheral:
8
  *           + Extended Peripheral Control functions
9
  *
10
  ******************************************************************************
11
  * @attention
12
  *
13
  * Copyright (c) 2017 STMicroelectronics.
14
  * All rights reserved.
15
  *
16
  * This software is licensed under terms that can be found in the LICENSE file in
17
  * the root directory of this software component.
18
  * If no LICENSE file comes with this software, it is provided AS-IS.
19
  ******************************************************************************
20
  */
21
 
22
/* Includes ------------------------------------------------------------------*/
23
#include "stm32l1xx_hal.h"
24
 
25
/** @addtogroup STM32L1xx_HAL_Driver
26
  * @{
27
  */
28
 
29
#ifdef HAL_RCC_MODULE_ENABLED
30
 
31
/** @defgroup RCCEx RCCEx
32
  * @brief RCC Extension HAL module driver
33
  * @{
34
  */
35
 
36
/* Private typedef -----------------------------------------------------------*/
37
/* Private define ------------------------------------------------------------*/
38
/** @defgroup RCCEx_Private_Constants RCCEx Private Constants
39
  * @{
40
  */
41
/**
42
  * @}
43
  */
44
 
45
/* Private macro -------------------------------------------------------------*/
46
/** @defgroup RCCEx_Private_Macros RCCEx Private Macros
47
  * @{
48
  */
49
/**
50
  * @}
51
  */
52
 
53
/* Private variables ---------------------------------------------------------*/
54
/* Private function prototypes -----------------------------------------------*/
55
/* Private functions ---------------------------------------------------------*/
56
 
57
/** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
58
  * @{
59
  */
60
 
61
/** @defgroup RCCEx_Exported_Functions_Group1 Extended Peripheral Control functions
62
 *  @brief  Extended Peripheral Control functions
63
 *
64
@verbatim
65
 ===============================================================================
66
                ##### Extended Peripheral Control functions  #####
67
 ===============================================================================
68
    [..]
69
    This subsection provides a set of functions allowing to control the RCC Clocks
70
    frequencies.
71
    [..]
72
    (@) Important note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to
73
        select the RTC clock source; in this case the Backup domain will be reset in
74
        order to modify the RTC Clock source, as consequence RTC registers (including
75
        the backup registers) are set to their reset values.
76
 
77
@endverbatim
78
  * @{
79
  */
80
 
81
/**
82
  * @brief  Initializes the RCC extended peripherals clocks according to the specified
83
  *         parameters in the RCC_PeriphCLKInitTypeDef.
84
  * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
85
  *         contains the configuration information for the Extended Peripherals clocks(RTC/LCD clock).
86
  * @retval HAL status
87
  * @note   If HAL_ERROR returned, first switch-OFF HSE clock oscillator with @ref HAL_RCC_OscConfig()
88
  *         to possibly update HSE divider.
89
  */
90
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
91
{
92
  uint32_t tickstart;
93
  uint32_t temp_reg;
94
 
95
  /* Check the parameters */
96
  assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
97
 
98
  /*------------------------------- RTC/LCD Configuration ------------------------*/
99
  if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
100
#if defined(LCD)
101
   || (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
102
#endif /* LCD */
103
     )
104
  {
105
    /* check for RTC Parameters used to output RTCCLK */
106
    if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
107
    {
108
      assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
109
    }
110
 
111
#if defined(LCD)
112
    if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
113
    {
114
      assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->LCDClockSelection));
115
    }
116
#endif /* LCD */
117
 
118
    FlagStatus       pwrclkchanged = RESET;
119
 
120
    /* As soon as function is called to change RTC clock source, activation of the
121
       power domain is done. */
122
    /* Requires to enable write access to Backup Domain of necessary */
123
    if(__HAL_RCC_PWR_IS_CLK_DISABLED())
124
    {
125
      __HAL_RCC_PWR_CLK_ENABLE();
126
      pwrclkchanged = SET;
127
    }
128
 
129
    if(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
130
    {
131
      /* Enable write access to Backup domain */
132
      SET_BIT(PWR->CR, PWR_CR_DBP);
133
 
134
      /* Wait for Backup domain Write protection disable */
135
      tickstart = HAL_GetTick();
136
 
137
      while(HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
138
      {
139
        if((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
140
        {
141
          return HAL_TIMEOUT;
142
        }
143
      }
144
    }
145
 
146
    /* Check if user wants to change HSE RTC prescaler whereas HSE is enabled */
147
    temp_reg = (RCC->CR & RCC_CR_RTCPRE);
148
    if ((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CR_RTCPRE))
149
#if defined (LCD)
150
     || (temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CR_RTCPRE))
151
#endif /* LCD */
152
       )
153
    { /* Check HSE State */
154
      if ((PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL) == RCC_CSR_RTCSEL_HSE)
155
      {
156
        if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY))
157
        {
158
          /* To update HSE divider, first switch-OFF HSE clock oscillator*/
159
          return HAL_ERROR;
160
        }
161
      }
162
    }
163
 
164
    /* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
165
    temp_reg = (RCC->CSR & RCC_CSR_RTCSEL);
166
 
167
    if((temp_reg != 0x00000000U) && (((temp_reg != (PeriphClkInit->RTCClockSelection & RCC_CSR_RTCSEL)) \
168
      && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC))
169
#if defined(LCD)
170
      || ((temp_reg != (PeriphClkInit->LCDClockSelection & RCC_CSR_RTCSEL)) \
171
       && (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD))
172
#endif /* LCD */
173
     ))
174
    {
175
      /* Store the content of CSR register before the reset of Backup Domain */
176
      temp_reg = (RCC->CSR & ~(RCC_CSR_RTCSEL));
177
 
178
      /* RTC Clock selection can be changed only if the Backup Domain is reset */
179
      __HAL_RCC_BACKUPRESET_FORCE();
180
      __HAL_RCC_BACKUPRESET_RELEASE();
181
 
182
      /* Restore the Content of CSR register */
183
      RCC->CSR = temp_reg;
184
 
185
       /* Wait for LSERDY if LSE was enabled */
186
      if (HAL_IS_BIT_SET(temp_reg, RCC_CSR_LSEON))
187
      {
188
        /* Get Start Tick */
189
        tickstart = HAL_GetTick();
190
 
191
        /* Wait till LSE is ready */
192
        while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == 0U)
193
        {
194
          if((HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE)
195
          {
196
            return HAL_TIMEOUT;
197
          }
198
        }
199
      }
200
    }
201
#if defined(LCD)
202
    if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_LCD) == RCC_PERIPHCLK_LCD)
203
    {
204
      __HAL_RCC_LCD_CONFIG(PeriphClkInit->LCDClockSelection);
205
    }
206
#endif /* LCD */
207
 
208
    if(((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC)
209
    {
210
      __HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
211
    }
212
 
213
    /* Require to disable power clock if necessary */
214
    if(pwrclkchanged == SET)
215
    {
216
      __HAL_RCC_PWR_CLK_DISABLE();
217
    }
218
  }
219
 
220
  return HAL_OK;
221
}
222
 
223
/**
224
  * @brief  Get the PeriphClkInit according to the internal RCC configuration registers.
225
  * @param  PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
226
  *         returns the configuration information for the Extended Peripherals clocks(RTC/LCD clocks).
227
  * @retval None
228
  */
229
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef  *PeriphClkInit)
230
{
231
  uint32_t srcclk;
232
 
233
  /* Set all possible values for the extended clock type parameter------------*/
234
  PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_RTC;
235
#if defined(LCD)
236
  PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_LCD;
237
#endif /* LCD */
238
 
239
  /* Get the RTC/LCD configuration -----------------------------------------------*/
240
  srcclk = __HAL_RCC_GET_RTC_SOURCE();
241
  if (srcclk != RCC_RTCCLKSOURCE_HSE_DIV2)
242
  {
243
    /* Source clock is LSE or LSI*/
244
    PeriphClkInit->RTCClockSelection = srcclk;
245
  }
246
  else
247
  {
248
    /* Source clock is HSE. Need to get the prescaler value*/
249
    PeriphClkInit->RTCClockSelection = srcclk | (READ_BIT(RCC->CR, RCC_CR_RTCPRE));
250
  }
251
#if defined(LCD)
252
  PeriphClkInit->LCDClockSelection = PeriphClkInit->RTCClockSelection;
253
#endif /* LCD */
254
}
255
 
256
/**
257
  * @brief  Return the peripheral clock frequency
258
  * @note   Return 0 if peripheral clock is unknown
259
  * @param  PeriphClk Peripheral clock identifier
260
  *         This parameter can be one of the following values:
261
  *            @arg @ref RCC_PERIPHCLK_RTC      RTC peripheral clock
262
  *            @arg @ref RCC_PERIPHCLK_LCD      LCD peripheral clock (*)
263
  * @note   (*) means that this peripheral is not present on all the devices
264
  * @retval Frequency in Hz (0: means that no available frequency for the peripheral)
265
  */
266
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
267
{
268
  uint32_t frequency = 0;
269
  uint32_t srcclk;
270
 
271
  /* Check the parameters */
272
  assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
273
 
274
  switch (PeriphClk)
275
  {
276
  case RCC_PERIPHCLK_RTC:
277
#if defined(LCD)
278
  case RCC_PERIPHCLK_LCD:
279
#endif /* LCD */
280
    {
281
      /* Get the current RTC source */
282
      srcclk = __HAL_RCC_GET_RTC_SOURCE();
283
 
284
      /* Check if LSE is ready if RTC clock selection is LSE */
285
      if (srcclk == RCC_RTCCLKSOURCE_LSE)
286
      {
287
        if (HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSERDY))
288
        {
289
          frequency = LSE_VALUE;
290
        }
291
      }
292
      /* Check if LSI is ready if RTC clock selection is LSI */
293
      else if (srcclk == RCC_RTCCLKSOURCE_LSI)
294
      {
295
        if (HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSIRDY))
296
        {
297
          frequency = LSI_VALUE;
298
        }
299
      }
300
      /* Check if HSE is ready and if RTC clock selection is HSE */
301
      else if (srcclk == RCC_RTCCLKSOURCE_HSE_DIVX)
302
      {
303
        if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY))
304
        {
305
          /* Get the current HSE clock divider */
306
          switch (__HAL_RCC_GET_RTC_HSE_PRESCALER())
307
          {
308
            case RCC_RTC_HSE_DIV_16:  /* HSE DIV16 has been selected */
309
            {
310
              frequency = HSE_VALUE / 16U;
311
              break;
312
            }
313
            case RCC_RTC_HSE_DIV_8:   /* HSE DIV8 has been selected  */
314
            {
315
              frequency = HSE_VALUE / 8U;
316
              break;
317
            }
318
            case RCC_RTC_HSE_DIV_4:   /* HSE DIV4 has been selected  */
319
            {
320
              frequency = HSE_VALUE / 4U;
321
              break;
322
            }
323
            default:                  /* HSE DIV2 has been selected  */
324
            {
325
              frequency = HSE_VALUE / 2U;
326
              break;
327
            }
328
          }
329
        }
330
      }
331
      else
332
      {
333
        /* No clock source, frequency default init at 0 */
334
      }
335
      break;
336
    }
337
 
338
  default:
339
    break;
340
  }
341
 
342
  return(frequency);
343
}
344
 
345
#if defined(RCC_LSECSS_SUPPORT)
346
/**
347
  * @brief  Enables the LSE Clock Security System.
348
  * @note   If a failure is detected on the external 32 kHz oscillator, the LSE clock is no longer supplied
349
  *         to the RTC but no hardware action is made to the registers.
350
  *         In Standby mode a wakeup is generated. In other modes an interrupt can be sent to wakeup
351
  *         the software (see Section 5.3.4: Clock interrupt register (RCC_CIR) on page 104).
352
  *         The software MUST then disable the LSECSSON bit, stop the defective 32 kHz oscillator
353
  *         (disabling LSEON), and can change the RTC clock source (no clock or LSI or HSE, with
354
  *         RTCSEL), or take any required action to secure the application.
355
  * @note   LSE CSS available only for high density and medium+ devices
356
  * @retval None
357
  */
358
void HAL_RCCEx_EnableLSECSS(void)
359
{
360
  *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)ENABLE;
361
}
362
 
363
/**
364
  * @brief  Disables the LSE Clock Security System.
365
  * @note   Once enabled this bit cannot be disabled, except after an LSE failure detection
366
  *         (LSECSSD=1). In that case the software MUST disable the LSECSSON bit.
367
  *         Reset by power on reset and RTC software reset (RTCRST bit).
368
  * @note   LSE CSS available only for high density and medium+ devices
369
  * @retval None
370
  */
371
void HAL_RCCEx_DisableLSECSS(void)
372
{
373
  /* Disable LSE CSS */
374
  *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)DISABLE;
375
 
376
  /* Disable LSE CSS IT */
377
  __HAL_RCC_DISABLE_IT(RCC_IT_LSECSS);
378
}
379
 
380
/**
381
  * @brief  Enable the LSE Clock Security System IT & corresponding EXTI line.
382
  * @note   LSE Clock Security System IT is mapped on RTC EXTI line 19
383
  * @retval None
384
  */
385
void HAL_RCCEx_EnableLSECSS_IT(void)
386
{
387
  /* Enable LSE CSS */
388
  *(__IO uint32_t *) CSR_LSECSSON_BB = (uint32_t)ENABLE;
389
 
390
  /* Enable LSE CSS IT */
391
  __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS);
392
 
393
  /* Enable IT on EXTI Line 19 */
394
  __HAL_RCC_LSECSS_EXTI_ENABLE_IT();
395
  __HAL_RCC_LSECSS_EXTI_ENABLE_RISING_EDGE();
396
}
397
 
398
/**
399
  * @brief Handle the RCC LSE Clock Security System interrupt request.
400
  * @retval None
401
  */
402
void HAL_RCCEx_LSECSS_IRQHandler(void)
403
{
404
  /* Check RCC LSE CSSF flag  */
405
  if(__HAL_RCC_GET_IT(RCC_IT_LSECSS))
406
  {
407
    /* RCC LSE Clock Security System interrupt user callback */
408
    HAL_RCCEx_LSECSS_Callback();
409
 
410
    /* Clear RCC LSE CSS pending bit */
411
    __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS);
412
  }
413
}
414
 
415
/**
416
  * @brief  RCCEx LSE Clock Security System interrupt callback.
417
  * @retval none
418
  */
419
__weak void HAL_RCCEx_LSECSS_Callback(void)
420
{
421
  /* NOTE : This function should not be modified, when the callback is needed,
422
            the @ref HAL_RCCEx_LSECSS_Callback should be implemented in the user file
423
   */
424
}
425
#endif /* RCC_LSECSS_SUPPORT */
426
 
427
/**
428
  * @}
429
  */
430
 
431
/**
432
  * @}
433
  */
434
 
435
/**
436
  * @}
437
  */
438
 
439
/**
440
  * @}
441
  */
442
 
443
#endif /* HAL_RCC_MODULE_ENABLED */
444
/**
445
  * @}
446
  */
447