RT1010 PWM 组成配置和 PWMX 的使用

news2024/10/6 20:38:04

1. 前言

        本篇博文将着眼于 i.MX RT1010 内部的 eFlexPWM,介绍其各个功能模块,以及 PWM 产生的原理。

2. 功能模块组成

        以下是 RT1010 内部 PWM 的一个 Submoudle 的组成框图,从框图中我们可以看到:

  1. 自左向右依次有 Prescaler 对时钟进行预分频,分频之后的时钟作为 16 bit counter 计数器的时钟,驱动其计数,计数的初始值由 Counter preload mux 根据不同的同步方式进行选择重载;
  2. 接下来将由 3 组 6 个比较器对 0-5 Campare value 寄存器的数值与 16 bit counter 的计数值进行比较:
    1. 对由 Compare 0 value 寄存器和 Compare 1 value 寄存器为一组的数值与当前的计数值进行比较,输出的比较值连接到 Reload Logic 进行 Master Reload 控制;另外通过 Compare 0 value 寄存器与当前计数值的值进行比较,通过 Pin Mux 可将四个 GPIO 端口复用为 PWMX 进行 PWM 的输出。
    2. 对由 Compare 2 value 寄存器和 Compare 3 value 寄存器为一组的数值与当前的计数值进行比较,分别控制一个 SR 触发的 S 端和 R 端,当 S 为 1 时 PWM 输出高电平,R 为 1 时,PWM 输出低电平,这样通过  Compare 2 value 寄存器和 Compare 3 value 寄存器即可输出一路 PWM23;
    3. 类似的可以通过 Compare 4 value 寄存器和 Compare 5 value 寄存器输出另一路 PWM45;
  3. PWM23 和 PWM45 经过 Comp. vs Indep. 模块的处理用于控制输出独立的或互补的 PWM 的波形,通过 Deed Time Cenerator 的处理用以插入死区时间,通过 Mux Select Logic 用以选择 GPIO 的引脚复用;最后一级的模块将对这两路 PWM 由 Fault protection 和 Output override control  进行出错保护。

 图 1. PWM 子模块框图

        通过 MCUXpresso Config Tools 可以看到芯片内部只有一个 PWM1,PWM1 下面有 4 个 Submoudles,每个 Submodle 可以控制 A 和 B 两个可互补的通道和一个 X  通道,可以针对有相应复用功能的引脚进行 PWM 功能复用。

        参考 SDK 的 PWM 例程,在枚举 _pwm_init_source 中对 counter 的重载方式进行了定义,可选的方式有本地同步(LocalSync)、主模块重载同步(MasterReload)、主模块同步(MasterSync)、外部同步(ExtSync)。不同的同步方式将影响到模块 4 个 Submodle 的计数器同步方式。例如对于选用主模块同步 MasterSync 这种方式将导致四个模块的计数器重载与 Submoulde 0 的重载时机一样,而采用本地同步(LocalSync)则不会受到主模块同步的影响。

/*! @brief PWM counter initialization options */
typedef enum _pwm_init_source
{
    kPWM_Initialize_LocalSync = 0U, /*!< Local sync causes initialization */
    kPWM_Initialize_MasterReload,   /*!< Master reload from submodule 0 causes initialization */
    kPWM_Initialize_MasterSync,     /*!< Master sync from submodule 0 causes initialization */
    kPWM_Initialize_ExtSync         /*!< EXT_SYNC causes initialization */
} pwm_init_source_t;

        PWM 模式,在枚举 _pwm_mode 中定义,kPWM_SignedCenterAligned 和 kPWM_CenterAligned 是中央对其方式,kPWM_SignedEdgeAligned 和 kPWM_EdgeAligned 是边缘对齐方式,Signed 和 Unsigned 指的是 INIT 计数器的初始值是有符号数和无符号数。

        由于 SDK 中没有 PWMX PWM 生成的代码例程,本篇博文将添加一种 kPWM_NonAligned 方式进行测试。 

