/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V4.0.1
 * @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.
 *
 ******************************************************************************/

#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
#include<stdio.h>

#define               PWM_U                   PWM0
#define               PWM_V                   PWM1
#define               PWM_W                   PWM2
#define               LINK_PWM_U              SEL_PWM0
#define               INC_PWM_U               INC_PWM0
#define               INC_PWM_V               INC_PWM1
#define               INC_PWM_W               INC_PWM2


#if defined(SPC1158) || defined(SPC1168)
    #define                 PWM_U_GPIO             GPIO_18
    #define                 PWM_U_GPIO_FUNC        GPIO18_PWM0A

    #define                 PWM_V_GPIO             GPIO_36
    #define                 PWM_V_GPIO_FUNC        GPIO36_PWM1A

    #define                 PWM_W_GPIO             GPIO_22
    #define                 PWM_W_GPIO_FUNC        GPIO22_PWM2A

#elif defined(SPD1178) || defined(SPD1188) || defined(SPD1148) 
    #define                 PWM_U_GPIO             GPIO_30
    #define                 PWM_U_GPIO_FUNC        GPIO30_PWM0A
    
    #define                 PWM_V_GPIO             GPIO_36
    #define                 PWM_V_GPIO_FUNC        GPIO36_PWM1A
    
    #define                 PWM_W_GPIO             GPIO_16
    #define                 PWM_W_GPIO_FUNC        GPIO16_PWM2A

#else
    #define                 PWM_U_GPIO             GPIO_30
    #define                 PWM_U_GPIO_FUNC        GPIO30_PWM0A
    
    #define                 PWM_V_GPIO             GPIO_36
    #define                 PWM_V_GPIO_FUNC        GPIO36_PWM1A
    
    #define                 PWM_W_GPIO             GPIO_16
    #define                 PWM_W_GPIO_FUNC        GPIO16_PWM2A    
#endif




#define               PWM_FREQ                20000                              /* 20kHz PWM */
#define               PWM_DB_NS               1000                               /* 1000ns */ 
#define               PWM_CMPA                2500                               /* the CPMA value for all three */

#define               PWM_BlankWIN_Size       100                                /* 100 TBCNT CLK */
#define               PWM_Blank_Offset        50                                 /* 50 TBCNT CLK */
#define               ValueToVoltage(x)       ((x * 3657) / 8192) /1000
#define               THRESHOLD_VAL           2200                                 

int32_t               i32PPUResult;
ErrorStatus           eStatus = ERROR;

 
void PWMx_Set_Digiter_Compare(PWM_REGS * PWMx)
{
    /* Affected by results monitored from ADCPPU0TZ */
    PWM_EnableDCAHTripEvent(PWMx, DC_TRIP_ADCPPU0TZ);
     
    /*
     * 1.Configure DC event filter
     *
     * 2.Input is DCAEVT0, apply blank window with original polarity
     *
     * 3.Set the blank window position relative to TBCNT=0
     */
    PWM_SetDCFilter(PWMx, DCF_FROM_RAW_DCAEVT0, DCF_ALIGN_ON_ZERO);
   
    /* Enbale PWM DC filter blank function */
    PWM_EnableDCFilterBlank(PWMx);
   
    /* Set blank window size as 100 TBCLK and offset as 50 TBCLK */
    PWM_SetDCFilterBlankWindow(PWMx, PWM_BlankWIN_Size, PWM_Blank_Offset);
   
    /* 
     * Set the filtered event signal as the final event signal sent to Time-base/Trip-Zone/Event-Trigger
     * submodule, and then set the moment to trigger TZ sb-model when DCH is high 
     */
    PWM_SetDCAEVT0(PWMx, DCEVT_FILTERED);
    PWM_SetRawDCAEVT0(PWMx, DCH_HIGH_DCL_X);
   
    /* Set output to tri-state upon DCAEVT0 trip event */
    PWM_SetCHAOutputWhenTrip(PWMx, TZU_TRIP_DO_NOTHING |
                                   TZD_TRIP_DO_NOTHING |
                                   DCEVT0U_TRIP_AS_TRI_STATE |
                                   DCEVT0D_TRIP_AS_TRI_STATE |
                                   DCEVT1U_TRIP_DO_NOTHING |
                                   DCEVT1D_TRIP_DO_NOTHING);
                                    
    PWM_SetCHBOutputWhenTrip(PWMx, TZU_TRIP_DO_NOTHING |
                                   TZD_TRIP_DO_NOTHING |
                                   DCEVT0U_TRIP_AS_TRI_STATE |
                                   DCEVT0D_TRIP_AS_TRI_STATE |
                                   DCEVT1U_TRIP_DO_NOTHING |
                                   DCEVT1D_TRIP_DO_NOTHING);
                                    
    PWM_EnableDCAEVT0TripInt(PWMx);
}

