示例#1
0
文件: fsl_ftm.c 项目: flit/argon-rtos
static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints)
{
    uint32_t chnlNumber = 0;
    uint32_t reg = 0;

    /* Need CNTINC bit to be 1 for CNTIN register to update with its buffer value on reload  */
    base->SYNCONF |= FTM_SYNCONF_CNTINC_MASK;

    reg = base->COMBINE;
    for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
    {
        /* Need SYNCEN bit to be 1 for CnV reg to update with its buffer value on reload  */
        reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
    }
    base->COMBINE = reg;

    /* Set the reload points */
    reg = base->PWMLOAD;

    /* Enable the selected channel match reload points */
    reg &= ~((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1);
    reg |= (reloadPoints & ((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1));

#if defined(FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD) && (FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD)
    /* Enable half cycle match as a reload point */
    if (reloadPoints & kFTM_HalfCycMatch)
    {
        reg |= FTM_PWMLOAD_HCSEL_MASK;
    }
    else
    {
        reg &= ~FTM_PWMLOAD_HCSEL_MASK;
    }
#endif /* FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD */

    base->PWMLOAD = reg;

    /* These reload points are used when counter is in up-down counting mode */
    reg = base->SYNC;
    if (reloadPoints & kFTM_CntMax)
    {
        /* Reload when counter turns from up to down */
        reg |= FTM_SYNC_CNTMAX_MASK;
    }
    else
    {
        reg &= ~FTM_SYNC_CNTMAX_MASK;
    }

    if (reloadPoints & kFTM_CntMin)
    {
        /* Reload when counter turns from down to up */
        reg |= FTM_SYNC_CNTMIN_MASK;
    }
    else
    {
        reg &= ~FTM_SYNC_CNTMIN_MASK;
    }
    base->SYNC = reg;
}
/*See fsl_ftm_driver.h for documentation of this function.*/
void FTM_DRV_Init(uint8_t instance, ftm_user_config_t * info)
{
    assert(instance < HW_FTM_INSTANCE_COUNT);

    uint32_t ftmBaseAddr = g_ftmBaseAddr[instance];
    uint8_t chan = FSL_FEATURE_FTM_CHANNEL_COUNTn(instance);

    /* clock setting initialization*/
    CLOCK_SYS_EnableFtmClock(instance);

    FTM_HAL_Reset(ftmBaseAddr);
    /* Reset the channel registers */
    for(int i = 0; i < chan; i++)
    {
        HW_FTM_CnSC_WR(ftmBaseAddr, i, 0);
        HW_FTM_CnV_WR(ftmBaseAddr, i, 0);
    }

    FTM_HAL_Init(ftmBaseAddr);

    FTM_HAL_SetSyncMode(ftmBaseAddr, info->syncMethod);

    FTM_HAL_SetTofFreq(ftmBaseAddr, info->tofFrequency);
    FTM_HAL_SetWriteProtectionCmd(ftmBaseAddr, info->isWriteProtection);
    FTM_HAL_SetBdmMode(ftmBaseAddr,info->BDMMode);

    NVIC_ClearPendingIRQ(g_ftmIrqId[instance]);
    INT_SYS_EnableIRQ(g_ftmIrqId[instance]);
}
示例#3
0
文件: fsl_ftm.c 项目: flit/argon-rtos
static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod)
{
    uint8_t chnlNumber = 0;
    uint32_t reg = 0, syncReg = 0;

    syncReg = base->SYNC;
    /* Enable PWM synchronization of output mask register */
    syncReg |= FTM_SYNC_SYNCHOM_MASK;

    reg = base->COMBINE;
    for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
    {
        /* Enable PWM synchronization of registers C(n)V and C(n+1)V */
        reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
    }
    base->COMBINE = reg;

    reg = base->SYNCONF;

    /* Use enhanced PWM synchronization method. Use PWM sync to update register values */
    reg |= (FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_CNTINC_MASK | FTM_SYNCONF_INVC_MASK | FTM_SYNCONF_SWOC_MASK);

    if (syncMethod & FTM_SYNC_SWSYNC_MASK)
    {
        /* Enable needed bits for software trigger to update registers with its buffer value */
        reg |= (FTM_SYNCONF_SWRSTCNT_MASK | FTM_SYNCONF_SWWRBUF_MASK | FTM_SYNCONF_SWINVC_MASK |
                FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWOM_MASK);
    }

    if (syncMethod & (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK))
    {
        /* Enable needed bits for hardware trigger to update registers with its buffer value */
        reg |= (FTM_SYNCONF_HWRSTCNT_MASK | FTM_SYNCONF_HWWRBUF_MASK | FTM_SYNCONF_HWINVC_MASK |
                FTM_SYNCONF_HWSOC_MASK | FTM_SYNCONF_HWOM_MASK);

        /* Enable the appropriate hardware trigger that is used for PWM sync */
        if (syncMethod & FTM_SYNC_TRIG0_MASK)
        {
            syncReg |= FTM_SYNC_TRIG0_MASK;
        }
        if (syncMethod & FTM_SYNC_TRIG1_MASK)
        {
            syncReg |= FTM_SYNC_TRIG1_MASK;
        }
        if (syncMethod & FTM_SYNC_TRIG2_MASK)
        {
            syncReg |= FTM_SYNC_TRIG2_MASK;
        }
    }

    /* Write back values to the SYNC register */
    base->SYNC = syncReg;

    /* Write the PWM synch values to the SYNCONF register */
    base->SYNCONF = reg;
}
/*See fsl_ftm_driver.h for documentation of this function.*/
void FTM_DRV_PwmStop(uint8_t instance, ftm_pwm_param_t *param, uint8_t channel)
{
    assert((param->mode == kFtmEdgeAlignedPWM) || (param->mode == kFtmCenterAlignedPWM) ||
           (param->mode == kFtmCombinedPWM));
    assert(instance < HW_FTM_INSTANCE_COUNT);
    assert(channel < FSL_FEATURE_FTM_CHANNEL_COUNTn(instance));

    uint32_t ftmBaseAddr = g_ftmBaseAddr[instance];

    /* Stop the FTM counter */
    FTM_HAL_SetClockSource(ftmBaseAddr, kClock_source_FTM_None);

    FTM_HAL_DisablePwmMode(ftmBaseAddr, param, channel);

    /* Clear out the registers */
    FTM_HAL_SetMod(ftmBaseAddr, 0);
    FTM_HAL_SetCounter(ftmBaseAddr, 0);
}
示例#5
0
文件: fsl_ftm.c 项目: flit/argon-rtos
uint32_t FTM_GetEnabledInterrupts(FTM_Type *base)
{
    uint32_t enabledInterrupts = 0;
    int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);

    /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
    assert(chnlCount != -1);

    /* Check if timer overflow interrupt is enabled */
    if (base->SC & FTM_SC_TOIE_MASK)
    {
        enabledInterrupts |= kFTM_TimeOverflowInterruptEnable;
    }
    /* Check if fault interrupt is enabled */
    if (base->MODE & FTM_MODE_FAULTIE_MASK)
    {
        enabledInterrupts |= kFTM_FaultInterruptEnable;
    }

#if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
    /* Check if the reload interrupt is enabled */
    if (base->SC & FTM_SC_RIE_MASK)
    {
        enabledInterrupts |= kFTM_ReloadInterruptEnable;
    }
#endif

    /* Check if the channel interrupts are enabled */
    while (chnlCount > 0)
    {
        chnlCount--;
        if (base->CONTROLS[chnlCount].CnSC & FTM_CnSC_CHIE_MASK)
        {
            enabledInterrupts |= (1U << chnlCount);
        }
    }

    return enabledInterrupts;
}
void FTM_DRV_PwmChangeDutyCycle(uint8_t instance, ftm_pwm_param_t *param, uint8_t channel)
{
    uint32_t uFTMhz;
    uint16_t uMod, uCnv, uCnvFirstEdge = 0;

    assert(instance < HW_FTM_INSTANCE_COUNT);
    assert(param->uDutyCyclePercent <= 100);
    assert(channel < FSL_FEATURE_FTM_CHANNEL_COUNTn(instance));

    uint32_t ftmBaseAddr = g_ftmBaseAddr[instance];


    uMod = FTM_HAL_GetMod(ftmBaseAddr);

    uCnv = uMod * param->uDutyCyclePercent / 100;
    /* For 100% duty cycle */
    if(uCnv >= uMod)
    {
      uCnv = uMod + 1;
    }
    FTM_HAL_SetChnCountVal(ftmBaseAddr, channel, uCnv);
}
void FTM_DRV_CounterStart(uint8_t instance, ftm_counting_mode_t countMode, uint32_t countStartVal,
                                 uint32_t countFinalVal, bool enableOverflowInt)
{
    assert(instance < HW_FTM_INSTANCE_COUNT);

    uint32_t ftmBaseAddr = g_ftmBaseAddr[instance];
    uint32_t channel = 0;

    /* Clear the overflow flag */
    FTM_HAL_ClearTimerOverflow(ftmBaseAddr);
    FTM_HAL_SetCounterInitVal(ftmBaseAddr, countStartVal);
    FTM_HAL_SetMod(ftmBaseAddr, countFinalVal);
    FTM_HAL_SetCounter(ftmBaseAddr, 0);

    /* Use FTM as counter, disable all the channels */
    for (channel = 0; channel < FSL_FEATURE_FTM_CHANNEL_COUNTn(instance); channel++)
    {
        FTM_HAL_SetChnEdgeLevel(ftmBaseAddr, channel, 0);
    }

    if (countMode == kCounting_FTM_UP)
    {
        FTM_HAL_SetQuadDecoderCmd(ftmBaseAddr, false);
        FTM_HAL_SetCpwms(ftmBaseAddr, 0);
    }
    else if (countMode == kCounting_FTM_UpDown)
    {
        FTM_HAL_SetQuadDecoderCmd(ftmBaseAddr, false);
        FTM_HAL_SetCpwms(ftmBaseAddr, 1);
    }

    /* Activate interrupts if required */
    FTM_DRV_SetTimeOverflowIntCmd(instance, enableOverflowInt);

    /* Set clock source to start the counter */
    FTM_HAL_SetClockSource(ftmBaseAddr, kClock_source_FTM_SystemClk);
}
示例#8
0
文件: fsl_ftm.c 项目: flit/argon-rtos
void FTM_UpdatePwmDutycycle(FTM_Type *base,
                            ftm_chnl_t chnlNumber,
                            ftm_pwm_mode_t currentPwmMode,
                            uint8_t dutyCyclePercent)
{
    uint16_t cnv, cnvFirstEdge = 0, mod;

    mod = base->MOD;
    if ((currentPwmMode == kFTM_EdgeAlignedPwm) || (currentPwmMode == kFTM_CenterAlignedPwm))
    {
        cnv = (mod * dutyCyclePercent) / 100;
        /* For 100% duty cycle */
        if (cnv >= mod)
        {
            cnv = mod + 1;
        }
        base->CONTROLS[chnlNumber].CnV = cnv;
    }
    else
    {
        /* This check is added for combined mode as the channel number should be the pair number */
        if (chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
        {
            return;
        }

        cnv = (mod * dutyCyclePercent) / 100;
        cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV;
        /* For 100% duty cycle */
        if (cnv >= mod)
        {
            cnv = mod + 1;
        }
        base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
    }
}
示例#9
0
文件: fsl_ftm.c 项目: flit/argon-rtos
status_t FTM_SetupPwm(FTM_Type *base,
                      const ftm_chnl_pwm_signal_param_t *chnlParams,
                      uint8_t numOfChnls,
                      ftm_pwm_mode_t mode,
                      uint32_t pwmFreq_Hz,
                      uint32_t srcClock_Hz)
{
    assert(chnlParams);

    uint32_t mod, reg;
    uint32_t ftmClock = (srcClock_Hz / (1U << (base->SC & FTM_SC_PS_MASK)));
    uint16_t cnv, cnvFirstEdge;
    uint8_t i;

    switch (mode)
    {
        case kFTM_EdgeAlignedPwm:
        case kFTM_CombinedPwm:
            base->SC &= ~FTM_SC_CPWMS_MASK;
            mod = (ftmClock / pwmFreq_Hz) - 1;
            break;
        case kFTM_CenterAlignedPwm:
            base->SC |= FTM_SC_CPWMS_MASK;
            mod = ftmClock / (pwmFreq_Hz * 2);
            break;
        default:
            return kStatus_Fail;
    }

    /* Return an error in case we overflow the registers, probably would require changing
     * clock source to get the desired frequency */
    if (mod > 65535U)
    {
        return kStatus_Fail;
    }
    /* Set the PWM period */
    base->MOD = mod;

    /* Setup each FTM channel */
    for (i = 0; i < numOfChnls; i++)
    {
        /* Return error if requested dutycycle is greater than the max allowed */
        if (chnlParams->dutyCyclePercent > 100)
        {
            return kStatus_Fail;
        }

        if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
        {
            /* Clear the current mode and edge level bits */
            reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
            reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);

            /* Setup the active level */
            reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);

            /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
            reg |= FTM_CnSC_MSB(1U);

            /* Update the mode and edge level */
            base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;

            if (chnlParams->dutyCyclePercent == 0)
            {
                /* Signal stays low */
                cnv = 0;
            }
            else
            {
                cnv = (mod * chnlParams->dutyCyclePercent) / 100;
                /* For 100% duty cycle */
                if (cnv >= mod)
                {
                    cnv = mod + 1;
                }
            }

            base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
            /* Set to output mode */
            FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
#endif
        }
        else
        {
            /* This check is added for combined mode as the channel number should be the pair number */
            if (chnlParams->chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
            {
                return kStatus_Fail;
            }

            /* Return error if requested value is greater than the max allowed */
            if (chnlParams->firstEdgeDelayPercent > 100)
            {
                return kStatus_Fail;
            }

            /* Configure delay of the first edge */
            if (chnlParams->firstEdgeDelayPercent == 0)
            {
                /* No delay for the first edge */
                cnvFirstEdge = 0;
            }
            else
            {
                cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100;
            }

            /* Configure dutycycle */
            if (chnlParams->dutyCyclePercent == 0)
            {
                /* Signal stays low */
                cnv = 0;
                cnvFirstEdge = 0;
            }
            else
            {
                cnv = (mod * chnlParams->dutyCyclePercent) / 100;
                /* For 100% duty cycle */
                if (cnv >= mod)
                {
                    cnv = mod + 1;
                }
            }

            /* Clear the current mode and edge level bits for channel n */
            reg = base->CONTROLS[chnlParams->chnlNumber * 2].CnSC;
            reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);

            /* Setup the active level for channel n */
            reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);

            /* Update the mode and edge level for channel n */
            base->CONTROLS[chnlParams->chnlNumber * 2].CnSC = reg;

            /* Clear the current mode and edge level bits for channel n + 1 */
            reg = base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC;
            reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);

            /* Setup the active level for channel n + 1 */
            reg |= (FTM_CnSC_ELSA(chnlParams->level) | FTM_CnSC_ELSB(chnlParams->level));

            /* Update the mode and edge level for channel n + 1*/
            base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC = reg;

            /* Set the channel pair values */
            base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge;
            base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;

            /* Set the combine bit for the channel pair */
            base->COMBINE |=
                (1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlParams->chnlNumber)));