/*! @brief PWM operation mode */
typedef enum _pwm_mode
{
    kPWM_SignedCenterAligned = 0U, /*!< Signed center-aligned */
    kPWM_CenterAligned,            /*!< Unsigned cente-aligned */
    kPWM_SignedEdgeAligned,        /*!< Signed edge-aligned */
    kPWM_EdgeAligned,               /*!< Unsigned edge-aligned */
	kPWM_NonAligned               //added by joey wang 2023.2.8
} pwm_mode_t;

中央对齐模式:

        在此模式下,INIT 将向上计数,由 VAL2 通过比较器与计数值进行比较打开 PWMA 的上升边沿,VAL3 打开 PWMA 的下降边沿; 由 VAL4 打开 PWMB 的上升边沿,VAL5 打开 PWMB 的下降边沿,不难看出 Singed 模式下数值对称,有利于计算。

 边沿对齐模式:

        在边沿对齐模式下,INIT 的取值和 VAL2 和 VAL4 的取值一样,即 PWMA 和 PWMB 上升沿 PWM 打开的时机一样,即达到了边沿对齐的目的,只需要指定 VAL3 和 VAL5 的数值,即可改变 PWMA 或 PWMB 的占空比。

实验现象:

在 PWM_SetupPwm 中增加 kPWM_NonAligned 的 case 判断:

