Hey everyone, I am trying to get 4 PWM channels (2 sets of complimentary signals, with one pair phase shifted dynamically.
Below is my current code, it is built from code I found here, as I cannot find any documentation on how to use the FlexPWM registers. This code works for Channels A & B (FlexPWM 4.2 - pins 2/3), but does not work for Channels C & D (FlexPWM 2.2 - pins 6/9).
I have two questions:
Thanks for any help!
Below is my current code, it is built from code I found here, as I cannot find any documentation on how to use the FlexPWM registers. This code works for Channels A & B (FlexPWM 4.2 - pins 2/3), but does not work for Channels C & D (FlexPWM 2.2 - pins 6/9).
I have two questions:
- How do I get channels C & D working? I assumed I could simply copy over the A & B code and change from timer FlexPWM 4 to FlexPWM 2 because they are both X.2, however this does not appear to work.
- What is the best way to add a shift angle to this? I have found shift angle examples here, but they use analogWrite()
Thanks for any help!
Code:
#include "imxrt.h"
#include "core_pins.h"
#include "debug/printf.h"
#define Mask 4
#define ResolutionPWM 12 //12-Bit PWM
#define ChannelA 2
#define ChannelB 3
#define ChannelC 6
#define ChannelD 9
#define SET_AB 0
#define SET_CD 1
void hbridge_setFreq(uint8_t setIdx, float freqHz) {
if(setIdx == SET_AB) {
// Set AB
uint32_t CurrentCycles = (uint32_t)((float)F_BUS_ACTUAL / freqHz + 0.5);
uint32_t Prescaler = 0;
//Falls Frequenz zu gering Prescaler switchen!
while (CurrentCycles > 65535 && Prescaler < 7) {
CurrentCycles = CurrentCycles >> 1;
Prescaler = Prescaler + 1;
}
if (CurrentCycles > 65535) {
CurrentCycles = 65535;
} else if (CurrentCycles < 2) {
CurrentCycles = 2; //minimale Cycles --> 10nS oder so
}
FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_CLDOK(Mask);
FLEXPWM4_SM2CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(Prescaler); //Erst nach vollem Cycle updaten und Prescaler setzen!
FLEXPWM4_SM2VAL1 = CurrentCycles - 1; //Cycles für Periodendauer setzen!
FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_LDOK(Mask);
}
else if(setIdx == SET_CD) {
// Set CD
uint32_t CurrentCycles = (uint32_t)((float)F_BUS_ACTUAL / freqHz + 0.5);
uint32_t Prescaler = 0;
//Falls Frequenz zu gering Prescaler switchen!
while (CurrentCycles > 65535 && Prescaler < 7) {
CurrentCycles = CurrentCycles >> 1;
Prescaler = Prescaler + 1;
}
if (CurrentCycles > 65535) {
CurrentCycles = 65535;
} else if (CurrentCycles < 2) {
CurrentCycles = 2; //minimale Cycles --> 10nS oder so
}
FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_CLDOK(Mask);
FLEXPWM2_SM2CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(Prescaler); //Erst nach vollem Cycle updaten und Prescaler setzen!
FLEXPWM2_SM2VAL1 = CurrentCycles - 1; //Cycles für Periodendauer setzen!
FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_LDOK(Mask);
}
}
void hbridge_setDuty(uint8_t setIdx, uint16_t val) {
if(setIdx == SET_AB) {
// Set AB
uint32_t PeriodendauerCycles = FLEXPWM4_SM2VAL1; //Periodendauer
uint32_t Cycles = ((uint32_t)val * (PeriodendauerCycles + 1)) >> ResolutionPWM;
if (Cycles > PeriodendauerCycles) Cycles = PeriodendauerCycles;
FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_CLDOK(Mask);
FLEXPWM4_SM2VAL3 = Cycles;
FLEXPWM4_SM2VAL4 = FLEXPWM4_SM2VAL3 + (((FLEXPWM4_SM2VAL1 - 2 * Cycles) / 2)); //PauseOffset anpassen!
FLEXPWM4_SM2VAL5 = FLEXPWM4_SM2VAL4 + (Cycles); //tOn für Channel B anpassen
FLEXPWM4_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(Mask); //ChannelA aktivieren
FLEXPWM4_OUTEN |= FLEXPWM_OUTEN_PWMB_EN(Mask); //ChannelB aktivieren
FLEXPWM4_MCTRL |= FLEXPWM_MCTRL_LDOK(Mask);
*(portConfigRegister(ChannelA)) = 1;//Maske;
*(portConfigRegister(ChannelB)) = 1;//Maske;
}
else if(setIdx == SET_CD) {
// Set CD
uint32_t PeriodendauerCycles = FLEXPWM2_SM2VAL1; //Periodendauer
uint32_t Cycles = ((uint32_t)val * (PeriodendauerCycles + 1)) >> ResolutionPWM;
if (Cycles > PeriodendauerCycles) Cycles = PeriodendauerCycles;
FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_CLDOK(Mask);
FLEXPWM2_SM2VAL3 = Cycles;
FLEXPWM2_SM2VAL4 = FLEXPWM2_SM2VAL3 + (((FLEXPWM2_SM2VAL1 - 2 * Cycles) / 2)); //PauseOffset anpassen!
FLEXPWM2_SM2VAL5 = FLEXPWM2_SM2VAL4 + (Cycles); //tOn für Channel B anpassen
FLEXPWM2_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(Mask); //ChannelA aktivieren
FLEXPWM2_OUTEN |= FLEXPWM_OUTEN_PWMB_EN(Mask); //ChannelB aktivieren
FLEXPWM2_MCTRL |= FLEXPWM_MCTRL_LDOK(Mask);
*(portConfigRegister(ChannelC)) = 1;//Maske;
*(portConfigRegister(ChannelD)) = 1;//Maske;
}
}
#define HBRIDGE_FREQ_HZ 100000
#define HBRIDGE_DUTY 0 // todo - make definition for allocating dead time
// Start H-Bridge Timing H-Bridge
void hbridge_on() {
hbridge_setFreq(SET_AB, HBRIDGE_FREQ_HZ);
hbridge_setDuty(SET_AB, 2000);
hbridge_setFreq(SET_CD, HBRIDGE_FREQ_HZ);
hbridge_setDuty(SET_CD, 2000);
//hbridge_setDuty(SET_AB, 820); // 10% PWM
}
// Turn off H-Bridge
void hbridge_off() {
*(portConfigRegister(ChannelA)) = 0;
*(portConfigRegister(ChannelB)) = 0;
*(portConfigRegister(ChannelC)) = 0;
*(portConfigRegister(ChannelD)) = 0;
}
void setup() {
hbridge_on();
}
void loop() {
}