Exemple #1
0
void motor_pwm_manip(const enum motor_pwm_phase_manip command[MOTOR_NUM_PHASES])
{
	irq_primask_disable();
	phase_reset_all_i();
	irq_primask_enable();

	for (int phase = 0; phase < MOTOR_NUM_PHASES; phase++) {
		if (command[phase] == MOTOR_PWM_MANIP_HIGH) {
			// We don't want to engage 100% duty cycle because the high side pump needs switching
			const int pwm_val = motor_pwm_compute_pwm_val(0.80f);
			irq_primask_disable();
			phase_set_i(phase, pwm_val, false);
			irq_primask_enable();
		} else if (command[phase] == MOTOR_PWM_MANIP_HALF) {
			irq_primask_disable();
			phase_set_i(phase, _pwm_half_top, false);
			irq_primask_enable();
		} else if (command[phase] == MOTOR_PWM_MANIP_LOW) {
			irq_primask_disable();
			phase_set_i(phase, 0, false);
			irq_primask_enable();
		} else if (command[phase] == MOTOR_PWM_MANIP_FLOATING) {
			// Nothing to do
		} else {
			assert(0);
		}
	}

	adjust_adc_sync(_pwm_half_top);  // Default for phase manip
	apply_phase_config();
}
Exemple #2
0
void motor_rtctl_start(float duty_cycle, bool reverse)
{
    motor_rtctl_stop();                    // Just in case

    if (!_initialization_confirmed) {
        return; // Go home you're drunk
    }

    if (duty_cycle <= 0) {
        assert(0);
        return;
    }

    /*
     * Initialize the structs
     */
    memset(&_diag, 0, sizeof(_diag));
    memset(&_state, 0, sizeof(_state));    // Mighty reset

    motor_forced_rotation_detector_reset();

    _diag.started_at = motor_timer_hnsec();

    _state.comm_table = reverse ? COMMUTATION_TABLE_REVERSE : COMMUTATION_TABLE_FORWARD;

    _state.pwm_val_after_spinup = motor_pwm_compute_pwm_val(duty_cycle);

    init_adc_filters();

    /*
     * Initial spinup.
     */
    const tprio_t orig_priority = chThdSetPriority(HIGHPRIO);

    motor_pwm_prepare_to_start();

    const bool started = do_bemf_spinup(duty_cycle);

    /*
     * Engage the normal mode if started
     * At this point, if the spinup was OK, we're sutiated RIGHT AFTER THE DETECTED ZERO CROSS, engaged.
     */
    if (started) {
        _state.blank_time_deadline = motor_timer_hnsec() + _params.comm_blank_hnsec;
        _state.zc_detection_result = ZC_DETECTED;
        _state.flags = FLAG_ACTIVE | FLAG_SPINUP;
        motor_timer_set_relative(_state.comm_period / 3);
        lowsyslog("Motor: Spinup OK, comm period: %u usec\n", (unsigned)(_state.comm_period / HNSEC_PER_USEC));
    } else {
        lowsyslog("Motor: Spinup failed\n");
        motor_rtctl_stop();
    }

    chThdSetPriority(orig_priority);
}
Exemple #3
0
void motor_rtctl_set_duty_cycle(float duty_cycle)
{
    // We don't need a critical section to write an integer
    _state.pwm_val = motor_pwm_compute_pwm_val(duty_cycle);
}
Exemple #4
0
static bool do_bemf_spinup(const float max_duty_cycle)
{
    assert(chThdGetPriority() == HIGHPRIO);  // Mandatory

    // Make sure we're not going to underflow during time calculations
    while (motor_timer_hnsec() < _params.spinup_start_comm_period) {
        ;
    }

    const uint64_t deadline = motor_timer_hnsec() + _params.spinup_timeout;
    float dc = _params.spinup_duty_cycle_increment;
    unsigned num_good_comms = 0;

    _state.comm_period = _params.spinup_start_comm_period;
    _state.prev_zc_timestamp = motor_timer_hnsec() - _state.comm_period / 2;
    _state.pwm_val = motor_pwm_compute_pwm_val(dc);

    while (motor_timer_hnsec() <= deadline) {
        // Engage the current comm step
        irq_primask_disable();
        motor_pwm_set_step_from_isr(_state.comm_table + _state.current_comm_step, _state.pwm_val);
        irq_primask_enable();

        uint64_t step_deadline = motor_timer_hnsec() + _state.comm_period;
        motor_timer_hndelay(_params.comm_blank_hnsec);

        // Wait for the next zero crossing
        const uint64_t zc_timestamp = spinup_wait_zc(step_deadline);
        num_good_comms = (zc_timestamp > 0) ? (num_good_comms + 1) : 0;

        // Compute the next duty cycle
        dc += _params.spinup_duty_cycle_increment;
        if (dc > max_duty_cycle) {
            dc = max_duty_cycle;
        }
        _state.pwm_val = motor_pwm_compute_pwm_val(dc);

        if (zc_timestamp > 0) {
            assert(zc_timestamp > _state.prev_zc_timestamp);

            // Update comm period
            const uint32_t new_comm_period = zc_timestamp - _state.prev_zc_timestamp;
            _state.prev_zc_timestamp = zc_timestamp;
            _state.comm_period = (_state.comm_period + new_comm_period) / 2;
            step_deadline = zc_timestamp + _state.comm_period / 2;

            // Check the termination condition
            const bool enough_good_comms = num_good_comms > _params.spinup_num_good_comms;
            const bool fast_enough = _state.comm_period <= _params.spinup_end_comm_period;
            if (enough_good_comms || fast_enough) {
                break;
            }
        } else {
            // If ZC was not detected, we need to fake the previous ZC timestamp now
            _state.prev_zc_timestamp = step_deadline - _state.comm_period / 2;
        }

        // Wait till the end of the current step
        while (motor_timer_hnsec() <= step_deadline) {
            ;
        }

        // Next step
        _state.current_comm_step++;
        if (_state.current_comm_step >= MOTOR_NUM_COMMUTATION_STEPS) {
            _state.current_comm_step = 0;
        }
    }

    return _state.comm_period < _params.comm_period_max;
}