Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronize timers #5

Open
GUIANSIBLE opened this issue Sep 13, 2023 · 3 comments
Open

Synchronize timers #5

GUIANSIBLE opened this issue Sep 13, 2023 · 3 comments

Comments

@GUIANSIBLE
Copy link

Hi, so I'm using the eFlexPwm library, and for now I can't find a way to synchronize two different modules. Is the library capable of doing that? Or only submodules?

So, I have this code, and when I check with an oscilloscope the signals from FlexPWM2 there's almost no deviation (100ns). But when I compare outputs from PWM2 and PWM 4 there's a delay of 3.0 us. Is there any way to synchronize the timers? So they start at the same time?

/*
eFlexPwm Simple Example

This example generates 3 pairs of PWM signals on a Teensy 4.1 board
Each signal pair corresponds to the PWMA output and the PWMB (A's complement)
output of an eFlexPWM submodule.
In this example, sub-modules 0, 2 and 3 of PWM2 are used. On the Teensy 4.1 board,
this corresponds to the following pins:

PWM SubModule Pol Teensy Native
2 0 A 4 EMC_06
2 0 B 33 EMC_07
2 2 A 6 B0_10
2 2 B 9 B0_11
2 3 A 36 B1_02
2 3 B 37 B1_03
The frequency is fixed by the constant PwmFreq, here at 18 kHz
On sub-module 0, the duty cycle changes by 5 in 5 from 0 to 100% every 100 PWM periods.
The duty cycle of sub-module 2 is equal to that of sub-module 0 divided by 2.
The duty cycle of sub-module 3 is equal to that of sub-module 0 divided by 4.

This example displays a message on the Serial link (USB CDC), and any error messages:

eFlexPwm Simple Example
Submodules successfuly started
*/
#include <Arduino.h>
#include <eFlexPwm.h>
//#include "TeensyTimerTool.h"

// Definitions
// ----------------------------------------------------------------------------
// avoid systematically prefixing objects with the namespace
using namespace eFlex;
//using namespace TeensyTimerTool;

// Variables
// ----------------------------------------------------------------------------
/* PWM frequence in hz. */
const uint32_t PwmFreq = 15000;
const uint32_t sinefreq = 50;

// My eFlexPWM submodules (Hardware > PWM2: SM[0], SM[2], SM[3])
SubModule Sm20(4,33);
SubModule Sm22(6,9);

SubModule Sm40(22);
SubModule Sm41(23);
SubModule Sm42(2,3);

// Initialize Timers for PWM2 and PWM4
Timer &Tm2 = Sm20.timer();
Timer &Tm4 = Sm40.timer();

// Duty Cycle in %
uint8_t dutyCyclePercent = 0;

// Code
void setup_FlexPWM2() {

Config myConfig;

myConfig.setReloadLogic(kPWM_ReloadPwmFullCycle); // Use full cycle reload
myConfig.setPwmFreqHz(PwmFreq); // Set PWM Frequency for PWM2.

// Initialize SubModule 0
Sm20.configure(myConfig);

// Initialize SubModule 2
myConfig.setClockSource(kPWM_Submodule0Clock); //Same clock as SubModule 0
myConfig.setPrescale(kPWM_Prescale_Divide_1);
myConfig.setInitializationControl(kPWM_Initialize_MasterSync);

Sm22.configure (myConfig);
}

void setup_FlexPWM4() {

Config myConfig;

myConfig.setReloadLogic(kPWM_ReloadPwmFullCycle); // Use full cycle reload
myConfig.setPwmFreqHz(PwmFreq); // Set PWM Frequency for PWM2.

// Initialize SubModule 0
Sm40.configure(myConfig);

// Initialize SubModule 1
myConfig.setClockSource(kPWM_Submodule0Clock); //Same clock as SubModule 0
myConfig.setPrescale(kPWM_Prescale_Divide_1);
myConfig.setInitializationControl(kPWM_Initialize_MasterSync);

Sm41.configure(myConfig);
Sm42.configure(myConfig);
}

void setup(){

setup_FlexPWM2();
setup_FlexPWM4();

Tm2.begin();
Tm4.begin();
}

void loop() {

int dutyCyclePercent_A = 50;
int dutyCyclePercent_B = 50;

Sm20.updateDutyCyclePercent (dutyCyclePercent_A, ChanA);
Sm20.updateDutyCyclePercent (dutyCyclePercent_B, ChanB);
Sm22.updateDutyCyclePercent (dutyCyclePercent_A, ChanA);
Sm22.updateDutyCyclePercent (dutyCyclePercent_B, ChanB);
Sm40.updateDutyCyclePercent (dutyCyclePercent_A); //Only has one channel
Sm41.updateDutyCyclePercent (dutyCyclePercent_B); //Only has one channel
Sm42.updateDutyCyclePercent (dutyCyclePercent_A, ChanA);
Sm42.updateDutyCyclePercent (dutyCyclePercent_B, ChanB);;

Tm2.setPwmLdok();
Tm4.setPwmLdok();
}

@lfarrand
Copy link

lfarrand commented Sep 13, 2023

I don't think the eFlexPwm library exposes this functionality, but you should be able to achieve it by fiddling with the registers directly and using xbar connect in addition to using the eFlexPwm library for everything else.

Here are some interesting links related to your question:
https://forum.pjrc.com/threads/60396-Teensy-4-synchronize-ADC-sampling-with-flexPWM-timing
https://forum.pjrc.com/threads/66665-Teensy-4-1-DMA-transfer-XBAR-does-not-work-as-expected
https://community.nxp.com/t5/i-MX-RT/Synchronize-flexPWM-Modules/td-p/897154
https://www.nxp.com/docs/en/application-note/AN12214.pdf

