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

#if defined(SPD1188)
    #define               PWM_U                             PWM0
    #define               PWM_V                             PWM1
    #define               PWM_W                             PWM2
    #define               LINK_PWM_U                        SEL_PWM0
    #define               GPIO_PWM_U_H                      GPIO_30
    #define               GPIO_PWM_V_H                      GPIO_36
    #define               GPIO_PWM_W_H                      GPIO_38
    #define               GPIO_PWM_U_H_SEL                  GPIO30_PWM0A
    #define               GPIO_PWM_V_H_SEL                  GPIO36_PWM1A
    #define               GPIO_PWM_W_H_SEL                  GPIO38_PWM2A
    #define               GPIO_PWM_U_L                      GPIO_21
    #define               GPIO_PWM_V_L                      GPIO_37
    #define               GPIO_PWM_W_L                      GPIO_39
    #define               GPIO_PWM_U_L_SEL                  GPIO21_PWM0B
    #define               GPIO_PWM_V_L_SEL                  GPIO37_PWM1B
    #define               GPIO_PWM_W_L_SEL                  GPIO39_PWM2B
    #define               PGA0_CH_P                         PGA0_CH_P_ADC8
    #define               PGA0_P_PIN                        GPIO_8
    #define               PGA1_CH_P                         PGA1_CH_P_ADC10
    #define               PGA1_P_PIN                        GPIO_10
    #define               PGA2_CH_P                         PGA2_CH_P_ADC12
    #define               PGA2_P_PIN                        GPIO_12
#else
    #define               PWM_U                             PWM5
    #define               PWM_V                             PWM1
    #define               PWM_W                             PWM2
    #define               LINK_PWM_U                        SEL_PWM5
    #define               GPIO_PWM_U_H                      GPIO_28
    #define               GPIO_PWM_V_H                      GPIO_20
    #define               GPIO_PWM_W_H                      GPIO_22
    #define               GPIO_PWM_U_H_SEL                  GPIO28_PWM5A
    #define               GPIO_PWM_V_H_SEL                  GPIO20_PWM1A
    #define               GPIO_PWM_W_H_SEL                  GPIO22_PWM2A
    #define               GPIO_PWM_U_L                      GPIO_29
    #define               GPIO_PWM_V_L                      GPIO_21
    #define               GPIO_PWM_W_L                      GPIO_23
    #define               GPIO_PWM_U_L_SEL                  GPIO29_PWM5B
    #define               GPIO_PWM_V_L_SEL                  GPIO21_PWM1B
    #define               GPIO_PWM_W_L_SEL                  GPIO23_PWM2B
    #define               PGA0_CH_P                         PGA0_CH_P_ADC8
    #define               PGA0_P_PIN                        GPIO_8
    #define               PGA1_CH_P                         PGA1_CH_P_ADC10
    #define               PGA1_P_PIN                        GPIO_10
    #define               PGA2_CH_P                         PGA2_CH_P_ADC12
    #define               PGA2_P_PIN                        GPIO_12
#endif


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

#define               PWM_BlankWIN_Size       100                                /* 100 TBCNT CLK */
#define               PWM_Blank_Offset        50                                 /* 50 TBCNT CLK */
#define               COMP_FilterWIN          300                                /* 300ns */
#define               SampleRegisterNVol      1650                               /* Sampler register negative voltage : 1650mV */
#define               VolOffsetmV             550                                /* COMP monitor voltage range offset */

