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

#include "spd1188.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;

#define                     PRE_DRIVER_PWM_U                             PWM5
#define                     PRE_DRIVER_PWM_V                             PWM4
#define                     PRE_DRIVER_PWM_W                             PWM3
#define                     PRE_DRIVER_LINK_PWM_U                        SEL_PWM5
#define                     PRE_DRIVER_PWM_FREQ                          1000                  /* 1kHz PWM */
#define                     PWM_DB_NS                                    1000                  /* 1us */
#define                     PWM_BlankWIN_Size                            100                   /* 100 TBCNT CLK */
#define                     PWM_Blank_Offset                             50                    /* 50 TBCNT CLK */
#define                     EPWR_TH_VAL_NS                               10                    /* 10 ns */
#define                     EPWR_WIN_VAL_NS                              10                    /* 10 ns */

uint32_t                    u32PWMPeriod;
uint8_t                     u8PREDRIID                                    = 0;                 /* PRE-DRIVER mode ID */
uint8_t                     u8PREDRIDATA;                                                       /* Data read from PRE-DRIVER */
ErrorStatus                 eErrorState;
uint32_t                    u32SSPBaundrate                               = 1000000;           /* The baundrate of SSP communicating with PRE-DRIVER mode */
uint32_t                    u32Timeout                                    = 500;               /* The number of times try to get PRE-DRIVER mode ID */
uint8_t                     u8Count;


