/******************************************************************************
文 件 名：PWM.h
功能描述：PWM设置及驱动头文件
作    者：张暄
版    本：V1.0
日    期：2016.11.3
******************************************************************************/

#ifndef _PWM_H_
#define _PWM_H_

#include "CRG.h"

/******************************************************************************
PWM共有4个可用的时钟：clock A, clock B, clock SA 和 clock SB (scaled B), 这些时
钟都是基于总线时钟(BUSCLK)生成的. clock A/B 直接由总线时钟(BUSCLK)分频得到,
clock SA/SB 则是由 clock A/B 进一步分频得到

PWM通道 0 / 1 / 4 / 5 可以选择 clock A / clock SA 中的一个作为其时钟输入
PWM通道 2 / 3 / 6 / 7 可以选择 clock B / clock SB 中的一个作为其时钟输入

各个PWM通道以其各自选择的时钟输入为基础,可以生成各自不同频率、不同相位、不同占
空比的PWM脉冲
******************************************************************************/

/******************************************************************************
PWM Clock A/B 频率选择
******************************************************************************/
#define     PWM_CLKA_FREQ                  BUS_CLK_DIV_8
#define     PWM_CLKB_FREQ                  BUS_CLK_DIV_8
/******************************************************************************
PWM Clock A/B 可选频率列表
******************************************************************************/
#define     BUS_CLK_DIV_1                  0x00
#define     BUS_CLK_DIV_2                  0x01
#define     BUS_CLK_DIV_4                  0x02
#define     BUS_CLK_DIV_8                  0x03
#define     BUS_CLK_DIV_16                 0x04
#define     BUS_CLK_DIV_32                 0x05
#define     BUS_CLK_DIV_64                 0x06
#define     BUS_CLK_DIV_128                0x07

/******************************************************************************
PWM Clock SA/SB 频率设置
*******************************************************************************
注意：设置的Clock SA/SB频率,必须是依照如下公式可以生成的值
Clock SA = Clock A / (2 * PWMSCLA)
Clock SB = Clock B / (2 * PWMSCLB)
******************************************************************************/
#define     PWM_CLKSA_FREQ                 10000
#define     PWM_CLKSB_FREQ                 2000000
/******************************************************************************
PWM通道极性选择
******************************************************************************/
#define    PWM_POL_NGE                     0x00
#define    PWM_POL_POS                     (!PWM_POL_NGE)

/******************************************************************************
PWM通道时钟源选择
******************************************************************************/
#define    PWM_CLOCK_A                     0x00
#define    PWM_CLOCK_SA                    (!PWM_CLOCK_A)

#define    PWM_CLOCK_B                     0x00
#define    PWM_CLOCK_SB                    (!PWM_CLOCK_B)

/******************************************************************************
PWM通道对齐方式
******************************************************************************/
#define    PWM_LEFT_ALIGN                  0x00
#define    PWM_CENTER_ALIGN                (!PWM_LEFT_ALIGN )

/******************************************************************************
PWM输出端口选择
******************************************************************************/
#define    PWM0_PP0                        0x00
#define    PWM0_PS4                        0x01

#define    PWM1_PP1                        0x00
#define    PWM1_PS5                        0x02

#define    PWM2_PP2                        0x00
#define    PWM2_PS6                        0x04

#define    PWM3_PP3                        0x00
#define    PWM3_PS7                        0x08

#define    PWM4_PP4                        0x00
#define    PWM4_PS2                        0x01
#define    PWM4_PV0                        0x02
#define    PWM4_PM0                        0x03

#define    PWM5_PP5                        0x00
#define    PWM5_PS3                        0x04
#define    PWM5_PV1                        0x08
#define    PWM5_PM1                        0x0C

#define    PWM6_PP6                        0x00
#define    PWM6_PS0                        0x10
#define    PWM6_PV2                        0x20
#define    PWM6_PM2                        0x30

#define    PWM7_PP7                        0x00
#define    PWM7_PS1                        0x40
#define    PWM7_PV3                        0x80
#define    PWM7_PM3                        0xC0

/******************************************************************************
PWM 时钟频率预处理
******************************************************************************/
#ifndef PWM_CLKA_FREQ
  #error    Please define PWM_CLKA_FREQ in PWM.h
#endif

