SmartOS/Platform/STM32F4/Pwm.cpp

210 lines
6.9 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 "Kernel\Sys.h"
#include "Device\Port.h"
#include "Device\Pwm.h"
#include "Platform\stm32.h"
/*================ 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};
typedef void(*TIM_OCPldCfg)(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
const static TIM_OCPldCfg TIM_OCPldCfgs[4] = { TIM_OC1PreloadConfig,TIM_OC2PreloadConfig,TIM_OC3PreloadConfig,TIM_OC4PreloadConfig, };
typedef void(*SetCompare)(TIM_TypeDef* TIMx, uint32_t TIM_ICPSC);
const static SetCompare SetCompares[4] = { TIM_SetCompare1,TIM_SetCompare2,TIM_SetCompare3,TIM_SetCompare4, };
void Pwm::Config()
{
TS("Pwm::Config");
Timer::Config(); // 主要是配置时钟基础部分 TIM_TimeBaseInit
auto ti = (TIM_TypeDef*)_Timer;
if(Opened)
Flush();
else
{
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(Enabled[i])
{
oc.TIM_Pulse = Pulse[i];
OCInits[i](ti, &oc);
TIM_OCPldCfgs[i](ti, TIM_OCPreload_Enable);
debug_printf("Pwm%d::Config %d \r\n", _index+1, i);
}
}
}
// PWM模式用不上中断 直接就丢了吧 给中断管理减减麻烦
TIM_ITConfig(ti, TIM_IT_Update, DISABLE);
TIM_ClearFlag(ti, TIM_FLAG_Update);
TIM_SetCounter(ti, 0x00000000); // 清零定时器CNT计数寄存器
TIM_ARRPreloadConfig(ti, ENABLE); // 使能预装载寄存器ARR
}
void Pwm::Flush()
{
for (int i = 0; i < 4; i++)
{
if (Ports[i]) SetCompares[i]((TIM_TypeDef*)_Timer, Pulse[i]);
}
}
void Pwm::Open()
{
// 设置映射
//if(Remap=0) GPIO_PinRemapConfig(Remap, ENABLE);
Timer::Open();
if(_index == 0 ||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, ENABLE);
// 打开引脚
const Pin g_Pins[][4] = TIM_PINS;
//const Pin g_Pins2[][4] = TIM_PINS_FULLREMAP;
// 仅支持标准引脚和完全映射,非完全映射需要外部自己初始化
auto pss = g_Pins;
//if(Remap) pss = g_Pins2;
auto ps = pss[_index];
for(int i=0; i<4; i++)
{
if(Enabled[i] && Ports[i] == nullptr)
Ports[i] = new AlternatePort(ps[i]);
}
}
void Pwm::Close()
{
if(_index == 0 ||_index == 14 ||_index == 15|| _index == 16)
TIM_CtrlPWMOutputs((TIM_TypeDef*)_Timer, DISABLE);
for (int i = 0; i < 4; i++)
{
if (Ports[i]) TIM_OCPldCfgs[i]((TIM_TypeDef*)_Timer, TIM_OCPreload_Disable);
}
Timer::Close();
}
void PwmData::Config()
{
Pwm::Config();
// 如果需要连续调整宽度,那么需要中断
if(Pulses) SetHandler(true);
}
void PwmData::OnInterrupt()
{
if(!Pulses || !PulseCount || PulseIndex > PulseCount) return;
auto ti = (TIM_TypeDef*)_Timer;
// 动态计算4个寄存器中的某一个并设置宽度
auto reg = &(ti->CCR1);
reg += Channel;
// 发送完成以后,最后一次中断,把占空比调整为一半
if(PulseIndex >= PulseCount)
{
PulseIndex++;
*reg = Period >> 1;
return;
}
// 在中断里面切换宽度
ushort p = Pulses[PulseIndex++];
// 设置宽度
*reg = p;
// 重复
if(Repeated && PulseIndex >= PulseCount) PulseIndex = 0;
}
/*
//STM32F103C8T6 Time3PWM输出初始化 可用
//arr自动重装值
//psc时钟预分频数
void Time3PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟使能
//用于TIM3的CH2输出的PWM通过该LED显示
//设置该引脚为复用输出功能
//GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); // PB0 PB1 PB4 PB5 都是复用引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM3_CH4
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // PB4 是 NJTRST
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //TIM3_CH1
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM3_CH2
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCMode_PWM2 TIM_OCMode_PWM1 波形为反向
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器
TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
}
更新PWM输出函数 可用
TIM_SetCompare1(TIM3,led0pwmval);
TIM_SetCompare2(TIM3,led0pwmval);
TIM_SetCompare3(TIM3,led0pwmval);
TIM_SetCompare4(TIM3,led0pwmval);
*/