/**
  ******************************************************************************
  * @file    main.c
  *
  * @brief   Выполняется однократный запуск преобразования 0 канала.
  *          Будет произведено 48 измерений, который через DMA будут записаны
  *          в массив. DMA по окончанию передач вызвывает прерывание, в котором
  *          устанавливает флаг, разрешающий вывод результатов измерений через
  *          UART2.
  *
  *          Компилятор: GCC ARM 4.9.3
  *          Среда: Qt Creator 3.4.2
  *
  * @author  НИИЭТ
  *             - Богдан Колбов (bkolbov), kolbov@niiet.ru
  * @date    23.12.2015
  *
  ******************************************************************************
  * @attention
  *
  * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО
  * ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
  * ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ
  * НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
  * ПРЕДНАЗНАЧЕНО ДЛЯ ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЕЙ И НАПРАВЛЕНО ТОЛЬКО НА
  * ПРЕДОСТАВЛЕНИЕ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ О ПРОДУКТЕ, С ЦЕЛЬЮ СОХРАНИТЬ ВРЕМЯ
  * ПОТРЕБИТЕЛЮ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
  * ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА ПРЯМОЙ ИЛИ КОСВЕННЫЙ УЩЕРБ, ИЛИ
  * ПО ИНЫМ ТРЕБО ВАНИЯМ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
  * ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
  *
  * <h2><center>&copy; 2015 ОАО "НИИЭТ"</center></h2>
  ******************************************************************************
  */

#include "niietcm4.h"
#include "retarget.h"

// общее количество измерений
#define ADC_MEASURE_TOTAL   48

DMA_ConfigData_TypeDef DMA_CONFIGDATA __attribute__ ((aligned (1024)));

uint32_t seq0_arr[ADC_MEASURE_TOTAL];

void SystemInit()
{
    // переходим на системную частоту 72МГц
    RCC_PLLAutoConfig(RCC_PLLRef_XI_OSC, 72000000);

    // инициализация printf
    retarget_init();

    // хак, чтобы избежать зависших секвенсоров от выставленных запросов по 0 каналу
    // цифровыми компараторами. Хотя в данном случае это необязательно, т.к. 0-ой канал используется.
    for (uint32_t i = 0; i < 24; i++)
    {
        ADC_DC_DeInit((ADC_DC_Module_TypeDef)i);
    }

    // включаем тактирование 0-модуля ацп (0 и 1 каналы)
    // делим системную частоту на 6, и получаем тактирование АЦП 12МГц.
    RCC_ADCClkDivConfig(RCC_ADCClk_0, 2, ENABLE);
    RCC_PeriphClkCmd(RCC_PeriphClk_ADC, ENABLE);
    RCC_ADCClkCmd(RCC_ADCClk_0, ENABLE);

    // настройка модуля АЦП
    ADC_Init_TypeDef ADC_InitStruct;
    ADC_StructInit(&ADC_InitStruct);
    ADC_InitStruct.ADC_Resolution = ADC_Resolution_12bit;
    ADC_InitStruct.ADC_Average = ADC_Average_64;
    ADC_InitStruct.ADC_Mode = ADC_Mode_Active;
    ADC_Init(ADC_Module_0, &ADC_InitStruct);
    // включение модуля АЦП
    ADC_Cmd(ADC_Module_0, ENABLE);

    // секвенсор 0 работает по программному запросу
    ADC_SEQ_Init_TypeDef ADC_SEQ_InitStruct;
    ADC_SEQ_StructInit(&ADC_SEQ_InitStruct);
    ADC_SEQ_InitStruct.ADC_SEQ_ConversionCount = ADC_MEASURE_TOTAL;
    ADC_SEQ_InitStruct.ADC_SEQ_StartEvent = ADC_SEQ_StartEvent_SWReq;
    ADC_SEQ_InitStruct.ADC_Channels = ADC_Channel_0;
    ADC_SEQ_Init(ADC_SEQ_Module_0, &ADC_SEQ_InitStruct);
    ADC_SEQ_DMAConfig(ADC_SEQ_Module_0, ADC_SEQ_FIFOLevel_16);

    // включаем генерацию запросов DMA секвенсора
    ADC_SEQ_DMACmd(ADC_SEQ_Module_0, ENABLE);

    // включаем секвенсор
    ADC_SEQ_Cmd(ADC_SEQ_Module_0, ENABLE);

    // Инцииализация DMA
    // Базовый указатель
    DMA_BasePtrConfig((uint32_t)(&DMA_CONFIGDATA));
    // Инициализация каналов
    DMA_ChannelInit_TypeDef DMA_ChannelInitStruct;
    DMA_ChannelStructInit(&DMA_ChannelInitStruct);
    DMA_ChannelInitStruct.DMA_SrcDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_DstDataSize = DMA_DataSize_32;
    DMA_ChannelInitStruct.DMA_ArbitrationRate = DMA_ArbitrationRate_1;
    DMA_ChannelInitStruct.DMA_Mode = DMA_Mode_Basic;
    DMA_ChannelInitStruct.DMA_SrcDataInc = DMA_DataInc_Disable;
    DMA_ChannelInitStruct.DMA_DstDataInc = DMA_DataInc_32;
    // DMA8 - SEQ0
    DMA_ChannelInitStruct.DMA_TransfersTotal = ADC_MEASURE_TOTAL;
    DMA_ChannelInitStruct.DMA_SrcDataEndPtr = (uint32_t *)(&NT_ADC->SEQ[0].FIFO);
    DMA_ChannelInitStruct.DMA_DstDataEndPtr = &(seq0_arr[ADC_MEASURE_TOTAL-1]);
    DMA_ChannelInit(&DMA_CONFIGDATA.PRM_DATA.CH[8], &DMA_ChannelInitStruct);

    // Инциализация контроллера DMA
    DMA_Init_TypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_Channel = DMA_Channel_ADCSEQ0;
    DMA_InitStruct.DMA_ChannelEnable = ENABLE;
    DMA_Init(&DMA_InitStruct);
    DMA_MasterEnableCmd(ENABLE);

    // NVIC прерывание dma
    NVIC_EnableIRQ(DMA_Stream8_IRQn);
}

volatile uint32_t dma_irq_flag = 0;

int main()
{
    // вывод проверялся в minicom под Linux
    // если информация отображается некорректно в вашей программе, то следует
    // закомментировать те prinf в которых используются escape-последовательсности
    printf("\x1b[0J"); //очистка терминала от текущего положения курсора до конца экрана
    printf("Start!\n");

    // запускаем измерения
    ADC_SEQ_SWReq();

    // ждем пока все измерения не пройдут
    // и dma не закончит все передачи
    while (!dma_irq_flag);

    printf("Measure results from channel 0:\n");
    for (uint32_t i = 0; i < ADC_MEASURE_TOTAL; i++)
    {
        printf("%02d: %04d\n", i, seq0_arr[i]);
    }

    printf("End!\n");
    printf("\x1b[%dA", (ADC_MEASURE_TOTAL+3)); // переводим курсор на начальную позицию вывода значений
    while(1);
}

void DMA_Stream8_IRQHandler()
{
   dma_irq_flag = 1;
}

