/******************************************************************************* * COPYRIGHT (C) 2021 CMS Technologies Ltd. * * * ******************************************************************************** * FileName : tim.c * * Author : * * Version : 1.0.2 * * Date : 2024.04.07 * * Description : * * Function List : * ********************************************************************************/ #include "tim.h" #include "cgc.h" //#if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN) #define TIM_CHAN_MAX_NUM 8u #define TIM_MAX_NUM 2u static IRQn_Type TIM_IRQTable[TIM_MAX_NUM][TIM_CHAN_MAX_NUM] = {{TM00_IRQn, TM01_IRQn, TM02_IRQn, TM03_IRQn}, {TM10_IRQn, TM11_IRQn, TM12_IRQn, TM13_IRQn,TM14_IRQn,TM15_IRQn,TM16_IRQn,TM17_IRQn}, }; //#else //#define TIM_CHAN_MAX_NUM 4u //#define TIM_MAX_NUM 1u //static IRQn_Type TIM_IRQTable[TIM_MAX_NUM][TIM_CHAN_MAX_NUM] = //{{TM00_IRQn, TM01_IRQn, TM02_IRQn, TM03_IRQn}}; //#endif /** * @brief Enables the specified TIMER channel. * @param TIMx: the specified tim, it can be TIM40 TIM41 * @param ChxIdx where ChxIdx can be 0, 1,2,3. * @arg TTM_Index_Channel0 * @arg TTM_Index_Channel1 * @arg TTM_Index_Channel2 * @arg TTM_Index_Channel3 * @arg TIM_Index_Channel4 * @arg TIM_Index_Channel5 * @arg TIM_Index_Channel6 * @arg TIM_Index_Channel7 * @retval None */ void TIM_Start(TMx_Type* TMx, uint8_t ChxIdx) { assert_param(IS_TIM(TMx)); assert_param(IS_TIM_CHANIDEX(ChxIdx)); TMx->TS = (1 << ChxIdx); } /** * @brief Disable the specified TIMER channel count. * @param tim: the specified tim, it can be TIM40 TIM41 * @param ChxIdx where ChxIdx can be 0, 1,2,3. * @arg TIM_Index_Channel0 * @arg TIM_Index_Channel1 * @arg TIM_Index_Channel2 * @arg TIM_Index_Channel3 * @arg TIM_Index_Channel4 * @arg TIM_Index_Channel5 * @arg TIM_Index_Channel6 * @arg TIM_Index_Channel7 * @retval None */ void TIM_Stop(TMx_Type* TMx, uint8_t ChxIdx) { assert_param(IS_TIM(TMx)); assert_param(IS_TIM_CHANIDEX(ChxIdx)); TMx->TT = (1 << ChxIdx); } /** * @brief Enables or disables the specified TIMER channel. * @param TIMx: TMx is TM40 or TM81. * @param Chx: where x can be 0, 1,2,3 select channel of specified TIMER peripheral. * @param NewState: new state of the TIEMR channel. * This parameter can be: ENABLE or DISABLE. * @retval None */ void TIM_Cmd(TMx_Type* TMx, uint8_t Chx, FunctionalState NewState) { if(NewState == ENABLE) TIM_Start(TMx,Chx); else TIM_Stop(TMx,Chx); } /** * @brief Set the specified TIMER channel's count num. * @param TIMx: where x can be 0, 1, select TIEMR peripheral. * @param Chx: where x can be 0, 1,2,3 4.5.6.7 * @param counter: the count num of the TIEMR channel. * @retval None */ void TIM_SetCounter(TMx_Type* TMx, uint8_t ChxIdx, uint16_t counter) { assert_param(IS_TIM(TMx)); assert_param(IS_TIM_CHANIDEX(ChxIdx)); TMx->TDR[ChxIdx] = counter; } /** * @brief Get the specified TIMER channel's status. * @param TIMx: where x can be 0, 1, select TIEMR peripheral. * @param Chx: where x can be 0, 1,2,3.4.5.6.7 select channel of specified TIMER peripheral. * @retval bool: 1 it occurs overflow * 0 it does not occur overflow */ bool TIM_GetStatus(TMx_Type* TMx, uint8_t ChxIdx) { assert_param(IS_TIM(TMx)); assert_param(IS_TIM_CHANIDEX(ChxIdx)); return (bool)(TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS); } /** * @brief Initializes the TIEMR peripheral according to the specified * parameters in the TIM_InitStruct . * @param TIM_InitStruct: pointer to a TIM_InitTypeDef structure that contains * the configuration information for the specified TIEMR peripheral. * @retval initial result */ int TIM_Init(TMx_Type* TMx,TIM_InitTypeDef *TIM_InitStruct) { int ret = TIM_SUCC; uint16_t clkselect = TM_CLOCK_SELECT_CKM0; uint8_t chanPos =0,chanNum=0,pos=0; uint8_t masterPos =0,masterNum=0,posm=0; assert_param(IS_TIM(TMx)); assert_param(IS_TIM_CHANNEL(TIM_InitStruct->TIM_Channel)); if(TMx == TM40) { CGC_PER0PeriphClockCmd(CGC_PER0Periph_TIM40,ENABLE); } #if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN) if(TMx == TM81) { CGC_PER2PeriphClockCmd(CGC_PER2Periph_TM81,ENABLE); } #endif if(IS_TIM_CLK0(TIM_InitStruct->TIM_ClkDivision)){ TMx->TPS &= ~TIM_CLK0_MASK; TMx->TPS |= TIM_InitStruct->TIM_ClkDivision; clkselect = TM_CLOCK_SELECT_CKM0; }else if(IS_TIM_CLK1(TIM_InitStruct->TIM_ClkDivision)){ TMx->TPS &= ~TIM_CLK1_MASK; TMx->TPS |= TIM_InitStruct->TIM_ClkDivision; clkselect = TM_CLOCK_SELECT_CKM1; }else if(IS_TIM_CLK2(TIM_InitStruct->TIM_ClkDivision)){ TMx->TPS &= ~TIM_CLK2_MASK; TMx->TPS |= TIM_InitStruct->TIM_ClkDivision; clkselect = TM_CLOCK_SELECT_CKM2; }else if(IS_TIM_CLK3(TIM_InitStruct->TIM_ClkDivision)){ TMx->TPS &= ~TIM_CLK3_MASK; TMx->TPS |= TIM_InitStruct->TIM_ClkDivision; clkselect = TM_CLOCK_SELECT_CKM3; }else{ return TIM_ERR; } if(IS_TTM_Master_Chan(TIM_InitStruct->TIM_Selection_Master))//multi-tim combination { for(masterPos = 0; masterPos < TIM_CHAN_MAX_NUM; masterPos++) { posm = ((char)0x01) << masterPos; masterNum = TIM_InitStruct->TIM_Selection_Master & posm; if(masterNum == posm) { if(masterPos == TIM_Index_Channel0) { TMx->TMR[masterPos] = clkselect | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_Mode_PWM_Master | TIM_InitStruct->TIM_StartInt; } else { TMx->TMR[masterPos] = clkselect | 0x0800 |TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_Mode_PWM_Master | TIM_InitStruct->TIM_StartInt; } TMx->TDR[masterPos] = TIM_InitStruct->TIM_Period[masterPos] -1; TMx->TOE &= ~(1 << masterPos); TMx->TO &= ~(1 << masterPos); MISC->NFEN1 |= (1<<masterPos); //??? } } for(chanPos = 0; chanPos < TIM_CHAN_MAX_NUM; chanPos++) //??????????? { pos = ((uint8_t)0x01) << chanPos; chanNum = TIM_InitStruct->TIM_Channel & pos; if(chanNum == pos) { TMx->TMR[chanPos] = clkselect | TIM_Trigger_UseMaster_Int | TIM_Mode_SinglePulse |TIM_InitStruct->TIM_StartInt; TMx->TDR[chanPos] = TIM_InitStruct->TIM_Period[chanPos]; TMx->TO &= ~(1 << chanPos); TMx->TOE |= (1 << chanPos); TMx->TOM |= (1 << chanPos); } } TMx->TOL|= TIM_InitStruct->TIM_Slave_Polarity; } else { for(chanPos = 0; chanPos < TIM_CHAN_MAX_NUM; chanPos++) { pos = ((uint8_t)0x01) << chanPos; chanNum = TIM_InitStruct->TIM_Channel & pos; if(chanNum == pos) { TMx->TDR[chanPos] = TIM_InitStruct->TIM_Period[chanPos] -1; TMx->TT |= TIM_InitStruct->TIM_Channel; //TIM stop TMx->TMR[chanPos] = clkselect | TIM_InitStruct->TIM_Trigger | TIM_InitStruct->TIM_Pulse_Edge | TIM_InitStruct->TIM_StartInt; TMx->TO &= ~ TIM_InitStruct->TIM_Channel; /*g??TIM_Mode_Interval/TIM_Mode_Square/TIM_Mode_DivFreq TMR?J???g??????0x0000*/ if(TIM_InitStruct->TIM_Mode == TIM_Mode_Interval) //?????g??????TO??????? { TMx->TOE &= ~TIM_InitStruct->TIM_Channel; } else if(TIM_InitStruct->TIM_Mode == TIM_Mode_Square) { TMx->TOE |= TIM_InitStruct->TIM_Channel; } else if(TIM_InitStruct->TIM_Mode == TIM_Mode_DivFreq) //???g?h???????channel0 ??? { assert_param(IS_TIM_CHANNEL0(TIM_InitStruct->TIM_Channel)); if(IS_TIM_CHANNEL0(TIM_InitStruct->TIM_Channel)) { TMx->TOE |= TIM_InitStruct->TIM_Channel; } } else //input event for tim { TMx->TOE &= ~ TIM_InitStruct->TIM_Channel; TMx->TMR[chanPos] |= TIM_InitStruct->TIM_Mode; if(TIM_InitStruct->TIM_Mode == TIM_Mode_EventCount) { TMx->TMR[chanPos] |= 0x1000; //????????w???? } if(TMx == TM40) { MISC->NFEN1 |= TIM_InitStruct->TIM_Channel; } #if defined(BAT32G1XX_80PIN) || defined(BAT32G1XX_100PIN) if(TMx == TM81) { MISC->NFEN2 |= TIM_InitStruct->TIM_Channel; } #endif if((TIM_InitStruct->TIM_Channel == TIM_Channel_0 || TIM_InitStruct->TIM_Channel == TIM_Channel_1) && (TMx == TM40)) { MISC->TIOS0 |= TIM_InitStruct->TIM4_Input; if(TIM_InitStruct->TIM4_Input) { MISC->NFEN1 &= ~(TIM_InitStruct->TIM_Channel); } } } } } } return ret; } /** * @brief The Timer operates as pulse width measure. * @param tim - choose timer unit it can choose TIM40 TIM41 * @param chxIdx - choose 0~7 * @retval period - return the pulse period at specified edge */ uint32_t TIM_GetPulsePeriod(TMx_Type* TMx, uint8_t ChxIdx) { uint8_t tindex = 0; uint32_t width = 0; assert_param(IS_TIM_CHANIDEX(ChxIdx)); assert_param(IS_TIM(TMx)); if(TMx == TM40) { tindex = 0; } else { tindex = 1; } if(INTC_GetPendingIRQ(TIM_IRQTable[tindex][ChxIdx])) { INTC_ClearPendingIRQ(TIM_IRQTable[tindex][ChxIdx]); /* clear INTTMA interrupt flag */ } if (1U == (TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS)) { width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL) + 0x10000UL; } else { width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL); } return (width); } /** * @brief The Timer operates as pulse width measure. * @param tim - choose timer unit it can choose TIM40 TIM41 * @param chxIdx - choose 0~7 * @retval pulse width - return the width of pulse */ uint32_t TIM_GetPulseWidth(TMx_Type* TMx, uint8_t ChxIdx) { uint8_t tindex = 0; uint32_t width = 0; assert_param(IS_TIM_CHANIDEX(ChxIdx)); assert_param(IS_TIM(TMx)); if(TMx == TM40) { tindex = 0; } else { tindex = 1; } if(INTC_GetPendingIRQ((TIM_IRQTable[tindex][ChxIdx]))) { INTC_ClearPendingIRQ(TIM_IRQTable[tindex][ChxIdx]); /* clear INTTM interrupt flag */ } else { return (width); } if (1U == (TMx->TSR[ChxIdx] & _0001_TM4_OVERFLOW_OCCURS)) { width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL) + 0x10000UL; } else { width= (uint32_t)(TMx->TDR[ChxIdx] + 1UL); } return (width); }