/**
  ******************************************************************************
  * @file    Project/Internal_OSC_Calib/src/LSIMeasurement.c
  * @author  MCD Application Team
  * @version V1.1.0
  * @date    24-January-2012
  * @brief   This file provides all the LSI Measurement firmware functions.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * FOR MORE INFORMATION PLEASE READ CAREFULLY THE LICENSE AGREEMENT FILE
  * LOCATED IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE.
  *
  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32l1xx.h"
#include "LSIMeasurement.h"
#include "main.h"

/** @addtogroup Internal_OSC_Calib
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
NVIC_InitTypeDef NVIC_InitStructureForLSI;

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Measures the LSI clock frequency using TIM10 capture interrupt.
  * @param  The system clock source value:
  *         In case of using HSI oscillator as system clock source:
  *         InternOscFrequency should be 16000000 (or a more accurate value.
  *         In case of using HSI oscillator as system clock source:
  *         InternOscFrequency should correspond to the selected range (or a more accurate value).
  * @retval The LSI frequency value.
  */
uint16_t LSI_FreqMeasure(uint32_t InternOscFrequency)
{
  uint32_t measuredfrequency = 0;
  uint8_t loopcounter = 0;

  /* Configure CLK for LSI measurement process */
  CLK_ConfigForLSI();
  
  /* Configure GPIO for LSI measurement process: Output LSI on MCO */
  GPIO_ConfigForLSI();

  /* Configure TIM10 for LSI measurement process */
  TIM10_ConfigForLSI();

  /* Reset counter */
  loopcounter = 0;
  
  /**************************** START of LSI Measurement **********************/
  while (loopcounter <= LSI_PERIOD_NUMBERS)
  {
    CaptureState = CAPTURE_START;

    /* Generate update */
    TIM_GenerateEvent(TIM10, TIM_EventSource_Update);

    /* Clear all TM10 flags */
    TIM10->SR = 0;

    /* Enable capture 1 interrupt */
    TIM_ITConfig(TIM10, TIM_IT_CC1, ENABLE);

    /* Enable TIM */
    TIM_Cmd(TIM10, ENABLE);

    /* Enable the TIM10 global Interrupt */
    NVIC_InitStructureForLSI.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructureForLSI);

    /* Wait for end of capture: two consecutive captures */
    while(CaptureState != CAPTURE_COMPLETED);

    /* Disable IRQ channel */
    NVIC_InitStructureForLSI.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&NVIC_InitStructureForLSI);
    
    /* Disable TIM10 */
    TIM_Cmd(TIM10, DISABLE);

    if (loopcounter != 0)
    {
      /* Compute the frequency value: multiplying by 8 is due to TIM_ICPSC_DIV8 */
      /* Then add the current frequency to previous cumulation */
      measuredfrequency += (uint32_t) 8 * (InternOscFrequency / Capture);
    }
    
    /* Increment counter */
    loopcounter++;
  }
  /**************************** END of LSI Measurement ************************/

  /* Compute the average of LSI frequency value */
  measuredfrequency = (uint16_t) (measuredfrequency / LSI_PERIOD_NUMBERS);

  /* Return the LSI frequency */
  return (uint16_t)(measuredfrequency);
}

/**
  * @brief  Configures the TIM 10 channel 1 in input capture to measure the LSI oscillator.
  * @param  None.
  * @retval None.
  */
void TIM10_ConfigForLSI(void)
{
  TIM_ICInitTypeDef  TIM_ICInitStructure;

  /* Enable TIM10 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);

  /* Reset TIM10 registers */
  TIM_DeInit(TIM10);

  /* Configure TIM10 prescaler */
  TIM_PrescalerConfig(TIM10, 0, TIM_PSCReloadMode_Immediate);

  /* Connect LSI clock to TIM10 Input Capture 1 */
  TIM_RemapConfig(TIM10, TIM10_LSI);

  /* TIM10 configuration: Input Capture mode ---------------------
     The reference clock(LSE or external) is connected to TIM10 CH1
     The Rising edge is used as active edge,
     The TIM10 CCR1 is used to compute the frequency value 
  ------------------------------------------------------------ */
  TIM_ICInitStructure.TIM_Channel     = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICPolarity  = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_ICInit(TIM10, &TIM_ICInitStructure);

  /* Enable the TIM10 global Interrupt */
  NVIC_InitStructureForLSI.NVIC_IRQChannel = TIM10_IRQn;
  NVIC_InitStructureForLSI.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructureForLSI.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructureForLSI.NVIC_IRQChannelCmd = DISABLE;
  NVIC_Init(&NVIC_InitStructureForLSI);
}

/**
  * @brief  Configures the clock: set prescaler, enable LSI
  * @param  None.
  * @retval None.
  */
void CLK_ConfigForLSI(void)
{
  /* Set AHB and APB2 prescalers to 1 so TIM10 is clocked by SYSCLK (no divider) */
  RCC_HCLKConfig(RCC_SYSCLK_Div1);
  RCC_PCLK2Config(RCC_HCLK_Div1);

  /* Enable LSI clock */
  RCC_LSICmd(ENABLE);
  
  /* Wait for LSI clock to be ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {
  }
}

/**
  * @brief  Configures the GPIO: configure PA8 in Alternate function (MCO)
  * @param  None.
  * @retval None.
  */
void GPIO_ConfigForLSI(void)
{
#ifdef OUTPUT_LSI_ON_MCO

  GPIO_InitTypeDef GPIO_InitStructure;
  
  /* Enable the GPIOA peripheral */ 
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  /* Output the system clock on MCO pin (PA.08) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /* Select PA8 as MCO pin */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_MCO);

  /* Output LSI on MCO pin */
  RCC_MCOConfig(RCC_MCOSource_LSI, RCC_MCODiv_1);
  
#endif /* OUTPUT_INTERNOSC_ON_MCO */
}

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2012 STMicroelectronics *****END OF FILE****/
