1. 简介

FTM(FlexTimer)是由一个简单的定时器——HCS08 定时器 PWM(TPM)模块建立而来的,在飞思卡尔 8bit 微控制器上已经使用多年。Flextimer模块应用领域包括马达控制,照明控制和电源等。

FTM是一个2到8通道定时器,支持输入捕获,输出比较,pwm信号发生和正交解码功能。

2. Features

  • FTM source clock is selectable

  • 可选的FTM时钟源

  • Source clock can be the FTM input clock, the fixed frequency clock, or an external clock.

  • 时钟源可以是FTM输入时钟/固定频率时钟/外部时钟。

  • Fixed frequency clock is an additional clock input to allow the selection of an on chip clock source other than the FTM input clock.

  • 固定频率时钟允许使用片上其他时钟源作为时钟输入补充。

  • Selecting external clock connects FTM clock to a chip level input pin therefore allowing to synchronize the FTM counter with an off chip clock source

  • 选择外部时钟即连接FTM时钟到外部管脚,允许使用外部时钟同步FTM计数器。

  • Prescaler divide-by 1, 2, 4, 8, 16, 32, 64, or 128.

  • 预分频支持1,2,4,8,16,32,64,128。

  • 16-bit counter

  • 16bit计数器。

  • It can be a free-running counter or a counter with initial and final value.

  • 自由运行计数器或拥有初始值和终止值的计数器。

  • The counting can be up or up-down.

  • 可以递增或递减。

  • Each channel can be configured for input capture, output compare, or edge-aligned PWM mode.

  • 每个通道可以配置为输入捕获、输出比较或边沿对齐PWM模式。

  • In Input Capture mode:

  • 输入捕获模式下:

  • The capture can occur on rising edges, falling edges or both edges.

  • 可以是上升沿、下降沿或边沿捕获。

  • An input filter can be selected for some channels. One unique prescaler is available for all filters.

  • 一些通道可以选择输入滤波器,所有的滤波器可选一个唯一的分频器。

  • In Output Compare mode the output signal can be set, cleared, or toggled on match.

  • 在输出比较模式,输出信号在匹配触发时可以置位,复位,或翻转。

  • All channels can be configured for center-aligned PWM mode

  • 所有的通道可以配置为中心对齐PWM模式。

  • Each pair of channels can be combined to generate a PWM signal with independent control of both edges of PWM signal.

  • 每一对通道可以组合生成一个PWM信号,对PWM信号两个边沿进行独立控制。

  • The FTM channels can operate as pairs with equal outputs, pairs with complementary outputs, or independent channels with independent outputs

  • FTM通道可以成对相同输出,成对输出互补,或各通道独立输出。

  • The deadtime insertion is available for each complementary pair.

  • 每个互补输出可以设置死区。

  • Generation of match triggers.

  • 匹配触发发生器(生成匹配触发器??????)

  • Software control of PWM outputs.

  • 软件可控的PWM输出。

  • The polarity of each channel is configurable

  • 所有通道极性可配。

  • Up to 4 fault inputs for global fault control.

  • 最多支持4个故障输入作为全局故障控制。

  • The generation of an interrupt per channel

  • 每个通道可产生中断。

  • The generation of an interrupt when the counter overflows

  • 计数器溢出中断。

  • The generation of an interrupt when the fault condition is detected.

  • 故障条件触发中断。

  • The generation of an interrupt when a register reload point occurs.

  • 寄存器重新加载点触发中断。

  • Synchronized loading of write buffered FTM registers.

  • FTM写缓冲寄存器同步加载。

  • Half cycle and Full cycle register reload capacity.

  • 半周期/全周期寄存器重载能力。

  • Write protection for critical registers

  • 关键寄存器写保护。

  • Backwards compatible with TPM.

  • 向后兼容TPM。

  • Testing of input capture mode.

  • 输入捕获模式测试。

  • Direct access to input pin states.

  • 输入引脚状态直接访问。

  • Dual edge capture for pulse and period width measurement.

  • 用于脉冲宽度和周期测量的双边沿捕获模式。

  • Quadrature decoder with input filters, relative position counting, and interrupt on position count or capture of position count on external event.

  • 带有输入滤波器的正交译码器,相对位置计数,位置计数中断或位置计数捕获。

  • The FTM channels can be selected to generate a trigger pulse on channel output instead of a PWM.

  • 可以选择FTM通道来产生通道输出的触发脉冲,而不是PWM。

  • Dithering capability to simulate fine edge control for both PWM period or PWM duty cycle.

  • 抖动功能可模拟PWM周期或PWM占空比的精细边沿控制。

  • 3. S32K144 FTM结构框图

     

    Flextimer模块图,左上角为Flextimer基准时钟信号,默认状态为无时钟选择,即Flextimer计数器关闭。

    右上角为时钟分频控制,可以控制Flextimer计数时钟频率。框图中包括中断控制,模式选择,故障信号检测以及输出信号。

    Flextimer工作模式包括:输入捕获,输出比较,PWM波形输出,正交解码器。

    FTM模块的核心是一个16bit计数器,该计数器的时钟源可以选择,如果我们选择由FTM来实现PWM,输入捕捉,或者输出比较,定时中断,脉宽测量等功能,则一般选择system clock。如果我们选择由FTM实现对外部脉冲的计数,也可选择外部时钟,如果是外部编解码器输入的AB相脉冲,用于电机正反转测速,则可以使用PHA和PHB输入,由计数器自动加减计数。

    每个FTM模块拥有一个FTM Couter计数器,所有通道共用同一计数器。

  • CNTIN – 初始值

  • MOD – 结束值

  • 三种计数方式

    1. 递增计数。

    2. 先加后减,循环往复。

    3. 正交解码模式下自动递增或递减。

    4. 功能描述

    4.1 时钟源

  • FTM时钟

  • 固定频率时钟

  • 外部时钟

  • 4.2 分频

    支持1、2、4、8、16、32、64、128分频。

    4.3 计数器

    16bit计数器

  • 向上递增模式,主要用于EPWM。

  • CNTIN定义计数开始值,MOD定义技术终止值。FTM使能后会加载CNTIN值,累加计数直到达到MOD终止值。之后会重新装载CNTIN计数开始值。当计数值重新加载CNTIN值时,TOF(计数器溢出标志位)置位。

  • 向上递增再向下递减循环模式,主要用于CPWM模式。

  • CNTIN定义计数开始值,MOD定义技术终止值。FTM使能后会加载CNTIN值,累加计数直到达到MOD终止值,之后计数器将递减计数值直到计数值为CNTIN。之后会重复递增递减计数的过程。

  • 正交解码模式,根据AB相序增减计数。

  • 4.4 通道模式

    下表显示了通道的模式选择

      

    每个通道都可以配置成输入捕获,输出比较或者边沿对齐PWM波输出。

    输入捕获可以配置捕获方式:上升沿、下降沿或者双沿捕获。

    一些通道可以配置输入信号滤波。

    输出比较模式下,输出信号可以配置为输出高或低或者每次匹配翻转。

    所有通道都可以配置成PWM中心对齐输出。

    每对通道均可以结合输出PWM波。

    每对通道可以配置相同输出,相反(互补)输出或者作为独立通道。

    每对互补通道可以提供死区插入功能。

    4.5 FTM操作模式

    4.5.1 边沿对齐PWM(EPWM)模式

    在边沿对齐PWM模式下, FTM计数器从FTM_CNTIN值向上计数到FTM_MOD值。当FTM计数器从MOD值变为CNTIN值时,所有FTM通道的信号都在边缘对齐。 当QUADEN = 0, DECAPEN = 0, MCOMBINE = 0, COMBINE = 0, CPWMS = 0和MSnB =1时,选择边沿对齐PWM模式。 边沿对齐PWM周期由MOD – CNTIN + 0x0001决定,脉冲宽度(或占空比)由 CnV – CNTIN or MOD – CNTIN – CnV决定,具体取决于控制位 ELSnB:ELSnA。

    在中,示波器通道CH1, CH2, CH3和 CH4 分别代表FTM模块的FTM_CH0,FTM_CH1, FTM_CH2和 FTM_CH3。第一个通道对(FTM_CH0/FTM_CH1)和第二 个通道对(FTM_CH2/FTM_CH3)在互补模式下工作,分别具有50%和25%的占空比。 第二个通道对(FTM_CH2/FTM_CH3)演示了边缘对齐。

    4.5.2 中心对齐PWM(CPWM)模式

    在中心对齐PWM模式下, FTM计数器从FTM_CNTIN向上计数到FTM_MOD,然后从FTM_MOD向下计数到FTM_CTNIN。所有FTM通道的信号在FTM计数器达到FTM_MOD值的点对齐。当 QUADEN = 0, DECAPEN = 0, MCOMBINE = 0, COMBINE = 0和CPWMS = 1时,选择中心对齐PWM模式。

    中心对齐PWM的占空比确定为 2 × (CnV – CNTIN)。周期确定为 2 × (MOD – CNTIN)。

     

    图中,示波器通道CH1、 CH2、 CH3和CH4分别代表FTM模块的FTM_CH0、FTM_CH1、 FTM_CH2和FTM_CH3。第一个通道对(FTM_CH0/FTM_CH1)和第二 个通道对(FTM_CH2/FTM_CH3)在互补模式下工作, 分别具有50%和25%的占空比。 第二个通道对(FTM_CH2/FTM_CH3)演示了中心对齐。

    4.5.3 互补模式和死区时间插入

    FTM模式支持互补模式。如果通过FTM_COMBINE寄存器中的COMP位启用互补模式,则输出信号仅由偶数FTM通道生成。奇数输出信号由互补逻辑生成,作为偶数FTM通道的补码。 对于FTM的每个通道对,是否输出互补信号是可以单独配置的。

     为避免短路,死区时间必须插入互补信号中。死区插入由死区逻辑提供,遵循互补逻辑。该功能可以通过FTMxCOMBINEm寄存器中的DTEN位使能。死区逻辑将每个上升沿延迟一段时间,该时间由FTM_DEADTIME寄存器设置。死区时间由两部分组成,前两个最高有效位DTPS[1:0]定义系统时钟的预分频器。位DTVAL[5:0]使用预分频时钟定义占空比值。 互补模式和死区插入应用于边沿对齐PWM和中心对齐PWM模式,如前几节所述。

    4.5.4 组合模式

    组合模式提供了更高的灵活性,因为PWM通道( n)输出是通过组合偶数通道( n)和相邻的奇数通道(n+1)产生的。这意味着偶数和奇数通道必须在互补模式下工作。

    组合模式仅允许使用递增计数器、非对称PWM或相移PWM来生成EPWM和CPWM。相移PWM通常用于移相全桥转换器和电机控制应用,其中三相定子电流由采样电阻得到。有关更多详细信息,请参阅使用Kinetis KEA128的三相 BLDC电机无传感器控制参考设计(文档DRM151)。

    当QUADEN = 0, DECAPEN = 0, MCOMBINE = 0, COMBINE = 1和CPWMS = 0时,选择组合模式。

    要生成具有高真脉冲的相移PWM,请将控制位设置为ELSnB:ELSnA = 1: 0。

    void Phase_Shifted_PWM()
    {
        /* Enable clock for FTM1 */
        PCC->PCCn[PCC_FLEXTMR1_INDEX] = PCC_PCCn_PCS(6) | PCC_PCCn_CGC_MASK;
        /* Enable clock for PORTB */
        PCC->PCCn[PCC_PORTB_INDEX] = PCC_PCCn_CGC_MASK;
        /* Enable clock for PORTD */
        PCC->PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK;
        PORTB->PCR[2] = PORT_PCR_MUX(2); // Set PTB2 for FTM1 – Channel0 
        PORTB->PCR[3] = PORT_PCR_MUX(2); // Set PTB3 for FTM1 – Channel1 
        PORTD->PCR[8] = PORT_PCR_MUX(6); // Set PTD8 for FTM1 – Channel4 
        PORTD->PCR[9] = PORT_PCR_MUX(6); // Set PTd9 for FTM1 –Channel5
        /* Enable combine, complementary mode and dead-time for channel pair CH0/CH1 and CH4/CH5 */
        FTM1->COMBINE = FTM_COMBINE_COMBINE0_MASK | FTM_COMBINE_COMP0_MASK | FTM_COMBINE_DTEN0_MASK | FTM_COMBINE_COMBINE2_MASK | FTM_COMBINE_COMP2_MASK | FTM_COMBINE_DTEN2_MASK;
        FTM1->CONTROLS[0].CnSC=FTM_CnSC_ELSB_MASK; // Select high-true pulses 
        FTM1->CONTROLS[1].CnSC=FTM_CnSC_ELSB_MASK; // Select high-true pulses
        FTM1->CONTROLS[4].CnSC=FTM_CnSC_ELSB_MASK; // Select high-true pulses 
        FTM1->CONTROLS[5].CnSC=FTM_CnSC_ELSB_MASK; // Select high-truepulses
        /* Set Modulo (10kHz PWM frequency @112MHz system clock) */
        FTM1->MOD = FTM_MOD_MOD(11200-1); // Set modulo
        FTM1->CONTROLS[0].CnV=FTM_CnV_VAL(2800); // Set channel Value
        FTM1->CONTROLS[1].CnV=FTM_CnV_VAL(8400); // Set channel Value 
        FTM1->CONTROLS[4].CnV=FTM_CnV_VAL(5600); // Set channel Value
        FTM1->CONTROLS[5].CnV=FTM_CnV_VAL(11200); // Set channel Value 
        FTM1->CNT = 0;  // Counter reset
        /* Insert DeadTime (1us) */
        FTM1->DEADTIME = FTM_DEADTIME_DTPS(3) | FTM_DEADTIME_DTVAL(7);
        FTM1->SC|=FTM_SC_CLKS(1)|FTM_SC_PWMEN0_MASK | FTM_SC_PWMEN1_MASK | FTM_SC_PWMEN4_MASK | FTM_SC_PWMEN5_MASK; // Select clock and enable PWM
    }

    图中,示波器通道 CH1、 CH2、 CH3和CH4分别代表FTM1模块通道FTM1_CH0、FTM1_CH1、 FTM_CH4和FTM_CH5。第一个通道对( FTM_CH0/FTM_CH1)和第二个通道对( FTM_CH4/FTM_CH5)都在互补模式下工作,占空比为50%。第二个通道对(FTM_CH4/FTM_CH5)与第一个通道对(FTM_CH0/FTM_CH1)相移90°。

    图中还显示了PWM生成的灵活性,因为50%的占空比可以根据特定的应用要求进行 边沿对齐、中心对齐或各种偏移。

    4.5.4B 改进组合模式

    改进的组合PWM模式是为了生成周期不变但是占空比会变得PWM。通道n和n+1结合生成PWM信号,通常通道n匹配边沿是固定的,通道n+1匹配边沿可以被修改。

    一般使用多个通道时,配置每个通道n的匹配边沿带有固定偏移的输出,这样在产生照明PWM控制信号时是有用的,当需要的边缘不与其他对一致,以帮助消除噪声产生。

    4.5.5 单边输入捕获模式

    FTM 捕获模式主要用于测量信号的脉冲宽度或周期。 FTM 捕获模式的另一个选择是检测外部信号的上升/下降沿并产生中断以通知外部事件出现。 FTM 捕获模式也用于BLDC电机控制应用,其中霍尔传感器用于检测转子位置并计算转子速度,从而可以稳定速度环。 霍尔传感器连接到独立的FTM (FTM_CHx) 的通道。然后, FTM 可以检测霍尔传感器信号的下降沿和上升沿并生成捕获中断。在捕获中断程序中, PWM 信号的占空比会根据霍尔传感器逻辑进行更新。 当 DECAPEN = 0、 MCOMBINE = 0、 COMBINE = 0、 CPWMS = 0、 MSnB:MSnA =0:0 且 ELSnB:ELSnA ≠ 0:0 时,选择单边沿捕获模式。 要测量信号的脉冲宽度或周期,请选择FTM模块 FTM_CHx 的输入通道,并通过控制位 ELSnB:ELSnA 选择边沿触发。当通道输入上出现所选边沿时, FTM计数器的当前值将被存储到 CnV 寄存器中并产生通道中断(如果 CH(n)IE = 1)。在例程中断中,将 CnV 寄存器的值保存到一个变量中,并将当前值与前一个中断例程中保存的值进行区分。如果所选捕获模式在上升沿 (ELSnB:ELSnA= 0:1) 或下降沿 (ELSnB:ELSnA= 1:0) 触发,则差值等于信号周期。如果所选的捕获模式在两个边沿都触发 (ELSnB:ELSnA = 1:1),则差值等于被测信号的脉冲宽度。

    此示例显示FTM0的输入捕获模式,该模式测量通过FTM0_CH0通道的输入信号的时间周期。

    在图 5中,示波器通道CH0表示输入到FTM0_CH0通道的测试信号。 每次出现上升沿,都会产生捕获中断,并在中断程序中计算信号周期。

    4.5.6 双边捕获模式

    双边沿捕获模式使用两个 FTM 通道,可以测量信号的正极或负极脉冲宽度。在此模式下,信号必须通过偶数 FTM 通道输入,而忽略奇数通道。

    DECAPEN = 1 时选择双边沿捕获模式。 FTM 的双边沿捕获模式可以工作在一次性捕获模式或连续捕获模式。 MS(n)A = 0 时选择一次性捕获模式。如果使能 DECAP 位,则捕获边沿。对于每次新的测量,必须清除 CH(n)F 和 CH(n+1)F,并且必须再次设置 DECAP位。 MS(n)A = 1 时选择连续捕获模式。在这种模式下,如果 DECAP 位被设置,则边沿被连续捕获。对于每次新的测量,都需要清除 CH(n)F 和 CH(n+1)F 位。

    要测量被测信号的正极脉宽(无论是单次模式还是连续模式),通道(n)必须配置为捕获上升沿( ELS( n) B: ELS( n) A = 1:0) 和通道 (n+1) 必须配置为捕获下降沿(ELS(n+1)B:ELS(n+1)A = 0:1)。当检测到被测信号的第二个下降沿时, CH(n+1)F 置位,DECAP 位清零,并产生中断(如果 CH(n+1)IE=1)。在中断程序中,将C(n+1)V和C(n)V寄存器中保存的值相减,确定被测信号的正极脉宽,并清除CH(n+1)F 位。

    如 果 应 用 需 要 测 量 信 号 的 负 极 性 脉 宽 , 则 通 道 (n) 必 须 配 置 为 捕 获 下 降 沿(ELS(n)B:ELS(n)A = 0:1)和通道(n) +1) 必须配置为捕获上升沿 (ELS(n+1)B:ELS(n+1)A =1:0)。 要确定被测信号周期,通道 (n) 和通道 (n+1) 必须在相同的边沿上敏感。

    此示例显示了 FTM0 模块的双边沿捕获模式,该模式用于确定两个输入信号的正脉冲度。

    图中显示了通过 FTM0_CH0 和 FTM0_CH2 通道输入 FTM0 模块的两个测量信号。它们的正极性脉冲宽度为 17.8 µs 和 50 µs。

    4.5.7 输出比较模式

    输出比较模式下,FTM可以产生位置、极性、持续时长和周期可编程的时间脉冲。当计数器值匹配CnV寄存器的值,通道n输出可以被设置、清除或翻转。

    当一个通道被配置为翻转模式,通道输出前一个值会保持,直到下一个比较事件发生。

    4.5.8 捕获测试模式

    捕获测试模式允许对CnV寄存器、FTM计数器以及FTM计数器与CnV寄存器之间的对接逻辑进行测试。

    该模式下,所有通道必须配置为输入捕获模式,FTM计数器必须配置为向上递增。

    当捕获测试模式被启用(CAPTEST = 1)时,FTM计数器被冻结,任何对CNT寄存器的写入都直接更新FTM计数器;见下图。

    在写入后,所有CnV寄存器都将写入的值更新为CNT寄存器,并设置CHF位。因此,根据FTM计数器的配置,它的下一个值将被更新。它的下一个值取决于CNTIN、MOD和写入FTM计数器的值。

    4.5.9 DMA

    支持CHF通过DMA传输

    4.6 其他特性

    4.6.1 屏蔽、反相和软件控制功能

    屏蔽和软件控制功能强制 FTM 通道的输出处于非活动/需要状态,保持通道输出的恒定逻辑。 这些 FTM 功能可以通过软件打开/关闭电源设备。反相功能翻转 FTM 通道对的信号。 屏蔽功能用于 BLDC 电机控制应用。三相 BLDC 电机通常由配备六个 MOSFET 或六个 IGB(绝缘栅双极晶体管)的三相功率逆变器供电。 BLDC 电机常用的控制技术是 6 步换向法。在这种控制技术中,两相通电,第三相断开。因此,必须关闭相应逆变器支路的两个功率器件。 FTM 模块的屏蔽特性可以在这个应用程序中实现来实现这样的功能。 每个FTM 通道在FTM_OUTMASK 寄存器中有一个对应的位。对 OUTMASK 寄存器的任何写操作只是将值锁存到其写缓冲区中。

    当FTM时钟被禁用(在FTM_SYNC[SYNCHOM]=0时在FTM输入时钟的每个上升沿)或着在软件或硬件同步更新FTM_SYNCONF 寄存器中的 SWOM 位或 HWOM 位时候,FTM 通道的输出逻辑可以在写入 FTM_OUTMASK 寄存器后立即更新(参见Section 4.3,“Updating FTM registers”)。 当 FTM_CHx 通道被屏蔽时,根据 FTM_POL 寄存器中使能的位来控制输出逻辑保持高/低。

    软件控制功能通过设置或清除 FTM_SWOCTRL 寄存器中的 CHxOC 位来强制 FTM 通道的输出为软件定义的值。如果 CHxOC 位清零, FTM 通道的输出仍由 PWM 或其他源驱动。如果CHxOC 位被置位,相应的 FTM 通道的输出受软件影响。 FTM_SWOCTRL 寄存器中的 CHxOCV 位控制各个 FTM 通道的逻辑。当 CHxOCV = 1 时, FTM_CHx 通道的输出为1,否则为 0。

    反相功能通常用于直流电机控制应用。直流电机由 H 桥供电,一个通道对(FTM_CH0/CH1) 连接到一个分支,而另一对通道 (FTM_CH2/CH3) 连接到另一个分支。两个通道对都在互补模式下工作。此类应用要求对角线功率器件同时开启/关闭,这意味着 FTM_CH0 和FTM_CH3 必须具有相同的时序。为了保证这样的条件, FTM_CH1 和 FTM_CH3 必须工作在反相模式。 FTM_INVCTRL 寄存器中的 INVmEN 位使能相应通道对的反相。从写入缓冲区的值更新FTM_INVCTRL 寄存器的值与更新FTM_OUTMASK 寄存器值的方式相同。

    4.6.2 故障控制功能

    FTM 模块的故障控制在电机控制应用中发挥着重要作用,因为它提供了在关键时刻保护功率设备以及整个电力驱动系统的机会,当出现过温、过压、 或发生过电流。在这种情况下,故障信号可以通过传感器或特殊电路产生。一旦在 FTM 故障引脚的输入端检测到故障信号,故障控制就能够停止所有 PWM 通道。接收到故障信号后可以产生中断以减轻故障损失。

    所有 FTM 中断源(故障中断、 FTM 计数器溢出和重装载中断、通道比较事件中断和捕获中断)共享相同的中断向量号。当出现故障信号时, FTM 通道的输出被禁用并保持在FTM_POL 寄存器中定义的安全逻辑电平。例如,如果 POL0 = 1并且存在故障,则FTM_CH0 被禁用并强制为高电平。相反,如果 POL0 = 0 并且存在故障,则 FTM_CH0 被禁用,但被强制为低电平。

    FTM 有多个通道。然而, FTM 不能通过特定的故障信号来禁用特定的通道。故障信号是由所有进入的故障信号OR 运算的结果。 FTM 通道是否可以被故障信号禁用取决于FTM_COMBINE 寄存器中的 FAULTENx 位。由此产生的故障信号可以禁用所有 FTM 通道或仅禁用偶数通道 (FTM_CH0/CH2/CH4/CH6),这取决于 FTM_MODE 寄存器中的FAULTM 位字段 。

    PWM 通 道 的 输 出 恢 复 有 两 种 方 式 : FAULTM[1:0]=11 设 置 的 自 动 故 障 清 除 和FAULTM[1:0]=0:1或1:0时的手动故障清除。从下一个PWM周期中的安全状态恢复PWM信号,在选择自动故障清除模式时,无需任何软件干预。要在手动清除模式下恢复 PWM 信号,必须清除 FTM_MODE 寄存器中的 FAULTF 位,然后在下一个 PWM 周期使能 PWM。

    在以下代码示例中,启动了两个 FTM 模块以演示故障控制功能。 FTM0 配置为中心对齐 PWM模式, FTM1 用于生成故障信号,该信号通过故障引脚 FTM0_FLT0 从外部影响FTM0 通道的输出。

    在图中,示波器通道 CH1、 CH2 和 CH3 分别代表 FTM0 模块通道 FTM0_CH0、FTM0_CH1 和 FTM0_CH2。 FTM0_CH0 和 FTM0_CH1 工作在互补和组合模式,与FTM0_CH2 和 FTM0_CH3 相同。通道 CH4 显示外部故障信号(由 FTM1 产生),其频率为 FTM0 频率的十分之一。 当在 FTM0_FLT0 故障输入引脚上检测到上升沿时,所有 FTM0通道都被强制为安全(低)逻辑。 图 11 还显示,当故障输入信号为 0 时,所有 FTM0 通道都在下一个计数器周期恢复。

    4.6.3 更新FTM寄存器

    在电机控制或开关电源应用中,施加在负载上的电压必须由 PWM 占空比控制。 PWM占空比可以通过在 FTM_CnV 和 FTM_CNTIN 寄存器中设置适当的值来控制。某些应用还需要更改 PWM 的周期。该周期由 FTM_MOD 寄存器中的值控制。

    FTM_CnV、 FTM_CNTIN 和 FTM_MOD 是双缓冲寄存器,这意味着对这些寄存器的写入只是将它们的值锁存到它们的写入缓冲区中。 FTM 模块的双缓冲寄存器有通道 (n) 值(FTM_CnV) 、 计 数 器 初 始 值 (FTM_CNTIN) 、 模 数 (FTM_MOD) 、 半 周 期 寄 存 器(FTM_HCR)、输出掩码 (OUTMASK)、软件输出控制 (SWOCTRL ) 和反相控制寄存器(INVCTRL)。然后可以根据选择的更新方案用它们的缓冲值更新双缓冲寄存器。 S32K 器件上的当前实现更新寄存器方法有使用半周期或全周期重载策略、软件或硬件 PWM 同步,或者直接禁用缓冲器。下表总结了所有双缓冲寄存器及其更新方法:

    更新双缓冲FTM寄存器

    Update technique Double-buffered FTM registers Note
    Initialization stage CLKS[1:0] = 0:0 CnV, CNTIN, MOD, HCR The registers are loaded immediately.
    TPM compatibility CLKS[1:0] ≠ 0:0, FTMEN = 0 CnV, CNTIN, MOD, HCR The CNTIN register is loaded immediately and the CnV, MOD, and HCR registers at the end of the FTM counter period. The CnV register is loaded immediately in the output compare mode.
    Software synchronization CLKS[1:0] ≠ 0:0, FTMEN=1, SYNCMODE = 1 CnV, CNTIN, MOD, HCR (SWWRBUF = 1) The registers are updated by the software trigger-enabling SWSYNC bit. If SWRSTCNT = 1, the software trigger resets the FTM counter reset.
    .. SWOCTRL (SWOC = 1, SWSOC = 1) The registers are updated by the software trigger-enabling SWSYNC bit.
    .. OUTMASK (SYNCHOM = 1, SWOM = 1) ..
    .. INVCTRL (INVC = 1, SWINVC = 1) ..
    Hardware synchronization CLKS[1:0] ≠ 0:0, FTMEN=1, SYNCMODE = 1 CnV, CNTIN, MOD, HCR (HWWRBUF = 1) The registers are updated when TRIGn = 1 and the hardware trigger is detected at the trigger (n) input signal. If HWTRIGMODE = 1, the hardware trigger clears the TRIGn bit.
    .. SWOCTRL (SWOC = 1, HWSOC = 1) ..
    .. OUTMASK (SYNCHOM = 1, HWOM = 1) ..
    .. INVCTRL (INVC = 1, HWINVC = 1) ..
    Half and full cycle reload strategy CLKS[1:0] ≠ 0:0, FTMEN=1, CnV, CNTIN, MOD, HCR In the up-counting mode, the synchronization points are when the FTM counter changes from MOD to CNTIN, enable CNTMIN, or CNTMAX bit. For the up/down-counting mode, see Table below.

    向上/向下计数模式下的重新加载机会

    FTM_SYNC bits Reload opportunities selected
    CNTMIN = 0 and CNTMAX = 0 When the counter turns from up to down (compatibility mode).
    CNTMIN = 1 and CNTMAX = 0 When the counter turns from down to up.
    CNTMIN = 0 and CNTMAX = 1 When the counter turns from up to down.
    CNTMIN = 1 and CNTMAX = 1 When the counter turns from down to up and when the counter turns from up to down.

    (1)在初始化阶段更新FTM寄存器

    (2)半周期和全周期重装策略

    (3)通过软件触发更新FTM寄存器–软件同步

    (4)通过硬件触发更新FTM寄存器–硬件同步

    4.6.4 全局时基(GTB)

    芯片上有多个FTM,但多个FTM模块是独立的。如果应用需要的 PWM 通道多于一个FTM 所能提供的通道数,则可以使用多个 FTM 模块,但它们必须同步。两个(或多个)FTM 模块的同步意味着它们的计数器在任何时刻都具有相同的值。

    S32K 设备提供了 GTB 机制来同步多个 FTM。 GTB 是由主 FTM 生成的同步信号,它启动所有使用的 FTM 的计数器。使用 GTB 功能时必须满足这两个条件:每个 FTM 必须具有相同的时钟源,并且每个 FTM 必须同时启动。

    要使能 GTB 功能,请对每个参与的 FTM 模块执行以下步骤:

    1. 停止FTM计数器(将00b写入SC[CLKS])。

    2. 将FTM编程为预期配置。 FTM 计数器模式必须在所有参与模块中保持一致。

    3. 向CONF[GTBEEN]写入1,同时向CONF[GTBEOUT]写入0。

    4. 在 SC[CLKS] 中选择预期的 FTM 计数器时钟源。 所有参与模块的时钟源必须一致。

    5. 重置FTM计数器(向CNT寄存器写入一些值)。

      以下示例显示了FTM0 和 FTM2 的同步。两个 PWM 的占空比都调整为非常低的值,以更好地展示 GTB 机制的功能。

    在图 16 和图 17 中,示波器通道 CH1、 CH2、 CH3 和 CH4 分别代表 FTM0 和 FTM2模块的通道 FTM0_CH0、 FTM0_CH1、 FTM2_CH0 和 FTM2_CH1。 FTM0_CH0 和FTM0_CH1 工作在互补模式,与 FTM2_CH0 和 FTM2_CH1 相同。调整示波器的时基,以便在示波器显示屏上可以清楚地看到通道 FTM0 和 FTM2 的 1% 占空比。如果全局时基未激活,则所使用的 FTM 的加减计数器不会完全对齐,它们的通道信号也不会对齐(参见图16)。通过将 GTB 功能应用于 FTM 模块来处理此类问题(参见图 17)。 注意 GTB 功能不提供 FTM 计数器的连续同步,这意味着 FTM 计数器可能会在 FTM 操作期间失去同步。 GTB 功能仅允许 FTM 计数器启动时同步 。

    4.6.5 ADC由FTM和PDB模块触发

    在电机控制应用以及开关电源应用中,有必要测量 PWM 信号中心的电流。功率器件在这个瞬间没有切换,因此分流电阻上检测到的压降是稳定的。

    S32K 设备的所有四个 FTM 模块都有多达八个通道。六个通道通常足以生成控制常用三相电机所需的 PWM 信号。 FTM 模块的其余两个通道随后可用于控制 ADC 转换的时间点。

    FTM 模块的触发信号可以在 FTM_EXTTRIG 寄存器中选择。所有 FTM 通道均可用于触发 ADC 模块。例如,如果在 FTM_EXTTRIG 寄存器中设置 CH0,则 FTM 计数器计数,直到达到写入 C0V 寄存器中的值。此时, CH0 产生一个信号,在每个 FTM 计数器周期触发 ADC 模块。如果 FTM_EXTTRIG 寄存器中的 INITTRIG 位被设置,则每次 FTM 计数器达到 CNTIN 寄存器的值时都会产生触发信号。

    ADC 模块的默认和建议硬件触发方案是通过可编程延迟块 (PDB)。 S32K配备了两个成对工作的 ADC 模块和两个 PDB 模块。这意味着 PDB0 与 ADC0 链接, PDB1 与 ADC1 链接。每个 PDB 模块都可以由软件或硬件触发。 FTM 模块是可以通过 TRGMUX 寄存器TRGMUX_PDB0 和 TRGMUX_PDB1 选择的触发源之一。

    要在中心对齐 PWM模式下 并通过 FTM0 到 PDB0 触发 ADC0,请执行以下步骤:

    1. 初始化FTM0模块为中心对齐PWM模式并使能FTM0_EXTTRIG寄存器中的 INITTRIGEN 位产生ADC0模块的硬件触发信号。

    2. 通过向TRGMUX_PDB0寄存器中的SEL0位域写入0x16,配置TRGMUX模块由 FTM0通过PDB0模块触发ADC0。

    3. 通过将适当的值写入 PDB0_MOD 和 PDB0_CH0DLY0 寄存器,延迟 PDB0 模块的 FTM0 初始化触发,以在 PWM 周期的中心触发 ADC0。

    4. 初始化ADC0模块,使能ADC0_SC2寄存器中的ADTRG位,由FTM0模块触发 ADC0。 以下代码示例演示了 FTM0、 PDB0 和 ADC0 模块的配置,其中 FTM0 用于生成中心对齐 PWM信号并通过 PDB0 模块触发 ADC0。

    在图中,示波器通道 CH1 和 CH2 分别代表 FTM0 通道 FTM0_CH0 和 FTM0_CH1。通道对 FTM0_CH0/FTM0_CH1 工作在互补模式,与通道对 FTM0_CH2/FTM0_CH3 相同。示波器通道 CH3 和 CH4 演示了 FTM0、 PDB0 和 ADC0 模块之间的互连。通道 CH3 表示每次 FTM0 计数器达到 CNTIN 寄存器的值时 PDB0 中断程序中让PTD2 引脚翻转,每次ADC0 转换完成(COCO = 1)时,通道 CH4 显示 ADC0 中断程序中让 PTD3 引脚翻转。FTM0 触发信号由 PDB0 模块延迟,以便 ADC0 转换发生在 PWM 信号的中心。

    4.6.6 精细控制

    FTM实现了一个分数延迟,以实现对产生的PWM信号的精细分辨率控制。抖动可用于需要一个单位以上的FTM计数器分辨率的应用程序。

    支持两种抖动方式:PWM周期抖动和边沿抖动

    4.6.6.1 PWM周期抖动

    5. FTM的寄存器

    5.1 寄存器特性

  • 寄存器具有buffer,写入后并不能立即更新。

  • 系统设置载入点(load point),配合软硬件触发来从缓冲器更新寄存器的值。

  • 很多寄存器具有写保护功能。

  • 5.2 寄存器

    5.2.1 状态和控制寄存器(FTMx_SC)

  • TOF

  • TOIE

  • CPWMS

  • CLKS

  • PS

  • 5.2.2 计数器(FTMx_CNT)

    向该寄存器写入任何值将会使该寄存器回到初始设定值。

    BDM模式下,FTM计数器被冻结。

    5.2.3 模数寄存器(FTMx_MOD)

    5.2.4 通道n状态及控制寄存器(FTMx_CnSC)

    每个通道都有一个CnSC寄存器。该寄存器中包含通道中断标志位、中断使能控制位、通道设置以及引脚功能设置。

  • CHF

  • CHIE

  • MSB/MSA

  • ELSB/ELSA

  • DMA

  • 提前提到的 DECAPEN/COMBINE

  • 5.2.5 通道n计数值寄存器(FTMx_CnV)

    每个通道有一个CnV寄存器。

    输入捕获模式下

    当捕捉到设置的边沿时,此时FTM计数器的值自动保存到CnV寄存器中,该值可用于反映捕捉事件发生的时刻。

    输出模式下

    Cnv寄存器保存输出匹配值,该值用于和FTM计数器的值进行比较,当相等时,则比较成功。

    在输入捕捉、捕捉测试和双边沿捕捉模式下,任何对该寄存器的写入操作都无效。在输出模式下,写入该寄存器的值会先锁存到缓冲器内,何时更新寄存器更新设置有关。

    5.2.6 计数器初始值寄存器(FTMx_CNTIN)

    该寄存器保存FTM计数器的初始值。

    5.2.7 捕捉和比较状态寄存器(FTMx_STATUS)

    该寄存器中包含了每个通道的FTMx_CSC寄存器中的CHnF位的拷贝,以方便编程。这样一次就可以读出一个FTM模块的所有通道的标志位。

    5.2.8 特性模式选择寄存器(FTMx_MODE)

    该寄存器主要设置错误中断、错误控制、捕捉测试模式、PWM同步、写保护、通道输出初始化、FTM增强特性使能。这些控制和所有通道都有关。

  • FAULTIE:错误中断使能。

  • FAULTM:定义错误控制模式。

  • CAPTEST:捕捉测试使能。

  • PWMSYNC:PWM同步模式,即如何将某些寄存器的值从Buffer中更新的一种机制。

  • WPDIS:写保护禁止,与WPEN相反。

  • INIT:通道输出初始化。

  • FTMEN:FTM使能。

  • 5.2.9 同步寄存器(FTMx_SYNC)

    该寄存器用于设置PWM同步。一个同步事件能够执行MOD,CV,OUTMASK寄存器的同步,即使用缓冲器中的值更新这几个寄存器,这是FTM计数器也可以重新初始化。当FTMEN=1时,该寄存器必须合理设置。

  • SWSYNC:PWM同步软件触发。

  • TRIG2:PWM同步硬件触发器2。使能硬件触发器2触发PWM同步,触发器2输入引脚上出现上升沿时硬件触发。

  • TRIG1:PWM同步硬件触发器1。使能硬件触发器2触发PWM同步,触发器1输入引脚上出现上升沿时硬件触发。

  • TRIG0:PWM同步硬件触发器0。使能硬件触发器2触发PWM同步,触发器0输入引脚上出现上升沿时硬件触发。

  • SYNCHOM:输出屏蔽同步,选择OUTMASK寄存器是否从缓冲器里更新。

  • RENINT:FTM计数器重新初始化。

  • CNTMAX:最大载入点使能,当触发事件发生后,知道FTM计数器达到某一个值时,这一时刻才会发生更新寄存器值的同步,这一时刻就是载入点。

    当该位为1时,当FTM计数器达到最大值时,即MOD值,这一时刻将作为一个同步的载入点。

  • CNTMIN:最小装载点使能。当该位为1时,当FTM计数器达到最小值时,即CNTIN值,这一时刻将作为一个同步的载入点。

  • 5.2.10 通道输出初始状态(FTMx_OUTINIT)

  • CHxOI:通道x输出初始值。

  • 5.2.11 输出屏蔽寄存器(FTMx_OUTMASK)

  • CHxOM:通道x输出屏蔽

  • 5.2.12 通道联合功能寄存器(FTMx_COMBINE)

    该寄存器包含:错误控制、同步、死区插入、双边沿捕捉模式、补偿、双通道联合等功能。该寄存器在使用双通道联合功能时,主要是非对称PWM输出,双通道互补输出,双边沿捕捉等功能时需要合理设置。

  • FAULTENn:使能通道2n和2n+1的错误控制。

  • SYNCENn:使能寄存器C(2n)V和C(2n+1)V的PWM同步,即这两个寄存器能否被触发事件触发更新。

  • DTENn:死区使能。

  • DECAPn:双边沿捕获。(何为通道的双边沿)

  • COMPn:使能通道2n和2n+1的互补模式,即两个通道波形相反。

  • COBINEn:通道2n和2n+1联合设置。只有COMBINEn=1,才可使用上面那些位设置的功能。

  • 5.2.13 死区插入控制寄存器(FTMx_DEADTIME)

    该寄存器设置死区时间分频系数和死区值。所有的FTM通道都使用这个时钟分频和死区值。

  • DTPS:分频设置。死区时间的定时也是由对BusClock计数实现的,DTPS对BusClock分频的设置。

  • DTVAL:DTVAL设置对DTPS分频后的时钟计数值以确定死区插入的时间。死区插入的时间=DTPS x DTVAL x 总线时钟周期。

  • 5.2.14 通道极性寄存器(FTMx_POL)

    当各通道处于非活动状态,给寄存器设置各通道非活动状态下的值。

    5.2.15 输入捕捉滤波控制寄存器(FTMx_FILTER)

    该寄存器设置输入通道的滤波值,通道4、5、6、7无输入滤波器。

    滤波模式一般只在输入捕捉时使用,当启用滤波功能时,如果输入端发生变化,则滤波器内部的5bit计数器开始累加计数,一旦溢出,输入端变化才提交给边沿检测器。如果计数过程中,输入端再次发生相反变化,则计数器会被复位并重新开始计数,这样一些比过滤时间短的脉冲则会被视为干扰且不会提交给边沿计数器,只有滤波模块计数期间保持稳定的信号才会提交给边沿计数器。

    5.2.16 正交解码控制和状态寄存器(FTMx_QDCTRL)

    正交解码一般用于正反向脉冲计数,由旋转编码器输入A相和B相脉冲,由FTM模块根据相位自动增加或减少。在电机正反转测速时非常有用。

  • PHAFLTREN:A相输入滤波使能设置。

  • PHBFLTREN:B相输入滤波使能设置。

  • PHAPOL:A相输入极性选择。

  • PHBPOL:B相输入极性选择。

  • QUADMODE:正交解码模式。

  • QUADIR:正交解码模式下的FTM计数方向状态位,查询该位可获知当前计数方向。

  • TOFDIR:正交解码模式下FTM计数器溢出方向。在溢出时,查询该位可获知溢出方向。

  • QUADEN:正交编解码模式使能位。

  • 5.2.17 设置寄存器(FTMx_CONF)

  • GTBEOUT:全局时间基准输出,使能全局时间基准信号给其他FTM。

  • GTBEEN:全局时间基准使能,设置FTM使用一个其它FTM模块产生的外部的全局时间基准。

  • BDMMODE:选择FTM在BDM模式下的行为。

  • NUMOF:设置计数器溢出次数和TOF标志置位次数的比值,NUMTOF=n,每溢出n+1次,TOF置位一次。

  • 5.2.18 同步设置寄存器(FTMx_SYNCONF)

    该寄存器主要设置软件触发和硬件触发对于某些寄存器的影响。

    5.2.19 FTM反相设置寄存器(FTMx_INVCTRL)

    该寄存器中的各位设置通道2n和通道2n+1颠倒使用,即n通道成为n+1通道的输出,n+1通道输出n通道的输出。可用于控制电机正反转切换。该功能在双通道联合互补输出时可用。

  • INVnEN:通道2n和通道2n+1切换输出使能。

  • 5.2.20 FTM软件输出控制寄存器(FTMx_SWOCTRL)

    该寄存器设置各通道强制输出高电平或低电平。

  • CHnOS=1时对于通道n强制输出:

  • CHnOCV=0,当强制输出时,输出低电平;

  • CHnOCV=1,当强制输出时,输出高电平。

  • 5.2.21 FTMPWM装载寄存器(FTMx_PWMLOAD)

    使能PWM的自动载入功能,当FTM计数计到MOD设定值并变化到下一个值或该通道设置为输出比较且比较成功时,MOD、CNTIN、C(n)V、C(n+1)V载入缓冲器中的值。

  • LDOK:载入使能。

  • CHnSEL:载入时是否包括通道n

  • 6. Demo

    6.0 外设引脚配置示例

    /* Generate array of configured pin structures */
    pin_settings_config_t g_pin_mux_InitConfigArr_ftm_pwm1[NUM_OF_CONFIGURED_PINS_FTM_PWM1] = {
        {
            .base            = PORTA,
            .pinPortIdx      = 22U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 21U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 3U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 2U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTB,
            .pinPortIdx      = 0U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 31U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 30U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 23U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 14U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 13U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 18U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 16U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 28U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
        {
            .base            = PORTA,
            .pinPortIdx      = 29U,
            .pullConfig      = PORT_INTERNAL_PULL_NOT_ENABLED,
            .driveSelect     = PORT_STRENGTH_DISABLED,
            .mux             = PORT_MUX_ALT2,
            .hysteresisSelect = PORT_HYSTERESYS_DISABLED,
            .gpioBase        = NULL,
            .direction       = GPIO_UNSPECIFIED_DIRECTION,
            .initValue       = 0,
            .intConfig       = PORT_INT_DISABLED,
            .clearIntFlag    = false,
            .debounceEnable  = false,
        },
    };
    /*******************************************************************************************************
     * EOF
    *******************************************************************************************************/

    6.1 EPWM

    /**
     * @page misra_violations MISRA-C:2012 violations
     *
     * @section [global]
     * Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
     * The external variables will be used in other source files in application code.
     *
     */
    ​
    /* Global configuration of flexTimer_pwm_1 InitConfig */
    ftm_user_config_t flexTimer_pwm_1_InitConfig_pwm =
    {
        {
            true, /* Software trigger state */
            false, /* Hardware trigger 1 state */
            false, /* Hardware trigger 2 state */
            false, /* Hardware trigger 3 state */
            false, /* Max loading point state */
            false, /* Min loading point state */
            FTM_PWM_SYNC, /* Update mode for INVCTRL register */
            FTM_PWM_SYNC, /* Update mode for SWOCTRL register */
            FTM_PWM_SYNC, /* Update mode for OUTMASK register */
            FTM_PWM_SYNC, /* Update mode for CNTIN register */
            true, /* Automatic clear of the trigger*/
            FTM_UPDATE_NOW, /* Synchronization point */
        },
        FTM_MODE_EDGE_ALIGNED_PWM, /* Mode of operation for FTM */
        FTM_CLOCK_DIVID_BY_1, /* FTM clock prescaler */
        FTM_CLOCK_SOURCE_SYSTEMCLK,   /* FTM clock source */
        FTM_BDM_MODE_11, /* FTM debug mode */
        false,    /* Interrupt state */
        false     /* Initialization trigger */
    };
    ​
    /* PWM configuration for flexTimer_pwm_1 */
    ftm_pwm_param_t flexTimer_pwm_1_PwmConfig_pwm =
    {
        1U, /* Number of independent PWM channels */
        0U, /* Number of combined PWM channels */
        FTM_MODE_EDGE_ALIGNED_PWM, /* PWM mode */
        0U, /* Dead time value */
        FTM_DEADTIME_DIVID_BY_1, /* Dead time prescale */
        1000U, /* PWM frequency */
        flexTimer_pwm_1_IndependentChannelsConfig_pwm, /* The independent PWM channels configuration structure */
        NULL, /* Combined PWM channels configuration structure */
        &flexTimer_pwm_1_FaultConfig /* PWM fault configuration structure */
    };
    ​
    /*!
      \brief The FTMTestEdgePwm function for the project.
      \details The startup initialization sequence is the following:
     * - startup asm routine
     * - FTMTestEdgePwm()
    */
    int FTMTestEdgePwm(void)
    {
        /* Write your local variable definition here */
        ftm_state_t ftmStateStruct;
        uint16_t dutyCycle = flexTimer_pwm_1_IndependentChannelsConfig_pwm[0].uDutyCyclePercent;
    ​
        /* Initialize pins */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_PWM1, g_pin_mux_InitConfigArr_ftm_pwm1);
    ​
        /* Initialize FTM instance */
        FTM_DRV_Init(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_InitConfig_pwm, &ftmStateStruct);
    ​
        /* Initialize FTM PWM */
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig_pwm);
    ​
        /* Infinite loop */
        for ( ;; )
        {
            dutyCycle += 50;
            if (dutyCycle >= 0x8000U)
            {
                dutyCycle = 1U;
            }
            FTM_DRV_UpdatePwmChannel(INST_FLEXTIMER_PWM_1,
                                     flexTimer_pwm_1_IndependentChannelsConfig_pwm[0].hwChannelId,
                                     FTM_PWM_UPDATE_IN_DUTY_CYCLE, dutyCycle,
                                     0U,
                                     true);
            OS_DelayMs(5);
        }
    ​
        return exit_code;
    }

    6.2 CPWM

    /*!
      \brief The FTMTestCenterPwm function for the project.
      \details The startup initialization sequence is the following:
     * - startup asm routine
     * - FTMTestCenterPwm()
    */
    int FTMTestCenterPwm(void)
    {
        /* Write your local variable definition here */
        ftm_state_t ftmStateStruct;
        uint16_t dutyCycle = flexTimer_pwm_1_IndependentChannelsConfig_pwm[0].uDutyCyclePercent;
    ​
        /* Initialize pins */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_PWM1, g_pin_mux_InitConfigArr_ftm_pwm1);
    ​
        flexTimer_pwm_1_PwmConfig_pwm.mode = FTM_MODE_CEN_ALIGNED_PWM;
    ​
        /* Initialize FTM instance */
        FTM_DRV_Init(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_InitConfig_pwm, &ftmStateStruct);
    ​
        /* Initialize FTM PWM */
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig_pwm);
    ​
        /* Infinite loop */
        for ( ;; )
        {
            dutyCycle += 50;
            if (dutyCycle >= 0x8000U)
            {
                dutyCycle = 1U;
            }
            FTM_DRV_UpdatePwmChannel(INST_FLEXTIMER_PWM_1,
                                     flexTimer_pwm_1_IndependentChannelsConfig_pwm[0].hwChannelId,
                                     FTM_PWM_UPDATE_IN_DUTY_CYCLE, dutyCycle,
                                     0U,
                                     true);
            OS_DelayMs(5);
        }
        return exit_code;
    }

    6.3 Input Capture

    /* Global configuration of flexTimer_ic_1 InitConfig */
    ftm_user_config_t flexTimer_ic_1_InitConfig =
    {
        {
            true,    /* Software trigger state */
            false,  /* Hardware trigger 1 state */
            false,  /* Hardware trigger 2 state */
            false,  /* Hardware trigger 3 state */
            false, /* Max loading point state */
            false, /* Min loading point state */
            FTM_SYSTEM_CLOCK, /* Update mode for INVCTRL register */
            FTM_SYSTEM_CLOCK, /* Update mode for SWOCTRL register */
            FTM_SYSTEM_CLOCK, /* Update mode for OUTMASK register */
            FTM_SYSTEM_CLOCK, /* Update mode for CNTIN register */
            false, /* Automatic clear of the trigger */
            FTM_UPDATE_NOW, /* Synchronization point */
        },
            FTM_MODE_INPUT_CAPTURE, /* Mode of operation for FTM */
            FTM_CLOCK_DIVID_BY_1, /* FTM clock prescaler */
            FTM_CLOCK_SOURCE_SYSTEMCLK,   /* FTM clock source */
            FTM_BDM_MODE_11, /* FTM debug mode */
            false,    /* Interrupt state */
            false     /* Initialization trigger */
    };
    ​
    ​
    /* Input capture configuration for flexTimer_ic_1 */
    ftm_input_param_t flexTimer_ic_1_InputCaptureConfig =
    {
        1U, /* Number of channel configurations */
        65535U, /* Maximum count value */
        flexTimer_ic_1_InputCaptureChannelConfig /* Channels configuration*/
    };
    ​
    /*!
      \brief The ftm_signal_measure_entry function for the project.
      \details The startup initialization sequence is the following:
     * - startup asm routine
    */
    int FTMTestCapture(void)
    {
        ftm_state_t ftm1StateStruct;
        ftm_state_t ftm2StateStruct;
        /* Variables used to store PWM frequency,
         * input capture measurement value
         */
        uint16_t inputCaptureMeas = 0U;
        uint32_t frequency;
    ​
        bool conversionComplete = false;
        /* Buffer for string processing */
        char txBuff[255];
    ​
        /* Initialize pins
         *    -    See PinSettings component for more info
         */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_SG0, g_pin_mux_InitConfigArr_ftm_sg0);
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_SG1, g_pin_mux_InitConfigArr_ftm_sg1);
    ​
        /* Initialize FTM instances, PWM and Input capture
         *  -   See ftm component for more details
         */
        FTM_DRV_Init(INST_FLEXTIMER_IC_1, &flexTimer_ic_1_InitConfig, &ftm1StateStruct);
        FTM_DRV_Init(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_InitConfig, &ftm2StateStruct);
    ​
        /* Setup input capture */
        FTM_DRV_InitInputCapture(INST_FLEXTIMER_IC_1, &flexTimer_ic_1_InputCaptureConfig);
    ​
        /* Start PWM */
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig);
    ​
        /* Get the FTM frequency to calculate
         * the frequency of the measured signal.
         */
        frequency = FTM_DRV_GetFrequency(INST_FLEXTIMER_IC_1);
    ​
        /* Send the hello message */
        log_info("This example will show you how to use FTM's signal measurement feature.\r\n"
              "To achieve that we will generate a modifiable frequency PWM and read it with Input Capture.\r\n");
    ​
        /* Infinite loop
         *  -   Wait for user input
         *  -   Measure and calculate the signal frequency
         *  -   Send original and measured freq via LPUART
         *  -   Modify the PWM frequency
         */
        for ( ;; )
        {
            //log_info("Press any key to initiate a new conversion...\r\n");
            OS_DelayS(5);
            /* Wait for user input */
            //LPUART_DRV_ReceiveDataBlocking(INST_LPUART_1, (uint8_t *)&txBuff, 1U, 1 << 31U);
            conversionComplete = false;
    ​
            while (conversionComplete == false)
            {
                /* Wait a number of cycles for the PWM to reach stability */
                delayCycles(0x7FFFFU);
    ​
                /* Get the latest value */
                inputCaptureMeas = FTM_DRV_GetInputCaptureMeasurement(INST_FLEXTIMER_IC_1, 0U);
                /* Calculate the signal frequency using recorded data*/
                inputCaptureMeas = frequency / (inputCaptureMeas);
    ​
                /* Stop PWM */
                FTM_DRV_DeinitPwm(INST_FLEXTIMER_PWM_1);
    ​
                /* Convert the integer to char array and send it*/
                sprintf(txBuff, "PWM frequency:%6lu, Measured frequency:%6u [Hz]\r\n",
                        flexTimer_pwm_1_PwmConfig.uFrequencyHZ, inputCaptureMeas);
                log_info("%s\n", txBuff);
    ​
                /* Increase frequency */
                if (flexTimer_pwm_1_PwmConfig.uFrequencyHZ < 3000U)
                {
                    flexTimer_pwm_1_PwmConfig.uFrequencyHZ += 100U;
                }
                else
                {
                    flexTimer_pwm_1_PwmConfig.uFrequencyHZ = 1000U;
                    conversionComplete = true;
                }
    ​
                /* Restart PWM with new settings */
                FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig);
            }
        }
    ​
        return exit_code;
    }

    6.4 中断

    /*!
      \brief The ftm_periodic_interrupt function for the project.
      \details The startup initialization sequence is the following:
     * - startup asm routine
     * - FTMTestInterrupt()
    */
    int FTMTestInterrupt(void)
    {
        /* Write your local variable definition here */
        ftm_state_t state;
    ​
        /* Initialize pins */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_INT0, g_pin_mux_InitConfigArr_int0);
    ​
        /* Initialize FTM */
        FTM_DRV_Init(INST_FLEXTIMER_MC_1, &flexTimer_mc_1_InitConfig_0, &state);
    ​
        /* Initialize counter */
        FTM_DRV_InitCounter(INST_FLEXTIMER_MC_1, &flexTimer_mc_1_TimerConfig_0);
    ​
        /* Start Counter */
        FTM_DRV_CounterStart(INST_FLEXTIMER_MC_1);
    ​
        /* Loop */
        for (;;)
        {
            /* Do no thing, just wait for the interrupt */
        }
    ​
        return exit_code;
    }

    6.5 Combined pwm

    /**
     * @page misra_violations MISRA-C:2012 violations
     *
     * @section [global]
     * Violates MISRA 2012 Advisory Rule 8.7, External variable could be made static.
     * The external variables will be used in other source files in application code.
     *
     */
    ​
    /* Global configuration of flexTimer_pwm_1 InitConfig */
    ftm_user_config_t flexTimer_pwm_1_InitConfig_cb =
    {
        {
            true, /* Software trigger state */
            false, /* Hardware trigger 1 state */
            false, /* Hardware trigger 2 state */
            false, /* Hardware trigger 3 state */
            false, /* Max loading point state */
            false, /* Min loading point state */
            FTM_PWM_SYNC, /* Update mode for INVCTRL register */
            FTM_PWM_SYNC, /* Update mode for SWOCTRL register */
            FTM_PWM_SYNC, /* Update mode for OUTMASK register */
            FTM_PWM_SYNC, /* Update mode for CNTIN register */
            true, /* Automatic clear of the trigger*/
            FTM_UPDATE_NOW, /* Synchronization point */
        },
        FTM_MODE_EDGE_ALIGNED_PWM, /* Mode of operation for FTM */
        FTM_CLOCK_DIVID_BY_1, /* FTM clock prescaler */
        FTM_CLOCK_SOURCE_SYSTEMCLK,   /* FTM clock source */
        FTM_BDM_MODE_11, /* FTM debug mode */
        false,    /* Interrupt state */
        false     /* Initialization trigger */
    };
    ​
    /* PWM configuration for flexTimer_pwm_1 */
    ftm_pwm_param_t flexTimer_pwm_1_PwmConfig_cb =
    {
        0U, /* Number of independent PWM channels */
        1U, /* Number of combined PWM channels */
        FTM_MODE_EDGE_ALIGNED_PWM, /* PWM mode */
        48U, /* Dead time value */
        FTM_DEADTIME_DIVID_BY_4, /* Dead time prescale */
        10000U, /* PWM frequency */
        NULL, /* The independent PWM channels configuration structure */
        flexTimer_pwm_1_CombinedChannelsConfig, /* Combined PWM channels configuration structure */
        &flexTimer_pwm_1_FaultConfig /* PWM fault configuration structure */
    };
    ​
    /*!
      \brief The ftm_combined_pwm function for the project.
      \details The startup initialization sequence is the following:
     * - startup asm routine
     * - ftm_combined_pwm()
    */
    int FTMTestCombinedPwm(void)
    {
        /* Write your local variable definition here */
        ftm_state_t ftmStateStruct;
        bool increaseDutyCycle = true;
        uint32_t dutyCycle  = 0UL;
    ​
        /* Initialize pins */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_PWM0, g_pin_mux_InitConfigArr_ftm_pwm0);
    ​
        /* Initialize FTM */
        FTM_DRV_Init(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_InitConfig_cb, &ftmStateStruct);
    ​
        /* Initialize FTM PWM */
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig_cb);
    ​
        /* Infinite loop
         *  -   increment or decrement duty cycleU
         *  -   Update channel duty cycle
         *  -   Wait for a number of cycles to make
         *      the change visible
         */
        for ( ;; )
        {
            if (increaseDutyCycle == false)
            {
                dutyCycle -= 1U;
                if (dutyCycle < 1U)
                    increaseDutyCycle = true;
            }
            else
            {
                dutyCycle += 1U;
                if (dutyCycle > 0x7FFF)
                    increaseDutyCycle = false;
            }
    ​
            /* Update PWM channels */
            FTM_DRV_UpdatePwmChannel(INST_FLEXTIMER_PWM_1, 0U, FTM_PWM_UPDATE_IN_DUTY_CYCLE, 0UL, dutyCycle, true);
            delayCycles(0xFFU);
        }
    ​
        return exit_code;
    }

    6.6 Deadtime PWM

    6.7 Fault Control

    int FTMTestFaultControl(void)
    {
        /* Write your local variable definition here */
        ftm_state_t ftmStateStruct;
        ftm_state_t ftmStateStruct_1;
        bool increaseDutyCycle = true;
        uint32_t dutyCycle  = 0UL;
        bool result = false;
        int32_t idx = 0U;
    ​
        OS_IoWrite32((void *)0x40080230, 0xffffffff);
        OS_IoWrite32((void *)0x40080234, 0xffffffff);
        OS_IoWrite32((void *)0x40080238, 0xffffffff);
        OS_IoWrite32((void *)0x4008023C, 0xffffffff);
        OS_IoWrite32((void *)0x40080240, 0xffffffff);
        OS_IoWrite32((void *)0x40080244, 0xffffffff);
        OS_IoWrite32((void *)0x400800A8, 0x1);
        OS_IoWrite32((void *)0x400800B4, 0x1);
        OS_IoWrite32((void *)0x400800C0, 0x1);
        OS_IoWrite32((void *)0x400800CC, 0x1);
    ​
        /* Initialize pins */
        PINS_DRV_Init(NUM_OF_CONFIGURED_PINS_FTM_PWM0, g_pin_mux_InitConfigArr_ftm_pwm0);
    ​
        /* Initialize FTM */
    ​
        //flexTimer_pwm_1_InitConfig_cb.BDMMode = FTM_BDM_MODE_00;
        FTM_DRV_Init(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_InitConfig_cb, &ftmStateStruct);
    ​
        //FTM_DRV_EnableInterrupts(INST_FLEXTIMER_PWM_1, FTM_FAULT_INT_ENABLE);
    ​
        /* Initialize FTM PWM */
        flexTimer_pwm_1_PwmConfig_cb.faultConfig->faultMode = FTM_FAULT_CONTROL_AUTO_ALL;
        flexTimer_pwm_1_PwmConfig_cb.faultConfig->pwmFaultInterrupt = false;
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_1, &flexTimer_pwm_1_PwmConfig_cb);
    ​
        /* Infinite loop
         *  -   increment or decrement duty cycleU
         *  -   Update channel duty cycle
         *  -   Wait for a number of cycles to make
         *      the change visible
         */
        delayCycles(1000U);
    ​
        FTM_DRV_Init(INST_FLEXTIMER_PWM_2, &flexTimer_pwm_1_InitConfig_cb, &ftmStateStruct_1);
        flexTimer_pwm_1_PwmConfig_cb.faultConfig->faultMode = FTM_FAULT_CONTROL_DISABLED;
        flexTimer_pwm_1_PwmConfig_cb.uFrequencyHZ = flexTimer_pwm_1_PwmConfig_cb.uFrequencyHZ / 10;
        FTM_DRV_InitPwm(INST_FLEXTIMER_PWM_2, &flexTimer_pwm_1_PwmConfig_cb);
    ​
        while (1);
    ​
        return result;
    }

    7. 应用举例

    7.1 步进电机驱动

    步进电机控制示意图,通过FTM模块控制电机的两个H桥,比较器可以用作电机线圈过流保护,ADC模块提供过流检测参考信号。

    7.2 基于霍尔传感器的BLDC驱动

    直流无刷电机控制示意图,六路FTM通道控制电机的三相线圈,霍尔传感器提供电机转速信息(使用一路FTM来测量脉冲周期)。

    7.3 ACIM/PMSM电机控制

    永磁同步电机控制示意图,使用六路FTM控制电机三相桥,正交信号提供电机转速信息(使用FTM正交译码功能)

     

    物联沃分享整理
    物联沃-IOTWORD物联网 » S32K FlexTimer模块详解

    发表评论