Hi All,
I'm trying to make a "generic" portable (Between the STM32 family) 3 phase brushless DC motor.
I've got some code down using the capture compare registers for timer 2 and have some 3 phase looking pulses coming out from my chip.
Realistically, I would use 5 capture compare channels to create my required waveform. Unfortunately, there are only 4. My efforts on how to produce these waveforms so far are:
Key:
CC1,2,3 (Capture compare 1,2,3)
TP/3 (Timer period / 3)
Phase A,B,C (Outputs wired to push pull Mosfet drivers)
On Timer update (Cnt = 0): Set phase A high, set CC1register to PWM value (between 0 and Timer Period/3 -1)
CC1 Interrupt: Set phase A low
CC2 Interrupt (initially set to TP/3): Set phase B high, set CC2 register to TP/3 + PWM
CC2 Interrupt 2: Set phase B low, set CC2 to TP/3
CC3 Interrupt (Initially set to 2*TP/3): Set phase C high, set CC3 register to 2*TP/3 + PWM
CC3 Interrupt 2: Set phase C low, set CC3 register to 2*TP/3
NOW! This does actually work for low frequencies and mid range PWM values. I'm currently testing at 1.57kHz though many commercial ESC's have frequencies at around 8khz. The PWM value doesn't work below 5 as phase B and phase C stick on until a whole timer period has elapsed.
I've also tried to do this using a non interrupt method but that was too jitterful and temperamental. I'd rather not use dedicated timer pins within the STM32 but if thats the final option, I suppose I'll have to. I'm just wondering more so what other people do!
For safety too, I'm thinking of having a 3 input and gate between each phase and the mosfet driver, the STM32 output connected to one input of the inputs, an external switch connected to another input and the final input connected to the STM32 output enable pin (not included in my code yet). Once I receive a hall effect throttle, I'll start thinking of fail safes if that decides to disconnect itself.
The PWM variable can vary between 0(hopefully) and X. I'm not sure what X should be for maximum "BLDC" power because I assume that for maximum, it is when all three phases are on for maximum possible time? meaning that the maximum PWM value should be 99 (allowing for 99/100 ontime for each phase).
Code:
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_tim.h>
#include <stm32f0xx_misc.h>
GPIO_InitTypeDef G;
TIM_TimeBaseInitTypeDef T;
TIM_OCInitTypeDef TO;
NVIC_InitTypeDef N;
#define PhaseA GPIO_Pin_0
#define PhaseB GPIO_Pin_1
#define PhaseC GPIO_Pin_2
#define PhaseGPIO GPIOA
#define TPeriod 300
#define PWMRefA (TPeriod/3)
#define PWMRefB (PWMRefA*2)
volatile uint8_t PWM = 5;
void TIM2_IRQHandler(void){
static uint8_t PStateA = 0, PStateB = 0, PStateC = 0;
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_SetBits(PhaseGPIO, PhaseA);
TIM2->CCR1 = PWM;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == SET){
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_ResetBits(PhaseGPIO, PhaseA);
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET){
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
if(PStateB){
GPIO_SetBits(PhaseGPIO, PhaseB);
TIM2->CCR2 = PWMRefA + PWM;
}
else{
GPIO_ResetBits(PhaseGPIO, PhaseB);
TIM2->CCR2 = PWMRefA;
}
PStateB^=1;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET){
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
if(PStateC){
GPIO_SetBits(PhaseGPIO, PhaseC);
TIM2->CCR3 = PWMRefB + PWM;
}
else{
GPIO_ResetBits(PhaseGPIO, PhaseC);
TIM2->CCR3 = PWMRefB;
}
PStateC^=1;
}
}
int main(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
G.GPIO_Pin = PhaseA | PhaseB | PhaseC;
G.GPIO_PuPd = GPIO_PuPd_DOWN;
G.GPIO_OType = GPIO_OType_PP;
G.GPIO_Mode = GPIO_Mode_OUT;
G.GPIO_Speed = GPIO_Speed_Level_3;
GPIO_Init(PhaseGPIO, &G);
T.TIM_ClockDivision = TIM_CKD_DIV1;
T.TIM_CounterMode = TIM_CounterMode_Up;
T.TIM_Period = TPeriod;
T.TIM_Prescaler = 100;
TIM_TimeBaseInit(TIM2, &T);
TIM_Cmd(TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_CCxCmd(TIM2, TIM_Channel_1, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
TIM2->CCR2 = PWMRefA;
TIM_CCxCmd(TIM2, TIM_Channel_2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
TIM2->CCR3 = PWMRefB;
TIM_CCxCmd(TIM2, TIM_Channel_3, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE);
N.NVIC_IRQChannel = TIM2_IRQn;
N.NVIC_IRQChannelCmd = ENABLE;
N.NVIC_IRQChannelPriority = 0;
NVIC_Init(&N);
uint16_t CTim;
while(1);
}
I've also included some pictures of my logic analyze'd phases to show it actually works
.