void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) { unsigned int ccwpat[] = {-1, 3, 6, 2, 5, 1, 4, -1}; unsigned int cwpat[] = {-1, 5, 3, 1, 6, 4, 2, -1}; state = (S3 << 2) | (S2 << 1) | S1; //Read hall effect sensors if(motoron == 1){ //If the motor has been turned on // is state transition valid? if (last_state == -1 || (state == ccwpat[last_state] || state == cwpat[last_state])) { commutate(state); //Change outputs based on hall effect sensor state } } else { //If the motor is off commutate(0); //Set all motor outputs to float printf("motor off: current state is %d\n", state); } if(USER) { commutate(0); motoron = 0; } if (last_state && (state != ccwpat[last_state] && state != cwpat[last_state])) { LED1 = 0; //commutate(0); //printf("noisy state...ending program\n"); //printf("last state: %u next state: %u valid next states: %u %u\n", // last_state, state, ccwpat[last_state], cwpat[last_state]); /* while (1) { LED3 = !(state & 0x1); LED2 = !(state & 0x2); LED1 = !(state & 0x4); } */ } else { LED1 = 1; } if(state == 0 || state == 7) { char reread = (S3 << 2) | (S2 << 1) | S1; //Read hall effect sensors commutate(0); printf("error state...ending program\n"); printf("last state: %u next state: %u valid next states: %u %u\n", last_state, state, ccwpat[last_state], cwpat[last_state]); printf("reread port and got %d as the current state\n", reread); while (1); } last_state = state; //LED1 = !LED1; //printf("%d",state); PORTD; //Clear mismatch condition IFS1bits.CNIF = 0; //Clear interrupt flag }
/* _CNInterrupt is the change notification interrupt trigger by a change in * state of the hall effect sensor inputs. The interrupt service routine reads * the hall effect sensor state and calls the commutate function to change the * motor lead outputs. * * Interrupt vector names are in Table 7-4 p101 of the MPLAB C30 User's Guide */ void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) { state = (S3 << 2) | (S2 << 1) | S1; //Read hall effect sensors if(motoron == 1){ //If the motor has been turned on commutate(state); //Change outputs based on hall effect sensor state } else { //If the motor is off commutate(0); //Set all motor outputs to float } LED1 = !LED1; //printf("%d",state); PORTD; //Clear mismatch condition IFS1bits.CNIF = 0; //Clear interrupt flag }
void TIM3_IRQHandler(void) { /* "Read" all sensors sequence and execute the BLDC coils commutation */ commutate (); /* Save current time between each hall sensor signal change */ hall_sensors_time = TIM_GetCapture1(TIM3); // clear interrupt flag TIM_ClearITPendingBit (TIM3, TIM_IT_Trigger); }
int main(void) { int duty = 500; initialize(); write_duty(duty); //apply duty cycle change motoron = 1;//turn motor on kick();//kick start commutation while (1){ commutate(2); __delay32(40000000); commutate(4); __delay32(40000000); commutate(3); __delay32(40000000); if(USER){ motoron=0; } LED1 = !S3; LED2 = !S2; LED3 = !S1; //test_MayDay(); } return 0; }
/* The kick function needs to be called when the motor is starting from rest. * If the motor is not rotating the change notification interrupt will not * trigger and the commutate function will not be called. The kick function * drives the motor to change the hall effect sensor inputs. */ void kick(void){ int kick; int state; int CWtable[6] = {5,3,1,6,4,2}; int CCWtable[6] = {3,6,2,5,1,4}; state = (S3 << 2) | (S2 << 1) | S1; if(direction==CW){ kick = CWtable[state-1]; } else{ //direction == CCW kick = CCWtable[state-1]; } printf("%d",kick); commutate(kick); }
void motor_start(MOTOR *p) { p->state = STATE_START; p->phase = 1; p->start_counter = 0; *(p->phase_a_pwm) = 800; *(p->phase_b_pwm) = 800; *(p->phase_c_pwm) = 800; p->start_comm_period = US_TO_TICKS(10000); commutate(p); // TIM_ITConfig(TIM10, TIM_IT_CC1, ENABLE); TIM10->DIER |= TIM_IT_CC1; *(p->commutate_timer) = *(p->commutate_counter) + p->start_comm_period; p->prev_comm_ticks = *(p->commutate_timer); p->start_comm_period = ((p->start_comm_period * 15) >> 4); }
/* The pulse width modulation module controls the motor torque by changing the * amount of time the on voltage is applied. The PWM module runs at 20kHz in * complementary mode to work with the HIP4086 BLDC driver. * In complementary mode each of the three PWM modules controls two outputs * whose states are the inverse of each other. * The module incorporates a dead time delay between the falling edge of one * signal and the rising edge of the next to prevent shoot through. */ void initialize_PWM(void){ PTCON2bits.PCLKDIV = 0b010; //PWM input clock prescaled by 1:4 //Period = 80 MHz / (PTPER * Prescaler) //PTPER = 80 MHz / (20kHz * 4) = 1000 PTPER = 1000; //PTPER = 80 MHz / (50kHz * 4) = 400 PTPER = 400; IOCON1bits.PMOD = 0; //Set PWM1 to Complementary Mode IOCON2bits.PMOD = 0; //Set PWM2 to Complementary Mode IOCON3bits.PMOD = 0; //Set PWM3 to Complementary Mode //DTR = Fosc * Deadtime / Prescaler //DTR = 80MHz * 0.5us / 4 DTR1 = DTR2 = DTR3 = 10; //Set deadtime of 0.5us ALTDTR1 = ALTDTR2 = ALTDTR3 = 10; //Set alternate deadtime of 0.5us //Enable PWM outputs IOCON1bits.PENH = 1; IOCON1bits.PENL = 1; IOCON2bits.PENH = 1; IOCON2bits.PENL = 1; IOCON3bits.PENH = 1; IOCON3bits.PENL = 1; //Set polarity of PWM registers IOCON1bits.POLH = 1; //PWM1H pin is active-low IOCON2bits.POLH = 1; //PWM1H pin is active-low IOCON3bits.POLH = 1; //PWM1H pin is active-low IOCON1bits.POLL = 0; //PWM1L pin is active-high IOCON2bits.POLL = 0; //PWM1L pin is active-high IOCON3bits.POLL = 0; //PWM1L pin is active-high //Use MDC register to provide duty cycle information for all PWM modules PWMCON1bits.MDCS = 1; PWMCON2bits.MDCS = 1; PWMCON3bits.MDCS = 1; MDC = 100; // Sets master duty cycle at 10%. 100% is at MDC = 1000 MDC = 10; commutate(0); //Set all motor outputs to float PTCONbits.PTEN = 1; //Enable PWM }
void initialize_pwm(void){ PTCON2bits.PCLKDIV = 0b010; //PWM input clock prescaled by 1:4 //Period = 80 MHz / (PTPER * Prescaler) //Period = 80 MHz / (20kHz * 4) = 1000 PTPER = 1000; IOCON1bits.PMOD = 00; //Set PWM to Complementary Mode IOCON2bits.PMOD = 00; //Set PWM to Complementary Mode IOCON3bits.PMOD = 00; //Set PWM to Complementary Mode DTR1 = DTR2 = DTR3 = 10; ALTDTR1 = ALTDTR2 = ALTDTR3 = 10; IOCON1bits.PENH = 1; IOCON1bits.PENL = 1; IOCON2bits.PENH = 1; IOCON2bits.PENL = 1; IOCON3bits.PENH = 1; IOCON3bits.PENL = 1; IOCON1bits.POLH = 1; IOCON2bits.POLH = 1; IOCON3bits.POLH = 1; IOCON1bits.POLL = 0; IOCON2bits.POLL = 0; IOCON3bits.POLL = 0; PWMCON1bits.MDCS = 1; //MDC register provides duty cycle information PWMCON2bits.MDCS = 1; PWMCON3bits.MDCS = 1; MDC = 100; // Sets master duty cycle at 10% commutate(0); PTCONbits.PTEN = 1; }
void commutate_state(comm_state_t n_state) { state = n_state; commutate(); }