/**
  ******************************************************************************
  * @file    VAPC-meter/lib/adc.c
  * @author  "Vladimir N. Shilov" <shilow@ukr.net>
  * @version V1
  * @date    24-March-2016
  * @brief   This file contains the ADC functions.
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "adc.h"

/** @addtogroup ADC
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint16_t Buffer[BUFFER_SIZE]  = {0, 0};
uint16_t Voltage = 0;
uint16_t Current = 0;
uint16_t RefVolt = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void ADC_Config(void);
static void DMA_Config(void);
static void TIM2_Config(void);

/* Public functions ----------------------------------------------------------*/

/**
  * @brief  Initialize and start ADC
  * @param  None
  * @retval None
  */
void Init_ADC(void)
{
    /* ADC configuration */
    ADC_Config();
    /* DMA configuration */
    DMA_Config();
    /* TIM2 configuration */
    TIM2_Config();

    /* Enable ADC1 DMA requests*/
    ADC_DMACmd(ADC1, ENABLE);

    /* Start ADC1 Conversion using TIM1 TRGO*/
    ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger3,
                         ADC_ExtTRGSensitivity_Rising);

    /* Master Mode selection: Update event */
    TIM2_SelectOutputTrigger(TIM2_TRGOSource_Update);

    /* Enable TIM2 */
    TIM2_Cmd(ENABLE);

}

/**
  * @brief  Configure ADC peripheral
  * @param  None
  * @retval None
  */
static void ADC_Config(void)
{
  /* Enable ADC1 clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);

  /* Initialize and configure ADC1 */
  ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles);
  ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_384Cycles);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 Voltage meter channel */
  ADC_ChannelCmd(ADC1, VOLTAGE_CHANNEL, ENABLE);
  ADC_SchmittTriggerConfig(ADC1, VOLTAGE_CHANNEL, DISABLE);
  /* Enable ADC1 Current meter channel */
  ADC_ChannelCmd(ADC1, CURRENT_CHANNEL, ENABLE);
  ADC_SchmittTriggerConfig(ADC1, CURRENT_CHANNEL, DISABLE);

  /* ADC Voltage Reference */
  ADC_VrefintCmd(ENABLE);
  /* Enable ADC1 Vrefint Channel */
  ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE);
}

/**
  * @brief  Configure DMA peripheral
  * @param  None
  * @retval None
  */
static void DMA_Config(void)
{
  /* Enable DMA1 clock */
  CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);

  /* Connect ADC to DMA channel 0 */
  SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0);

  DMA_Init(DMA1_Channel0, BUFFER_ADDRESS,
           ADC1_DR_ADDRESS,
           BUFFER_SIZE,
           DMA_DIR_PeripheralToMemory,
           DMA_Mode_Circular,
           DMA_MemoryIncMode_Inc,
           DMA_Priority_High,
           DMA_MemoryDataSize_HalfWord);

  /* DMA Channel0 enable */
  DMA_Cmd(DMA1_Channel0, ENABLE);

  /* Enable DMA1 channel0 Transfer complete interrupt */
  DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE);

  /* DMA enable */
  DMA_GlobalCmd(ENABLE);
}

/**
  * @brief  Configure TIM2 peripheral
  * @param  None
  * @retval None
  */
static void TIM2_Config(void)
{
    /* Enable TIM2 clock */
    CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);

    //Волшебное число 1250 получилось так:
    // Частота МК (16 МHz) / Предделитель таймера (128) * Нужное время в секундах (0.01)
    TIM2->ARRH = 1250>>8; //Записываем сначала старший байт
    TIM2->ARRL = (uint8_t)(1250); //Потом младший
    TIM2->CR1 |= TIM_CR1_URS; //Настраиваем источник события update
//    TIM2->CR2 |= (2<<4); //Настраиваем на подачу сигнала для АЦП при переполнении таймера == TIM2_TRGOSource_Update
    TIM2->PSCR = 7; //Предделитель = 2^7 = 128
    TIM2->EGR |= TIM_EGR_UG;  //Генерим событие update, чтобы обновился предделитель
    TIM2->CR1 |= TIM_CR1_CEN; //Запускаем
}

/**
  * @}
  */

/************************ (C) Vladimir N. Shilov *****END OF FILE****/
