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

Last change on this file since 20 was 6, checked in by f.jahn, 8 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.