#if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
            /* Set to output mode */
            FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2), true);
            FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2 + 1), true);
#endif
        }
        chnlParams++;
    }

    return kStatus_Success;
}
/*See fsl_ftm_driver.h for documentation of this function.*/
void FTM_DRV_PwmStart(uint8_t instance, ftm_pwm_param_t *param, uint8_t channel)
{
    uint32_t uFTMhz;
    uint16_t uMod, uCnv, uCnvFirstEdge = 0;

    assert(instance < HW_FTM_INSTANCE_COUNT);
    assert(param->uDutyCyclePercent <= 100);
    assert(channel < FSL_FEATURE_FTM_CHANNEL_COUNTn(instance));

    uint32_t ftmBaseAddr = g_ftmBaseAddr[instance];

    /* Clear the overflow flag */
    FTM_HAL_ClearTimerOverflow(g_ftmBaseAddr[instance]);

    FTM_HAL_EnablePwmMode(ftmBaseAddr, param, channel);

#if FSL_FEATURE_FTM_BUS_CLOCK
    CLOCK_SYS_GetFreq(kBusClock, &uFTMhz);
#else
    CLOCK_SYS_GetFreq(kSystemClock, &uFTMhz);
#endif

    /* Based on Ref manual, in PWM mode CNTIN is to be set 0*/
    FTM_HAL_SetCounterInitVal(ftmBaseAddr, 0);

    uFTMhz = uFTMhz / (1 << FTM_HAL_GetClockPs(ftmBaseAddr));

    switch(param->mode)
    {
        case kFtmEdgeAlignedPWM:
            uMod = uFTMhz / (param->uFrequencyHZ) - 1;
            uCnv = uMod * param->uDutyCyclePercent / 100;
            /* For 100% duty cycle */
            if(uCnv >= uMod)
            {
                uCnv = uMod + 1;
            }
            FTM_HAL_SetMod(ftmBaseAddr, uMod);
            FTM_HAL_SetChnCountVal(ftmBaseAddr, channel, uCnv);
            break;
        case kFtmCenterAlignedPWM:
            uMod = uFTMhz / (param->uFrequencyHZ * 2);
            uCnv = uMod * param->uDutyCyclePercent / 100;
            /* For 100% duty cycle */
            if(uCnv >= uMod)
            {
                uCnv = uMod + 1;
            }
            FTM_HAL_SetMod(ftmBaseAddr, uMod);
            FTM_HAL_SetChnCountVal(ftmBaseAddr, channel, uCnv);
            break;
        case kFtmCombinedPWM:
            uMod = uFTMhz / (param->uFrequencyHZ) - 1;
            uCnv = uMod * param->uDutyCyclePercent / 100;
            uCnvFirstEdge = uMod * param->uFirstEdgeDelayPercent / 100;
            /* For 100% duty cycle */
            if(uCnv >= uMod)
            {
                uCnv = uMod + 1;
            }
            FTM_HAL_SetMod(ftmBaseAddr, uMod);
            FTM_HAL_SetChnCountVal(ftmBaseAddr, FTM_HAL_GetChnPairIndex(channel) * 2,
                                   uCnvFirstEdge);
            FTM_HAL_SetChnCountVal(ftmBaseAddr, FTM_HAL_GetChnPairIndex(channel) * 2 + 1,
                                   uCnv + uCnvFirstEdge);
            break;
        default:
            assert(0);
            break;
    }

    /* Set clock source to start counter */
    FTM_HAL_SetClockSource(ftmBaseAddr, kClock_source_FTM_SystemClk);
}