/*
 * This function output Three-Phase waveform for BLDC(Brushless Derect Current)
 */
void PWM_Output_Three_Phase(void)
{
    /*
     * Init PWM0/1/2 and output 20kHz waveform on both channel A and channel B.
     */
    PWM_ComplementaryPairChannelInit(PWM_U, PWM_FREQ, PWM_DB_NS);
    PWM_ComplementaryPairChannelInit(PWM_V, PWM_FREQ, PWM_DB_NS);
    PWM_ComplementaryPairChannelInit(PWM_W, PWM_FREQ, PWM_DB_NS);
    
    /* Start counting */
    PWM_RunCounter(PWM_U);
    PWM_RunCounter(PWM_V);
    PWM_RunCounter(PWM_W);
    
    /* PWM0 set CMPA and loading the same value to PWM1/2 synchronously */
    PWM_LinkCMPA(PWM_V, LINK_PWM_U);
    PWM_LinkCMPA(PWM_W, LINK_PWM_U);
    PWM_SetCMPA(PWM_U, PWM_CMPA);
}




 /*************************************************************************************************************************
 *
 * @brief      In this case, we use the PPU to trigger the TZ

 *             1.Check the Output of the ADC PPU to judge if the voltage is over THRESHOLD_VAL.
 *
 *             2.In the DC sub-module of the PWM, we sent the corresponding event signal to the TZ sub-module to judge if
 *               there is a need to stop PWM or not, this module with a filter in order to eliminate the probable noise.
 *
 *************************************************************************************************************************/


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

    TIMER_Init(TIMER1, 3000);
    TIMER_EnableADCSOC(TIMER1);

    /* ADC Init */
    eStatus = ADC_EasyInit1(ADC_SOC_0, ADC8_GPIO8, ADCTRIG_Timer1);
    if (ERROR != eStatus)
    {
        printf("ADC_Init ERROR\n");
        return 1;
    }

    /* Init ADC PPU , set the offset value to 0 */
    ADC_PPUInit(ADC_PPU_0, 0, 0, ADC_PPU_CODE_MINUS_REF);

    /* Enable the interrupt of PPU0 */
    NVIC_EnableIRQ(ADCPPU0_IRQn);

    /* Enable too high interrupt of ADC PPU0 */
    ADC_EnablePPUInt(ADC_PPU_0, ADC_PPU_TOO_HIGH);

    /* Enable ADC PPU Trip-zone Event */
    ADC_EnablePPUTripEvent(ADC_PPU_0, ADC_PPU_TOO_HIGH);

    /* Set PPU0 high threshold */
    ADC_SetPPUTooHighThreshold(ADC_PPU_0, THRESHOLD_VAL);

    /* Generate a three-phase waveform */ 
    PWM_Output_Three_Phase();

    /* Choose the output GPIO */
    GPIO_SetPinChannel(PWM_U_GPIO, PWM_U_GPIO_FUNC);
    GPIO_SetPinChannel(PWM_V_GPIO, PWM_V_GPIO_FUNC);
    GPIO_SetPinChannel(PWM_W_GPIO, PWM_W_GPIO_FUNC);

    /* Set the DC sub-module for PWM_U */
    PWMx_Set_Digiter_Compare(PWM_U);

    /* Set the DC sub-module for PWM_V */
    PWMx_Set_Digiter_Compare(PWM_V);

    /* Set the DC sub-module for PWM_W */
    PWMx_Set_Digiter_Compare(PWM_W);

    while(1)
    {

    }
}

void ADCPPU0_IRQHandler(void)
{
    if(ADC_GetPPUIntFlag(ADC_PPU_0, ADC_PPU_TOO_HIGH) != 0)
    {
        printf("too high INT had happened\n");
    }

    i32PPUResult = ADC_GetResult(ADC_SOC_0);
    printf("ADC SOC0 Voltage = %2fV(data is %d)\n", (double)ValueToVoltage(i32PPUResult), i32PPUResult);
}
