Files
ArduinoCore-AT32F4/cores/arduino/libcore/timer.c

609 lines
14 KiB
C
Raw Normal View History

2022-07-10 21:37:33 +08:00
/*
* MIT License
* Copyright (c) 2017 - 2022 _VIFEXTech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "timer.h"
typedef enum
{
TIMER1, TIMER2, TIMER3, TIMER4, TIMER5, TIMER6, TIMER7, TIMER8,
TIMER9, TIMER10, TIMER11, TIMER12, TIMER13, TIMER14, TIMER15,
TIMER_MAX
} TIMER_Type;
static Timer_CallbackFunction_t Timer_CallbackFunction[TIMER_MAX] = { 0 };
/**
* @brief
* @param TIMx:
* @param NewState: ENABLE启动DISABLE关闭
* @retval
*/
void Timer_ClockCmd(tmr_type* TIMx, bool Enable)
{
int index;
typedef struct
{
tmr_type* tmr;
crm_periph_clock_type crm_periph_clock;
} crm_tmr_clock_map_t;
# define CLOCK_MAP_DEF(n) {TMR##n, CRM_TMR##n##_PERIPH_CLOCK}
static const crm_tmr_clock_map_t clock_map[] =
{
CLOCK_MAP_DEF(1),
CLOCK_MAP_DEF(2),
CLOCK_MAP_DEF(3),
CLOCK_MAP_DEF(4),
CLOCK_MAP_DEF(5),
CLOCK_MAP_DEF(6),
CLOCK_MAP_DEF(7),
CLOCK_MAP_DEF(8),
CLOCK_MAP_DEF(9),
CLOCK_MAP_DEF(10),
CLOCK_MAP_DEF(11),
CLOCK_MAP_DEF(12),
CLOCK_MAP_DEF(13),
CLOCK_MAP_DEF(14)
};
for(index = 0; index < sizeof(clock_map) / sizeof(crm_tmr_clock_map_t); index++)
{
if(TIMx == clock_map[index].tmr)
{
crm_periph_clock_enable(clock_map[index].crm_periph_clock, Enable ? TRUE : FALSE);
}
}
}
static float Qsqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = *(long*)&y;
i = 0x5f3759df - (i >> 1);
y = *(float*)&i;
y = y * (threehalfs - (x2 * y * y));
y = y * (threehalfs - (x2 * y * y));
return 1.0f / y;
}
/**
* @brief
* @param freq: (Hz)
* @param clock:
* @param *period:
* @param *prescaler:
* @retval (Hz)
*/
static bool Timer_FreqFactorization(
uint32_t freq,
uint32_t clock,
uint16_t* factor1,
uint16_t* factor2,
int32_t* error
)
{
uint32_t targetProdect;
uint16_t fct1;
uint16_t fct2;
uint16_t fct1_save = 1;
uint16_t fct2_save = 1;
uint16_t fct_max;
uint16_t max_error = 0xFFFF;
if(freq == 0 || freq > clock)
{
return false;
}
/* 获取目标乘积 */
targetProdect = clock / freq;
/* 从targetProdect的平方根开始计算 */
fct1 = Qsqrt(targetProdect);
/* 计算因数最大值,减少遍历次数 */
fct_max = (targetProdect < 0xFFFF) ? targetProdect : 0xFFFF;
/* 遍历使两因数的乘积足够接近prodect */
for(; fct1 > 1; fct1--)
{
for(fct2 = fct1; fct2 < fct_max; fct2++)
{
/* 求误差 */
int32_t newerr = fct1 * fct2 - targetProdect;
if(newerr < 0)
{
newerr = -newerr;
}
if(newerr < max_error)
{
/* 保存最小误差 */
max_error = (uint16_t)newerr;
fct1_save = fct1;
fct2_save = fct2;
/* 最佳 */
if(max_error == 0)
{
break;
}
}
}
}
*factor1 = fct1_save;
*factor2 = fct2_save;
*error = (freq - clock / (fct1_save * fct2_save));
return true;
}
/**
* @brief
* @param time: ()
* @param clock:
* @param *period:
* @param *prescaler:
* @retval
*/
static void Timer_TimeFactorization(
uint32_t time,
uint32_t clock,
uint16_t* factor1,
uint16_t* factor2
)
{
const uint32_t cyclesPerMicros = clock / 1000000U;
const uint32_t prodect = time * cyclesPerMicros;
uint16_t fct1, fct2;
if(prodect < cyclesPerMicros * 30)
{
fct1 = 10;
fct2 = prodect / 10;
}
else if(prodect < 65535 * 1000)
{
fct1 = prodect / 1000;
fct2 = prodect / fct1;
}
else
{
fct1 = prodect / 20000;
fct2 = prodect / fct1;
}
*factor1 = fct1;
*factor2 = fct2;
}
/**
* @brief 使
* @param TIMx:
* @param Enable: 使
* @retval
*/
void Timer_SetEnable(tmr_type* TIMx, bool Enable)
{
tmr_counter_enable(TIMx, Enable ? TRUE : FALSE);
}
/**
* @brief
* @param TIMx:
* @param Time: ()
* @param Function:
* @retval
*/
void Timer_SetInterrupt(tmr_type* TIMx, uint32_t Time, Timer_CallbackFunction_t Function)
{
uint16_t period = 0;
uint16_t prescaler = 0;
uint32_t clock = Timer_GetClockMax(TIMx);
if(Time == 0)
{
return;
}
/*将定时中断时间转换为重装值和时钟分频值*/
Timer_TimeFactorization(
Time,
clock,
&period,
&prescaler
);
/*定时中断配置*/
Timer_SetInterruptBase(
TIMx,
period,
prescaler,
Function,
TIMER_PREEMPTIONPRIORITY_DEFAULT,
TIMER_SUBPRIORITY_DEFAULT
);
}
/**
* @brief
* @param TIMx:
* @param Freq:
* @retval true:
*/
bool Timer_SetInterruptFreqUpdate(tmr_type* TIMx, uint32_t Freq)
{
uint16_t period, prescaler;
uint32_t clock = Timer_GetClockMax(TIMx);
int32_t error;
if(Freq == 0)
return false;
bool success = Timer_FreqFactorization(
Freq,
clock,
&period,
&prescaler,
&error
);
if(!success)
{
return false;
}
tmr_base_init(TIMx, period - 1, prescaler - 1);
return true;
}
/**
* @brief
* @param TIMx:
* @retval
*/
uint32_t Timer_GetClockMax(tmr_type* TIMx)
{
static crm_clocks_freq_type crm_clocks_freq_struct = {0};
if(!crm_clocks_freq_struct.sclk_freq)
{
crm_clocks_freq_get(&crm_clocks_freq_struct);
}
return crm_clocks_freq_struct.apb1_freq * 2;
}
/**
* @brief
* @param TIMx:
* @retval
*/
uint32_t Timer_GetClockOut(tmr_type* TIMx)
{
uint32_t clock = Timer_GetClockMax(TIMx);
return (clock / ((TIMx->pr + 1) * (TIMx->div + 1)));
}
/**
* @brief
* @param TIMx:
* @param Time: ()
* @retval
*/
void Timer_SetInterruptTimeUpdate(TIM_TypeDef* TIMx, uint32_t Time)
{
uint16_t period, prescaler;
uint32_t clock = Timer_GetClockMax(TIMx);
Timer_TimeFactorization(
Time,
clock,
&period,
&prescaler
);
tmr_base_init(TIMx, period - 1, prescaler - 1);
}
/**
* @brief
* @param TIMx:
* @param Period:
* @param Prescaler:
* @param Function:
* @param PreemptionPriority:
* @param SubPriority:
* @retval
*/
void Timer_SetInterruptBase(
tmr_type* TIMx,
uint16_t Period,
uint16_t Prescaler,
Timer_CallbackFunction_t Function,
uint8_t PreemptionPriority,
uint8_t SubPriority
)
{
IRQn_Type TMRx_IRQn = (IRQn_Type)0;
TIMER_Type TIMERx = TIMER1;
#define TMRx_IRQ_DEF(n,x_IRQn)\
do{\
if(TIMx == TIM##n)\
{\
TIMERx = TIMER##n;\
TMRx_IRQn = x_IRQn;\
goto match;\
}\
}\
while(0)
/*如果编译器提示identifier "xxx_IRQn" is undefined
*
*/
TMRx_IRQ_DEF(1, TMR1_OVF_TMR10_IRQn);
TMRx_IRQ_DEF(2, TMR2_GLOBAL_IRQn);
TMRx_IRQ_DEF(3, TMR3_GLOBAL_IRQn);
TMRx_IRQ_DEF(4, TMR4_GLOBAL_IRQn);
TMRx_IRQ_DEF(5, TMR5_GLOBAL_IRQn);
TMRx_IRQ_DEF(6, TMR6_GLOBAL_IRQn);
TMRx_IRQ_DEF(7, TMR7_GLOBAL_IRQn);
TMRx_IRQ_DEF(8, TMR8_OVF_TMR13_IRQn);
TMRx_IRQ_DEF(9, TMR1_BRK_TMR9_IRQn);
TMRx_IRQ_DEF(10, TMR1_OVF_TMR10_IRQn);
TMRx_IRQ_DEF(11, TMR1_TRG_HALL_TMR11_IRQn);
TMRx_IRQ_DEF(12, TMR8_BRK_TMR12_IRQn);
TMRx_IRQ_DEF(13, TMR8_OVF_TMR13_IRQn);
TMRx_IRQ_DEF(14, TMR8_TRG_HALL_TMR14_IRQn);
match:
if(TMRx_IRQn == 0)
{
return;
}
Timer_CallbackFunction[TIMERx] = Function;
tmr_reset(TIMx);
Timer_ClockCmd(TIMx, true);
tmr_repetition_counter_set(TIMx, 0);
tmr_cnt_dir_set(TIMx, TMR_COUNT_UP);
tmr_base_init(TIMx, Period - 1, Prescaler - 1);
nvic_irq_enable(TMRx_IRQn, PreemptionPriority, SubPriority);
tmr_flag_clear(TIMx, TMR_OVF_FLAG);
tmr_interrupt_enable(TIMx, TMR_OVF_INT, TRUE);
}
/**
* @brief
* @param TIMx:
* @param TimerChannel:
* @param Compare:
* @retval
*/
void Timer_SetCompare(TIM_TypeDef* TIMx, uint8_t TimerChannel, uint32_t Compare)
{
switch(TimerChannel)
{
case 1:
tmr_channel_value_set(TIMx, TMR_SELECT_CHANNEL_1, Compare);
break;
case 2:
tmr_channel_value_set(TIMx, TMR_SELECT_CHANNEL_2, Compare);
break;
case 3:
tmr_channel_value_set(TIMx, TMR_SELECT_CHANNEL_3, Compare);
break;
case 4:
tmr_channel_value_set(TIMx, TMR_SELECT_CHANNEL_4, Compare);
break;
default:
break;
}
}
/**
* @brief
* @param TIMx:
* @param TimerChannel:
* @retval
*/
uint16_t Timer_GetCompare(TIM_TypeDef* TIMx, uint8_t TimerChannel)
{
uint16_t retval = 0;
switch(TimerChannel)
{
case 1:
retval = tmr_channel_value_get(TIMx, TMR_SELECT_CHANNEL_1);
break;
case 2:
retval = tmr_channel_value_get(TIMx, TMR_SELECT_CHANNEL_2);
break;
case 3:
retval = tmr_channel_value_get(TIMx, TMR_SELECT_CHANNEL_3);
break;
case 4:
retval = tmr_channel_value_get(TIMx, TMR_SELECT_CHANNEL_4);
break;
default:
break;
}
return retval;
}
/**
* @brief
* @param TIMx:
* @param rescaler:
* @retval
*/
void Timer_SetPrescaler(tmr_type* TIMx, uint16_t rescaler)
{
TIMx->div = rescaler;
}
/**
* @brief
* @param TIMx:
* @param Reload:
* @retval
*/
void Timer_SetReload(tmr_type* TIMx, uint16_t Reload)
{
TIMx->pr = Reload;
}
/**
* @brief
* @param TIMx:
* @retval
*/
void Timer_GenerateUpdate(tmr_type* TIMx)
{
TIMx->swevt_bit.ovfswtr = TRUE;
}
#define TMRx_IRQHANDLER(n) \
do{\
if (tmr_flag_get(TMR##n, TMR_OVF_FLAG) != RESET)\
{\
if(Timer_CallbackFunction[TIMER##n])\
{\
Timer_CallbackFunction[TIMER##n]();\
}\
tmr_flag_clear(TMR##n, TMR_OVF_FLAG);\
}\
}while(0)
/**
* @brief 110
* @param
* @retval
*/
2022-09-04 20:47:15 +08:00
void TMR1_OVF_TMR10_IRQHandler(void)
2022-07-10 21:37:33 +08:00
{
TMRx_IRQHANDLER(1);
TMRx_IRQHANDLER(10);
}
/**
* @brief 2
* @param
* @retval
*/
void TMR2_GLOBAL_IRQHandler(void)
{
TMRx_IRQHANDLER(2);
}
/**
* @brief 3
* @param
* @retval
*/
void TMR3_GLOBAL_IRQHandler(void)
{
TMRx_IRQHANDLER(3);
}
/**
* @brief 4
* @param
* @retval
*/
void TMR4_GLOBAL_IRQHandler(void)
{
TMRx_IRQHANDLER(4);
}
/**
* @brief 5
* @param
* @retval
*/
void TMR5_GLOBAL_IRQHandler(void)
{
TMRx_IRQHANDLER(5);
}
/**
* @brief 6
* @param
* @retval
*/
void TMR6_GLOBAL_IRQHandler(void)
{
#ifdef TMR6
TMRx_IRQHANDLER(6);
#endif
}
/**
* @brief 7
* @param
* @retval
*/
void TMR7_GLOBAL_IRQHandler(void)
{
#ifdef TMR7
TMRx_IRQHANDLER(7);
#endif
}
/**
* @brief 813
* @param
* @retval
*/
2022-09-04 20:47:15 +08:00
void TMR8_OVF_TMR13_IRQHandler(void)
2022-07-10 21:37:33 +08:00
{
TMRx_IRQHANDLER(8);
#ifdef TMR13
TMRx_IRQHANDLER(13);
#endif
}
/**
* @brief 15
* @param
* @retval
*/
2022-09-04 20:47:15 +08:00
void TMR15_OVF_IRQHandler(void)
2022-07-10 21:37:33 +08:00
{
#ifdef TMR15
TMRx_IRQHANDLER(15);
#endif
}