AnsweredAssumed Answered

BLDC commutation with hall sensors

Question asked by sivcev.satja on May 30, 2014
Latest reply on Mar 17, 2016 by galea.glenn
Hello,

I want to use timer 5 to get signals from 3 hall sensor and use them to make commutation for BLDC, and to control BLDC with PWM which is on timer 1. I configured all the registers that I taught should that should be configured but something is not working. I must have missed something. Can anyone help me?

Here is the code:

// BLDC motor steps
// every row from 1 to 6 is called by a hall state
// every column a FET from 3-phase bridge
// motor off is at row 0 BLDC_BRIDGE_STATE_VORWARD[0]
// cw - rechtslauf - positiv
// {    1H,1L      ,      2H,2L      ,     3H,3L    }
// BLDC motor steps
// every row from 1 to 6 is one of the 6 motor vector state
// every column a FET from 3-phase bridge
// all FETs off at row 0 or 8 (this pattern should not come from the hallsensor)
// cw - rechtslauf - positiv
// {    1H,1L      ,      2H,2L      ,     3H,3L    }
static const uint8_t BLDC_BRIDGE_STATE_VORWARD[8][6] =   // Motor step //Redosled vrednosti: 1-3-2-6-4-5-1...
{   //BH1   BL1         BH2   BL2        BH3   BL3
   { FALSE,FALSE   ,   FALSE,FALSE   ,  FALSE,FALSE },  // 0 - Ne desava se
   { FALSE,TRUE    ,   FALSE, FALSE  ,  TRUE ,FALSE },  // 1 - Korak 1.
   { TRUE ,FALSE   ,   FALSE,TRUE    ,  FALSE,FALSE },  // 2 - Korak 3.
   { FALSE,FALSE   ,   FALSE,TRUE    ,  TRUE ,FALSE },  // 3 - Korak 2.
   { FALSE,FALSE   ,   TRUE ,FALSE   ,  FALSE,TRUE  },  // 4 - Korak 5.
   { FALSE,TRUE    ,   TRUE ,FALSE   ,  FALSE,FALSE },  // 5 - Korak 6.
   { TRUE ,FALSE   ,   FALSE,FALSE   ,  FALSE,TRUE  },  // 6 - Korak 4.
   { FALSE,FALSE   ,   FALSE,FALSE   ,  FALSE,FALSE },  // 7 - Ne desava se
};