#if     (PWM_CLKA_FREQ == BUS_CLK_DIV_1)
  #define   PWMCLKA                        BUSCLK
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_2)
  #define   PWMCLKA                        (BUSCLK / 2)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_4)
  #define   PWMCLKA                        (BUSCLK / 4)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_8)
  #define   PWMCLKA                        (BUSCLK / 8)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_16)
  #define   PWMCLKA                        (BUSCLK / 16)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_32)
  #define   PWMCLKA                        (BUSCLK / 32)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_64)
  #define   PWMCLKA                        (BUSCLK / 64)
#elif   (PWM_CLKA_FREQ == BUS_CLK_DIV_128)
  #define   PWMCLKA                        (BUSCLK / 128)
#else
  #error    Please define PWM_CLKA_FREQ within a valid value range
#endif

#ifndef PWM_CLKB_FREQ
  #error    Please define PWM_CLKB_FREQ in PWM.h
#endif

#if    (PWM_CLKB_FREQ == BUS_CLK_DIV_1)
  #define   PWMCLKB                        BUSCLK
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_2)
  #define   PWMCLKB                        (BUSCLK / 2)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_4)
  #define   PWMCLKB                        (BUSCLK / 4)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_8)
  #define   PWMCLKB                        (BUSCLK / 8)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_16)
  #define   PWMCLKB                        (BUSCLK / 16)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_32)
  #define   PWMCLKB                        (BUSCLK / 32)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_64)
  #define   PWMCLKB                        (BUSCLK / 64)
#elif  (PWM_CLKB_FREQ == BUS_CLK_DIV_128)
  #define   PWMCLKB                        (BUSCLK / 128)
#else
  #error    Please define PWM_CLKB_FREQ within a valid value range
#endif

#ifndef PWM_CLKSA_FREQ
  #error Please define PWM_CLKSA_FREQ in PWM.h
#endif

#if    (PWM_CLKSA_FREQ == 0)
  #error Please define PWM_CLKSA_FREQ within a valid value range
#elif  (PWM_CLKSA_FREQ > PWMCLKA / 2)
  #error Please define PWM_CLKSA_FREQ within a valid value range
#else
  #if  (((PWMCLKA / 2) % PWM_CLKSA_FREQ == 0) && ((PWMCLKA / 2) / PWM_CLKSA_FREQ <= 256))
    #define   PWMCLKSA                     PWM_CLKSA_FREQ
    #if  ((PWMCLKA / 2) / PWM_CLKSA_FREQ == 256)
      #define  PWMSCLAREG                  0x00
    #else
      #define  PWMSCLAREG                  (PWMCLKA / 2) / PWM_CLKSA_FREQ
    #endif
  #else
    #error  Can not generate PWM_CLKSA_FREQ by current setting
  #endif
#endif

#ifndef PWM_CLKSB_FREQ
  #error Please define PWM_CLKSB_FREQ in PWM.h
#endif

#if    (PWM_CLKSB_FREQ == 0)
  #error Please define PWM_CLKSB_FREQ within a valid value range
#elif  (PWM_CLKSB_FREQ > PWMCLKB / 2)
  #error Please define PWM_CLKSB_FREQ within a valid value range
#else
  #if  (((PWMCLKB / 2) % PWM_CLKSB_FREQ == 0) && ((PWMCLKB / 2) / PWM_CLKSB_FREQ <= 256))
    #define   PWMCLKSB                     PWM_CLKSB_FREQ
    #if  ((PWMCLKB / 2) / PWM_CLKSB_FREQ == 256)
      #define  PWMSCLBREG                  0x00
    #else
      #define  PWMSCLBREG                  (PWMCLKB / 2) / PWM_CLKSB_FREQ
    #endif
  #else
    #error  Can not generate PWM_CLKSB_FREQ by current setting
  #endif
#endif

/******************************************************************************
函数声明
******************************************************************************/
void PWM_Init(void);
void PWM_Channel_Init(uint8_t Ch, uint8_t ClkSrc, uint8_t Pol, uint8_t Cae, uint8_t IOSel);
void PWM_Channel_Set_Freq(uint8_t Ch, uint32_t Freq);
void PWM_Channel_Set_Duty_Cycle(uint8_t Ch, uint8_t Dty);
void PWM_Channel_Start(uint8_t Ch);
void PWM_Channel_Stop(uint8_t Ch);

#endif