/**************************************************************************//**
 * @file     pan_timer.c
 * @version  V1.00
 * $Revision: 2 $
 * $Date: 16/02/24 15:37 $
 * @brief    Panchip series TIMER driver source file
 *
 * @note
 * Copyright (C) 2025 Panchip Technology Corp. All rights reserved.
*****************************************************************************/
#include "pan271x.h"
#include "pan_timer.h"
#include "pan_clk.h"

/** @addtogroup Panchip_Device_Driver Panchip Device Driver
  @{
*/

/** @addtogroup Panchip_TIMER_Driver TIMER Driver
  @{
*/


/** @addtogroup Panchip_TIMER_EXPORTED_FUNCTIONS TIMER Exported Functions
  @{
*/


/**
  * @brief This API stops Timer counting and disable the Timer interrupt function
  * @param[in] timer The base address of Timer module
  * @return None
  */
void TIMER_Close(TIMER_T *timer)
{
    timer->TIMER_CTL &= ~TIMER_CTL_CNT_EN_Msk;
}

/**
  * @brief This API is used to create a delay loop for u32usec micro seconds
  * @param[in] timer The base address of Timer module
  * @param[in] u32Usec Delay period in micro seconds with 10 usec every step. Valid values are between 10~1000000 (10 micro second ~ 1 second)
  * @return None
  * @note This API overwrites the register setting of the timer used to count the delay time.
  * @note This API use polling mode. So there is no need to enable interrupt for the timer module used to generate delay
  */
void TIMER_Delay(TIMER_T *timer, uint32_t u32Usec)
{
    uint32_t u32Clk = CLK_GetPeripheralFreq(timer);
    uint32_t delay = SystemCoreClock / u32Clk;
    float fCmpr;

    // Clear current timer configuration
    timer->TIMER_CTL = 0;

    if(u32Clk == 10000) {         // min delay is 100us if timer clock source is LIRC 10k
        u32Usec = ((u32Usec + 99) / 100) * 100;
    } else {    // 10 usec every step
        u32Usec = ((u32Usec + 9) / 10) * 10;
    }

    // u32Usec * u32Clk might overflow if using uint32_t
    fCmpr = (float)u32Usec * u32Clk / 1000000.0f;

	timer->TIMER_CTL = (timer->TIMER_CTL & ~TIMER_CTL_CMPDATA_Msk) | ((uint32_t)fCmpr << TIMER_CTL_CMPDATA_Pos);
    timer->TIMER_CTL |= TIMER_CTL_CNT_EN_Msk;

    // When system clock is faster than timer clock, it is possible timer active bit cannot set in time while we check it.
    // And the while loop below return immediately, so put a tiny delay here allowing timer start counting and raise active flag.
    for(; delay > 0; delay--) {
        __NOP();
    }

    while(!(timer->TIMER_CTL & TIMER_CTL_TIMER_FLAG_Msk));
	TIMER_ClearTFFlag(timer, TIMER_CTL_TIMER_FLAG_Msk);
}

void TIMER_SetCmpValue(TIMER_T *timer, uint32_t u32Value)
{
	uint32_t clk_src = 0;
	
	(void)clk_src;
	uint8_t compare_compensate = 0;

	clk_src = CLK->APB1_CLK_CTRL0 & APB1_CLK_CTRL0_TMR0SEL_Msk;

//	/*timer clk source is apb clk */
//	if (clk_src == 0) {
//		compare_compensate = FIXED_DEVIATION;
//	}

	/*here has 12 apb clk for hw timer sync operation*/
	timer->TIMER_CTL = (timer->TIMER_CTL & ~TIMER_CTL_CMPDATA_Msk) | ((u32Value - compare_compensate) << TIMER_CTL_CMPDATA_Pos);
}

/*@}*/ /* end of group Panchip_TIMER_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group Panchip_TIMER_Driver */

/*@}*/ /* end of group Panchip_Device_Driver */

/*** (C) COPYRIGHT 2016 Panchip Technology Corp. ***/
