/**
  ******************************************************************************
  * @file    Project/Internal_OSC_Calib/src/MSIMeasurement.c
  * @author  MCD Application Team
  * @version V1.1.0
  * @date    24-January-2012
  * @brief   This file provides all the MSI 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 "MSIMeasurement.h"
#include "main.h"

/** @addtogroup Internal_OSC_Calib
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
NVIC_InitTypeDef NVIC_InitStructureForMSI;

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

/**
  * @brief  Measures the MSI clock frequency using TIM11 capture interrupt.
            MSI is set to range 1 MHz.
  * @param  InternOscFrequency: The system clock source value:
            In case of using HSI oscillator as system clock source:
             InternOscFrequency should be 16 MHz (or a more accurate value).
  * @retval The measured frequency of MSI oscillator.
  */
uint32_t MSI_FreqMeasure(uint32_t InternOscFrequency)
{
  uint32_t measuredfrequency = 0;
  uint8_t loopcounter = 0;

  /* Configure clock for MSI measurement process */
  CLK_ConfigForMSI();
  /* Configure GPIO for MSI measurement process */
  GPIO_ConfigForMSI();
  /* Configure TIM11 for MSI measurement process */
  TIM11_ConfigForMSI();

  /* Set MSI range to 1 Mhz */
  RCC_MSIRangeConfig(RCC_MSIRange_4);

  /* reset counter */
  loopcounter = 0;
  /**************************** START of MSI Measurement **********************/
  while (loopcounter <= MSI_PERIOD_NUMBERS)
  {
    CaptureState = CAPTURE_START;
    /* Generate update */
    TIM_GenerateEvent(TIM11, TIM_EventSource_Update);
    /* Clear all TM10 flags */
    TIM11->SR = 0;
    /* Enable capture 1 interrupt */
    TIM_ITConfig(TIM11, TIM_IT_CC1, ENABLE);
    /* Enable TIM */
    TIM_Cmd(TIM11, ENABLE);

    /* Enable the TIM11 global Interrupt */
    NVIC_InitStructureForMSI.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructureForMSI);

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

    /* Disable IRQ channel */
    NVIC_InitStructureForMSI.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&NVIC_InitStructureForMSI);
    /* Disable TIM11 */
    TIM_Cmd(TIM11, 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 MSI Measurement ************************/

  /* Compute the average of MSI frequency value */
  measuredfrequency = (uint32_t) (measuredfrequency / MSI_PERIOD_NUMBERS);

  /* Return the MSI frequency */
  return (uint32_t)(measuredfrequency);
}

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

  /* Enable TIM11 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM11, ENABLE);

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

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

  /* Connect MSI clock to TIM11 Input Capture 1 */
  TIM_RemapConfig(TIM11, TIM11_MSI);

  /* TIM11 configuration: Input Capture mode ---------------------
     The reference clock(LSE or external) is connected to TIM11 CH1
     The Rising edge is used as active edge,
     The TIM11 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(TIM11, &TIM_ICInitStructure);

  /* Enable the TIM11 global Interrupt */
  NVIC_InitStructureForMSI.NVIC_IRQChannel = TIM11_IRQn;
  NVIC_InitStructureForMSI.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructureForMSI.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructureForMSI.NVIC_IRQChannelCmd = DISABLE;
  NVIC_Init(&NVIC_InitStructureForMSI);
}

/**
  * @brief  Configures the clock: set prescalers to 1, Enable MSI oscillator
  * @param  None.
  * @retval None.
  */
void CLK_ConfigForMSI(void)
{
  /* Set AHB and APB2 prescalers to 1 so TIM11 is clocked by SYSCLK (no divider) */
  RCC_HCLKConfig(RCC_SYSCLK_Div1);
  RCC_PCLK2Config(RCC_HCLK_Div1);

  /* Enable MSI clock */
  RCC_MSICmd(ENABLE);
  /* Wait for MSI clock to be ready */
  while (RCC_GetFlagStatus(RCC_FLAG_MSIRDY) == RESET);
}

/**
  * @brief Configures the GPIO: configure each used I/O in the suitable setting
  * @param None.
  * @retval None.
  */
void GPIO_ConfigForMSI(void)
{
#ifdef OUTPUT_MSI_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 MSI on MCO pin */
  RCC_MCOConfig(RCC_MCOSource_MSI, RCC_MCODiv_1);
#endif /* OUTPUT_MSI_ON_MCO */
}

/**
  * @}
  */ 

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