void configHallSensorTimer(void)
{
 
  GPIO_InitTypeDef GPIO_InitStructure; //Sadrzi GPIO_Pin, GPIO_Mode, GPIO_Speed, GPIO_OType, GPIO_PuPd
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //Sadrzi TIM_Prescaler, TIM_CounterMode, TIM_Period, TIM_ClockDivision, TIM_RepetitionCounter
  TIM_OCInitTypeDef  TIM_OCInitStructure; //Sadrzi TIM_OCMode, TIM_OutputState, TIM_OutputNState, TIM_Pulse, TIM_OCPolarity, TIM_OCNPolarity, TIM_OCIdleState, TIM_OCIdleState
  TIM_ICInitTypeDef  TIM_ICInitStructure; //Ovo sam ja dodao - Sadrzi: TIM_Channel, TIM_ICPolarity, TIM_ICSelection, TIM_ICPrescaler, TIM_ICFilter
  NVIC_InitTypeDef   NVIC_InitStructure;  //ovo sam dodao - Sadrzi: uint8_t NVIC_IRQChannel, NVIC_IRQChannelPreemptionPriority, NVIC_IRQChannelSubPriority, FunctionalState NVIC_IRQChannelCmd

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Clock ENABLE for GPIOA
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //AF - Alternate function (S obziron da signali sa kanala 1 2 i 3 idu na XOR izgleda da je AF), mozda je i IN ali ne verujem
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Najbrza moguca
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Ovo ne bi trebalo da igra nikakvu ulogu posto koristim kanale kao ulaze a ne izlaze (pa cak ni kao prave dig. ulaze vec AF)
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;  //Mislim da je ovako najbolje ali nisam siguran. Moze i GPIO_PuPd_UP ili PuPd_NOPULL
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //Clock ENABLE for Timer 5 - Bilo je RCC_APB1PeriphClockCmd(TIM5_CLK, ENABLE); medjutim, ne prepoznaje TIM5_CLK
 
  /* Biranje parametara za Timer 5 - "Interfacing Timer fro Hall sensors" - str. 542 - STM32F4 Reference manual
    Maksimalan broj obrtaja motora je n = 4390 rpm
    Mi pravimo timer tako da ne sme da nam se desi overflow ni kad se motor krece najmanjom brzinom kojom ce se kretati. Kao referentnu uzimamo 1% brzine - 44 rpm
    43,9 rpm -> 263,4stepeni/sec
    1 round -> 0.455s -> 455ms -> 2,19Hz
    S obzirom da nam je AutoReload, tj. TIM_Period = 65536 -> OsnCLK/65535 = 2,19Hz -> OsnCLK = 143521,65 */ 
 
  TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock)/143522 - 1; //Sad je CLK 143522
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //Ovim smo dobili da dve promene signala sa hall senzora mora da se dese brze od 455ms
 
  TIM_SelectHallSensor(TIM5, ENABLE); //setting the TI1S bit in the TIMx_CR2 register - The “interfacing timer” captures the 3 timer input pins (TIMx_CH1, TIMx_CH2, and TIMx_CH3) connected through a XOR to the TI1 input channel //setting the TI1S bit in the TIMx_CR2 register
 
  // HallSensor event is delivered with singnal TI1F_ED (this is XOR of the three hall sensor lines)
  // Signal TI1F_ED: falling and rising ddge of the inputs is used - Na svaku promenu hall senzora dize se TI1F_ED flag
  TIM_SelectInputTrigger(TIM5, TIM_TS_TI1F_ED); //Ova linija koda nema u uputstvima u Reference manualu, ali deluje logicno.
 
  // On every TI1F_ED event the counter is resetted and update is tiggered
  TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset); //TIM_SlaveMode_Reset: Rising edge of the selected trigger signal(TRGI) reinitialize the counter and triggers an update of the registers //Thus, each time one of the 3 inputs toggles, the counter restarts counting from 0. This creates a time base triggered by any change on the Hall inputs.

  // Channel 1 in input capture mode - on every TCR edge (build from TI1F_ED which is a HallSensor edge) the timervalue is copied into ccr register and a CCR1 Interrupt TIM_IT_CC1 is fired
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_TRC; //Program channel 1 in capture mode (TRC selected): write the CC1S bits in the TIMx_CCMR1 register to ‘11’
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // Div:1, every edge
  TIM_ICInitStructure.TIM_ICFilter = 0x11; //Filter ide od 0x0 do 0xF - ovo je kao neki debouncing. Str. 526 STM32f4 Reference manual. Mislim da moze i 0 da bude, jer nam ne igra ulogu, tj. signal sa hall senzora bi trebao da je stabilan.
  TIM_ICInit(TIM5, &TIM_ICInitStructure);
 
   // channel 2 can be use for commution delay between hallsensor edge and switching the FET into the next step. if this delay time is over the channel 2 generates the commutation signal to the motor timer
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_Pulse = 1; // 1 is no delay; 2000 = 7ms //bilo je 1
  TIM_OC2Init(TIM5, &TIM_OCInitStructure);
  
  TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_OC2Ref); //TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output(TRGO)

  TIM_ClearFlag(TIM5, TIM_FLAG_CC2);
 
  //Zasto su i ove dve linije koda zakomentarisane?
  TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable); //TIM_MasterSlaveMode_Enable: synchronization between the current timer and its slaves (through TRGO)
  // TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_OC1); //Ovo bi se kosilo sa linijom 351 zar ne?
 
  TIM_ITConfig(TIM5, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);//specifies the TIM interrupts sources to be enabled or disabled
 
  // Zasto je komentarisano? Odakle se pojacio OC4 kad ga ne koristimo?
  // Enable output compare preload
  //TIM_OC4PreloadConfig(TIM5, TIM_OCPreload_Enable);
 
  // Enable ARR preload
  TIM_ARRPreloadConfig(TIM5, ENABLE); //Ovo je bilo zakomentarisano ali mi je logicno da ostane ovako
 
  // Enable update event - Ovde pise enable a ispod disable. Ja ne znam sta treba a ni cemu sluzi.
  //TIM_ClearFlag(TIM5, TIM_FLAG_Update);
  //TIM_ITConfig(TIM5, TIM_IT_Update, DISABLE); //Mozda treba enabel, pogledati str. 544.
 
  // we use preemption interrupts here,  BLDC Bridge switching and Hall has highest priority - Ne znam sta hoce da kaze...
  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
 
  // HallSensor is now configured, if BLDC Timer is also configured. after enabling timer 5 the motor will start after next overflow of the hall timer because this generates the first startup motor cummutation event
  TIM_Cmd(TIM5, ENABLE);
}


