1

I am trying to make a sensorless bldc motor control driver. I found an Arduino code and I want to convert it ARM Stm32. But I don't understand totally what happens in ISR interrupt part. Can anyone explain me shortly? Why used bldc_step&1 and when decreased i.

byte bldc_step = 0, motor_speed, pin_state;
 
void setup()
{
  DDRD  |= 0xE0;  // configure pins 5, 6 and 7 as outputs
  PORTD  = 0x00;
  DDRB  |= 0x0E;  // configure pins 9, 10 and 11 as outputs
  PORTB  = 0x31;

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
}
 
// pin change interrupt 2 (PCINT2) ISR
ISR (PCINT2_vect)
{
  if( (PIND & PCMSK2) != pin_state )
    return;
  // BEMF debounce
  for(byte i = 0; i < 20; i++)
  {
    if(bldc_step & 1){
      if(PIND & PCMSK2)     i -= 1;
    }
    else {
      if(!(PIND & PCMSK2))  i -= 1;
    }
  }
 
  bldc_move();
  bldc_step++;
  bldc_step %= 6;
}
 
// BLDC motor commutation function
void bldc_move()
{
  switch(bldc_step)
  {
    case 0:
      AH_BL();
      BEMF_C_FALLING();
      break;
    case 1:
      AH_CL();
      BEMF_B_RISING();
      break;
    case 2:
      BH_CL();
      BEMF_A_FALLING();
      break;
    case 3:
      BH_AL();
      BEMF_C_RISING();
      break;
    case 4:
      CH_AL();
      BEMF_B_FALLING();
      break;
    case 5:
      CH_BL();
      BEMF_A_RISING();
  }
}
  
  PCICR  = 4;  // enable pin change interrupt for pins PCINT23..16 (Arduino 0 to 7)
  
 
 
void BEMF_A_RISING()
{
  PCMSK2 = 0x04;    // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
  pin_state = 0x04;
}
void BEMF_A_FALLING()
{
  PCMSK2 = 0x04;    // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
  pin_state = 0;
}
void BEMF_B_RISING()
{
  PCMSK2 = 0x08;    // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
  pin_state = 0x08;
}
void BEMF_B_FALLING()
{
  PCMSK2 = 0x08;    // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
  pin_state = 0;
}
void BEMF_C_RISING()
{
  PCMSK2 = 0x10;    // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
  pin_state = 0x10;
}
void BEMF_C_FALLING()
{
  PCMSK2 = 0x10;    // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
  pin_state = 0;
}
 
void AH_BL()
{
  PORTD &= ~0xA0;
  PORTD |=  0x40;
  TCCR1A =  0;      // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
  TCCR2A =  0x81;   //
}
void AH_CL()
{
  PORTD &= ~0xC0;
  PORTD |=  0x20;
  TCCR1A =  0;      // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
  TCCR2A =  0x81;   //
}
void BH_CL()
{
  PORTD &= ~0xC0;
  PORTD |=  0x20;
  TCCR2A =  0;       // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
  TCCR1A =  0x21;    //
}
void BH_AL()
{
  PORTD &= ~0x60;
  PORTD |=  0x80;
  TCCR2A =  0;      // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
  TCCR1A =  0x21;   //
}
void CH_AL()
{
  PORTD &= ~0x60;
  PORTD |=  0x80;
  TCCR2A =  0;       // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
  TCCR1A =  0x81;    //
}
void CH_BL()
{
  PORTD &= ~0xA0;
  PORTD |=  0x40;
  TCCR2A =  0;       // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
  TCCR1A =  0x81;    //
}
 
void SET_PWM_DUTY(byte duty)
{
  OCR1A  = duty;  // set pin 9  PWM duty cycle
  OCR1B  = duty;  // set pin 10 PWM duty cycle
  OCR2A  = duty;  // set pin 11 PWM duty cycle
}
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61

2 Answers2

1

The speed of the motor depends of the applied voltage D.V where the D is the duty.

Fm = D.VP.KV.poles/120 = D.Vp/M
Tm = M/(D.Vp)

The ideal delay after bemf detection is 30 deg :

delay = Tm/12 = M/(12.D.Vp) = M'/(D.Vp)     : M'=M/12

M' – Volt*seconds for the 30° delay after zero crossing detection. The comparator ISR is counting up only during on time. As wider is the PWM pulse the faster is the counting.
Loop maximum time:

m = N.ticks.Cycles

Cycles are the ticks per instruction. Loop is counting (up) to N only during ton on rising or on falling BEMF. The counted PWM pulses will be:

Pc = m/ton  or  Pc = m/(D.Ts)

The estimated time of the loop is:

dt = Pc.Ts = m.Ts/(D.Ts) = m/D

The required delay and the time of the loop must be equal: delay = dt

M'/(Vp.D) = m/D or m = M'/Vp

This method is also called "Back-EMF Integration Method". M' = D.Vp.Tm' is the integrated bemf voltage from ZCP to the next commutation. You can read more about this briefly here: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3231115/

Adjusting N and PWM frequency (Fs=1/Ts) can give you almost perfect 30 deg delay after bemf detection. The poles and Kv of the motor should be known. This code will not work with any motor without adjustment. Cheers

fobi
  • 21
  • 4
0

This code is for debouncing the back electromagnetic force (BEMF) signal, equivalent code is in https://github.com/esden/open-bldc-mk/blob/master/bldc.c

ISR(ANA_COMP_vect){
unsigned char i;

/* debounce the bemf signal */
for(i=0; i<BEMF_DEBOUNCE_COUNT; i++){
    if(bldc_phase & 1){
        if(BEMF_L) i -= BEMF_DEBOUNCE_DEC;
    }else{
        if(BEMF_H) i -= BEMF_DEBOUNCE_DEC;
    }
}

For debouncing and why it is done see https://en.wikipedia.org/wiki/Switch#Contact_bounce

The exact algorithm implemented here is debouncing switches with vertical counters, cf https://www.compuphase.com/electronics/debouncing.htm - Debouncing switches with vertical counters

In bldc_step & 1 the & operator is bitwise AND i.e. 45 & 35 = 33 or 00101101 & 00100011 = 00100001 in binary bldc_step is a byte and bitwise-ANDing it with 1 is equivalent to testing if the last bit of bldc_step is set. With PIND & PCMSK2 is checked if PIND is high or low

This code and the rest of the debouncing loop implements the vertical counter described in https://www.compuphase.com/electronics/debouncing.htm

ralf htp
  • 9,149
  • 4
  • 22
  • 34