void PWMx_Set_Digiter_Compare(PWM_REGS * PWMx)
{
  /* 
   * The following step can is the coding style of Digital Compare sub-module structure in PWM module,
   * for more information, please refer to Figure 10-16 of SPC1158 TRM.
   */

  /* Step1. Set EPWRTZ0 as the DCAH input */
  PWM_EnableDCAHTripEvent(PWMx, DC_TRIP_EPWRTZ0 |
                                DC_TRIP_EPWRTZ1);

  /* Step2. Trip DCAEVT0 event when DCAH is high(be carefull about the DCH and DCL polarity) */
  PWM_SetRawDCAEVT0(PWMx, DCH_HIGH_DCL_X);

  /*
   * Step3. Config the Event filter function.
   *
   * <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);

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

  /* 
   * Step4. Set the event sent to Event processing logic.
   *
   * Set the Filtered DCAEVT0 event or the Raw DCAEVT0 as the event which
   * will be sent to Event processing logic. 
   */
  PWM_SetDCAEVT0(PWMx, DCEVT_FILTERED);

  /* Step5. Enable the Event processing logic output EVT0 signal(DCAEVT0 int) to Trip-zone sub-module */
  PWM_EnableDCAEVT0TripInt(PWMx);

  /* Step blow is the configuration of Trip-zone sub-module, nothing to do with Digital compare sub-module */
  /* Set Trip-Zone as one-shot mode */
  PWM_SetOneShotTripEvent(PWMx, TRIP_EVENT_DCAEVT, TRIP_OUTPUT_LATCH);

  /* Set PWM output 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);
}


 /*************************************************************************************************************************
 *
 * @brief      This case show how to use Vds monitor function of PRE-DRIVER, TZ event will be triggered and crossponding PWM
 *             channel waveform will stop immediately and the infomation in INT function will print when Vds too high event
 *             happended.
 *
 *                                                        SPD1188 CHIP
 *                            --------------------------------------------------------------------------------
 *                           |               MCU                                                              |
 *                           |    -------------------------------------                     --------------    |
 *                           |   |      -------------                  |                   |              |   |
 *                           |   |     |  --------   |TZ signal  ------|      TZ signal    |              |   |
 *                           |   |     | |  DC SUB|<-|----------|      |<------------------X              |   |
 *                           |   |     | |        |  |          |      |                   |              |   |
 *                           |   |     | |  MODE  |  |          | EPWR |                   | High voltage |   |
 *                           |   |     |  --------   |           ------|    PWM waveform   |  analog part |   |
 *                           |   |     |     PWM     |-----------------x------------------>|              |   |
 *                           |   |      -------------                  |                   |              |   |
 *                           |    -------------------------------------                     --------------    |
 *                            --------------------------------------------------------------------------------
 *             X : Chip internal PAD
 *             
 *             Key Point:
 *                       <1> Two step need for TZ function ��Enable TZ function on the EPWR side, Enable TZ function on the
 *                           MCU side.
 *             Key point:
 *                 PRE-DRIVER init include two step��
 *                     <1> Init the communication circuits(SSP circyits) with MCU, we call this step 'Init PRE-DRIVER module'.
 *                     <2> Init PRE-DRIVER socket itself, we call this step 'Power up PRE-DRIVER mode'.
 *
 *************************************************************************************************************************/


int main(void)
{
  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 PRE-DRIVER module(this step means 'Init PRE-DRIVER module') and get the ID */
  eErrorState = HV_Init(u32SSPBaundrate, &u8PREDRIID, u32Timeout);
  if(eErrorState == ERROR)
  {
    printf("Init PRE-DRIVER mode FAIL\n");
    return 0;
  }
  else
  {
    printf("Init PRE-DRIVER mode SUCCESS[ID:%d]\n",u8PREDRIID);
  }

  /* Set the PRE-DRIVER reference voltage(2.4V is recommanded) for high-side Vds monitor */
  eErrorState = HV_WriteReg(HV_REG_PDRVOCCTL, PDRVOCCTL_ALL_OCTH_2dot40_V);
  if(eErrorState == ERROR)
  {
    printf("Set PRE-DRIVER high-side Vds reference voltage FAIL\n");
    return ERROR;
  }
  
  /* Enable U/V/W-phase TZ0 signal of PRE-DRIVER when high/low side over current happened */
  eErrorState = HV_WriteReg(HV_REG_PDRVTZ0SEL1, PDRVTZ0SEL1_ALL_OCLU_ENABLE
                                                            | PDRVTZ0SEL1_ALL_OCLV_ENABLE
                                                            | PDRVTZ0SEL1_ALL_OCLW_ENABLE
                                                            | PDRVTZ0SEL1_ALL_OCHU_ENABLE
                                                            | PDRVTZ0SEL1_ALL_OCHV_ENABLE
                                                            | PDRVTZ0SEL1_ALL_OCHW_ENABLE);
  if(eErrorState == ERROR)
  {
    printf("Set over current protection FAIL\n");
    return 0;
  }

  /* PDRVCTL register can only be writable when CTLKEY=0x99 */
  eErrorState = HV_WriteReg(HV_REG_CTLKEY, CTLKEY_ALL_KEY_BUCKEN);
  if(eErrorState == ERROR)
  {
    printf("Write CTLKEY register FAIL\n");
    return 0;
  }

  /* Power up PRE-DRIVER mode(this step means 'Power up PRE-DRIVER mode') */
  eErrorState = HV_WriteReg(HV_REG_PDRVCTL, PDRVCTL_ALL_EN_ENABLE);
  if(eErrorState == ERROR)
  {
    printf("Power up PRE-DRIVER FAIL\n");
    return 0;
  }
  
  /* Delay 100us to wait for the VDDG LDO ready */
  Delay_Us(100);
  
  /* After PRE-DRIVER power on, clear all the status */
  eErrorState = HV_WriteReg(HV_REG_GLBSTSCLR1, GLBSTSCLR1_ALL_OCLU_CLEAR
                                                           | GLBSTSCLR1_ALL_OCLV_CLEAR
                                                           | GLBSTSCLR1_ALL_OCLW_CLEAR
                                                           | GLBSTSCLR1_ALL_OCHU_CLEAR
                                                           | GLBSTSCLR1_ALL_OCHV_CLEAR
                                                           | GLBSTSCLR1_ALL_OCHW_CLEAR);
  if(eErrorState == ERROR)
  {
    printf("Clear PRE-DRIVER status FAIL\n");
    return 0;
  }
  
  /* Wait for PRE-DRIVER mode become enable */
  u8Count = 0;
  do{
    eErrorState = HV_ReadReg(HV_REG_GLBSTS0, &u8PREDRIDATA);
    if(eErrorState == ERROR)
    {
      printf("PRE-DRIVER enable FAIL[%02x]\n",u8PREDRIDATA);
      return 0;
    }
    
    u8Count++;
    
    if(u8Count >= 10)
    {
      printf("PRE-DRIVER enable timeout\n");
      return 0;
    }
  }while(((u8PREDRIDATA & GLBSTS0_ALL_CPRDY_READY) == 0) && (u8Count < 10));
  
  /* additional delay after VDDG ready, for final power settling */
  Delay_Us(100);
  
  /* Enable write access to the protected EPWR registers */
  EPWR_WALLOW();

  /* Enbale EPWR module receive TZ signal from high voltage analog part */
  EPWR_EnableTripEvent(EPWR_TRIP_EVENT_TZ0);
  EPWR_EnableTripEvent(EPWR_TRIP_EVENT_TZ1);
  
  /* Set the input signal of TZ(bouth TZ 0 and 1) event as high */
  EPWR_SetTripEventInputActiveHigh(EPWR_TRIP_EVENT_TZ0);
  EPWR_SetTripEventInputActiveHigh(EPWR_TRIP_EVENT_TZ1);

  /* 
   * PRE-DRIVER TZ signal jump from one PAD(on PRE-DRIVER side) to another side(on MCU side), this could cause erroneous TZ assertion
   * signal, so, another filter need to be set on the EPWR side(EPWR is a internal mode of MCU).
   */
  EPWR_SetFilterWindowTimeNs(EPWR_TRIP_EVENT_TZ0, EPWR_WIN_VAL_NS, EPWR_TH_VAL_NS);
  EPWR_SetFilterWindowTimeNs(EPWR_TRIP_EVENT_TZ1, EPWR_WIN_VAL_NS, EPWR_TH_VAL_NS);
  
  /* Select TZ output signal(was sent to MCU) type */
  EPWR_SetTripEventOutputType(EPWR_TRIP_EVENT_TZ0, EPWR_OUTPUT_FILTERED);
  EPWR_SetTripEventOutputType(EPWR_TRIP_EVENT_TZ1, EPWR_OUTPUT_FILTERED);
  
  /* Disable write access to the protected EPWR registers */
  EPWR_WDIS();
  
  /* 
   * Init PWM0~5
   *
   * Warnning : 
   *           when PWM is used for PRE-DRIVER, the dead-band of the pair complementary waveform of one PWM channel
   *           must not equal zero, bigger than 600 is recommanded.
   */
  PWM_ComplementaryPairChannelInit(PRE_DRIVER_PWM_U, PRE_DRIVER_PWM_FREQ, PWM_DB_NS);
  PWM_ComplementaryPairChannelInit(PRE_DRIVER_PWM_V, PRE_DRIVER_PWM_FREQ, PWM_DB_NS);
  PWM_ComplementaryPairChannelInit(PRE_DRIVER_PWM_W, PRE_DRIVER_PWM_FREQ, PWM_DB_NS);

  /* 
   * PWM_U set CMPA and loading the same value to PWM_V/PWM_W synchronously, LINK must be set earlier than CAMP value is set,
   * otherwaise, the LINK function will be invalid.
   */
  PWM_LinkCMPA(PRE_DRIVER_PWM_V, PRE_DRIVER_LINK_PWM_U);
  PWM_LinkCMPA(PRE_DRIVER_PWM_W, PRE_DRIVER_LINK_PWM_U);

  /* Set PWM5A output 75% duty waveform */
  u32PWMPeriod = PWMPeriod(PRE_DRIVER_PWM_FREQ);
  PWM_SetCMPA(PRE_DRIVER_PWM_U, u32PWMPeriod / 4);
  
  /* Enabel global INT for WPM TZ(bouth of six PWM TZ) */
  NVIC_EnableIRQ(PWM3TZ_IRQn);
  NVIC_EnableIRQ(PWM4TZ_IRQn);
  NVIC_EnableIRQ(PWM5TZ_IRQn);
  
  /* Enable the TZ function on MCU side(each of six PWM is enable) */
  PWMx_Set_Digiter_Compare(PRE_DRIVER_PWM_U);
  PWMx_Set_Digiter_Compare(PRE_DRIVER_PWM_V);
  PWMx_Set_Digiter_Compare(PRE_DRIVER_PWM_W);
  
  /* Set PWM of PRE-DRIVER 1 start to count */
  PWM_RunCounter(PRE_DRIVER_PWM_U);
  PWM_RunCounter(PRE_DRIVER_PWM_V);
  PWM_RunCounter(PRE_DRIVER_PWM_W);

  while(1)
  {
  }
}

void PWM3TZ_IRQHandler()
{
  printf("PWM3 TZ INT happened\n");
}

void PWM4TZ_IRQHandler()
{
  printf("PWM4 TZ INT happened\n");
}

void PWM5TZ_IRQHandler()
{
  printf("PWM5 TZ INT happened\n");
}
