Generating a fixed number of PWM cycles when using flexPWM in complementary mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Generating a fixed number of PWM cycles when using flexPWM in complementary mode

Jump to solution
1,777 Views
PseudoCircuit
Contributor II

Hello,

We are using RT1064 and for our application, it is necessary that only a specific amount (under 100) of PWM cycles is generated and PWM signal is then stopped immediately. We were able to achieve this in Independent PWM mode by using DMA to write to VAL3 register (for PWM A) the corresponding duty cycle and writing 0 as the last value - this would drop the PWM output to 0 without delay. However, this approach does not work in complementary mode, as writing 0 to VAL3 when using kPWM_ComplementaryPwmA mode results in PWM B being always on (100% duty cycle) regardless of VAL5 value. In our case, it is also necessary to use DMA to change the PWM frequency. We were able to stop PWM A and PWM B (both go to 0) by manually triggering a PWM fault using this command in DMA callback:

XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0);

Unfortunately, the stopping does not happen immediately, for example at PWM frequency of around 700kHz it takes about 12 more cycles after DMA transfer is finished for PWM signal to stop. Do you have any suggestions on some other approaches we could use to stop the complementary PWM after a specific number of samples?

0 Kudos
1 Solution
1,702 Views
PseudoCircuit
Contributor II

You're right, I needed to set the IOMUXC bit to select XBARA as input for QTMR. I did not need to change anything with the PWMAOT0 bit. However, this was not the only issue I had to fix. For future reference: I also needed to set TMR_CTRL_ONCE and TMR_CTRL_LENGTH bits to 1 and TMR_CTRL_OUTMODE to 2 (set on compare). To perform this PWM cycle counting and fault triggering operation multiple times, I also had to set TMR_SCTRL_VAL as 0 and write 1 to TMR_SCTRL_FORCE to reset the OFLAG (which is connected to the PWM fault) back to 0 before starting the timer again.

View solution in original post

0 Kudos
7 Replies
1,765 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

do you considering the method to disable just the PWM output while the eFlexPWM module still runs? After you disable the PWM output enabling bit in eFlexPWM->OUTEN, the PWM signal become low or high immediately.

Pls refer to section 28.4.45.2 Diagram in IMXRT1050RM.pdf, when you set the corresponding bit, the PWM signal will output, when  you clear the bit, the PWM signal pin will in tri-state, external pull up/down will determine the logic. Note that the eFlexPWM still run, if you still want to output the PWM signal, after you set the PWMx_EN bit, the PWM signal will drive the pin immediately.

I think you can connect the PWM signal to another time, for example quadTimer, have the quadTimer count the PWM cycle number, when the counter of quadTimer reach up to a threshold defined in compare reg of quadTimer, an ISR of quadTimer will be triggered, in the ISR, you can set/clear the eFlexPWM->OUTEN register.

 

xiangjun_rong_0-1654074334549.png

Hope it can help you

BR

XiangJun Rong

 

 

 

0 Kudos
1,750 Views
PseudoCircuit
Contributor II

Setting the OUTEN bit to 0 results in both PWM A and PWM B being active and gradually dropping off, which is very undesirable:

pwm_en_slow_drop.png

Using PWM faults does drop both outputs properly to 0. I'm trying to set up QTMR to count the PWM cycles as you described and then trigger the PWM fault. However, the quad timer does not seem to work, is there an example of using Quad Timer as a counter with external input? Here is my initialization code, maybe you can spot what is wrong with it.

QTimer Initialisation:

const qtmr_config_t TMR3_Channel_0_config = {
  .primarySource = kQTMR_ClockCounter0InputPin,
  .secondarySource = kQTMR_Counter0InputPin,
  .enableMasterMode = false,
  .enableExternalForce = false,
  .faultFilterCount = 0,
  .faultFilterPeriod = 0,
  .debugMode = kQTMR_RunNormalInDebug
};

static void TMR3_init(void) {
  /* Quad timer channel Channel_0 peripheral initialization */
  QTMR_Init(TMR3_PERIPHERAL, TMR3_CHANNEL_0_CHANNEL, &TMR3_Channel_0_config);
  /* Setup the timer period of the channel */
  QTMR_SetTimerPeriod(TMR3_PERIPHERAL, TMR3_CHANNEL_0_CHANNEL, 5U);
  /* Enable interrupt requests of the timer channel */
  QTMR_EnableInterrupts(TMR3_PERIPHERAL, TMR3_CHANNEL_0_CHANNEL, kQTMR_CompareInterruptEnable);
  /* Interrupt vector TMR3_IRQn priority settings in the NVIC. */
  NVIC_SetPriority(TMR3_IRQN, TMR3_IRQ_PRIORITY);
  /* Enable interrupt TMR3_IRQn request in the NVIC. */
  EnableIRQ(TMR3_IRQN);
  /* Start the timer - select the timer counting mode */
  QTMR_StartTimer(TMR3_PERIPHERAL, TMR3_CHANNEL_0_CHANNEL, kQTMR_PriSrcRiseEdge);
}