status_t PWM_SetupPwm(PWM_Type *base,
                      pwm_submodule_t subModule,
                      const pwm_signal_param_t *chnlParams,
                      uint8_t numOfChnls,
                      pwm_mode_t mode,
                      uint32_t pwmFreq_Hz,
                      uint32_t srcClock_Hz)
{
    assert(chnlParams);
    assert(pwmFreq_Hz);
    assert(numOfChnls);
    assert(srcClock_Hz);

    uint32_t pwmClock;
    uint16_t pulseCnt = 0, pwmHighPulse = 0;
    uint16_t modulo = 0;
    uint8_t i, polarityShift = 0, outputEnableShift = 0;

    if (numOfChnls > 3U)
    {
        /* Each submodule has 3 signals; PWM A & PWM B & PWM X*/
        return kStatus_Fail;
    }

    /* Divide the clock by the prescale value */
    pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
    pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);

    /* Setup each PWM channel */
    for (i = 0; i < numOfChnls; i++)
    {
        /* Calculate pulse width */
        pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100U;

        /* Setup the different match registers to generate the PWM signal */
        switch (mode)
        {
            case kPWM_SignedCenterAligned:
                /* Setup the PWM period for a signed center aligned signal */
                if (i == 0U)
                {
                    modulo = (pulseCnt >> 1U);
                    /* Indicates the start of the PWM period */
                    base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
                    /* Indicates the center value */
                    base->SM[subModule].VAL0 = 0;
                    /* Indicates the end of the PWM period */
                    /* The change during the end to start of the PWM period requires a count time */
                    base->SM[subModule].VAL1 = modulo - 1U;
                }

                /* Setup the PWM dutycycle */
                if (chnlParams->pwmChannel == kPWM_PwmA)
                {
                    base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
                    base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
                }
                else if(chnlParams->pwmChannel == kPWM_PwmB)
                {
                    base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
                    base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
                }
                break;
            case kPWM_CenterAligned:
                /* Setup the PWM period for an unsigned center aligned signal */
                /* Indicates the start of the PWM period */
                if (i == 0U)
                {
                    base->SM[subModule].INIT = 0;
                    /* Indicates the center value */
                    base->SM[subModule].VAL0 = (pulseCnt / 2U);
                    /* Indicates the end of the PWM period */
                    /* The change during the end to start of the PWM period requires a count time */
                    base->SM[subModule].VAL1 = pulseCnt - 1U;
                }

                /* Setup the PWM dutycycle */
                if (chnlParams->pwmChannel == kPWM_PwmA)
                {
                    base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
                    base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
                }
                else
                {
                    base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
                    base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
                }
                break;
            case kPWM_SignedEdgeAligned:
                /* Setup the PWM period for a signed edge aligned signal */
                if (i == 0U)
                {
                    modulo = (pulseCnt >> 1U);
                    /* Indicates the start of the PWM period */
                    base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
                    /* Indicates the center value */
                    base->SM[subModule].VAL0 = 0;
                    /* Indicates the end of the PWM period */
                    /* The change during the end to start of the PWM period requires a count time */
                    base->SM[subModule].VAL1 = modulo - 1U;
                }

                /* Setup the PWM dutycycle */
                if (chnlParams->pwmChannel == kPWM_PwmA)
                {
                    base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
                    base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
                }
                else
                {
                    base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
                    base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
                }
                break;
            case kPWM_EdgeAligned:
                /* Setup the PWM period for a unsigned edge aligned signal */
                /* Indicates the start of the PWM period */
                if (i == 0U)
                {
                    base->SM[subModule].INIT = 0;
                    /* Indicates the center value */
                    base->SM[subModule].VAL0 = (pulseCnt / 2U);
                    /* Indicates the end of the PWM period */
                    /* The change during the end to start of the PWM period requires a count time */
                    base->SM[subModule].VAL1 = pulseCnt - 1U;
                }

                /* Setup the PWM dutycycle */
                if (chnlParams->pwmChannel == kPWM_PwmA)
                {
                    base->SM[subModule].VAL2 = 0;
                    base->SM[subModule].VAL3 = pwmHighPulse;
                }
                else
                {
                    base->SM[subModule].VAL4 = 0;
                    base->SM[subModule].VAL5 = pwmHighPulse;
                }
                break;
			/*added by joey wang at 2023.2.14*/
			case kPWM_NonAligned:
                /* Setup the PWM period for a signed center aligned signal */
                if (i == 0U)
                {
					/* Setup the PWM period for a PWM_X non-aligned signal */
						pulseCnt = base->SM[subModule].VAL1;
					/* Indicates the start of the PWM period */
						base->SM[subModule].INIT = 0;
					/* Indicates the center value */
						base->SM[subModule].VAL0 = (pulseCnt / 2);
					/* Indicates the end of the PWM period */
						base->SM[subModule].VAL1 = pulseCnt;
                }

                /* Setup the PWM dutycycle */
                if (chnlParams->pwmChannel == kPWM_PwmA)
                {
                    base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
                    base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
                }
                else if(chnlParams->pwmChannel == kPWM_PwmB)
                {
                    base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
                    base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
                }
    			/*initialize duty circle, VAL0/VAL1 is the duty circle*/
				else if(chnlParams->pwmChannel == kPWM_PwmX)
				{
					PRINTF("kPWM_PwmX duty is set\t\n");
                    base->SM[subModule].VAL0 = pwmHighPulse;
					base->SM[subModule].VAL1 = pwmHighPulse*2;
					PRINTF("VAL0 = %d\r\n",base->SM[subModule].VAL0);
					PRINTF("VAL1 = %d\r\n",base->SM[subModule].VAL1);
				}
                break;
            default:
                assert(false);
                break;
        }
        /* Setup register shift values based on the channel being configured.
         * Also setup the deadtime value
         */
        if (chnlParams->pwmChannel == kPWM_PwmA)
        {
            polarityShift              = PWM_OCTRL_POLA_SHIFT;
            outputEnableShift          = PWM_OUTEN_PWMA_EN_SHIFT;
            base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
        }
        else if(chnlParams->pwmChannel == kPWM_PwmB)
        {
            polarityShift              = PWM_OCTRL_POLB_SHIFT;
            outputEnableShift          = PWM_OUTEN_PWMB_EN_SHIFT;
            base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
        }
		else
		{		
			polarityShift              = PWM_OCTRL_POLX_SHIFT;
            outputEnableShift          = PWM_OUTEN_PWMX_EN_SHIFT;
            base->SM[subModule].DTCNT0 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
		}

        /* Set PWM output fault status */
        switch (chnlParams->pwmChannel)
        {
            case kPWM_PwmA:
                base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
                base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) &
                                              (uint16_t)PWM_OCTRL_PWMAFS_MASK);
                break;
            case kPWM_PwmB:
                base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
                base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) &
                                              (uint16_t)PWM_OCTRL_PWMBFS_MASK);
                break;
            case kPWM_PwmX:
                base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMXFS_MASK);
                base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMXFS_SHIFT) &
                                              (uint16_t)PWM_OCTRL_PWMXFS_MASK);
                break;
            default:
                assert(false);
                break;
        }

        /* Setup signal active level */
        if ((bool)chnlParams->level == kPWM_HighTrue)
        {
            base->SM[subModule].OCTRL &= ~((uint16_t)1U << (uint16_t)polarityShift);
        }
        else
        {
            base->SM[subModule].OCTRL |= ((uint16_t)1U << (uint16_t)polarityShift);
        }
        /* Enable PWM output */
        base->OUTEN |= ((uint16_t)1U << ((uint16_t)outputEnableShift + (uint16_t)subModule));

        /* Get the next channel parameters */
        chnlParams++;
    }

    return kStatus_Success;
}

