/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V4.0.0
 * @date     30-July-2026
 *
 * @note
 * Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd.. All rights reserved.
 *
 * @attention
 * THIS SOFTWARE JUST PROVIDES CUSTOMERS WITH CODING INFORMATION REGARDING
 * THEIR PRODUCTS, WHICH AIMS AT SAVING TIME FOR THEM. SPINTROL SHALL NOT BE
 * LIABLE FOR THE USE OF THE SOFTWARE. SPINTROL DOES NOT GUARANTEE THE
 * CORRECTNESS OF THIS SOFTWARE AND RESERVES THE RIGHT TO MODIFY THE SOFTWARE
 * WITHOUT NOTIFICATION.
 *
 ******************************************************************************/

#include<stdio.h>

#if defined(SPC1158)
#include "spc1158.h"
#elif defined(SPD1148)
#include "spd1148.h"
#elif defined(SPD1178)
#include "spd1178.h"
#elif defined(SPD1188)
#include "spd1188.h"
#elif defined(SPD1163)
#include "spd1163.h"
#else
#include "spc1168.h"
#endif

/* This macro is used to get the PWM period with a specified frequency */
#define PWMPeriod(u32PWMFreqHz)  ((CLOCK_GetModuleClock(PWM_MODULE))/u32PWMFreqHz)/2;

/* Usd the count to calculate the period */
#define CNTTOFREQ(x) (CLOCK_GetModuleClock(ECAP_MODULE) / (x))

#define PWM_FREQ                                    10000                                            /* 10kHz PWM */
#define ECAP_PIN                                    GPIO_28                                          /* ECAP PIN */
#define ECAP_PIN_GPIO_FUNC                          GPIO28_GPIO28                                    /* ECAP PIN act as GPIO function */
#define ECAP_PIN_PWM_FUNC                           GPIO28_PWM5A                                     /* ECAP PIN act as PWM function */
#define PWM_Sel                                     PWM5


uint32_t u32PWMPeriod;
uint32_t TStamp0, TStamp1, TStamp2, TStamp3;


/*************************************************************************************************************************
*
* @brief      In this case, In this case, GPIO28 used as PWM output and ECAP input, and ECAP work in oneshot absolute
*             operation mode .
*
*            -------                            GPIO28                       -------
*           |       |                               -                       |       |
*           | ECAP  |<-----------------------------| |<---------------------|  PWM  |
*           |       |  ECAP captured pin           | |    PWM output        |       |
*           |       |                               -                        -------
*            -------                               / \
*                                                   |
*                                                   |
*                                                    -------GPIO28 used as PWM output, also as the ECAP captured pin
*
*             Key Point:
*                      <1>:If user care about exactly each incoming event, need add extra 4 dummy
*                          event cycle to initialize the divider, because due to the design of SOC,
*                          the first 4 signal event is ignored, as showed below:
*
*                                                         |
*                                      -   -   -    -    |   -------          --------
*                                     | | | | | |  | |   |  |       |        |        |
*                                     | | | | | |  | |   |  |       |        |        |
*               ECAP PIN--------------   -   -   --   ---|--         --------          -------
*                                     |              |   | / \     / \      / \      / \
*                                     |              |   |  |       |        |        |
*                                   ->| 4 dummy event|<- |  1       2        3        4
*                                                        |
*
*
*************************************************************************************************************************/