void TIM5_IRQHandler(void)
{     
  // ------------- HallSensor interrupt handler -----------------
 
// this handles TIM5 irqs (from HallSensor)
  if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)
  {
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1);    // Da li je ono na svaku promenu signala sa hall senz?
    hallccr1 = TIM5->CCR1; //Ovde dobijem zapravo vreme izmedju poslednja dva signala sa hall senzora. Ali kao vrednost na sl nacin bar mislim: 1/(168MHz*prescaler*hallccr1) a na osnovu toga mogu da izracunam brzinu motora
  }
  else if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)
  {
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC2); // this interrupt handler is called AFTER the motor commutaton event is done. after commutation the next motor step must be prepared. use inline functions in irq handlers static __INLINE funct(..) {..}
    BLDCMotorPrepareCommutation();
  } else {
    ; // this should not happen
  }
}

void configMotorBridgeTimer(void)
{
 
  GPIO_InitTypeDef GPIO_InitStructure; //Sadrzi GPIO_Pin, GPIO_Mode, GPIO_Speed, GPIO_OType, GPIO_PuPd
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //Sadrzi TIM_Prescaler, TIM_CounterMode, TIM_Period, TIM_ClockDivision, TIM_RepetitionCounter
  TIM_OCInitTypeDef  TIM_OCInitStructure; //Sadrzi TIM_OCMode, TIM_OutputState, TIM_OutputNState, TIM_Pulse, TIM_OCPolarity, TIM_OCNPolarity, TIM_OCIdleState, TIM_OCIdleState
  TIM_BDTRInitTypeDef  TIM_BDTRInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
 
  // define the 6 output pins for the bridge, if needed define
  // the input pin for emergeny stop
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
 
  /* GPIOE Configuration: TIM1 CH1N (PE8), TIM1 CH1 (PE9), TIM1 CH2N (PE10), TIM1 CH2 (PE11), TIM1 CH3N (PE12), TIM1 CH3N (PE13) */
  GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
 
  // Connect TIM1 pins to AF //Nisam siguran da li ovo treba
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
 
  #define PeriodaPWM ((uint16_t) ((SystemCoreClock)/10000000 - 1))
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = PeriodaPWM; // Chopper Frequency (PWM for the FETs - 10MHz)
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
 
  // Channel 1, 2, 3 – set to PWM mode - all 6 outputs
  // per channel on output is  low side fet, the opposite is for high side fet
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //STO OVDE NIJE PWM?!?! bilo je TIM_OCMode_Timing
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  TIM_OCInitStructure.TIM_Pulse = ((uint16_t) (PeriodaPWM/10)); // 10% PWM - Mislim da je ovo ono sto se u pocetku zadaje...
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
 
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
  TIM_OC2Init(TIM1, &TIM_OCInitStructure);
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);
 
  // activate preloading the CCR register
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
 
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;  
  TIM_BDTRInitStructure.TIM_DeadTime = 15; // DeadTime[ns] = value * (1/SystemCoreFreq) (on 168MHz: 15 is 89ns)
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
  // enabel this if you use emergency stop signal
  // TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  // TIM_BDTRInitStructure.TIM_BreakPolarity = MOTOR_TMC603_EMSTOP_POLARITY;
  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
 
  // preload ARR register
  TIM_CCPreloadControl(TIM1, ENABLE);
 
  // activate COM (Commutation) Event from Slave (HallSensor timer) through TRGI //KO JE SLAVE KO MASTER?!!
  enableHallCommutateSignal();
 
  // Internal connection from Hall/Enc Timer to Motor Timer
  // eg. TIM1 (BLDC Motor Timer) is Slave of TIM5 (Hall Timer)
 
  /*Internal Connection from Hall/Enc Timer to Motor Timer. The HALL Timer Output is direct connected to the Motor Timer Commutation Trigger. If the correct combination of Motor and Hall/Enc Timer is selected then this is done for you. If you can not use the internal Connection you have to do this in an Interrupt manually.

Only following Combinations are possible[1]

If Motor is on Timer1 this is possible
• Hall/Enc is Timer 2 > Motor is Timer 1 > use TIM_TS_ITR1
• Hall/Enc is Timer 3 > Motor is Timer 1 > use TIM_TS_ITR2
• Hall/Enc is Timer 4 > Motor is Timer 1 > use TIM_TS_ITR3
• Hall/Enc is Timer 5 > Motor is Timer 1 > use TIM_TS_ITR0 //ovaj je nas

If Motor is on Timer8 this is possible
• Hall/Enc is Timer 1 > Motor is Timer 1 > use TIM_TS_ITR0
• Hall/Enc is Timer 2 > Motor is Timer 1 > use TIM_TS_ITR1
• Hall/Enc is Timer 4 > Motor is Timer 1 > use TIM_TS_ITR2
• Hall/Enc is Timer 5 > Motor is Timer 1 > use TIM_TS_ITR3
*/ 
  // Choose carefully from the following possible combination
  // check programmers reference manual
  TIM_SelectInputTrigger(TIM1, TIM_TS_ITR0);
  // MotorTimer = TIM1, HallTimer = TIM5
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR1);
  // MotorTimer = TIM1, HallTimer = TIM2
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR2);
  // MotorTimer = TIM1, HallTimer = TIM3
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR3);
  // MotorTimer = TIM1, HallTimer = TIM4
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR0);
  // MotorTimer = TIM8, HallTimer = TIM1
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR1);
  // MotorTimer = TIM8, HallTimer = TIM2
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR2);
  // MotorTimer = TIM8, HallTimer = TIM4
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR3);
  // MotorTimer = TIM8, HallTimer = TIM5
 
  // Enable interrupt, motor commutation has high piority and has a higher subpriority then the hall sensor
  //NVIC_InitStructure.NVIC_IRQChannel = TIM1_TRG_COM_IRQn; ovo je bilo
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_TRG_COM_TIM11_IRQn; // TIM1_TRG_COM_TIM11_IRQn = 26 //TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt
 
  // highest priority
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
 
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  // highest priority
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 
  NVIC_Init(&NVIC_InitStructure);
 
  // Interrupt for hardwired EmergencyStop
  //(if needed)
  // Timer 1 Motor Emergency Break Input
  // NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_IRQn;
  // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  // NVIC_Init(&NVIC_InitStructure);
 
  // --------- activate the bldc bridge ctrl. ----------
  // in a project this will be done late after complete configuration of other peripherie
 
  TIM_ITConfig(TIM1, TIM_IT_COM, ENABLE);// enable COM (commutation) IRQ
 
  TIM_Cmd(TIM1, ENABLE);// enable motor timer

  TIM_CtrlPWMOutputs(TIM1, ENABLE);// enable motor timer main output (the bridge signals)
}