再更新 PWM_UpdatePwmDutycycleHighAccuracy 函数

void PWM_UpdatePwmDutycycleHighAccuracy(
    PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle)
{
    assert((uint16_t)pwmSignal < 3U);
    uint16_t pulseCnt = 0, pwmHighPulse = 0;
    uint16_t modulo = 0;
	
		
    switch (currPwmMode)
    {
        case kPWM_SignedCenterAligned:
            modulo   = base->SM[subModule].VAL1 + 1U;
            pulseCnt = modulo * 2U;
            /* Calculate pulse width */
            pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;

            /* Setup the PWM dutycycle */
            if (pwmSignal == kPWM_PwmA)
            {
                base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
                base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
            }
            else
            {
                base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
                base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
            }
            break;
        case kPWM_CenterAligned:
            pulseCnt = base->SM[subModule].VAL1 + 1U;
            /* Calculate pulse width */
            pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;

            /* Setup the PWM dutycycle */
            if (pwmSignal == kPWM_PwmA)
            {
                base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
                base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
            }
            else
            {
                base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
                base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
            }
            break;
        case kPWM_SignedEdgeAligned:
            modulo   = base->SM[subModule].VAL1 + 1U;
            pulseCnt = modulo * 2U;
            /* Calculate pulse width */
            pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;

            /* Setup the PWM dutycycle */
            if (pwmSignal == kPWM_PwmA)
            {
                base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
                base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
            }
            else
            {
                base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
                base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
            }
            break;
        case kPWM_EdgeAligned:
            pulseCnt = base->SM[subModule].VAL1 + 1U;
            /* Calculate pulse width */
            pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;

            /* Setup the PWM dutycycle */
            if (pwmSignal == kPWM_PwmA)
            {
                base->SM[subModule].VAL2 = 0;
                base->SM[subModule].VAL3 = pwmHighPulse;
            }
            else
            {
                base->SM[subModule].VAL4 = 0;
                base->SM[subModule].VAL5 = pwmHighPulse;
            }
            break;
		case kPWM_NonAligned:
            pulseCnt = base->SM[subModule].VAL1 + 1U;
            /* Calculate pulse width */
            pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
            /* Setup the PWM dutycycle */
            if (pwmSignal == kPWM_PwmA)
            {
                base->SM[subModule].VAL2 = 0;
                base->SM[subModule].VAL3 = pwmHighPulse;
            }
            else if (pwmSignal == kPWM_PwmB)
            {
                base->SM[subModule].VAL4 = 0;
                base->SM[subModule].VAL5 = pwmHighPulse;
            }
            //add PWMX duty update here
			else
			{
				base->SM[subModule].VAL0 = pwmHighPulse;
                //base->SM[subModule].VAL1 = 0;
				PRINTF("pwmHighPulse = %d\r\n",pwmHighPulse);
				PRINTF("VAL1 = %d\r\n",base->SM[subModule].VAL1);
			}
			break;
        default:
            assert(false);
            break;
    }
}

        通过添加以上对 kPWM_NonAligned 输出 PWMX 的代码,再通过 PWM configure 函数,对 PWMX 的输出方式进行配置,代码如下,即可输出指定占空比的 PWMX 的 PWM 波形。