void PWMx_Set_Digiter_Compare(PWM_REGS *PWMx)
{
    /* Affected by results monitored from all three phases */
    PWM_EnableDCAHTripEvent(PWMx, DC_TRIP_COMP0H |
                            DC_TRIP_COMP1H |
                            DC_TRIP_COMP2H |
                            DC_TRIP_COMP0L |
                            DC_TRIP_COMP1L |
                            DC_TRIP_COMP2L);
    
    PWM_SetRawDCAEVT0(PWMx, DCH_HIGH_DCL_X);
    
    /* Set the filtered event as the final DCAEVT0, and trigger TZ sb-model when DCH is high */
    PWM_SetDCAEVT0(PWMx, DCEVT_FILTERED);
    
    /*
     * 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);
    
    /* Set blank window size as 100 TBCLK and offset as 50 TBCLK */
    PWM_SetDCFilterBlankWindow(PWMx, PWM_BlankWIN_Size, PWM_Blank_Offset);

    /* Enable PWM DC filter blank function */
    PWM_EnableDCFilterBlank(PWMx);

    PWM_SetOneShotTripEvent(PWMx, TRIP_EVENT_DCAEVT, TRIP_OUTPUT_LATCH);

    /* Set output to tri-state upon DCAEVT0 trip event */
    PWM_SetCHAOutputWhenTrip(PWMx, TZU_TRIP_AS_TRI_STATE |
                             TZD_TRIP_AS_TRI_STATE   |
                             DCEVT0U_TRIP_DO_NOTHING |
                             DCEVT0D_TRIP_DO_NOTHING |
                             DCEVT1U_TRIP_DO_NOTHING |
                             DCEVT1D_TRIP_DO_NOTHING);

    PWM_SetCHBOutputWhenTrip(PWMx, TZU_TRIP_AS_TRI_STATE |
                             TZD_TRIP_AS_TRI_STATE   |
                             DCEVT0U_TRIP_DO_NOTHING |
                             DCEVT0D_TRIP_DO_NOTHING |
                             DCEVT1U_TRIP_DO_NOTHING |
                             DCEVT1D_TRIP_DO_NOTHING);

    PWM_EnableDCAEVT0TripInt(PWMx);
}

/*
 * This function output Trip-Phase waveform for BLDC(Brushless Direct Current)
 */