void configMotorBridgeTimer(void)
{
 
  GPIO_InitTypeDef GPIO_InitStructure; //Sadrzi GPIO_Pin, GPIO_Mode, GPIO_Speed, GPIO_OType, GPIO_PuPd
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //Sadrzi TIM_Prescaler, TIM_CounterMode, TIM_Period, TIM_ClockDivision, TIM_RepetitionCounter
  TIM_OCInitTypeDef  TIM_OCInitStructure; //Sadrzi TIM_OCMode, TIM_OutputState, TIM_OutputNState, TIM_Pulse, TIM_OCPolarity, TIM_OCNPolarity, TIM_OCIdleState, TIM_OCIdleState
  TIM_BDTRInitTypeDef  TIM_BDTRInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
 
  // define the 6 output pins for the bridge, if needed define
  // the input pin for emergeny stop
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
 
  /* GPIOE Configuration: TIM1 CH1N (PE8), TIM1 CH1 (PE9), TIM1 CH2N (PE10), TIM1 CH2 (PE11), TIM1 CH3N (PE12), TIM1 CH3N (PE13) */
  GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
 
  // Connect TIM1 pins to AF //Nisam siguran da li ovo treba
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
 
  #define PeriodaPWM ((uint16_t) ((SystemCoreClock)/10000000 - 1))
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = PeriodaPWM; // Chopper Frequency (PWM for the FETs - 10MHz)
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
 
  // Channel 1, 2, 3 – set to PWM mode - all 6 outputs
  // per channel on output is  low side fet, the opposite is for high side fet
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //STO OVDE NIJE PWM?!?! bilo je TIM_OCMode_Timing
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  TIM_OCInitStructure.TIM_Pulse = ((uint16_t) (PeriodaPWM/10)); // 10% PWM - Mislim da je ovo ono sto se u pocetku zadaje...
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
 
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
  TIM_OC2Init(TIM1, &TIM_OCInitStructure);
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);
 
  // activate preloading the CCR register
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
 
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;  
  TIM_BDTRInitStructure.TIM_DeadTime = 15; // DeadTime[ns] = value * (1/SystemCoreFreq) (on 168MHz: 15 is 89ns)
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
  // enabel this if you use emergency stop signal
  // TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  // TIM_BDTRInitStructure.TIM_BreakPolarity = MOTOR_TMC603_EMSTOP_POLARITY;
  TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
 
  // preload ARR register
  TIM_CCPreloadControl(TIM1, ENABLE);
 
  // activate COM (Commutation) Event from Slave (HallSensor timer) through TRGI //KO JE SLAVE KO MASTER?!!
  enableHallCommutateSignal();
 
  // Internal connection from Hall/Enc Timer to Motor Timer
  // eg. TIM1 (BLDC Motor Timer) is Slave of TIM5 (Hall Timer)
 
  /*Internal Connection from Hall/Enc Timer to Motor Timer. The HALL Timer Output is direct connected to the Motor Timer Commutation Trigger. If the correct combination of Motor and Hall/Enc Timer is selected then this is done for you. If you can not use the internal Connection you have to do this in an Interrupt manually.

Only following Combinations are possible[1]

If Motor is on Timer1 this is possible
• Hall/Enc is Timer 2 > Motor is Timer 1 > use TIM_TS_ITR1
• Hall/Enc is Timer 3 > Motor is Timer 1 > use TIM_TS_ITR2
• Hall/Enc is Timer 4 > Motor is Timer 1 > use TIM_TS_ITR3
• Hall/Enc is Timer 5 > Motor is Timer 1 > use TIM_TS_ITR0 //ovaj je nas

If Motor is on Timer8 this is possible
• Hall/Enc is Timer 1 > Motor is Timer 1 > use TIM_TS_ITR0
• Hall/Enc is Timer 2 > Motor is Timer 1 > use TIM_TS_ITR1
• Hall/Enc is Timer 4 > Motor is Timer 1 > use TIM_TS_ITR2
• Hall/Enc is Timer 5 > Motor is Timer 1 > use TIM_TS_ITR3
*/ 
  // Choose carefully from the following possible combination
  // check programmers reference manual
  TIM_SelectInputTrigger(TIM1, TIM_TS_ITR0);
  // MotorTimer = TIM1, HallTimer = TIM5
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR1);
  // MotorTimer = TIM1, HallTimer = TIM2
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR2);
  // MotorTimer = TIM1, HallTimer = TIM3
  // TIM_SelectInputTrigger(TIM1, TIM_TS_ITR3);
  // MotorTimer = TIM1, HallTimer = TIM4
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR0);
  // MotorTimer = TIM8, HallTimer = TIM1
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR1);
  // MotorTimer = TIM8, HallTimer = TIM2
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR2);
  // MotorTimer = TIM8, HallTimer = TIM4
  // TIM_SelectInputTrigger(TIM8, TIM_TS_ITR3);
  // MotorTimer = TIM8, HallTimer = TIM5
 
  // Enable interrupt, motor commutation has high piority and has a higher subpriority then the hall sensor
  //NVIC_InitStructure.NVIC_IRQChannel = TIM1_TRG_COM_IRQn; ovo je bilo
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_TRG_COM_TIM11_IRQn; // TIM1_TRG_COM_TIM11_IRQn = 26 //TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt
 
  // highest priority
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
 
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  // highest priority
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 
  NVIC_Init(&NVIC_InitStructure);
 
  // Interrupt for hardwired EmergencyStop
  //(if needed)
  // Timer 1 Motor Emergency Break Input
  // NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_IRQn;
  // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  // NVIC_Init(&NVIC_InitStructure);
 
  // --------- activate the bldc bridge ctrl. ----------
  // in a project this will be done late after complete configuration of other peripherie
 
  TIM_ITConfig(TIM1, TIM_IT_COM, ENABLE);// enable COM (commutation) IRQ
 
  TIM_Cmd(TIM1, ENABLE);// enable motor timer

  TIM_CtrlPWMOutputs(TIM1, ENABLE);// enable motor timer main output (the bridge signals)
}