//PWM
void pwm_config(pwm_no_t pwm_no, uint32 frq ,gpio_no_t gpio_no)       //Configure PWM initial settings, frq: pwm frquency, 1 per 1Hz, 6 PWM channels share the same SCT, the frq value should be the same.  
{
		/* Structure of initialize PWM */
    pwm_config_t pwmConfig;
    pwm_fault_param_t faultConfig;
	
    CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); /* Set IPG PODF to 3, divede by 4 */

    /* Set the PWM Fault inputs to a low value */
    XBARA_Init(XBARA);
    XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0);
    XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1);
    XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault2);
    XBARA_SetSignalsConnection(XBARA, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault3);

	PWM_GetDefaultConfig(&pwmConfig);

#ifdef DEMO_PWM_CLOCK_DEVIDER
    pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER;
#endif

    /* Use full cycle reload */
    pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
    /* PWM A & PWM B form a complementary PWM pair */
    pwmConfig.pairOperation   = kPWM_Independent;
	pwmConfig.prescale        = kPWM_Prescale_Divide_4;
    pwmConfig.enableDebugMode = true;

    /* Initialize submodule 0 */
    if (PWM_Init(PWM1, kPWM_Module_0, &pwmConfig) == kStatus_Fail)
    {
        PRINTF("PWM initialization failed\r\n");
    }

    pwmConfig.clockSource           = kPWM_BusClock;
    pwmConfig.prescale              = kPWM_Prescale_Divide_4;
    pwmConfig.initializationControl = kPWM_Initialize_LocalSync;	//initializationControl
    if (PWM_Init(PWM1, kPWM_Module_1, &pwmConfig) == kStatus_Fail)
    {
        PRINTF("PWM initialization failed\r\n");
    }

    /* Initialize submodule 2 the same way as submodule 1 */
    if (PWM_Init(PWM1, kPWM_Module_2, &pwmConfig) == kStatus_Fail)
    {
        PRINTF("PWM initialization failed\r\n");
    }
		
		    /* Initialize submodule 3 the same way as submodule 1 */
    if (PWM_Init(PWM1, kPWM_Module_3, &pwmConfig) == kStatus_Fail)
    {
        PRINTF("PWM initialization failed\r\n");
    }

    /*
     *   config->faultClearingMode = kPWM_Automatic;
     *   config->faultLevel = false;
     *   config->enableCombinationalPath = true;
     *   config->recoverMode = kPWM_NoRecovery;
     */
    PWM_FaultDefaultConfig(&faultConfig);

#ifdef DEMO_PWM_FAULT_LEVEL
    faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL;
