/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V1.8.0
 * @date     31-Dec-2021
 *
 * @note
 * Copyright (C) 2021 Spintrol Limited Corporation. 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"spc1168.h"
#include<stdio.h>

/* 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_36                                          /* ECAP PIN */
#define ECAP_PIN_GPIO_FUNC                          GPIO36_GPIO36                                    /* ECAP PIN act as GPIO function */
#define ECAP_PIN_PWM_FUNC                           GPIO36_PWM5A                                     /* ECAP PIN act as PWM function */

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


 /*************************************************************************************************************************
 *
 * @brief      In this case, In this case, GPIO36 used as PWM output and ECAP input, and ECAP work in oneshot absolute
 *             operation mode .
 *
 *            -------                            GPIO36                       -------
 *           |       |                               -                       |       |
 *           | ECAP  |<-----------------------------| |<---------------------|  PWM  |
 *           |       |  ECAP captured pin           | |    PWM output        |       |
 *           |       |                               -                        -------
 *            -------                               / \
 *                                                   |
 *                                                   |
 *                                                    -------GPIO36 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();
  FLASH_SetTiming(200000000);
  /* Disable flash write access after flash operation had done */
  FLASH_WDIS();

  CLOCK_InitWithRCO(CLOCK_HCLK_200MHZ);

  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 PWM5, PWM freq will be set as 20kHz in this function */
  PWM_SingleChannelInit(PWM5,PWM_CHA,PWM_FREQ);

  /* Set PWM5A output 50% duty waveform */
  u32PWMPeriod = PWMPeriod(PWM_FREQ);
  PWM_SetCMPA(PWM5,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 discribed 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 intialize the event prescaler.
   */
  
  /*
   * EVT INT are opened in 'ECAP_CaptureModeInit', the 4 dummy events may cause dummy INT, 
   * so disable all EVT INT when senting 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 PWM5 */
  GPIO_SetPinChannel(ECAP_PIN,ECAP_PIN_PWM_FUNC);

  /* 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 EVT3 Interrupt */
  ECAP_EnableInt(ECAP, ECAP_INT_CEVT3);

  /* Enable global interrupt of EACP */
  NVIC_EnableIRQ(ECAP_IRQn);
  
  /* Start ECAP */
  ECAP_RunCounter(ECAP);
  
  /* Start PWM5 */
  PWM_RunCounter(PWM5);	

  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);
}