void PWM_Output_Trip_Phase(void)
{
    /*
     * Init PWM5/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);

    /* PWM5 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, The aim is to protect the trip-phase waveform from over/below current, but current is hard to
*             test, so we test the current sampling register instead. The step can be described as below:
*
*             1.Gain the current sampling register voltage through PGA.
*
*             2.Comparing the Output of the PGA to judge if the voltage is between 1.1V ~ 2.2V.
*
*             3.In the DC sub-module of the PWM, we accept and process the COMP module signal with a filter in order to
*               eliminate the probable noise, then sent the corresponding event signal to the TZ sub-module to judge if
*               there is a need to stop PWM or not.
*
*             (In this demo, the current sampling resistor is GPIO8/10/12 and the sample register is 5.5ohm and go through
*              current is 0.1A, connecting PAG negative to DAC1 which output 1.65V and divider resistor to positive which
*              voltage is 1.65V-0.55V < Vol <1.65V+0.55V)
*
*
*
*                                                  ---3.3V
*                                                   -
*                                                   |
*                                                   |
*                            |                     ---
*                            |                    |   |
*                            |                     ---
*                            |                      |
*                            |                      |
*                       |    |-----------           |---  1.65V-0.55V < Vol <1.65V+0.55V   ----------------
*                       |    |           |         ---  |                                 |   PWM module   |
*                0.1A   |   ---           --------|   |  ------|\          |\             |   ----    ---  |
*              current \|/ |5.5|                   ---         | \---------| \------------|--|    |  |   |-------PWMA
*                       |  |ohm|current sampling               |  \        |  \           |  |DC  |  |TZ | |
*                       |  |   |  resistor                     |PGA/       |  /           |  |sub |--|sub| |
*                       |   ---                      ----------|  /  ------| /------------|--|    |  |   |-------PWMB
*                       |    |                      |          | /   |     |/             |   ----    ---  |
*                       |    |                      |                | Comparator         |                |
*                            |                      |                |                     ----------------
*                            |                     ----            ----
*                            |                    |DAC1| 1.65V    |DACx|
*                            |                     ----            ----
*                         -------
*                          ----GND
*                           --
*
*
*             Key point:
*                       1. When selecting the GAIN value of PGA, keep in mind that the positive output of PGA(OUTP)
*                          must be lower then 3V, and negative output of PGA(OUTN) must be bigger then 0.3V, otherwise,
*                          the PGA output is not accurate.
*                       2. When over current is happened, 'PWMA' and 'PWMB' will be the action configured in code, in this
*                          demo, the action is "high-impedance".
*
*************************************************************************************************************************/


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

    /*
     * As the title described, we suppose GPIO8/10/12(ADC8/10/12) can be used to sample the voltage
     * of current sampling resistor in the BLDC circuit. so, we need to set the GPIOs as ADCs.
     */
    GPIO_SetPinAsAnalog(PGA0_P_PIN);
    GPIO_SetPinAsAnalog(PGA1_P_PIN);
    GPIO_SetPinAsAnalog(PGA2_P_PIN);

    /*
     * Set PGA in differential ended mode.
     *
     * 1.Set the GPIO8(ADC8)/GPIO10(ADC10)/GPIO12(ADC12) as the P-input of the PGA0/PGA1/PGA2.
     *
     * 2.Set the DAC1 as the N-input of the PGA0/PGA1/PGA2.
     *
     * 3.Set the PGA0/PGA1/PGA2 amplitude scale as 4x.
     *
     * 4.Enable the PGA0/PGA1/PGA2.
     */
    PGA_DifferentialInit(PGA0, PGA0_CH_P, PGA0_CH_N_DAC1, PGA_SCALE_4X);
    PGA_DifferentialInit(PGA1, PGA1_CH_P, PGA1_CH_N_DAC1, PGA_SCALE_4X);
    PGA_DifferentialInit(PGA2, PGA2_CH_P, PGA2_CH_N_DAC1, PGA_SCALE_4X);

    /* Set DAC1 output 1.65V */
    COMP_SetDACVoltage(DAC1, SampleRegisterNVol);
    COMP_EnableDAC(DAC1);

    /*
     * 1. Initialize comparator with 300ns deglitch filtering window and set over
     *    current value as 2.2V.
     * 2. Set DAC 2 & 3 as the comparator too-High trigger input and too-low trigger input.
     * 3. Set DAC 2 (too-high trigger input) output 1.65V + 0.55V = 2.2V
     */
    COMP_Init(COMP_0_HI, COMP0_FROM_PGA0P_OUT, SampleRegisterNVol + VolOffsetmV, COMP_FilterWIN);
    COMP_Init(COMP_0_LO, COMP0_FROM_PGA0P_OUT, SampleRegisterNVol - VolOffsetmV, COMP_FilterWIN);
    COMP_Init(COMP_1_HI, COMP1_FROM_PGA1P_OUT, SampleRegisterNVol + VolOffsetmV, COMP_FilterWIN);
    COMP_Init(COMP_1_LO, COMP1_FROM_PGA1P_OUT, SampleRegisterNVol - VolOffsetmV, COMP_FilterWIN);
    COMP_Init(COMP_2_HI, COMP2_FROM_PGA2P_OUT, SampleRegisterNVol + VolOffsetmV, COMP_FilterWIN);
    COMP_Init(COMP_2_LO, COMP2_FROM_PGA2P_OUT, SampleRegisterNVol - VolOffsetmV, COMP_FilterWIN);

    /* Select GPIO28/29 as the channel A/B output of PWM5 respectively */
    GPIO_SetPinChannel(GPIO_PWM_U_H, GPIO_PWM_U_H_SEL);
    GPIO_SetPinChannel(GPIO_PWM_U_L, GPIO_PWM_U_L_SEL);

    /* Select GPIO20/21 as the channel A/B output of PWM1 respectively */
    GPIO_SetPinChannel(GPIO_PWM_V_H, GPIO_PWM_V_H_SEL);
    GPIO_SetPinChannel(GPIO_PWM_V_L, GPIO_PWM_V_L_SEL);

    /* Select GPIO22/23 as the channel A/B output of PWM2 respectively */
    GPIO_SetPinChannel(GPIO_PWM_W_H, GPIO_PWM_W_H_SEL);
    GPIO_SetPinChannel(GPIO_PWM_W_L, GPIO_PWM_W_L_SEL);

    /* Generate a tri-phase waveform */
    PWM_Output_Trip_Phase();

    NVIC_EnableIRQ(PWM5TZ_IRQn);
    
    /* 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)
    {
        Delay_Ms(500);
        
        /* Restore the output of wave in oneshot mode*/
        PWM_ClearOneShotTripInt(PWM_U);
        PWM_ClearOneShotTripInt(PWM_V);
        PWM_ClearOneShotTripInt(PWM_W);
    }
}

void PWM5TZ_IRQHandler(void)
{
    uint32_t u32TZStatus = PWM5->TZSTS.all;
    
    if (u32TZStatus & TZSTS_ALL_DCAEVT0_OCCUR)
    {
        printf("Digital compare A event 0 one-shot trip event occurred\n");

        PWM5->TZSTSCLR.bit.DCAEVT0 = 1;
    }

    PWM_ClearTripGlobalInt(PWM5);
}



