source: trunk/firmware/HSI16/Src/hsi16.c @ 6

Last change on this file since 6 was 6, checked in by f.jahn, 3 months ago
File size: 19.7 KB
RevLine 
[6]1/**
2  ******************************************************************************
3  * @file    Project/STM32L0_Internal_RC_Oscillators_Calibration/Src/hsi16.c
4  * @author  MCD Application Team
5  * @version V0.1.0
6  * @date    17-December-2014
7  * @brief   This file provides all the HSI measurement and calibration firmware functions.
8  ******************************************************************************
9  * @attention
10  *
11  * <h2><center>&copy; COPYRIGHT 2014 STMicroelectronics</center></h2>
12  *
13  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
14  * You may not use this file except in compliance with the License.
15  * You may obtain a copy of the License at:
16  *
17  *        http://www.st.com/software_license_agreement_liberty_v2
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an "AS IS" BASIS,
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  *
25  ******************************************************************************
26  */
27
28/* Includes ------------------------------------------------------------------*/
29#include "hsi16.h"
30#include <stdio.h>
31/* Private typedef -----------------------------------------------------------*/
32/* Private define ------------------------------------------------------------*/
33#define HSI16_MEASURE_FREQUENCY_TABLE
34
35// Timer related Defines
36#define CAPTURE_START                           ((uint32_t) 0x00000001)
37#define CAPTURE_ONGOING                         ((uint32_t) 0x00000002)
38#define CAPTURE_COMPLETED                       ((uint32_t) 0x00000003)
39#define CAPTURE_READY_FOR_NEW                   ((uint32_t) 0x00000004)
40
41#define __TIMx_CLK_ENABLE()                     __HAL_RCC_TIM16_CLK_ENABLE()
42#define TIMx                                    TIM16
43#define TIM_CHANNEL_y                           TIM_CHANNEL_1
44#define HAL_TIM_ACTIVE_CHANNEL_y                HAL_TIM_ACTIVE_CHANNEL_1
45#define TIM_TIMx_GPIO                           TIM16_TI1_GPIO
46#define TIM_TIMx_LSE                            TIM_TIM16_TI1_LSE
47#define TIM_TIMx_MCO                            TIM16_TI1_MCO
48#define TIMx_IRQn                               TIM16_IRQn
49
50#define INITIAL_ERROR                           ((uint32_t)99999000)
51
52/* Exported macro ------------------------------------------------------------*/
53#define __HAL_GET_TIM_PRESCALER(__HANDLE__)     ((__HANDLE__)->Instance->PSC)
54#define ABS_RETURN(x)                           ((x < 0) ? (-x) : (x))
55
56#define HSI16_TIMx_COUNTER_PRESCALER            ((uint32_t)0)
57/* The signal in input capture is divided by 8 */
58#define HSI16_TIMx_IC_DIVIDER                   TIM_ICPSC_DIV8
59
60/* The LSE is divided by 8 => LSE/8 = 32768/8 = 4096 */
61#define REFERENCE_FREQUENCY                     ((uint32_t)4096) /*!< The reference frequency value in Hz */
62
63/* Number of measurements in the loop */
64#define HSI16_NUMBER_OF_LOOPS                   ((uint32_t)10)
65
66/* Timeout to avoid endless loop */
67#define HSI16_TIMEOUT                           ((uint32_t)0xFFFFFF)
68       
69/* Get actual trimming settings of HSI16 */     
70#define GET_HSI16_TRIMMING_VALUE()              ((RCC->ICSCR & RCC_ICSCR_HSITRIM) >> 8)
71
72/* Private macro -------------------------------------------------------------*/
73/* Private variables ---------------------------------------------------------*/
74
75TIM_HandleTypeDef       TimHandle; /* Timer handler declaration */
76
77static uint16_t  LSIFrequency = LSI_VALUE;
78static uint32_t  __IO CaptureState = 0;
79static uint32_t  __IO Capture = 0;
80static uint32_t  IC1ReadValue1 = 0, IC1ReadValue2 = 0;
81
82#ifdef HSI16_MEASURE_FREQUENCY_TABLE
83int32_t  aFrequenceChangeTable[128]; /* 2^7 positions*/
84#endif
85
86/* Private function prototypes -----------------------------------------------*/
87void HSI16_TIMx_ConfigForCalibration(void);
88void HSI16_RCC_AdjustCalibrationValue(uint8_t InternOsc, uint8_t TrimmingValue);
89uint32_t HSI16_FreqMeasure(void);
90void HSI16_MeasurementInit(void);
91
92void CLK_ConfigForCalibration(void);
93void GPIO_ConfigForCalibration(void);
94/* Private functions ---------------------------------------------------------*/
95
96/** @addtogroup STM32L0xx_AN4631
97  * @{
98  */
99
100/**
101  * @brief  Calibrates internal oscillators HSI to the minimum computed error.
102  *         The system clock source is checked:
103  *           - If HSI oscillator is used as system clock source, HSI is calibrated
104  *             and the new HSI value is returned.
105  *           - Otherwise function returns 0.
106  * @param  None.
107  * @retval The optimum computed frequency of HSI oscillator.
108  *         Returning 0 means that the system clock source is not HSI.
109  */
110uint32_t HSI16_CalibrateMinError(void)
111{
112  uint32_t  measuredfrequency = 0;
113  uint32_t  sysclockfrequency = 0;
114  uint32_t  optimumfrequency = 0;
115  uint32_t  frequencyerror = 0;
116  uint32_t  optimumfrequencyerror = INITIAL_ERROR; /* Large value */
117  uint32_t  numbersteps = 0;         /* Number of steps: size of trimming bits */
118  uint32_t  trimmingvalue = 0;
119  uint32_t  optimumcalibrationvalue = 0;
120
121  /* Set measurement environment */
122  HSI16_MeasurementInit();
123
124  /* Get system clock frequency */
125  sysclockfrequency = HAL_RCC_GetSysClockFreq();
126
127  /* HSI16TRIM is 7-bit length */
128  numbersteps = 128; /* number of steps is 2^7 = 128 */
129
130  /* Internal Osc frequency measurement for numbersteps */
131  for (trimmingvalue = 0; trimmingvalue < numbersteps; trimmingvalue++)
132  {
133
134    /* Set the Intern Osc trimming bits to trimmingvalue */
135    HSI16_RCC_AdjustCalibrationValue(__HAL_RCC_GET_SYSCLK_SOURCE(), trimmingvalue);
136
137    /* Get actual frequency value */
138    measuredfrequency = HSI16_FreqMeasure();
139
140    /* Compute current frequency error corresponding to the current trimming value:
141    measured value is subtracted from the typical one */
142    frequencyerror = ABS_RETURN((int32_t) (measuredfrequency - sysclockfrequency));
143
144    /* Get the nearest frequency value to typical one */
145    if (optimumfrequencyerror > frequencyerror)
146    {
147      optimumfrequencyerror = frequencyerror;
148      optimumcalibrationvalue = trimmingvalue;
149      optimumfrequency = measuredfrequency;
150    }
151
152  }
153
154  /* Set trimming bits corresponding to the nearest frequency */
155  HSI16_RCC_AdjustCalibrationValue(__HAL_RCC_GET_SYSCLK_SOURCE(), optimumcalibrationvalue);
156  /* Return the intern oscillator frequency after calibration */
157  printf("calilbration value : %d", optimumcalibrationvalue);
158  measuredfrequency = HSI16_FreqMeasure();
159  printf(":   frequency : %d\n", measuredfrequency);
160  return (optimumfrequency);
161
162}
163
164/**
165  * @brief  Calibrates the internal oscillator (HSI only) with the maximum allowed
166  *         error value set by user.
167  *         If this value was not found, this function sets the oscillator
168  *         to default value.
169  * @param  MaxAllowedError: maximum absolute value allowed of the HSI frequency
170  *                          error given in Hz.
171  * @param  Freq: returns value of calibrated frequency
172  * @retval ErrorStatus:
173  *            - SUCCESS: a frequency error =< MaxAllowedError was found.
174  *            - ERROR: a frequency error =< MaxAllowedError was not found.
175  */
176ErrorStatus HSI16_CalibrateFixedError(uint32_t MaxAllowedError, uint32_t* Freq)
177{
178  uint32_t  measuredfrequency;
179  uint32_t  frequencyerror = 0;
180  uint32_t  sysclockfrequency = 0;
181  uint32_t  trimmingindex = 0;
182  uint32_t  trimmingvalue = 0;
183  uint32_t  numbersteps;
184  int32_t   sign = 1;
185  ErrorStatus calibrationstatus = ERROR;
186
187  /* HSI16TRIM is 7-bit length */
188  numbersteps = 128; /* number of steps is 2^7 = 128 */
189
190  /* Set measurement environment */
191  HSI16_MeasurementInit();
192
193  /* Get system clock frequency */
194  sysclockfrequency = HAL_RCC_GetSysClockFreq();
195
196  /* Start frequency measurement for current trimming value */
197  measuredfrequency = 0;
198
199  /* RC Frequency measurement for different values */
200  for (trimmingindex = 0; trimmingindex < numbersteps; trimmingindex++)
201  {
202    /* Compute trimming value */
203    trimmingvalue = trimmingvalue + (trimmingindex * sign);
204    sign *= (-1);
205
206    /* Set the HSI16TRIM register to trimmingvalue to be ready for measurement */
207    __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(trimmingvalue);
208
209    /* Get actual frequency value */
210    measuredfrequency = HSI16_FreqMeasure();
211
212    /* Compute current frequency error corresponding to the current trimming value:
213       measured value is subtracted from the typical one */
214    frequencyerror = ABS_RETURN((int32_t) (measuredfrequency - sysclockfrequency));
215
216    /* Check if frequency error is less or equal to value set by the user */
217    if (frequencyerror <= MaxAllowedError)
218    {
219      calibrationstatus = SUCCESS; /* The calibration has succeed */
220      break; /* stop searching and measurements for frequencies */
221    }
222  }
223
224  /* Save the new HSI value */
225  *Freq = measuredfrequency;
226
227  /* If the frequency error set by the user was not found */
228  if (calibrationstatus == ERROR)
229  {
230    /* Set the HSI16TRIM register to default value */
231    __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(numbersteps / 2);
232  }
233
234  /* Return the calibration status: ERROR or SUCCESS */
235  return (calibrationstatus);
236}
237
238#ifdef HSI16_MEASURE_FREQUENCY_TABLE
239/**
240  * @brief  For all possible trimming values change of frequency is measured
241  * @retval None.
242  */
243void HSI16_GetCurve(void)
244{
245  uint32_t output;
246  uint32_t measuredfrequency;
247  uint32_t trimmingindex = 0;
248  uint32_t trimmingindexorig;
249  //uint32_t orig_frequency;
250  uint32_t numbersteps;
251  uint32_t x;
252
253  /* Set measurement environment */
254  HSI16_MeasurementInit();
255
256  /* HSI16TRIM is 7-bit length */
257  numbersteps = 128; /* number of steps is 2^7 = 128 */
258
259  /* Keep original values */
260  trimmingindexorig = GET_HSI16_TRIMMING_VALUE();
261  //orig_frequency = HSI16_FreqMeasure();
262
263  /* RC Frequency measurement for different values */
264  for (trimmingindex = 0; trimmingindex < numbersteps; trimmingindex++)
265  {
266    /* Set the HSI16TRIM register to trimmingvalue to be ready for measurement */
267    __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(trimmingindex);
268    /* Start measuring Internal Oscillator frequency */
269    output = 2;
270    while(output == 2)
271    {
272      output = HSI16_FreqMeasure();
273    }
274    measuredfrequency = 0;
275    measuredfrequency += output;
276
277    /* Compute current frequency error corresponding to the current trimming value:
278      measured value is subtracted from the typical one */
279    aFrequenceChangeTable[trimmingindex] =   (int32_t)measuredfrequency;
280    //aFrequenceChangeTable[trimmingindex] =   ((int32_t)(measuredfrequency - orig_frequency));
281    #ifdef PRINT_FREQUENCY_MEASURE_RESULT
282    printf(" %3d, %d\n", trimmingindex, aFrequenceChangeTable[trimmingindex]);
283    #endif
284  }
285
286  /* Set back the original frequency value */
287  __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(trimmingindexorig);
288}
289#endif
290
291#ifdef HSI16_MEASURE_FREQUENCY_TABLE
292/**
293 * @brief  Adjust calibration value (writing to trimming bits) of selected oscillator.
294  * @param  Freq: pointer to an uint32_t variable that will contain the value
295  *               of the internal oscillator frequency after calibration.
296  * @retval ErrorStatus:
297  *            - SUCCESS: successful calibration
298  *            - ERROR: if frequency could not be calibrated
299  */
300ErrorStatus HSI16_CalibrateCurve(uint32_t* Freq)
301{
302
303  uint32_t measuredfrequency;
304  uint32_t optimumcalibrationvalue;
305  uint32_t i;
306  uint32_t frequencyerror;
307  uint32_t numbersteps = 128;
308  uint32_t optimumfrequencyerror = INITIAL_ERROR; /* Large value */
309  ErrorStatus returnvalue = ERROR;
310
311  /* HSI16TRIM is 7-bit length */
312  numbersteps = 128; /* number of steps is 2^7 = 128 */
313
314  /* Get position */
315  measuredfrequency = HSI16_FreqMeasure();
316
317  /* Find the closest difference */
318  for (i = 0; i < numbersteps; i++)
319  {
320    frequencyerror = ABS_RETURN((int32_t) (HSI_VALUE - (int32_t)(measuredfrequency + aFrequenceChangeTable[i])));
321
322    /* Get the nearest frequency value to typical one */
323    if (frequencyerror < optimumfrequencyerror)
324    {
325      optimumfrequencyerror = frequencyerror;
326      optimumcalibrationvalue = i;
327    }
328  }
329
330  if (optimumfrequencyerror != INITIAL_ERROR)
331  {
332    __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(optimumcalibrationvalue);
333    /* Save the HSI measured value */
334    *Freq = measuredfrequency + aFrequenceChangeTable[optimumcalibrationvalue];
335    returnvalue = SUCCESS;
336  }
337
338  return returnvalue;
339}
340#endif
341
342/**
343  * @brief Measures actual value of HSI
344  * @param  None.
345  * @retval Actual HSI frequency
346  */
347static uint32_t frequencyMW;
348static int32_t loopCounter;
349
350uint32_t HSI16_FreqMeasure(void)
351{
352  uint32_t  measuredfrequency;
353  //uint32_t  timeout = HSI16_TIMEOUT;
354
355  /* Start frequency measurement for current trimming value */
356
357  /* Start measuring Internal Oscillator frequency */
358   
359  // EDIT ECS:
360  // state machine einbauen um Blocken des Programmablaufes durch die while() Schleife zu verhindern
361  // state machine ist schon da (globale var "CaptureState")
362 
363  if(CaptureState == CAPTURE_READY_FOR_NEW)
364  {
365    CaptureState = CAPTURE_START;
366
367    /* Enable capture 1 interrupt */
368    HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_y);
369
370    /* Enable the TIMx IRQ channel */
371    HAL_NVIC_EnableIRQ(TIMx_IRQn);
372    // Return Capture Start
373    return CAPTURE_ONGOING;
374  }
375
376  else if(CaptureState != CAPTURE_COMPLETED)
377  {
378    // Return Capture Ongoing
379    return CAPTURE_ONGOING;
380  }
381  /* Wait for end of capture: two consecutive captures */
382 
383  else if(CaptureState == CAPTURE_COMPLETED)
384  {
385   
386    /* Disable IRQ channel */
387    HAL_NVIC_DisableIRQ(TIMx_IRQn);
388
389    /* Disable TIMx */
390    HAL_TIM_IC_Stop_IT(&TimHandle, TIM_CHANNEL_y);
391
392    CaptureState = CAPTURE_READY_FOR_NEW;
393
394    if (loopCounter != 0)
395    {
396        /* Compute the frequency (the Timer prescaler isn't included) */
397        frequencyMW += (uint32_t) (REFERENCE_FREQUENCY * Capture);
398    }
399
400    if(loopCounter < HSI16_NUMBER_OF_LOOPS)
401    {
402      /* Increment loop counter */
403      loopCounter++;
404      return CAPTURE_ONGOING;
405    }
406    /* END of Measurement */
407    else
408    {
409      measuredfrequency = 0;
410      loopCounter = 0;
411      /* Compute the average value corresponding the current trimming value */
412      measuredfrequency = (uint32_t)((__HAL_GET_TIM_PRESCALER(&TimHandle) + 1) * (frequencyMW / HSI16_NUMBER_OF_LOOPS));
413      frequencyMW = 0;
414      return measuredfrequency;
415    }
416  }
417  return 0;
418}
419
420/**
421  * @brief Configures all the necessary peripherals necessary from frequency calibration.
422  * @param  None.
423  * @retval None.
424  */
425void HSI16_MeasurementInit(void)
426{
427
428  /* Configure the GPIO ports before starting calibration process */
429  //GPIO_ConfigForCalibration();
430
431  /* Configure clock before starting calibration process */
432  //CLK_ConfigForCalibration();
433
434  /* Configure TIMx before starting calibration process */
435  HSI16_TIMx_ConfigForCalibration();
436  CaptureState = CAPTURE_READY_FOR_NEW;
437}
438
439/**
440  * @brief Configures the TIMx in input capture to measure HSI frequency.
441  * @param  None.
442  * @retval None.
443  */
444void HSI16_TIMx_ConfigForCalibration(void)
445{
446  TIM_IC_InitTypeDef      ic_config; /* Timer Input Capture Configuration Structure declaration */
447
448  /* Enable TIMx clock */
449  __TIMx_CLK_ENABLE();
450
451  /* Set TIMx instance */
452  TimHandle.Instance = TIMx;
453
454  /* Reset TIMx registers */
455  HAL_TIM_IC_DeInit(&TimHandle);
456
457  /* Initialize TIMx peripheral as follows:
458       + Period = 0xFFFF
459       + Prescaler = 0
460       + ClockDivision = 0
461       + Counter direction = Up
462  */
463  TimHandle.Init.Period            = 0xFFFF;
464  TimHandle.Init.Prescaler         = HSI16_TIMx_COUNTER_PRESCALER;
465  TimHandle.Init.ClockDivision     = 0;
466  TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
467  if (HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
468  {
469    /* Initialization Error */
470    while(1);
471  }
472
473  /* Configure the Input Capture of channel y */
474  ic_config.ICPolarity  = TIM_ICPOLARITY_RISING;
475  ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI;
476  ic_config.ICPrescaler = HSI16_TIMx_IC_DIVIDER;
477  ic_config.ICFilter    = 0;
478  if (HAL_TIM_IC_ConfigChannel(&TimHandle, &ic_config, TIM_CHANNEL_y) != HAL_OK)
479  {
480    /* Configuration Error */
481    while(1);
482  }
483
484// EDIT ECS START
485  // Timer Input Source Selection
486  // LSE als Timer Input
487  if (HAL_TIMEx_TISelection(&TimHandle, TIM_TIM16_TI1_LSE, TIM_CHANNEL_1) != HAL_OK)
488  {
489    while(1);
490  }
491// EDIT ECS END
492
493  /* Configure the NVIC for TIMx */
494  HAL_NVIC_SetPriority(TIMx_IRQn, 0, 0);
495
496  /* Disable the TIMx global Interrupt */
497  HAL_NVIC_DisableIRQ(TIMx_IRQn);
498
499}
500
501
502/**
503  * @brief  Adjust calibration value (writing to trimming bits) of selected oscillator.
504  * @param  InternOsc: Internal Oscillator source: HSI
505  * @param  TrimmingValue: calibration value to be written in trimming bits.
506  * @retval None.
507  */
508void HSI16_RCC_AdjustCalibrationValue(uint8_t InternOsc, uint8_t TrimmingValue)
509{
510  __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(TrimmingValue);
511}
512
513/**
514  * @brief  Configures LSE to be used as RTC clock source
515  * @param  None.
516  * @retval None.
517  */
518void CLK_ConfigForCalibration(void)
519{
520
521  /* Enable the LSE OSC */
522  __HAL_RCC_LSE_CONFIG(RCC_LSE_ON);
523
524  /* Wait till LSE is ready */
525  while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
526  {}
527}
528
529
530/**
531  * @brief  Conversion complete callback in non blocking mode
532  * @param  htim : hadc handle
533  * @retval None
534  */
535void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
536{
537
538  if ((htim->Channel) == HAL_TIM_ACTIVE_CHANNEL_y)
539  {
540    if (CaptureState == CAPTURE_START)
541    {
542      /* Get the 1st Input Capture value */
543      IC1ReadValue1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_y);
544      //htim->Instance->CNT = 0;
545      CaptureState = CAPTURE_ONGOING;
546    }
547    else if (CaptureState == CAPTURE_ONGOING)
548    {
549      /* Get the 2nd Input Capture value */
550      IC1ReadValue2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_y);
551
552      // Timer interrupt ausschalten sonst treten Fehler auf
553      HAL_NVIC_DisableIRQ(TIMx_IRQn);
554      HAL_TIM_IC_Stop_IT(&TimHandle, TIM_CHANNEL_y);
555      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
556
557      /* Capture computation */
558      if (IC1ReadValue2 > IC1ReadValue1)
559      {
560        Capture = (IC1ReadValue2 - IC1ReadValue1);
561        if(REFERENCE_FREQUENCY * Capture < 13000000)
562        {
563          printf("Value not valid\n");
564          printf("Frequency Measured = %d\n", REFERENCE_FREQUENCY * Capture);
565          //while(1);
566        }
567      }
568      else if (IC1ReadValue2 < IC1ReadValue1)
569      {
570        Capture = ((0xFFFF - IC1ReadValue1) + IC1ReadValue2);
571        if(REFERENCE_FREQUENCY * Capture < 13000000)
572        {
573          printf("Value not valid\n");
574          printf("Frequency Measured = %d\n", REFERENCE_FREQUENCY * Capture);
575        }
576      }
577      else
578      {
579        /* If capture values are equal, we have reached the limit of frequency
580        measures */
581        while(1);
582      }
583
584      CaptureState = CAPTURE_COMPLETED;
585    }
586  }
587}
588
589/**
590  * @}
591  */
592
593void frequencyErrorTest(void)
594{   
595  uint32_t  HSIFrequencyBeforeCalib, highVal, lowVal;
596  highVal = 0;
597  lowVal = 20000000;
598  HSI16_MeasurementInit();
599  while(1)
600  {
601    HSIFrequencyBeforeCalib = 2;
602    while(HSIFrequencyBeforeCalib == 2)
603    {
604      HSIFrequencyBeforeCalib = HSI16_FreqMeasure();
605    }
606   
607    if(HSIFrequencyBeforeCalib > highVal)
608    {
609      highVal = HSIFrequencyBeforeCalib;
610      printf("highest frequency %d\n",highVal);
611      printf("lowest  frequency %d\n",lowVal);
612    }
613    if(HSIFrequencyBeforeCalib < lowVal)
614    {
615      lowVal = HSIFrequencyBeforeCalib;
616      printf("highest frequency %d\n",highVal);
617      printf("lowest  frequency %d\n",lowVal);
618    }
619  }
620}
621/******************* (C) COPYRIGHT 2014 STMicroelectronics *****END OF FILE****/
Note: See TracBrowser for help on using the repository browser.