flexPWM simultaneous start, single module

DrM

Well-known member
Hi,

This question has to do with simultaneous starting three submodules of a single flexpwm. The goal is that the three submodules should be in sync.

From the results below, it seems I am missing something in how to start the three submodules together. Here is what I have:

First the code snippets for how they are being started. The full source is attached. (This is work in progress, it started as c code, but will probably redo it as a class after a few things are sorted out. So for now its not great on style. But I think it demonstrates the question.)

Code:
inline void pwm_start_(IMXRT_FLEXPWM_t *p, uint8_t mask)
{
  //p->MCTRL |= (FLEXPWM_MCTRL_RUN(mask) | FLEXPWM_MCTRL_LDOK(mask));
  p->MCTRL |= FLEXPWM_MCTRL_RUN(mask);
  p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
}

inline void pwm_stop_(IMXRT_FLEXPWM_t *p, uint8_t mask)
{
  p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  p->MCTRL &= ~FLEXPWM_MCTRL_RUN(mask);
}

Code:
void pwm_lccd_start()
{
  pwm_stop_(icg_flexpwm,0xF);
  //icg_flexpwm->MCTRL |= FLEXPWM_MCTRL_CLDOK(0xF);           // stop everything

  icg_flexpwm->SM[ICG_SUBMODULE].STS = ICG_CMPF_MASK;       // clear any pending interrupts
  cnvst_flexpwm->SM[CNVST_SUBMODULE].STS = CNVST_CMPF_MASK;

  icg_skip_one = icg_skip_one_reload;             // reset the clear gate
  pwm_frame_counter = 0;
 
  read_pointer = read_buffer;                     // reset the readout
  read_counter = 0;                               // in case something this as a flag

  icg_flexpwm->SM[ICG_SUBMODULE].STS = ICG_CMPF_MASK;
  NVIC_ENABLE_IRQ(ICG_IRQ);
 
  pwm_start_(tcd1304_flexpwm,CLK_MASK|SH_MASK|ICG_MASK);
  //tcd1304_flexpwm->MCTRL |= 0xF<<8 | FLEXPWM_MCTRL_LDOK(CLK_MASK|SH_MASK|ICG_MASK);  // Start clk, sh, icg only
 
  pwm_frame_cyccnt_start = ARM_DWT_CYCCNT;
}

And here is the result:


TEK0017.JPG



TEK0018.JPG





TEK0019.JPG
 

Attachments

  • tcd1304_flexpwm.cpp
    22.5 KB · Views: 128
  • tcd1304_flexpwm.h
    1 KB · Views: 139
p/s In the above, I neglected to point out that the three channels are (a) out of sync, and (b) the offset in time is not constant. These are different starts. It seems like each start picks up a different error in offset.

Attached is an update to the source, one error is fixed at line 463. The behavior is the same. Offsets drift with each invocation

Also, in case it might be useful here is output from the setup function followed by a register dump from the flexPWM.

Thank you