void TIM1_TRG_COM_IRQHandler(void)
{
  TIM_ClearITPendingBit(TIM1, TIM_IT_COM);
  // commutationCount++; //valjda 6 komutacija znaci da se vratilo okrenulo za pun krug
}

//This is called from HALL timer interrupt handler.  remember:if hall a hall edge is detected irst the motor commutation event is done. next this routine is called which has to prepare the next motor step (which FET must be switched on or off). active freewhelling is used to minimize power loss
static __INLINE void BLDCMotorPrepareCommutation(void)
{
  // next bridge step calculated by HallSensor inputs
    // In principle, on every hall event you can go to the next motor step but i had sometimes problems that the motor was running on an harmonic wave (??) when the motor was without load
  uint16_t newhallpos = ((GPIO_ReadInputData(GPIOA) & 0x7)); // Da li ovo fuunkcionise iako mi je GPIOA postavljen na AF
  uint16_t BH1; //ovo sam ja dodao
  uint16_t BL1; //ovo sam ja dodao
  uint16_t BH2; //ovo sam ja dodao
  uint16_t BL2; //ovo sam ja dodao
  uint16_t BH3; //ovo sam ja dodao
  uint16_t BL3; //ovo sam ja dodao
 
  /*Hallpos
  Figure 129. str.543 STM32F4 Reference manual - TIH1 (LSB) TIM3 (MSB) //IZGLEDA DA SLIKA NIJE DOBRA!!!!! http://www.digikey.com/~/media/Images/Article%20Library/TechZone%20Articles/2011/October/Using%20Closed%20Loop%20Control%20in%20BLDC%20Systems/article-2011october-an53595-fig1.jpg
    001 - 1
    011 - 3
    010 - 2
    110 - 6
    100 - 4
    101 - 5
  Na osnovu hall senzora pripremamo PWM za prvi sledeci odgovarajuci ciklus
  */
  if (newhallpos == hallpos) return; // if there was an hall event without changing the hall position, do nothing.
  lasthallpos = hallpos;
  hallpos = newhallpos;
 
  // this is only for motor direction forward 

  BH1 = BLDC_BRIDGE_STATE_VORWARD[hallpos][0];
  BL1 = BLDC_BRIDGE_STATE_VORWARD[hallpos][1];
 
  BH2 = BLDC_BRIDGE_STATE_VORWARD[hallpos][2];
  BL2 = BLDC_BRIDGE_STATE_VORWARD[hallpos][3];
 
  BH3 = BLDC_BRIDGE_STATE_VORWARD[hallpos][4];
  BL3 = BLDC_BRIDGE_STATE_VORWARD[hallpos][5]; 
 
  // **** this is with active freewheeling **** 
 
  // Bridge FETs for Motor Phase U
  if (BH1) {
    // PWM at low side FET of bridge U
    // active freewheeling at high side FET of bridge U
    // if low side FET is in PWM off mode then the hide side FET
    // is ON for active freewheeling. This mode needs correct definition
    // of dead time otherwise we have shoot-through problems
    TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
    TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
    TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
  } else {
    // Low side FET: OFF
    TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
    if (BL1){
     // High side FET: ON
     TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_Active);
      TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
     } else {
      // High side FET: OFF
      TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
    }
  }
 
  // Bridge FETs for Motor Phase V
  if (BH2) {
    TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
    TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
    TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
  } else {
    TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
    if (BL2){
      TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_Active);
      TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
    } else {
      TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
    }
  }
 
  // Bridge FETs for Motor Phase W
 
  if (BH3) {
    TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
    TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
    TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
  } else {
    TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
    if (BL3){
      TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_Active);
      TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
    } else {
      TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
    }
  }
}

There is whole project in attachment.

Thanks in advance,

Satja

Attachments

Outcomes