PWM initialisation:

    XBARA_Init(XBARA1);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputFlexpwm1Pwm3OutTrig01, kXBARA1_OutputQtimer3Tmr0Input);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputQtimer3Tmr0Output, kXBARA1_OutputFlexpwm1Fault0);
    pwm_config_t pwmConfig;
    PWM_GetDefaultConfig(&pwmConfig);

    pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
    pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity;
    pwmConfig.pairOperation = kPWM_ComplementaryPwmA;
    pwmConfig.enableDebugMode = false;
    pwmConfig.enableWait = false;

    if (PWM_Init(PWM1, kPWM_Module_2, &pwmConfig) == kStatus_Fail)
    {
        DEBUG_ERROR("PWM initialization failed\n");
    }
    pwm_signal_param_t pwmSignal[2];
    timDeadTime = 10U;

    pwmSignal[0].pwmChannel = kPWM_PwmA;
    pwmSignal[0].level = kPWM_HighTrue;
    pwmSignal[0].dutyCyclePercent = 50;
    pwmSignal[0].deadtimeValue = timDeadTime;
    pwmSignal[0].faultState = kPWM_PwmFaultState0;

    pwmSignal[1].pwmChannel = kPWM_PwmB;
    pwmSignal[1].level = kPWM_HighTrue;
    pwmSignal[1].dutyCyclePercent = 50;
    pwmSignal[1].deadtimeValue = timDeadTime;
    pwmSignal[1].faultState = kPWM_PwmFaultState0;

    pwm_fault_param_t faultConfig;
    PWM_FaultDefaultConfig(&faultConfig);
    faultConfig.enableCombinationalPath = false;
    faultConfig.faultLevel = true;
    PWM_SetupFaults(PWM1, kPWM_Fault_0, &faultConfig);

    PWM_SetupFaultDisableMap(PWM1,
                             kPWM_Module_2,
                             kPWM_PwmA,
                             kPWM_faultchannel_0,
                             kPWM_FaultDisable_0);

    PWM_SetupFaultDisableMap(PWM1,
                             kPWM_Module_2,
                             kPWM_PwmB,
                             kPWM_faultchannel_0,
                             kPWM_FaultDisable_0);

    if (PWM_SetupPwm(PWM1,
                     kPWM_Module_2,
                     pwmSignal,
                     2,
                     kPWM_EdgeAligned,
                     700000U,
                     BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT)
        != kStatus_Success)
    {
        DEBUG_ERROR("PWM setup failed");
    }

    PWM_OutputTriggerEnable(PWM1, kPWM_Module_2, kPWM_ValueRegister_1, true);

Timer Compare Interrupt never fires so I assume something is wrong with the connection from PWM to Quad Timer.

XBARA inputs for PWM are kXBARA1_InputFlexpwm1Pwm[1-4]OutTrig01. I assume the number after PWM corresponds to the PWM submodule being used +1, as submodules are 0-3? Is there a document that properly documents what the XBAR inputs and outputs are? For example, I could not find any information on what the signal kXBARA1_InputDmaDone0 actually does and how it should be used.

 

0 Kudos
1,744 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Regarding the gradually dropping off issue, I suppose that PWM_xA and PWM_xB are in tri-state after you clear the OUTEN bits, pls connect an external  pull-down resistor on the PWM_xA and PWM_xB pins, I think the dropping-off phenomenon will disappear.  I think you can enable the pin on-chip pull-down resistor by configuring the IOMUXC_SW_PAD_CTL_PAD_GPIO_xxxx to have a test.

For the quadTimer issue, I will have a check.

BR

XiangJun Rong

0 Kudos
1,739 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

For the QuadTimer issue that you can not get interrupt for the quadTimer3_TMR0, I think you have to set the bit 8 of IOMUXC_GPR_GPR6 so that the input quadTimer3_TMR0 is from the XBAR.

xiangjun_rong_0-1654514568235.png

Hope it can help you

BR

XiangJun Rong

 

1,703 Views
PseudoCircuit
Contributor II

You're right, I needed to set the IOMUXC bit to select XBARA as input for QTMR. I did not need to change anything with the PWMAOT0 bit. However, this was not the only issue I had to fix. For future reference: I also needed to set TMR_CTRL_ONCE and TMR_CTRL_LENGTH bits to 1 and TMR_CTRL_OUTMODE to 2 (set on compare). To perform this PWM cycle counting and fault triggering operation multiple times, I also had to set TMR_SCTRL_VAL as 0 and write 1 to TMR_SCTRL_FORCE to reset the OFLAG (which is connected to the PWM fault) back to 0 before starting the timer again.

0 Kudos
1,737 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I suppose that you have to set either PWMAOT0 bit or PWMBOT1 bit od the EflexPWM_SM3.

 

xiangjun_rong_1-1654515308411.png

 

Hope it can help you

BR

XiangJun Rong

0 Kudos
1,012 Views
edisonlin
Contributor I

Dear Sir,

This is a really good reference for what I want to do with my project, but I have a question. The definition of XBARA input combines FlexPWM TRIG0 and TRIG1 together, like kXBARB2_InputFlexpwm1Pwm1OutTrig01.  How can I route each of them to the individual inputs of the timer of any sort?

Thanks,

Edison

0 Kudos