Code:
LCCD:
response:  pwm read 8.e-3 1.e-6 8.e-3 2
response:  setting skip one
response:  pwm_setup_flexpwmclk subm 0 chan 1 pinA 4 muxA 1 pinB 255 muxB 0 ; period 64 on 0 off 32 ; prescale 0 divider 1 => 64 0 32
response:  pwm_setup_flexpwmcnvst subm 3 chan 1 pinA 255 muxA 0 pinB 255 muxB 0 ; period 256 on 97 off 192 ; prescale 0 divider 1 => 256 97 192
response:  pwm_setup_flexpwmsh subm 2 chan 1 pinA 6 muxA 2 pinB 255 muxB 0 ; period 1200128 on 32 off 192 ; prescale 5 divider 32 => 37504 1 6
response:  pwm_setup_flexpwmicg subm 1 chan 1 pinA 5 muxA 1 pinB 255 muxB 0 ; period 1200128 on 0 off 416 ; prescale 5 divider 32 => 37504 0 13
pwm dump
response:  pwm dump
response:  MCTRL 0000000000000000 IPOL 0000 RUN 0000 LDOK 0000
response:  MCTRL2 MONPLL 0
response:  OUTEN 0000011100000000 PWMA 0111 PWMB 0000 PWMX 0000
response:  Submodule 0
response:  CNT 0
response:  INIT 0
response:  CTRL2 1110000000000000 DBGEN 1 WAITEN 1 INDEP 1 PWM23_INIT 0 PWM45_INIT 0 PWMX_INIT 0 INIT_SEL 0 FRCEN 0 FORCE 0 FORCE_SEL 0 RELOAD_SEL 0 CLK_SEL 0
response:  CTRL 0000010000000000 LDFQ 0 HALF 0 FULL 1 DT 00 COMPMODE 1 PRSC 0 SPLIT 0 LDMOD 0 DBLX 0 DBLEN 0
response:  OCTRL 0000000000000000 PWMA_IN 0 PWMB_IN 0 PWMX_IN 0 POLA 0 POLB 0 POLX 0 PWMA_FS 0 PWMB_FS 0 PWMX_FS 0
response:  VAL0 0 VAL1 63 VAL2 0 VAL3 31 VAL4 0 VAL5 0
response:  STS 0111000000111111 RUF 1 REF 1 RF 1 CFA1 0 CFA0 0 CFB1 0 CFB0 0 CFX1 0 CFX0 0 CMPF0 111111
response:  INTEN 0000000000000000 REIE 0 RIE 0 CA1IE 0 CA0IE 0 CB1IE 0 CB0IE 0 CX1IE 0 CX0IE 0 CMPIE 000000
response:  Submodule 1
response:  CNT 0
response:  INIT 0
response:  CTRL2 1110000000000000 DBGEN 1 WAITEN 1 INDEP 1 PWM23_INIT 0 PWM45_INIT 0 PWMX_INIT 0 INIT_SEL 0 FRCEN 0 FORCE 0 FORCE_SEL 0 RELOAD_SEL 0 CLK_SEL 0
response:  CTRL 0000010001010000 LDFQ 0 HALF 0 FULL 1 DT 00 COMPMODE 1 PRSC 5 SPLIT 0 LDMOD 0 DBLX 0 DBLEN 0
response:  OCTRL 0000010000000000 PWMA_IN 0 PWMB_IN 0 PWMX_IN 0 POLA 1 POLB 0 POLX 0 PWMA_FS 0 PWMB_FS 0 PWMX_FS 0
response:  VAL0 0 VAL1 37503 VAL2 0 VAL3 12 VAL4 0 VAL5 0
response:  STS 0111000000110111 RUF 1 REF 1 RF 1 CFA1 0 CFA0 0 CFB1 0 CFB0 0 CFX1 0 CFX0 0 CMPF0 110111
response:  INTEN 0000000000001000 REIE 0 RIE 0 CA1IE 0 CA0IE 0 CB1IE 0 CB0IE 0 CX1IE 0 CX0IE 0 CMPIE 001000
response:  Submodule 2
response:  CNT 0
response:  INIT 0
response:  CTRL2 1110000000000000 DBGEN 1 WAITEN 1 INDEP 1 PWM23_INIT 0 PWM45_INIT 0 PWMX_INIT 0 INIT_SEL 0 FRCEN 0 FORCE 0 FORCE_SEL 0 RELOAD_SEL 0 CLK_SEL 0
response:  CTRL 0000010001010000 LDFQ 0 HALF 0 FULL 1 DT 00 COMPMODE 1 PRSC 5 SPLIT 0 LDMOD 0 DBLX 0 DBLEN 0
response:  OCTRL 0000000000000000 PWMA_IN 0 PWMB_IN 0 PWMX_IN 0 POLA 0 POLB 0 POLX 0 PWMA_FS 0 PWMB_FS 0 PWMX_FS 0
response:  VAL0 0 VAL1 37503 VAL2 1 VAL3 5 VAL4 0 VAL5 0
response:  STS 0111000000111111 RUF 1 REF 1 RF 1 CFA1 0 CFA0 0 CFB1 0 CFB0 0 CFX1 0 CFX0 0 CMPF0 111111
response:  INTEN 0000000000000000 REIE 0 RIE 0 CA1IE 0 CA0IE 0 CB1IE 0 CB0IE 0 CX1IE 0 CX0IE 0 CMPIE 000000
response:  Submodule 3
response:  CNT 0
response:  INIT 0
response:  CTRL2 1110000000000000 DBGEN 1 WAITEN 1 INDEP 1 PWM23_INIT 0 PWM45_INIT 0 PWMX_INIT 0 INIT_SEL 0 FRCEN 0 FORCE 0 FORCE_SEL 0 RELOAD_SEL 0 CLK_SEL 0
response:  CTRL 0000010000000000 LDFQ 0 HALF 0 FULL 1 DT 00 COMPMODE 1 PRSC 0 SPLIT 0 LDMOD 0 DBLX 0 DBLEN 0
response:  OCTRL 0000000000000000 PWMA_IN 0 PWMB_IN 0 PWMX_IN 0 POLA 0 POLB 0 POLX 0 PWMA_FS 0 PWMB_FS 0 PWMX_FS 0
response:  VAL0 0 VAL1 255 VAL2 97 VAL3 191 VAL4 0 VAL5 0
response:  STS 0111000000110111 RUF 1 REF 1 RF 1 CFA1 0 CFA0 0 CFB1 0 CFB0 0 CFX1 0 CFX0 0 CMPF0 110111
response:  INTEN 0000000000001000 REIE 0 RIE 0 CA1IE 0 CA0IE 0 CB1IE 0 CB0IE 0 CX1IE 0 CX0IE 0 CMPIE 001000
 

