/*!
* COPYRIGHT NOTICE
* Copyright (c) 2013,山外科技
* All rights reserved.
* 技术讨论:山外初学论坛 http://www.vcan123.com
*
* 除注明出处外,以下所有内容版权均属山外科技所有,未经允许,不得用于商业用途,
* 修改内容时必须保留山外科技的版权声明。
*
* @file MK60_ftm.c
* @brief FTM定时器函数库
* @author 山外科技
* @version v5.1
* @date 2014-04-25
*/
/*
* 包含头文件
*/
#include "common.h"
#include "MK60_FTM.h"
/*
* 定义数组
*/
FTM_MemMapPtr FTMN[3] = {FTM0_BASE_PTR, FTM1_BASE_PTR, FTM2_BASE_PTR}; //定义三个指针数组保存 FTMn_e 的地址
/*!
* @brief 初始化FTM 的端口
* @param FTMn_e 模块号(FTM0、 FTM1、 FTM2)
* @param FTM_CHn_e 通道号(CH0~CH7)
* @since v5.0
*/
static void FTM_port_mux(FTMn_e ftmn, FTM_CHn_e ch)
{
/******************* 开启时钟 和 复用IO口*******************/
switch(ftmn)
{
case FTM0:
SIM_SCGC6 |= SIM_SCGC6_FTM0_MASK; //使能FTM0时钟
switch(ch)
{
case FTM_CH0:
if(FTM0_CH0 == PTC1)
{
port_init(FTM0_CH0, ALT4);
}
else if(FTM0_CH0 == PTA3)
{
port_init(FTM0_CH0, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH1:
if(FTM0_CH1 == PTC2)
{
port_init(FTM0_CH1, ALT4);
}
else if(FTM0_CH1 == PTA4)
{
port_init(FTM0_CH1, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH2:
if(FTM0_CH2 == PTC3)
{
port_init(FTM0_CH2, ALT4);
}
else if(FTM0_CH2 == PTA5)
{
port_init(FTM0_CH2, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH3:
if(FTM0_CH3 == PTC4)
{
port_init(FTM0_CH3, ALT4);
}
else if(FTM0_CH3 == PTA6)
{
port_init(FTM0_CH3, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH4:
if(FTM0_CH4 == PTD4)
{
port_init(FTM0_CH4, ALT4);
}
else if(FTM0_CH4 == PTA7)
{
port_init(FTM0_CH4, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH5:
if(FTM0_CH5 == PTD5)
{
port_init(FTM0_CH5, ALT4);
}
else if(FTM0_CH5 == PTA0)
{
port_init(FTM0_CH5, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH6:
if(FTM0_CH6 == PTD6)
{
port_init(FTM0_CH6, ALT4);
}
else if(FTM0_CH6 == PTA1)
{
port_init(FTM0_CH6, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH7:
if(FTM0_CH7 == PTD7)
{
port_init(FTM0_CH7, ALT4);
}
else if(FTM0_CH7 == PTA2)
{
port_init(FTM0_CH7, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
default:
return;
}
break;
case FTM1:
SIM_SCGC6 |= SIM_SCGC6_FTM1_MASK; //使能FTM1时钟
switch(ch)
{
case FTM_CH0:
if((FTM1_CH0 == PTA8) || (FTM1_CH0 == PTA12) || (FTM1_CH0 == PTB0) )
{
port_init(FTM1_CH0, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH1:
if((FTM1_CH1 == PTA9) || (FTM1_CH1 == PTA13) || (FTM1_CH1 == PTB1) )
{
port_init(FTM1_CH1, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
default:
return;
}
break;
case FTM2:
SIM_SCGC3 |= SIM_SCGC3_FTM2_MASK; //使能FTM2时钟
switch(ch)
{
case FTM_CH0:
if((FTM2_CH0 == PTA10) || (FTM2_CH0 == PTB18) )
{
port_init(FTM2_CH0, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
case FTM_CH1:
if((FTM2_CH1 == PTA11) || (FTM2_CH1 == PTB19))
{
port_init(FTM2_CH1, ALT3);
}
else
{
ASSERT(0); //设置管脚有误?
}
break;
default:
return;
}
break;
default:
break;
}
}
/*!
* @brief 初始化FTM 的PWM 功能
* @param FTMn_e 模块号(FTM0、 FTM1、 FTM2)
* @param FTM_CHn_e 通道号(CH0~CH7)
* @param freq 频率(单位为Hz)
* @param duty 占空比分子,占空比 = duty / FTMn_PRECISON
* @since v5.0
* @note 同一个FTM,PWM频率是必须一样的,但占空比可不一样。共3个FTM,即可以输出3个不同频率PWM
* Sample usage: FTM_PWM_init(FTM0, FTM_CH6,200, 10); //初始化 FTM0_CH6 为 频率 200Hz 的PWM,占空比为 10/FTM0_PRECISON
*/
void FTM_PWM_init(FTMn_e ftmn, FTM_CHn_e ch, uint32 freq, uint32 duty)
{
uint32 clk_hz ;
uint16 mod;
uint8 ps;
uint16 cv;
ASSERT( (ftmn == FTM0) || ( (ftmn == FTM1 || ftmn == FTM2 ) && (ch <= FTM_CH1)) ); //检查传递进来的通道是否正确
/******************* 开启时钟 和 复用IO口*******************/
FTM_port_mux(ftmn,ch);
/* 计算频率设置 */
// 若 CPWMS = 1 ,即双边捕捉脉冲,则 PMW频率 = bus频率 /2 /(2^预分频因子)/模数
// 若 CPWMS = 0 ,即单边捕捉脉冲,则 PMW频率 = bus频率 /(2^预分频因子)/模数
// EPWM的周期 :MOD - CNTIN + 0x0001 (CNTIN 设为0)
// 脉冲宽度:CnV - CNTIN
// 模数 MOD < 0x10000
// 预分频因子 PS < 0x07
// 预分频因子 PS 越小时,模数 mod 就越大,计数就越精准,PWM输出更为准确
// MOD = clk_hz/(freq*(1 << PS)) < 0x10000 ==> clk_hz/(freq*0x10000) < (1<< PS) ==> (clk_hz/(freq*0x10000) >> PS) < 1
// 即 (((clk_hz/0x10000 )/ freq ) >> PS ) < 1
// 以 CPWMS = 0 ,即单边捕捉脉冲为例
clk_hz = (bus_clk_khz * 1000) ; // bus频率
mod = (clk_hz >> 16 ) / freq ; // 临时用 mod 缓存一下
ps = 0;
while((mod >> ps) >= 1) // 等 (mod >> ps) < 1 才退出 while 循环 ,即求 PS 的最小值
{
ps++;
}
ASSERT(ps <= 0x07); // 断言, PS 最大为 0x07 ,超过此值,则 PWM频率设置过低,或 Bus 频率过高
mod = (clk_hz >> ps) / freq; // 求 MOD 的值
switch(ftmn) // 初值 CNTIN 设为0 ,脉冲宽度:CnV - CNTIN ,即 CnV 就是 脉冲宽度了。
{
// EPWM的周期 : MOD - CNTIN + 0x0001 == MOD - 0 + 1
// 则 CnV = (MOD - 0
评论2