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

#include "niietcm4.h"

/*
 * Функция настройки PWM0
 * PWM_A0 - меандр 1МГц
 */
void PWM0_Init()
{
    PWM_CTR_Init_TypeDef PWM_CTR_InitStruct;
    GPIO_Init_TypeDef GPIO_InitStruct;

    //включаем тактирование и выводим из сброса
    RCC_PeriphClkCmd(RCC_PeriphClk_PWM0, ENABLE);
    RCC_PeriphRstCmd(RCC_PeriphRst_PWM0, ENABLE);

    //настраиваем таймер
    PWM_CTR_StructInit(&PWM_CTR_InitStruct);
    //инверсия вывода каждый раз при равенстве таймера периоду
    PWM_CTR_InitStruct.PWM_ChAction_CTREqPeriod_A = PWM_ChAction_Inv;
    PWM_CTR_InitStruct.PWM_CTR_Mode = PWM_CTR_Mode_Up;
    // тактовую частоту 100МГц делим на 10 чтобы получить TBCLK=10МГц
    PWM_CTR_InitStruct.PWM_ClkDiv = PWM_ClkDiv_1;
    PWM_CTR_InitStruct.PWM_ClkDivExtra = PWM_ClkDivExtra_10;
    // период задаем таким, чтобы получить меандр 1МГц
    PWM_CTR_InitStruct.PWM_Period = 4;
    PWM_CTR_Init(NT_PWM0, &PWM_CTR_InitStruct);

    //настраиваем пины
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; //PWM_A0
    GPIO_Init(NT_GPIOG, &GPIO_InitStruct);
}

/*
 * Функция настройки PWM1
 * PWM_B1 - шим 50кГц заполнение 2/3
 */
void PWM1_Init()
{
    PWM_CTR_Init_TypeDef PWM_CTR_InitStruct;
    GPIO_Init_TypeDef GPIO_InitStruct;
    PWM_CMP_Init_TypeDef PWM_CMP_InitStruct;

    //включаем тактирование и выводим из сброса
    RCC_PeriphClkCmd(RCC_PeriphClk_PWM1, ENABLE);
    RCC_PeriphRstCmd(RCC_PeriphRst_PWM1, ENABLE);

    //настраиваем таймер
    PWM_CTR_StructInit(&PWM_CTR_InitStruct);
    PWM_CTR_InitStruct.PWM_ChAction_CTREqPeriod_B = PWM_ChAction_ToOne;
    PWM_CTR_InitStruct.PWM_CTR_Mode = PWM_CTR_Mode_Up;
    // тактовую частоту 100МГц делим на 20 чтобы получить TBCLK=5МГц
    PWM_CTR_InitStruct.PWM_ClkDiv = PWM_ClkDiv_2;
    PWM_CTR_InitStruct.PWM_ClkDivExtra = PWM_ClkDivExtra_10;
    // период задаем таким, чтобы получить частоту ШИМ 50кГц
    PWM_CTR_InitStruct.PWM_Period = 99;
    PWM_CTR_Init(NT_PWM1, &PWM_CTR_InitStruct);

    //настраиваем компаратор
    PWM_CMP_StructInit(&PWM_CMP_InitStruct);
    PWM_CMP_InitStruct.PWM_ChAction_CTREqCMPB_Up_B = PWM_ChAction_ToZero;
    PWM_CMP_InitStruct.PWM_CMPB = 66; // 2/3 от периода
    PWM_CMP_Init(NT_PWM1, &PWM_CMP_InitStruct);

    //настраиваем пины
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; //PWM_B1
    GPIO_Init(NT_GPIOF, &GPIO_InitStruct);
}

/*
 * Функция настройки PWM2
 * PWM_A2 - шим 50кГц с изменяемым в прерывании заполнением
 */
