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

#if defined(SPC1158) || defined(SPC1168) || defined(SPD1163)
    #define                 PWM0A_GPIO             GPIO_18
    #define                 PWM0B_GPIO             GPIO_21
    #define                 PWM0A_GPIO_FUNC        GPIO18_PWM0A
    #define                 PWM0B_GPIO_FUNC        GPIO21_PWM0B
    
    #define                 PWM1A_GPIO             GPIO_36
    #define                 PWM1B_GPIO             GPIO_37
    #define                 PWM1A_GPIO_FUNC        GPIO36_PWM1A
    #define                 PWM1B_GPIO_FUNC        GPIO37_PWM1B
    
    #define                 PWM2A_GPIO             GPIO_22
    #define                 PWM2B_GPIO             GPIO_23
    #define                 PWM2A_GPIO_FUNC        GPIO22_PWM2A
    #define                 PWM2B_GPIO_FUNC        GPIO23_PWM2B

#elif defined(SPD1178) || defined(SPD1188) || defined(SPD1148) 
    #define                 PWM0A_GPIO             GPIO_30
    #define                 PWM0B_GPIO             GPIO_31
    #define                 PWM0A_GPIO_FUNC        GPIO30_PWM0A
    #define                 PWM0B_GPIO_FUNC        GPIO31_PWM0B
    
    #define                 PWM1A_GPIO             GPIO_36
    #define                 PWM1B_GPIO             GPIO_37
    #define                 PWM1A_GPIO_FUNC        GPIO36_PWM1A
    #define                 PWM1B_GPIO_FUNC        GPIO37_PWM1B
    
    #define                 PWM2A_GPIO             GPIO_16
    #define                 PWM2B_GPIO             GPIO_17
    #define                 PWM2A_GPIO_FUNC        GPIO16_PWM2A
    #define                 PWM2B_GPIO_FUNC        GPIO17_PWM2B
    
#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 */
#define             PWM_DB_NS                         1000             /* 1ns */
#define             PWM_SYNC_ReLOADVAL                100              /* the value load to TBCNT after sync signal */

uint32_t            u32PWMPeriod;
uint32_t            u32ActureReLoadVal1;
uint32_t            u32ActureReLoadVal2;


/*************************************************************************************************************************
 *
 * @brief      In this case, PWM0 will output SYNC signal on the point 'TBCNT=CMPD', the SYNC signal reach the PWM1 and then
 *             pass to the PWM2, what's more, all the PWMs is counting at up mode, this makes there is no need to config 
 *             counting mode after SYNC. We can measure this waveform with these GPIOs connected to a oscilloscope.
 *
 *************************************************************************************************************************/


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

    /* Select GPIO as the channel A/B output of PWM0/1/2 respectively */
    GPIO_SetPinChannel(PWM0A_GPIO, PWM0A_GPIO_FUNC);
    GPIO_SetPinChannel(PWM0B_GPIO, PWM0B_GPIO_FUNC);
    GPIO_SetPinChannel(PWM1A_GPIO, PWM1A_GPIO_FUNC);
    GPIO_SetPinChannel(PWM1B_GPIO, PWM1B_GPIO_FUNC);
    GPIO_SetPinChannel(PWM2A_GPIO, PWM2A_GPIO_FUNC);
    GPIO_SetPinChannel(PWM2B_GPIO, PWM2B_GPIO_FUNC);

    /*
     * Init PWM0/1/2 and output 20kHz waveform on both channel A and channel B.
     */
    PWM_ComplementaryPairChannelInit(PWM0, PWM_FREQ, PWM_DB_NS);
    PWM_ComplementaryPairChannelInit(PWM1, PWM_FREQ, PWM_DB_NS);
    PWM_ComplementaryPairChannelInit(PWM2, PWM_FREQ, PWM_DB_NS);

    /* PWM0 generate SYNC when TBCNT=CMPD */
    PWM_SetSyncOutEvent(PWM0, SYNCO_TBCNT_EQU_CMPD);

    /* 
     * In 'PWM_ComplementaryPairChannelInit' PWM was configed TBCNT=CMPA, so TBCNT=CMPB
     * need to be re-configed manually.
     */
    PWM_ActionQualifierCHA(PWM0, ZRO_DO_NOTHING
                               | PRD_DO_NOTHING
                               | CBU_SET_HIGH
                               | CBD_SET_LOW);
                               
    PWM_ActionQualifierCHA(PWM1, ZRO_DO_NOTHING
                               | PRD_DO_NOTHING
                               | CBU_SET_HIGH
                               | CBD_SET_LOW);
                               
    PWM_ActionQualifierCHA(PWM2, ZRO_DO_NOTHING
                               | PRD_DO_NOTHING
                               | CBU_SET_HIGH
                               | CBD_SET_LOW);

    /*
     * In order to pass the SYNC signal to the PWM1 and then to the PWM2, we need 
     * to set PWM1 as 'SYNC_SYNCI_AND_FRCSYNC' mode. 'SYNC_SYNCI_AND_FRCSYNC' is the default
     * mode, so there is no need to set manually, but, keep in mind that you must set the mode
     * when you need.
     *
     * add the follow when you need.
     *   PWM_SetSyncOutEvent(PWM0,TBCTL_BIT_SYNCOSEL_SYNCI_OR_FRCSYNC);
     */

    /* Set PWMxB output 50% duty waveform */
    u32PWMPeriod = PWMPeriod(PWM_FREQ);
    PWM_SetCMPB(PWM0, u32PWMPeriod / 2);
    PWM_SetCMPB(PWM1, u32PWMPeriod / 2);
    PWM_SetCMPB(PWM2, u32PWMPeriod / 2);

    /* Enable PWM synchronization */
    PWM_EnableSync(PWM0);
    PWM_EnableSync(PWM1);
    PWM_EnableSync(PWM2);
    
    /* Start counting */
    PWM_RunCounter(PWM0);
    Delay_Us(7);
    PWM_RunCounter(PWM1);
    Delay_Us(7);
    PWM_RunCounter(PWM2);

    /*
     * As you see, the counter CLK(Tb-sub module of PWM) is obtained from PWM CLK with dividing num
     * not equal to 1, in order to make serious synchronization, it is important to keep PWMs CLK is
     * synchronous first.
     */
    PWM_ForceClockSync();

    /*
     * There is a delay between the moment SYNC signal generated and the time reached PWM1 and PWM2,
     * so PWM1 and PWM2 can not use the same reload value as PWM0, we must re-calculate the value for
     * PWM1 and PWM2.
     *
     *
     * Key point : in this mode, PWM0 reload count value from TBPRD register(not TBPHS register), in
     * this demo, PWM0 works at counting up-down mode, the value reload from TBPRD (when TNCNT=0, it 
     * begin reload value) is 0.
     */
    u32ActureReLoadVal1 = PWM_CalculateSyncReloadValue(u32PWMPeriod,
                                                       COUNT_UP_DOWN,
                                                       COUNT_UP,
                                                       0,
                                                       0);

    /* Set the re-load value when SYNC signal happended */
    PWM_SetSyncReloadValue(PWM1, u32ActureReLoadVal1);

    /* PWM1 reload value is 'u32ActureReLoadVal1', we use this value to calculate value for PWM2 */
    u32ActureReLoadVal2 = PWM_CalculateSyncReloadValue(u32PWMPeriod,
                                                       COUNT_UP_DOWN,
                                                       COUNT_UP,
                                                       u32ActureReLoadVal1,
                                                       0);

    /* Set the re-load value when SYNC signal happended */
    PWM_SetSyncReloadValue(PWM2, u32ActureReLoadVal2);

    while(1)
    {

    }
}
