void TIM1_CC_IRQHandler(void) { float max_dv, tiny_dp, vel_req; int32_t pos_err; TIMER_LED_ON; TIM1->SR &= ~TIM_SR_CC1IF; // clear capture/compare 1 event flag m1.active = 0; if (m1.current_period == 0) { // initiate movement // Calculate initial period needed for the calculation of acceleration m1.current_period = stepper_setf(1.0f / sqrtf(2.0f / (float) STEPPER_MAX_A)); // No movement in this iteration m1.dir = 0; if(m1.pos_cmd - m1.current_pos > 0) { // m1.dir = 1; STEPPER_SET_DIR_POS; } else if(m1.pos_cmd - m1.current_pos < 0){ // m1.dir = -1; STEPPER_SET_DIR_NEG; } // Set the counter to CCR1 value, so the first timer loop will not cause compare match TIM1->CNT = TIM1->CCR1; TIM1->EGR = TIM_EGR_UG; // Generate update event (reload registers) TIM1->SR &= ~TIM_SR_UIF; // clear update event flag TIM1->CCER |= TIM_CCER_CC1E; // Enable PWM output TIM1->CR1 |= TIM_CR1_CEN; // Count up, Enable timer } m1.current_pos += m1.dir; /* compute max change in velocity per servo period */ max_dv = STEPPER_MAX_A * (float) m1.current_period / (float) CPU_CLK; /* calculate desired velocity */ if (m1.enabled) { /* planner enabled, request a velocity that tends to drive pos_err to zero, but allows for stopping without position overshoot */ pos_err = m1.pos_cmd - m1.current_pos; /* positive and negative errors require some sign flipping to avoid sqrt(negative) */ if (pos_err > 0) { vel_req = -max_dv + sqrtf(2.0f * (float) STEPPER_MAX_A * (float) pos_err + max_dv * max_dv); /* mark planner as active */ m1.active = 1; } else if (pos_err < 0) { vel_req = max_dv - sqrtf(-2.0f * (float) STEPPER_MAX_A * (float) pos_err + max_dv * max_dv); /* mark planner as active */ m1.active = 1; } else { /* within 'tiny_dp' of desired pos, no need to move */ vel_req = 0.0; } } else { /* planner disabled, request zero velocity */ vel_req = 0.0; /* and set command to present position to avoid movement when next enabled */ m1.pos_cmd = m1.current_pos; } /* limit velocity request */ if (vel_req > m1.vmax) { vel_req = m1.vmax; } else if (vel_req < -m1.vmax) { vel_req = -m1.vmax; } /* ramp velocity toward request at accel limit */ if (vel_req > m1.current_vel + max_dv) { m1.current_vel += max_dv; } else if (vel_req < m1.current_vel - max_dv) { m1.current_vel -= max_dv; } else { m1.current_vel = vel_req; } // TODO poprawić - gubi pierwszy(?) krok if(m1.current_vel > 0) { m1.dir = 1; STEPPER_SET_DIR_POS; } else if(m1.current_vel < 0) { m1.dir = -1; STEPPER_SET_DIR_NEG; } /* check for still moving */ if(m1.current_vel != 0.0) { /* yes, mark planner active */ m1.active = 1; } /* integrate velocity to get new position */ //m1.current_pos += m1.current_vel * m1.current_period; if(m1.active == 0) { stepper_stop(); } else { m1.current_period = stepper_setf(fabsf(m1.current_vel)); } TIMER_LED_OFF; }