#endif

    /* Sets up the PWM fault protection */
    PWM_SetupFaults(PWM1, kPWM_Fault_0, &faultConfig);
    PWM_SetupFaults(PWM1, kPWM_Fault_1, &faultConfig);
    PWM_SetupFaults(PWM1, kPWM_Fault_2, &faultConfig);
    PWM_SetupFaults(PWM1, kPWM_Fault_3, &faultConfig);

    /* Set PWM fault disable mapping for submodule 0/1/2/3 */
    PWM_SetupFaultDisableMap(PWM1, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0,
                             kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
    PWM_SetupFaultDisableMap(PWM1, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0,
                             kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
    PWM_SetupFaultDisableMap(PWM1, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0,
                             kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);

    /* Call the init function with demo configuration */
    pwm_set_param(pwm_no, frq, gpio_no, pwm_mode);

    /* Set the load okay bit for all submodules to load registers from their buffer */
    PWM_SetPwmLdok(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2 | kPWM_Control_Module_3, true);

    /* Start the PWM generation from Submodules 0, 1 and 2 */
    PWM_StartTimer(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2 | kPWM_Control_Module_3);
}

static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;

static uint32_t PWM_GetInstance(PWM_Type *base)
{
    uint32_t instance;
    /* Find the instance index from base address mappings. */
    for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
    {
        if (s_pwmBases[instance] == base)
        {
            break;
        }
    }
    assert(instance < ARRAY_SIZE(s_pwmBases));

    return instance;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/483246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++入门】C++为什么要有缺省参数

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

后端程序员的前端必备【Vue】- 01 Vue入门

Vue概述与基础入门 1 Vue简介1.1 简介1.2 MVVM 模式的实现者——双向数据绑定模式1.3 其它 MVVM 实现者1.4 为什么要使用 Vue.js1.5 Vue.js 的两大核心要素1.5.1 数据驱动![请添加图片描述](https://img-blog.csdnimg.cn/963aca7d7a4447009a23f6900fdd7ee1.png)1.5.2 组件化 2 …

IDEA2022版教程上(下载、卸载、安装、新建工程、jdk设置、详细设置、新建/导入/删除 普通java模块、修改普通java模块名、同时打开多个工程、常用代码模板:非空判断,遍历,输出语句快捷键)

0、前景摘要 0.1 概览 0.2 套课程适用人群 初学Java语言&#xff0c;熟悉了记事本、EditPlus、NotePad或Sublime Text3等简易开发工具的Java初学者熟练使用其他Java集成开发环境&#xff08;IDE&#xff09;&#xff0c;需要转向IDEA工具的Java工程师们关注IDEA各方面特性的J…

BPMN2.0 任务-脚本任务

描述 脚本任务(script task)是自动执行的活动。当流程执行到达脚本任务时,会执行相应的脚本。 脚本任务用左上角有一个小“脚本”图标的标准BPMN 2.0任务(圆角矩形)表示。 脚本任务使用script与scriptFormat元素定义。 <scriptTask id="theScriptTask" nam…

Qt中的绘图事件

文章目录 QPainter 绘图绘图设备QPixmap QPainter 绘图 绘图事件 void paintEvent()声明一个画家对象 QPainter painter(this) this指定绘图设备画线、画圆、画矩形、画文字设置画笔 QPen 设置画笔宽度 、风格设置画刷 QBrush 设置画刷 风格 测试 #include "widget.h&quo…

科学计算库Numpy快速入门

目录 Numpy概述array数组数组结构数组类型数值运算排序操作数组形状操作数组生成函数四则运算随机模块文件读写 Numpy概述 NumPy 是 Python 中的一个开源数学库&#xff0c;提供了快速且便捷的数组处理功能&#xff0c;可以用来进行科学计算、数据分析、算法开发等多种任务。N…

InnoDB 磁盘结构及表空间 ( Tablespaces )

InnoDB磁盘主要包含Tablespaces&#xff0c;InnoDB Data Dictionary、Doublewrite Buffer、redo log和Undo Logs Tablespaces: 表空间分为系统表空间&#xff08;ibdata1文件&#xff09;、临时表空间、常规表空间、Undo表空间以及file-per-table表空间。系统表空间又包括双写…

CDH6.3.2-组件安装安全认证

HDFS 1.选择自定义。 2.选择HDFS ZK YARN然后点继续。 3.选择安装的主机。 4.审核更改默认就行&#xff0c;点继续。 5.配置HDFS的HA。 安装好以后点击hdfs进入实例就能够看到启动了高可用。 6.启动YARN的高可用。 KAFKA 更具需求修改资源 一直点继续就行了 FlUME HI…

CTF权威指南 笔记 -第二章二进制文件- 2.3 -静态链接

目录 地址空间分配 两个链接的方式 按序叠加 相似节合并 静态链接的详细过程 虚拟内存 重定位文件 静态链接库 地址空间分配 我们把之前的两函数分为两个文件 main.c extern int shared extern vooid fun(int *a,int *b); int main(){int a100;func(&a,&share…

MySQL监控告警及可视化:Zabbix+Percona PMP实现(Part III)

MySQL监控告警及可视化&#xff1a;ZabbixPercona PMP实现&#xff08;Part III&#xff09; 告警配置配置告警邮箱配置告警消息模板配置告警用户配置告警规则告警测试 告警配置 配置告警邮箱 在Zabbix Web前端的 Administration - Media Types - Email 中配置发送告警信息的…

什么是恺撒密码?如何用Python实现它(36)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 猫妹目前在看的&#xff0c;ycl Python等级考试五级教材&#xff0c;有一章是介绍恺撒密码的。 今天&#xff0c;咱们…

2023-5-2面试题学习

1、内存的可见性你了解吗&#xff0c;讲述一下&#xff1f; 内存可见性是指多个线程访问同一共享变量时&#xff0c;在一个线程修改了该变量值后&#xff0c;下一个线程能立即看到这种变化的能力。 如果一个变量在多个线程间共享&#xff0c;那么为了避免出现数据不一致的情况&…

为什么DDD难落地?

为什么DDD难落地&#xff1f; lorne 2023-04-23 视频地址&#xff1a; 为什么DDD难落地&#xff1f;_哔哩哔哩_bilibili 洋葱架构图&#xff1a; DDD能解决什么问题&#xff1f; 其实DDD的核心是&#xff1a;提升业务的聚合性、提升业务的拓展性。 DDD的错误认知&#xff…

CentOS7安装和部署Jenkins

安装Java环境 检查旧版&#xff1a; rpm -qa | grep java若已经安装了旧版本&#xff0c;则需要先删除&#xff0c;删除方法&#xff1a; rpm -qa nodeps [java package]安装新版&#xff1a; yum install java-11-openjdk yum install java-11-openjdk-devel&#xff08;开…

07 KVM虚拟机引导固件安装

文章目录 07 KVM虚拟机引导固件安装7.1 概述7.2 安装方法7.2.1 安装edk软件包7.2.2 查询edk软件是否安装成功 07 KVM虚拟机引导固件安装 7.1 概述 针对不同的架构&#xff0c;引导的方式有所差异。x86支持UEFI&#xff08;Unified Extensible Firmware Interface&#xff09;…

MySQL示例数据库(MySQL Sample Databases) 之 World数据库

文章目录 MySQL示例数据库(MySQL Sample Databases) 之 World数据库官方示例数据介绍World数据库World 数据库安装world-db/world.sql的脚本内容参考 MySQL示例数据库(MySQL Sample Databases) 之 World数据库 官方示例数据介绍 MySQL 官方提供了多个示例数据库&#xff0c;在…

【致敬未来的攻城狮计划】— 连续打卡第十九天:RA2E1串口通信基础知识

系列文章目录 1.连续打卡第一天&#xff1a;提前对CPK_RA2E1是瑞萨RA系列开发板的初体验&#xff0c;了解一下 2.开发环境的选择和调试&#xff08;从零开始&#xff0c;加油&#xff09; 3.欲速则不达&#xff0c;今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

什么是GPT模型,GPT下载和国内镜像

什么是GPT模型&#xff0c;GPT模型是通过预训练的方式&#xff0c;采用无监督学习方式&#xff0c;大量语料输入&#xff0c;经过多次训练后得到模型。它能够自动学习并理解自然语言中的语义、句法和语法信息&#xff0c;并可以用于文本生成、对话系统、情感分析、机器翻译等自…

HTTP第二讲——HTTP相关概念

与HTTP 相关的各种应用 1.网络世界 实际的互联网是由许许多多个规模略小的网络连接而成的&#xff0c;这些“小网络”可能是只有几百台电脑的局域网&#xff0c;可能是有几万、几十万 台电脑的广域网&#xff0c;可能是用电缆、光纤构成的固定网络&#xff0c;也可能是用基站、…

SQL之SQL索引

文章目录 一、索引概述介绍演示优缺点 二、索引结构二叉树B-Tree (多路平衡查找树)BTreeHash 三、索引分类四、索引语法五、SQL性能分析SQL执行频率慢查询日志profile详情 索引使用原则验证索引效率最左前缀法则索引列运算字符串不加引号模糊查询or连接的条件数据分布影响 .SQL…