int main()
{
    FLASH_WALLOW();

#if defined(SPC1158)
    FLASH_SetTiming(100000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(100000000UL);
#else
    FLASH_SetTiming(200000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(200000000UL);
#endif

    Delay_Init();

    /*
     * Init the UART
     *
     * 1.Set the GPIO34/35 as UART FUNC
     *
     * 2.Enable the UART CLK
     *
     * 3.Set the rest para
     */
    GPIO_SetPinChannel(GPIO_34, GPIO34_UART_TXD);
    GPIO_SetPinChannel(GPIO_35, GPIO35_UART_RXD);
    CLOCK_EnableModule(UART_MODULE);
    UART_Init(UART, 38400);

    /* Init PWM_Sel, PWM freq will be set as 10kHz in this function */
    PWM_SingleChannelInit(PWM_Sel, PWM_CHA, PWM_FREQ);

    /* Set PWM_SelA output 50% duty waveform */
    u32PWMPeriod = PWMPeriod(PWM_FREQ);
    PWM_SetCMPA(PWM_Sel, u32PWMPeriod / 2);

    /* ECAP Init */
    ECAP_CaptureModeInit(ECAP, ECAP_PIN);

    /* Set ECAP as onshot mode */
    ECAP_EnableOneshotMode(ECAP);

    /* Set EVT DIV to 1 */
    ECAP_SetEventDiv(ECAP, 1);

    /* ---------------Steps for fixing BUG : BEGIN------------------------ */
    /*
     * As described in technical reference manual, the ECAP event prescaler is implemented
     * with existing clock divider IP, so there is extra four event cycles (regarded as clock
     * cycles to the divider) required to initialize the divider after power-up. For one shot
     * mode, in which the user cares about exactly each incoming event, the first 4 events may
     * not work correctly. So we need software work-around to purposely generate 4 dummy events
     * via GPIO toggling in Gen 3 products to initialize the event prescaler.
     */

    /*
     * EVT INT are opened in 'ECAP_CaptureModeInit', the 4 dummy events may cause dummy INT,
     * so disable all EVT INT when sending the 4 dummy event to the ECAP module.
     */
    ECAP_DisableCEVT0Int(ECAP);
    ECAP_DisableCEVT1Int(ECAP);
    ECAP_DisableCEVT2Int(ECAP);
    ECAP_DisableCEVT3Int(ECAP);

    /* Set the ECAP PIN as the INPUT GPIO function in order to sent 4 dummy event */
    GPIO_SetPinChannel(ECAP_PIN, ECAP_PIN_GPIO_FUNC);
    GPIO_WritePin(ECAP_PIN, GPIO_LEVEL_LOW);
    GPIO_SetPinDir(ECAP_PIN, GPIO_OUTPUT);

    /* Toggle the ECAP PIN 4 times as 4 events */
    GPIO_TogglePin(ECAP_PIN);
    GPIO_TogglePin(ECAP_PIN);
    GPIO_TogglePin(ECAP_PIN);
    GPIO_TogglePin(ECAP_PIN);

    /* Dummy Event may cause accidental INT, So clear all INT there */
    ECAP->CAPIC.all = 0xFFFFFFFF;

    /* RE-arm ECAP event count register(in order to clear the impact of the 4 dummy events) */
    ECAP_OneshotReArm(ECAP);
    /* ---------------Steps for fixing BUG : END------------------------ */

    /* Select ECAP_PIN as the channel A output of PWM_Sel */
    GPIO_SetPinChannel(ECAP_PIN, ECAP_PIN_PWM_FUNC);

    /* Enable Pin input deglitch filter */
    GPIO_EnableDeglitch(ECAP_PIN);

    /* The smaller the value, the more accurate the measurement result, but the more susceptible to interference */
    GPIO_SetDeglitchWindow(DGCLKCTL_ALL_DIV_(0x0));

    /* Set the count reset back to zero when event3 happened */
    ECAP_DisableEventResetCounter(ECAP, ECAP_CEVT0);
    ECAP_DisableEventResetCounter(ECAP, ECAP_CEVT1);
    ECAP_DisableEventResetCounter(ECAP, ECAP_CEVT2);
    ECAP_EnableEventResetCounter(ECAP, ECAP_CEVT3);

    /* Enable global interrupt of EACP */
    NVIC_EnableIRQ(ECAP_IRQn);
    
    /* Enable EVT3 Interrupt */
    ECAP_EnableInt(ECAP, ECAP_INT_CEVT3);

    /* Start ECAP */
    ECAP_RunCounter(ECAP);

    /* Start PWM_Sel */
    PWM_RunCounter(PWM_Sel);

    while (1)
    {

    }
}

void ECAP_IRQHandler(void)
{
    uint32_t cnt;

    TStamp0 = ECAP->CAP0.all;
    TStamp1 = ECAP->CAP1.all;
    TStamp2 = ECAP->CAP2.all;
    TStamp3 = ECAP->CAP3.all;

    cnt = ((TStamp2 - TStamp0) + (TStamp3 - TStamp1)) / 2;
    printf("Frequency = %dHz\n", CNTTOFREQ(cnt));

    /* Clear CEVT3 */
    ECAP_ClearCEVT3Int(ECAP);

    /* Clear global INT of ECAP */
    ECAP_ClearGlobalInt(ECAP);

    /* Rearm the ECAP for next events */
    ECAP_OneshotReArm(ECAP);
}
