Hello, fellow bit-wise friend. If you, like me, arrived here trying to find a 6-wave pwm centered signal, being those 3 positive and 3 negative polarity (i.e. complementary pwm), I hope this helps:
Code: Select all
#define PWM_OUT_U PA8 //PWM output for U phase
#define PWM_OUT_U_COMP PB13 //complementary output for U phase
#define PWM_OUT_V PA9 //PWM output for V phase
#define PWM_OUT_V_COMP PB14 //complementary output for V phase
#define PWM_OUT_W PA10 //PWM output for W phase
#define PWM_OUT_W_COMP PB15 //complementary output for W phase
Remember, it is NOT possible to choose the output pins (PA8, PB13, etc). Those are hardware-defined pins. (Maybe on 100 or 144 pin-chips, but you don't have one of those, so, don't try).
Code: Select all
pinMode(PWM_OUT_U,PWM);
pinMode(PWM_OUT_U_COMP,PWM);
pinMode(PWM_OUT_V,PWM);
pinMode(PWM_OUT_V_COMP,PWM);
pinMode(PWM_OUT_W,PWM);
pinMode(PWM_OUT_W_COMP,PWM);
Ports/pins must be declared as PWM output mode.
Let's set the Timer1, which is capable of handling 3 synchronized PWM signals and it's complementary friends.
Code: Select all
HardwareTimer timer1(1);
timer1.pause();
timer1.setPeriod(200); //72000/(200/40) = 14400 // 200 = period, 40 = constant, 14400 = max value on pwmWrite(channel, value) (test before using 40 as constant! not sure why 40!)
TIMER1->regs.adv->CCER |= 0x555; //3ch compl enable. 0x55 = 2ch compl enable. 0x5 = 1ch compl enable. As seen on RM0008 pages 353 & 354, CCxNE and CCxE bits
TIMER1->regs.bas->CR1 |= 0x20; //centered ye PWM waveforms (RM0008, page 338, CMS bits)
timer1.refresh(); //go son
timer1.resume(); //support gay and women rights & be happy
200 on setPeriod will give you a 400-microsecond period or 1/400 = 2.5kHz for all the three PWM channels. Why not 200 microseconds? I don't know. Do I care? No.
72000 is the main frequency for STM32, in KHz (72MHz).
The timer will count up to 72000/(200/40) = 14400, so that's the maximum value you can/need to put on pwmWrite. This 14400 number is automatically calculated and set by the setPeriod function.
Another way to see how far is the counter counting to, is reading the register:
Code: Select all
int maxValue = TIMER1->regs.bas->ARR;
So, if you want a 0% to 100% PWM duty cycle, you can try this:
Code: Select all
int maxValue = TIMER1->regs.bas->ARR;
pwmWrite(your_PWM_pin, your_duty*maxValue/100);
As you can see, you only need to set the positive polarity, the negative/complementary is automatic. Here are all the three channels:
Code: Select all
pwmWrite(PWM_OUT_U, 1000); //This should now write to your Ports (PA8 -- PB13, PA9 -- PB14 and PA10 -- PB15 your PWM signal).
pwmWrite(PWM_OUT_V, 2000); //I love you
pwmWrite(PWM_OUT_W, 14400); //f! racism
Oh yes, one last thing, the setPeriod function takes care of both the prescaler factor and the overflow.
so that:
Code: Select all
timer.setPrescaleFactor(5);
timer.setOverflow(255);
is not necessary.
Apologies for my horrible english-writing abilities, and goodbye.