/******************************************************************************
 * @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;

#define              PWM_FREQ                            20000                               /* 20kHz PWM */

#if defined(SPD1163)
    #define             PWM_Sel                PWM2
    #define             PIN_PWMB               GPIO_39
    #define             PIN_PWMB_CH            GPIO39_PWM2B
    #define             PWMTZ_IRQn_Sel         PWM2TZ_IRQn
    #define             PIN_TZ0                GPIO_0
    #define             PIN_TZ1                GPIO_1
    #define             PIN_TZ2                GPIO_4
#elif defined(SPD1188) || defined(SPD1148)
    #define             PWM_Sel                PWM5
    #define             PIN_PWMB               GPIO_17
    #define             PIN_PWMB_CH            GPIO17_PWM5B
    #define             PWMTZ_IRQn_Sel         PWM5TZ_IRQn
    #define             PIN_TZ0                GPIO_36
    #define             PIN_TZ1                GPIO_37
    #define             PIN_TZ2                GPIO_38
#else
    #define             PWM_Sel                PWM5
    #define             PIN_PWMB               GPIO_29
    #define             PIN_PWMB_CH            GPIO29_PWM5B
    #define             PWMTZ_IRQn_Sel         PWM5TZ_IRQn
    #define             PIN_TZ0                GPIO_36
    #define             PIN_TZ1                GPIO_37
    #define             PIN_TZ2                GPIO_38
#endif

uint32_t             u32PWMPeriod;


/*************************************************************************************************************************
*
* @brief      In this case, 20kHz waveform with 50% duty will be output through PWM_Sel B channel, bringing out by PWM up-down
*             counting mode. we can measure this waveform.
*
*             GPIO36 or GPIO0 set as CBC TZ0 signal and trigger event when it is low, GPIO37 or GPIO1/GPIO38 or GPIO4 set as one-shot TZ1/2 signal and
*             trigger event when it is low. As a result, when GPIO36 or GPIO0 is low PWM disable the output waveform until TZ flag
*             is clear. when GPIO37 or GPIO1/GPIO38 or GPIO4 is low, PWM disable output waveform and enable output waveform immediately at the next
*             PWM clock.
*
*************************************************************************************************************************/


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 and output 20kHz waveform on channel B */
    PWM_SingleChannelInit(PWM_Sel, PWM_CHB, PWM_FREQ);

    /* Configure PWM counter as up counting mode */
    PWM_SetCounterMode(PWM_Sel, COUNT_DOWN);

    /*
     * The PWM counting mode is set to be up-down by default, as a result, we need
     * to re-config the AQCTLA register, which is used for controlling the PWM output
     * action when ZRO/CAU/PRD/CAD (for more information, please read the PWM application
     * note) event had happened.
     *
     * Key Point: the PWM freq will be double because of the ZRO/CAU/PRD/CAD event.
     */
    PWM_ActionQualifierCHB(PWM_Sel, AQCTLB_ALL_ZRO_SET_HIGH
                           | AQCTLB_ALL_CAU_DO_NOTHING
                           | AQCTLB_ALL_PRD_DO_NOTHING
                           | AQCTLB_ALL_CAD_SET_LOW);

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

    /* Select the channel B output of PWM_Sel */
    GPIO_SetPinChannel(PIN_PWMB, PIN_PWMB_CH);

    /* Start PWM_Sel */
    PWM_RunCounter(PWM_Sel);

    /* Trigger TZ0 event when GPIO is low */
    PWM_SetTZ0FromGPIO(PIN_TZ0, GPIO_LEVEL_LOW);

    /* Trigger TZ1 event when GPIO is low */
    PWM_SetTZ1FromGPIO(PIN_TZ1, GPIO_LEVEL_LOW);

    /* Trigger TZ2 event when GPIO is low */
    PWM_SetTZ2FromGPIO(PIN_TZ2, GPIO_LEVEL_LOW);

    /*
     * Set TZ0 as one-shot trip event. The one-shot mode means once the
     * corresponding event has happened, the PWM waveform will stop, and
     * will not start until the flag is cleared.
     *
     * The key point there is 'TZEVT_ASYNC_ONLY_FOR_DEBUG' can not be
     * set in practical engineering, it can only be used in DEBUG mode.
     */
    PWM_SetOneShotTripEvent(PWM_Sel, TRIP_EVENT_TZ0, TRIP_OUTPUT_ASYNC_OR_LATCH);

    /*
     * Set TZ1 and TZ2 as CBC trip event. The symbol 'CBC' means once the
     * corresponding event has happened, the PWM waveform will stop, but
     * start again at the next PWM CLK period with do nothing manually.
     *
     * The key point there is the same as 'PWM_SetOneShotTripEvent()'
     */
    PWM_SetCBCTripEvent(PWM_Sel, TRIP_EVENT_TZ1 | TRIP_EVENT_TZ2, TRIP_OUTPUT_ASYNC_OR_LATCH);

    /*
     * Set PWM0 output as tristate upon one-shot and CBC trip event,
     * need to explicitly specify actions for all 6 trip scenarios
     */
    PWM_SetCHAOutputWhenTrip(PWM_Sel, 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(PWM_Sel, 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);

    NVIC_EnableIRQ(PWMTZ_IRQn_Sel);
    
    PWM_EnableCBCTripInt(PWM_Sel);
    PWM_EnableOneShotTripInt(PWM_Sel);

    while (1)
    {
        Delay_Ms(500);

        /* Restore the output of wave in oneshot mode*/
        PWM_ClearOneShotTripInt(PWM_Sel);
    }
}

#if defined(SPD1163)
    void PWM2TZ_IRQHandler(void)
    {
        uint32_t u32TZStatus = PWM2->TZSTS.all;

        if (u32TZStatus & TZSTS_ALL_TZ0OST_OCCUR)
        {
            printf("TZ0 one-shot trip event occurred\n");

            PWM2->TZSTSCLR.bit.TZ0OST = 1;
        }

        if (u32TZStatus & TZSTS_ALL_TZ1CBC_OCCUR)
        {
            printf("TZ1 cycle-by-cycle trip event occurred\n");
            
            PWM2->TZSTSCLR.bit.TZ1CBC = 1;
        }

        if (u32TZStatus & TZSTS_ALL_TZ2CBC_OCCUR)
        {
            printf("TZ2 cycle-by-cycle trip event occurred\n");

            PWM2->TZSTSCLR.bit.TZ2CBC = 1;
        }

        PWM_ClearTripGlobalInt(PWM2);
    }
#else
    void PWM5TZ_IRQHandler(void)
    {
        uint32_t u32TZStatus = PWM5->TZSTS.all;

        if (u32TZStatus & TZSTS_ALL_TZ0OST_OCCUR)
        {
            printf("TZ0 one-shot trip event occurred\n");

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

        if (u32TZStatus & TZSTS_ALL_TZ1CBC_OCCUR)
        {
            printf("TZ1 cycle-by-cycle trip event occurred\n");

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

        if (u32TZStatus & TZSTS_ALL_TZ2CBC_OCCUR)
        {
            printf("TZ2 cycle-by-cycle trip event occurred\n");

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

        PWM_ClearTripGlobalInt(PWM5);
    }
#endif



