SmartOS/Device/Timer.cpp

567 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Timer.h"
#include "Platform\stm32.h"
static TIM_TypeDef* const g_Timers[] = TIMS;
const byte Timer::TimerCount = ArrayLength(g_Timers);
// 已经实例化的定时器对象
static Timer* Timers[16] = {
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
};
Timer::Timer(TIMER index)
{
assert_param(index <= ArrayLength(g_Timers));
Timers[index] = this;
_index = index;
_Timer = g_Timers[index];
// 默认情况下预分频到1MHz然后1000个周期即是1ms中断一次
/*Prescaler = Sys.Clock / 1000000;
Period = 1000;*/
SetFrequency(10);
Opened = false;
_Handler = nullptr;
_Param = nullptr;
}
Timer::~Timer()
{
Close();
if(_Handler) Register(nullptr);
Timers[_index] = nullptr;
}
// 创建指定索引的定时器如果已有则直接返回默认0xFF表示随机分配
Timer* Timer::Create(byte index)
{
TS("Timer::Create");
byte tcount = ArrayLength(g_Timers);
// 特殊处理随机分配
if(index == 0xFF)
{
// 找到第一个可用的位置,没有被使用,并且该位置定时器存在
byte i = 0;
for(; i<tcount && (Timers[i] || !g_Timers[i]); i++);
if(i >= tcount)
{
debug_printf("Timer::Create 失败!没有空闲定时器!\r\n");
return nullptr;
}
index = i;
}
assert_param(index < tcount);
if(Timers[index])
return Timers[index];
else
return new Timer((TIMER)index);
}
void Timer::Config()
{
TS("Timer::Config");
auto ti = (TIM_TypeDef*)_Timer;
// 配置时钟
TIM_TimeBaseInitTypeDef tr;
TIM_TimeBaseStructInit(&tr);
tr.TIM_Period = Period - 1;
tr.TIM_Prescaler = Prescaler - 1;
//tr.TIM_ClockDivision = 0x0;
tr.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(ti, &tr);
//TIM_PrescalerConfig(ti, tr.TIM_Period,TIM_PSCReloadMode_Immediate); // 分频数立即加载
// 打开中断
//TIM_ITConfig(ti, TIM_IT_Update | TIM_IT_Trigger, ENABLE);
TIM_ITConfig(ti, TIM_IT_Update, ENABLE);
//TIM_UpdateRequestConfig(ti, TIM_UpdateSource_Regular);
// 清除标志位 必须要有!! 否则 开启中断立马中断给你看
TIM_ClearFlag(ti, TIM_FLAG_Update);
//TIM_ClearITPendingBit(ti, TIM_IT_Update);
}
void Timer::Open()
{
if(Opened) return;
TS("Timer::Open");
#if DEBUG
// 获取当前频率
uint clk = RCC_GetPCLK();
#if defined(STM32F1) || defined(STM32F4)
if((uint)_Timer & 0x00010000) clk = RCC_GetPCLK2();
#endif
if(clk < Sys.Clock) clk <<= 1;
uint fre = clk / Prescaler / Period;
debug_printf("Timer%d::Open clk=%d Prescaler=%d Period=%d Fre=%d\r\n", _index + 1, clk, Prescaler, Period, fre);
assert(fre > 0, "频率超出范围");
#endif
// 打开时钟
ClockCmd(_index, true);
// 关闭。不再需要跟上面ClockCmd的效果一样
//TIM_DeInit((TIM_TypeDef*)_Timer);
Config();
// 打开计数
TIM_Cmd((TIM_TypeDef*)_Timer, ENABLE);
Opened = true;
}
void Timer::Close()
{
if(!Opened) return;
TS("Timer::Close");
debug_printf("Timer%d::Close\r\n", _index + 1);
auto ti = (TIM_TypeDef*)_Timer;
// 关闭计数器时钟
TIM_Cmd(ti, DISABLE);
TIM_ITConfig(ti, TIM_IT_Update, DISABLE);
TIM_ClearITPendingBit(ti, TIM_IT_Update); // 仅清除中断标志位 关闭不可靠
ClockCmd(_index, false); // 关闭定时器时钟
Opened = false;
}
void Timer::ClockCmd(int idx, bool state)
{
FunctionalState st = state ? ENABLE : DISABLE;
switch(idx + 1)
{
case 1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, st); break;
case 2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, st); break;
case 3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, st); break;
#if defined(STM32F1) && defined(STM32F4)
case 4: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, st); break;
case 5: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, st); break;
#endif
case 6: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, st); break;
#if defined(STM32F1) && defined(STM32F4)
case 7: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, st); break;
case 8: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, st); break;
#endif
#ifdef STM32F4
case 9: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, st); break;
case 10: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, st); break;
case 11: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM11, st); break;
case 12: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12, st); break;
case 13: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, st); break;
case 14: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, st); break;
#endif
#if defined(STM32F0) || defined(GD32F150)
case 14: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, st); break;
case 15: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, st); break;
case 16: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, st); break;
case 17: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM17, st); break;
#endif
}
}
// 设置预分频目标比如1MHz
/*void Timer::SetScaler(uint scaler)
{
assert_param(scaler);
uint ps = Sys.Clock / scaler;
assert_param(ps > 0 && ps <= 0xFFFF);
}*/
// 设置频率,自动计算预分频
void Timer::SetFrequency(uint frequency)
{
// 获取当前频率
#if defined(STM32F0) || defined(GD32F150)
uint clk = Sys.Clock;
#else
uint clk = RCC_GetPCLK();
if((uint)_Timer & 0x00010000) clk = RCC_GetPCLK2();
clk <<= 1;
#endif
// 120M时分频系数必须是120K才能得到1k的时钟超过了最大值64k
// 因此,需要增加系数
uint prd = clk / frequency;
uint psc = 1;
uint Div = 0;
while(prd > 0xFFFF)
{
prd >>= 1;
psc <<= 1;
Div++;
}
assert(frequency > 0 && frequency <= clk, "频率超出范围");
Prescaler = psc;
Period = prd;
// 如果已启动定时器,则重新配置一下,让新设置生效
if(Opened)
{
TIM_TimeBaseInitTypeDef tr;
TIM_TimeBaseStructInit(&tr);
tr.TIM_Period = Period - 1;
tr.TIM_Prescaler = Prescaler - 1;
//tr.TIM_ClockDivision = 0x0;
tr.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit((TIM_TypeDef*)_Timer, &tr);
}
}
uint Timer::GetCounter()
{
return TIM_GetCounter((TIM_TypeDef*)_Timer);
}
void Timer::SetCounter(uint cnt)
{
TIM_SetCounter((TIM_TypeDef*)_Timer, cnt);
}
void Timer::SetHandler(bool set)
{
const byte irqs[] = TIM_IRQns;
byte irq = irqs[_index];
if(set)
{
// 打开中断
//TIM_ITConfig((TIM_TypeDef*)_Timer, TIM_IT_Update, ENABLE);
Interrupt.SetPriority(irq, 1);
Interrupt.Activate(irq, OnHandler, this);
}
else
{
TIM_ITConfig((TIM_TypeDef*)_Timer, TIM_IT_Update, DISABLE);
Interrupt.Deactivate(irq);
}
}
void Timer::Register(EventHandler handler, void* param)
{
_Handler = handler;
_Param = param;
SetHandler(handler != nullptr);
}
void Timer::OnHandler(ushort num, void* param)
{
auto timer = (Timer*)param;
if(timer)
{
auto ti = (TIM_TypeDef*)timer->_Timer;
// 检查指定的 TIM 中断发生
if(TIM_GetITStatus(ti, TIM_IT_Update) == RESET) return;
// 必须清除TIMx的中断待处理位否则会频繁中断
TIM_ClearITPendingBit(ti, TIM_IT_Update);
timer->OnInterrupt();
}
}
void Timer::OnInterrupt()
{
if(_Handler) _Handler(this, _Param);
}
/*================ PWM ================*/
// STM32F030 的 先这么写着 后面再对 103 做调整
typedef void (*TIM_OCInit)(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
const static TIM_OCInit OCInits[4]={TIM_OC1Init, TIM_OC2Init, TIM_OC3Init, TIM_OC4Init};
// 外部初始化引脚 AFIO很头疼
/* @arg GPIO_AF_0:TIM15, TIM17, TIM14
* @arg GPIO_AF_1:Tim3, TIM15
* @arg GPIO_AF_2:TIM2, TIM1, TIM16, TIM17.
* @arg GPIO_AF_3:TIM15,
* @arg GPIO_AF_4:TIM14.
* @arg GPIO_AF_5:TIM16, TIM17.
* @arg GPIO_AF_6:
* @arg GPIO_AF_7:*/
//const static uint8_t TIM_CH_AFa[8]=
//{
//};
PWM::PWM(TIMER index) : Timer(index)
{
for(int i=0; i<4; i++) Pulse[i] = 0xFFFF;
Pulses = nullptr;
PulseCount = 0;
Channel = 0;
PulseIndex = 0xFF;
Repeated = false;
Configed = 0x00;
}
void PWM::Config()
{
TS("PWM::Config");
Timer::Config(); // 主要是配置时钟基础部分 TIM_TimeBaseInit
TIM_OCInitTypeDef oc;
TIM_OCStructInit(&oc);
oc.TIM_OCMode = TIM_OCMode_PWM1;
oc.TIM_OutputState = TIM_OutputState_Enable;
oc.TIM_OCPolarity = Polarity ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
oc.TIM_OCIdleState = IdleState ? TIM_OCIdleState_Reset : TIM_OCIdleState_Set;
auto ti = (TIM_TypeDef*)_Timer;
for(int i=0; i<4; i++)
{
if(Pulse[i] != 0xFFFF)
{
oc.TIM_Pulse = Pulse[i];
OCInits[i](ti, &oc);
Configed |= 0x1 << i;
}
}
if(!Pulses)
{
// PWM模式用不上中断 直接就丢了吧 给中断管理减减麻烦
TIM_ITConfig(ti, TIM_IT_Update, DISABLE);
TIM_ClearFlag(ti, TIM_FLAG_Update);
}
TIM_SetCounter(ti, 0x00000000); // 清零定时器CNT计数寄存器
TIM_ARRPreloadConfig(ti, ENABLE); // 使能预装载寄存器ARR
// 如果需要连续调整宽度,那么需要中断
if(Pulses) SetHandler(true);
}
void PWM::FlushOut()
{
TIM_OCInitTypeDef oc;
TIM_OCStructInit(&oc);
oc.TIM_OCMode = TIM_OCMode_PWM1;
oc.TIM_OutputState = TIM_OutputState_Enable;
oc.TIM_OCPolarity = Polarity ? TIM_OCPolarity_High : TIM_OCPolarity_Low;
oc.TIM_OCIdleState = IdleState ? TIM_OCIdleState_Reset : TIM_OCIdleState_Set;
for(int i=0; i<4; i++)
{
if(Pulse[i] != 0xFFFF)
{
oc.TIM_Pulse = Pulse[i];
OCInits[i]((TIM_TypeDef*)_Timer, &oc);
Configed |= 0x1 << i;
}
}
}
void PWM::Open()
{
Timer::Open();
#if defined(STM32F0) || defined(GD32F150)
if(_index == 0 ||_index == 7||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, ENABLE);
#endif
#if defined(STM32F1)
if(_index == 0 ||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, ENABLE);
#endif
#if defined(STM32F4)
#endif
}
void PWM::Close()
{
#if defined(STM32F1) || defined(GD32F150)
if(_index == 0 ||_index == 7||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, DISABLE);
#elif defined(STM32F1)
if(_index == 0 ||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, DISABLE);
#else //defined(STM32F4)
#endif
Timer::Close();
}
void PWM::SetPulse(int idx, ushort pulse)
{
if(Pulse[idx] == pulse) return;
Pulse[idx] = pulse;
if(Opened)
Config();
else
Open();
}
void PWM::OnInterrupt()
{
if(!Pulses || !PulseCount || PulseIndex > PulseCount) return;
auto ti = (TIM_TypeDef*)_Timer;
// 动态计算4个寄存器中的某一个并设置宽度
#ifdef STM32F1
volatile ushort* reg = &(ti->CCR1);
#else
volatile uint* reg = &(ti->CCR1);
#endif
reg += Channel;
// 发送完成以后,最后一次中断,把占空比调整为一半
if(PulseIndex >= PulseCount)
{
PulseIndex++;
*reg = Period >> 1;
return;
}
// 在中断里面切换宽度
ushort p = Pulses[PulseIndex++];
// 设置宽度
*reg = p;
// 重复
if(Repeated && PulseIndex >= PulseCount) PulseIndex = 0;
}
/*
#ifdef STM32F0
typedef uint32_t (*GetCap)(TIM_TypeDef* TIMx);
const static GetCap GetCapturex[4]={
TIM_GetCapture1,
TIM_GetCapture2,
TIM_GetCapture3,
TIM_GetCapture4
};
typedef void (*SetICxPres)(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
const static SetICxPres SetICPrescaler[]={
TIM_SetIC1Prescaler ,
TIM_SetIC2Prescaler ,
TIM_SetIC3Prescaler ,
TIM_SetIC4Prescaler ,
};
Capture::Capture(Timer * timer)
{
if(timer == nullptr)return ;
tr = timer;
// HaveCap = 0x00;
for(int i =0;i<4;i++)
{
_Handler [i]=nullptr; // 其实可以不赋值
_Param [i]=nullptr;
}
}
void Capture::Start(int channel)
{
}
void Capture::Stop(int channel)
{
}
uint Capture :: GetCapture (int channel)
{
if(channel >4 || channel <1)return 0;
return (GetCapturex[channel-1])(tr->_Timer );
}
#endif
void Capture::Register(int channel,EventHandler handler, void* param )
{
if(channel<1||channel>4) return ;
_Handler[channel-1] = handler;
_Param[channel-1]=param;
// if(handler != nullptr)
// tr->Register (OnHandler ,this);
int irq;
if(handler)
{
if(tr ->_index == 0)
irq = TIM1_CC_IRQn;
// else// stm32f103有个TIM8 这里留空
Interrupt.SetPriority(irq, 1);
Interrupt.Activate(irq, OnHandler, this);
}
else
{
_Handler[channel-1] = nullptr ;
_Param [channel-1]=nullptr;
for(int i =0 ;i<4;i++)
if(_Handler [i] != nullptr )return ;
Interrupt.Deactivate(irq);
}
}
// 直接用指针访问私有成员 不好
//void Capture :: OnHandler(void* sender, void* param)
//{
// Capture * cap= (Capture*)param;
// if(cap->_Handler != nullptr)
// cap->_Handler(sender,cap->_Param );
//}
void Capture :: OnHandler(ushort num, void* param)
{
Capture * cap= (Capture*)param;
if(cap != nullptr)
cap->OnInterrupt();
}
void Capture::OnInterrupt()
{
// 找出中断源
ushort ccx = TIM_FLAG_CC1;
for(int i =0;i<4;i++)
{
if(TIM_GetFlagStatus(tr->_Timer , ccx<<i ))
_Handler[i](this,_Param [i]);
}
// if(_Handler) _Handler[](this, _Param);
}
Capture::~Capture()
{
for(int i =0;i<4;i++)
Register(i,nullptr, nullptr );
delete(tr);
}
*/