void PWM2_Init()
{
    PWM_CTR_Init_TypeDef PWM_CTR_InitStruct;
    GPIO_Init_TypeDef GPIO_InitStruct;
    PWM_CMP_Init_TypeDef PWM_CMP_InitStruct;

    //включаем тактирование и выводим из сброса
    RCC_PeriphClkCmd(RCC_PeriphClk_PWM2, ENABLE);
    RCC_PeriphRstCmd(RCC_PeriphRst_PWM2, ENABLE);

    //настраиваем таймер
    PWM_CTR_StructInit(&PWM_CTR_InitStruct);
    PWM_CTR_InitStruct.PWM_ChAction_CTREqPeriod_A = PWM_ChAction_ToOne;
    PWM_CTR_InitStruct.PWM_CTR_Mode = PWM_CTR_Mode_Up;
    // тактовую частоту 100МГц делим на 20 чтобы получить TBCLK=5МГц
    PWM_CTR_InitStruct.PWM_ClkDiv = PWM_ClkDiv_2;
    PWM_CTR_InitStruct.PWM_ClkDivExtra = PWM_ClkDivExtra_10;
    // период задаем таким, чтобы получить частоту ШИМ 50кГц
    PWM_CTR_InitStruct.PWM_Period = 99;
    PWM_CTR_Init(NT_PWM2, &PWM_CTR_InitStruct);

    //настраиваем компаратор
    PWM_CMP_StructInit(&PWM_CMP_InitStruct);
    PWM_CMP_InitStruct.PWM_LoadMode_CMPA = PWM_LoadMode_Shadow;
    PWM_CMP_InitStruct.PWM_LoadEvent_CMPA = PWM_LoadEvent_CTREqPeriod;
    PWM_CMP_InitStruct.PWM_ChAction_CTREqCMPA_Up_A = PWM_ChAction_ToZero;
    PWM_CMP_InitStruct.PWM_CMPA = 9; // 10% от периода изначально
    PWM_CMP_Init(NT_PWM2, &PWM_CMP_InitStruct);

    //настраиваем прерывание на каждое 4ое равенство счетчика периоду
    PWM_ITConfig(NT_PWM2, PWM_Event_CTREqPeriod, 3);
    PWM_ITCmd(NT_PWM2, ENABLE);
    NVIC_EnableIRQ(PWM2_IRQn);

    //настраиваем пины
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
    GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
    GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; //PWM_A2
    GPIO_Init(NT_GPIOG, &GPIO_InitStruct);
}

void SystemInit()
{
    //выводим мк на максимальную частоту
    RCC_PLLAutoConfig(RCC_PLLRef_XI_OSC, 100000000);

    //настройка ШИМ
    PWM0_Init();
    PWM1_Init();
    PWM2_Init();

    //включаем предделители - таймеры начнут счет
    PWM_PrescCmd(PWM_Presc_0 |
                 PWM_Presc_1 |
                 PWM_Presc_2, ENABLE);
}

int main()
{
    while(1);
}

/*
 *  В прерывании изменяем значение компаратора по 10% в режиме вверх-вниз.
 *  Заполнение ШИМ будет изменяться от 10% до 90%, и от 90% до 10% циклически
 */
volatile uint32_t PWM2_CMPAInc = 1;
void PWM2_IRQHandler()
{
    PWM_ITStatusClear(NT_PWM2);

    if ((PWM_CMP_GetA(NT_PWM2) > 9) && (PWM_CMP_GetA(NT_PWM2) < 89))
    {
        if (PWM2_CMPAInc)
        {
            PWM_CMP_SetA(NT_PWM2, PWM_CMP_GetA(NT_PWM2)+10);
        }
        else
        {
            PWM_CMP_SetA(NT_PWM2, PWM_CMP_GetA(NT_PWM2)-10);
        }
    }
    else if (PWM_CMP_GetA(NT_PWM2) == 89)
    {
        PWM2_CMPAInc = 0;
        PWM_CMP_SetA(NT_PWM2, 79);
    }
    else if (PWM_CMP_GetA(NT_PWM2) == 9)
    {
        PWM2_CMPAInc = 1;
        PWM_CMP_SetA(NT_PWM2, 19);
    }

    PWM_ITPendClear(NT_PWM2);
}