I was working on a solution to this very problem a while ago and some code snippets I had were:

// The i.MXRT1062 uses one config register per two XBAR outputs, so a helper
// function to make code more readable. 
bool xbarConnect (uint8_t input, uint8_t output) {
  if (input >= 88 || output >= 132) 
    return false;
  volatile uint16_t * xbar_select_reg = &XBARA1_SEL0 + (output >> 1); // 1 reg per 2 outputs
  if (output & 1)  // high byte or low byte choice.
    *xbar_select_reg = (*xbar_select_reg & 0x00FF) | (input << 8);
  else
    *xbar_select_reg = (*xbar_select_reg & 0xFF00) | input;
  return true;
}

void enableXbar() {
    // Turn on XBAR1 clock for all but stop mode
  CCM_CCGR2 |= CCM_CCGR2_XBAR1(3);  

  // Connect trigger to synchronize PWM modules
  // IN is 1 based, i.e. 1-4, whereas OUT is 0 based, i.e. 0-3
  // IN_FLEXPWM2_PWM1 is PWM2.0
  // OUT_FLEXPWM3_EXT_SYNC1 is PWM3.1
  //xbarConnect (XBARA1_IN_FLEXPWM2_PWM1_OUT_TRIG0, XBARA1_OUT_FLEXPWM3_EXT_SYNC1);
  xbarConnect (XBARA1_IN_FLEXPWM2_PWM1_OUT_TRIG1, XBARA1_OUT_FLEXPWM3_EXT_SYNC1);

  // Use FlexPWM4/2 (pins 2&3) to send trigger signal to FlexPWM2/2 (pins 6&9) and FlexPWM1/3 (pins 8&7)
  //   xbar_connect (XBARA1_IN_FLEXPWM4_PWM3_OUT_TRIG0, XBARA1_OUT_FLEXPWM1_PWM3_EXT_SYNC) ;
  //   xbar_connect (XBARA1_IN_FLEXPWM4_PWM3_OUT_TRIG0, XBARA1_OUT_FLEXPWM2_PWM2_EXT_SYNC) ;

  // Select alt 3 for EMC_06 (XBAR), rather than original 5 (GPIO)
  CORE_PIN4_CONFIG = 3; // shorthand for IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_06 = 3;

  // Turn up drive & speed as very short pulse
  IOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_06 = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_SPEED(3) | IOMUXC_PAD_SRE;
}

The above code is untested and I got distracted from that particular bit of functionality. I'll come back to it at some point no doubt. Nevertheless you might find some useful bits in there to help you solve your problem. If you do find a solution then please paste it here.

@GUIANSIBLE
Copy link
Author

I considered incorporating this code ( https://www.nxp.com/docs/en/application-note/AN5142.pdf Chapter 3.14), but I'm having some trouble.
This is for my dissertation, so it really has to work. I'll post here when I have something to show.

.)

@lfarrand
Copy link

You might find this post quite interesting. It is doing exactly what you want to do.

Copied from the PJRC forum:

The medium term goal here was to synchronize 2 (or more) flexPWM modules (not submodules) by routing a trigger from one module to the EXT_SYNC input of (multiple) submodules.

I happen to recently having been attempting the same thing, synchronizing different FlexPWM modules. It took me quite some hours figuring this out and I think I can explain what you saw back in 2020 (!)

With this synchronization approach I was first trying to route a flexPWM trigger to a pin so I could look at it. XBARA1 output 6 is XBAR_INOUT40 which is ALT3 of pin EMC_04 which is Teensy 4.0 pin 2. XBARA1 input 40 is the trigger output from the 1st submodule of the 1st flexPWM module. So I needed to do 2 other things for which I have code: Enable the trigger output via the flexPWM's submodule TCTRL register, and select the XBAR_INOUT40 signal to the EMC_04 pin (it is ALT3). I never got a signal on this pin, so something is still not working.

Turns out the trigger outputs are one clock in duration (not the FlexPWM clock either - slowing this down doesn't help, I suspect
its the XBAR clocking that sets this) - you can only really see any pulses on an IO pin if you set max slewrate, full drive strength,
and even then they are runt pulses.

Another gotcha I discovered was the inconsistent numbering of FlexPWM submodules - in most of the documentation each FlexPWM unit has submodules 0..3, whereas the trigger output lines to the XBAR switch are named

  • FLEXPWM4_PWM1_OUT_TRIG0
  • FLEXPWM4_PWM2_OUT_TRIG0
  • FLEXPWM4_PWM3_OUT_TRIG0
  • FLEXPWM4_PWM4_OUT_TRIG0

so for many hours I was bashing my head against this by assuming FLEXPWM4_PWM2_OUT_TRIG0 was for submodule 2

Of course once I got past this then I would have used a different XBARA1 output to route the trigger to the EXT_SYNC input of a flexPWM submodule whose INIT_SEL would need to be programmed for EXT_SYNC. BTW: I am thinking of using the dead time insertion capability of the flexPWM. Otherwise maybe this could be accomplished with a Quad Timer but I have not looked into that at all (yet).

I've then routed the correct signal to EXT_SYNC on the other units and get them to sync up with only 20ns delay at 600MHz
(this is not dependent on the FlexPWM prescaler). I used the VAL1 trigger (0b000010 in the TCTRL register's
FLEXPWM_SMTCTRL_OUT_TRIG_EN field)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants