/*******************************************************************************
*                  COPYRIGHT (C) 2021 CMS Technologies Ltd.                    *
*                                                                              *
********************************************************************************
* FileName      : tima.c                                                  *
* Author        :                                                              *
* Version       : 1.0                                                          *
* Date          : 2021.08.13                                                   *
* Description   :                                                              *
* Function List :                                                              *
********************************************************************************/
#include "timb.h"
#include "cgc.h"



/**
  * @brief  This function stops the clock supplied for TMB.
  * @param  None
  * @retval None
  */
void TMB0_Set_PowerOff(void)
{
	CGC_PER1PeriphClockCmd(CGC_PER1Periph_TMB,DISABLE);
}

/**
  * @brief  This function starts TMA counter.
  * @param  None
  * @retval None
  */
void TMB_Start(void)
{
    volatile uint8_t tbsr_dummy;

    tbsr_dummy = TMB->TBSR; /* read TBSR before write 0 */
    TMB->TBSR = 0x00U;
	
    TMB->TBMR |= TMB_COUNT_START;	
}

/**
  * @brief  This function stops TMA counter.
  * @param  None
  * @retval None
  */
void TMB_Stop(void)
{
    volatile uint8_t tbsr_dummy;

    TMB->TBMR &= (uint8_t)~TMB_COUNT_START;

    tbsr_dummy = TMB->TBSR; /* read TBSR before write 0 */
    TMB->TBSR = 0x00U;
}

/**
  * @brief  Checks whether the specified TMB flag is set or not.
  * @param  TMB_FLAG: specifies the flag to check.
  *          This parameter can be one of the following values:
  *            @arg TMB_FLAG_TB_OVERFLOW: TB counter is overflow
  *            @arg TMB_FLAG_TB_UNDERFLOW: TB counter is underflow
  *            @arg TMB_FLAG_CHB_MATCHED: TB is matched with TBGRB
  *            @arg TMB_FLAG_CHA_MATCHED: TB is matched with TBGRA
  * @retval The new state of USART_FLAG (SET or RESET).
  */
FlagStatus TMB_GetStaus(uint8_t TMB_FLAG)
{
	FlagStatus bitstatus = RESET;	
	/* Check the parameters */
	assert_param(IS_TMB_FLAG(TMB_FLAG));

	
	if ((TMB->TBSR & TMB_FLAG) != (uint8_t)RESET)
	{
		bitstatus = SET;
	}
	else
	{
		bitstatus = RESET;
	}
	
	return bitstatus;
}


/**
  * @brief  Initializes the TIEMRB peripheral according to the specified
  *         parameters in the TIMB_InitStruct .
  * @param  TIMB_InitStruct: pointer to a TMB_InitTypeDef structure that contains
  *         the configuration information for the specified TIEMRB peripheral.
  * @retval none
  */