Attachments

  • tcd1304_flexpwm.cpp
    22.8 KB · Views: 128
  • tcd1304_flexpwm.h
    1 KB · Views: 128
the three channels are (a) out of sync, and (b) the offset in time is not constant. These are different starts.

FlexPWM has bitmask register which allow you to apply changes to more than 1 channel at the same moment.

I glanced only briefly at your code, but I immediately noticed these functions where you're setting only a single bit within those bitmap registers.

Code:
inline void pwm_start_(IMXRT_FLEXPWM_t *p, uint8_t mask)
{
  //p->MCTRL |= (FLEXPWM_MCTRL_RUN(mask) | FLEXPWM_MCTRL_LDOK(mask));
  p->MCTRL |= FLEXPWM_MCTRL_RUN(mask);
  p->MCTRL |= FLEXPWM_MCTRL_LDOK(mask);
}

inline void pwm_stop_(IMXRT_FLEXPWM_t *p, uint8_t mask)
{
  p->MCTRL |= FLEXPWM_MCTRL_CLDOK(mask);
  p->MCTRL &= ~FLEXPWM_MCTRL_RUN(mask);
}

Maybe the rest of your code is initializing the various channels and calling these functions to cause each new setting to take effect one at a time? The purpose of these registers as bitmaps capable of addressing all channels is to allow you to have multiple channels update at the same instant. I really don't have time to look any deeper, but hopefully this helps?
 
Maybe the rest of your code is initializing the various channels and calling these functions to cause each new setting to take effect one at a time?

Thank you Paul for looking at it.

I am calling the start function like this, the mask passed into pwm_start_() is the OR of the three start bits.

Code:
pwm_start_(tcd1304_flexpwm,CLK_MASK|SH_MASK|ICG_MASK);
 
@PaulStoffregen

Hi Paul,

Here is the answer. It's very simple and perhaps obvious, after the fact. I am figuratively smacking forehead with a great square book (my 1st edition H&H) as we speak.

Simply set all of the submodules 1 to 3 to use the clock from submodule 0.

if (submodule != 0) {
p->SM[submodule].CTRL2 |= 2; // use clock from submodule 0'
}

It is really surprising that this is needed, given that the clocks are all derived from the bus clock. If A = B and C = B, we would think A = C. But, not in this universe.

Anyway, setting the other modules to use the 0 module clock works perfectly. All the timings now look correct and as calculated, every time. No muss, no fuss.
 
Wel.. spoke a little too soon. The phases are constant and reproducible. But still have some issues with apparent though constant offsets, perhaps its me. Checking.
 
Back
Top