void TMB_Init(TMB_InitTypeDef *TIMB_InitStruct)
{
	assert_param(IS_TMB_CLOCK(TIMB_InitStruct->TMB_Clk));	
	assert_param(IS_TMB_CHANNEL(TIMB_InitStruct->TMB_Channel));	

	CGC_PER1PeriphClockCmd(CGC_PER1Periph_TMB,ENABLE);
	
	TMB->TBMR &= (uint8_t)~TMB_COUNT_START;	//TMB STOP
	TMB->TBMR = 0x00;

    TMB->TBCR = TIMB_InitStruct->TMB_CounterClear | TIMB_InitStruct->TMB_Clk;  

	if(TIMB_InitStruct->TMB_Mode == TMB_Mode_Capture)
	{		
		if((TIMB_InitStruct->TMB_Channel & TMB_Channel_A) == TMB_Channel_A)
		{
			TMB->TBIOR = 0x08 | 0x04 | TIMB_InitStruct->TMB_IC.TMB_CHA.TMB_ICPolarity;
			if(TIMB_InitStruct->TMB_IC.TMB_CHA.TMB_ICFilter == 1) //ʹ���˲�������
			{		
				TMB->TBMR |= 0x04;
				TMB->TBMR |= (TIMB_InitStruct->TMB_IC.TMB_CHA.TMB_Filter_Clk << 4);
			}
		}
		if((TIMB_InitStruct->TMB_Channel & TMB_Channel_B) == TMB_Channel_B)
		{
			TMB->TBIOR = (0x08 << 4) | 0x40 |( TIMB_InitStruct->TMB_IC.TMB_CHB.TMB_ICPolarity << 4);	
			if(TIMB_InitStruct->TMB_IC.TMB_CHB.TMB_ICFilter == 1) //ʹ���˲�������
			{		
				TMB->TBMR |= 0x08;
				TMB->TBMR |= (TIMB_InitStruct->TMB_IC.TMB_CHB.TMB_Filter_Clk << 4);				
			}
			
		}	
		if((TIMB_InitStruct->TMB_Channel & TMB_Channel_ELC) == TMB_Channel_ELC)
		{
			TMB->TBMR |= 0x40;		
		}

	}
	
	if(TIMB_InitStruct->TMB_Mode == TMB_Mode_Compare)
	{
		if((TIMB_InitStruct->TMB_Channel & TMB_Channel_A) == TMB_Channel_A)
		{
			TMB->TBIOR |= 0x08 | 0x00 | TIMB_InitStruct->TMB_OC.TMB_CHA.TMB_OCPolarity;
			TMB->TBGRA = TIMB_InitStruct->TMB_CHA_Pulse -1;
		}
		if((TIMB_InitStruct->TMB_Channel & TMB_Channel_B)== TMB_Channel_B)
		{
			TMB->TBIOR |= (0x08 << 4) | 0x00 |( TIMB_InitStruct->TMB_OC.TMB_CHB.TMB_OCPolarity << 4);
			TMB->TBGRB = TIMB_InitStruct->TMB_CHB_Pulse -1;				
		}
		TMB->TBGRC = TMB->TBGRA;
		TMB->TBGRD = TMB->TBGRB;	
	}
	if(TIMB_InitStruct->TMB_Mode == TMB_Mode_PWM)
	{
		TMB->TBMR |= 0x01;
		/* Please note that TBBUFB and TBBUFA bit of TBIOR register are still valid in PWM mode. */
		/* TBGRD/TBGRC is used as buffer register for TBGRB/TBGRA register */
		TMB->TBIOR = (0x08 << 4) | 0x08;
		TMB->TBGRA = TIMB_InitStruct->TMB_CHA_Pulse -1;
		TMB->TBGRB = TIMB_InitStruct->TMB_CHB_Pulse -1;				
		TMB->TBGRC = TMB->TBGRA;
		TMB->TBGRD = TMB->TBGRB;			
	}
	TMB->TBIER = 0x08 | 0x02 | 0x01;  //��������/�Ƚ������ж�

}


/**
  * @brief  Set the specified TMB PWM duty and period .
  * @param  period - the period of TBIO0 output wave
  * @param  duty - the duty of TBIO0 output wave      
  * @retval None
  */

void TMB_SetCounter(uint16_t period, uint16_t duty)
{
	TMB->TBGRA = period  -1;
	TMB->TBGRB = duty -1;				
	TMB->TBGRC = TMB->TBGRA;
	TMB->TBGRD = TMB->TBGRB;			
}

volatile uint16_t tmb_overflow_count_a = 0U;
volatile uint16_t tmb_overflow_count_b = 0U;

uint32_t TMB_GetPulseWidth(uint8_t channel)
{
	int32_t width=0;
	
    uint8_t tbsr_temp = TMB->TBSR;
    uint8_t tbier_temp = TMB->TBIER;
	
	if (INTC_GetPendingIRQ(TMB_IRQn) == 1)
	{
		INTC_ClearPendingIRQ(TMB_IRQn); /* clear INTTMA interrupt flag */
	}
	else
	{
		return 0;	
	}

    if (TMB_GetStaus(TMB_FLAG_TB_OVERFLOW) == SET) // count overflow
    {
        TMB->TBSR = tbsr_temp & (uint8_t)~TMB_FLAG_TB_OVERFLOW;
//        tmb_overflow_count_a += 1UL;
//        tmb_overflow_count_b += 1UL;
    }

	if(channel == TMB_Channel_A)
	{
		if (TMB_GetStaus(TMB_FLAG_CHA_MATCHED) == SET)
		{
			TMB->TBSR = tbsr_temp & ~TMB_FLAG_CHA_MATCHED;

			if (tmb_overflow_count_a == 0UL)
			{
				width = (TMB->TBGRA - TMB->TBGRC);
				tmb_overflow_count_a = 0;
				if(width < 0)
				{
					width += 0xffff;
				}
			}
			else
			{
				width = (TMB->TBGRA - TMB->TBGRC) + 0xffff;
				tmb_overflow_count_a = 0UL;
			}
		}
	}
	if(channel == TMB_Channel_B)
	{
		if (TMB_GetStaus(TMB_FLAG_CHB_MATCHED) == SET)
		{
			TMB->TBSR = tbsr_temp & ~TMB_FLAG_CHB_MATCHED;

			if (tmb_overflow_count_b == 0UL)
			{
				width = (TMB->TBGRB - TMB->TBGRD);
			}
			else
			{
				width = (TMB->TBGRB - TMB->TBGRD) + (0x10000UL * tmb_overflow_count_b);
				tmb_overflow_count_b = 0UL;
			}
		}
	}

    TMB->TBIER = tbier_temp;

	return width;
}