static void configure(void) { _params.timing_advance_deg64 = config_get("motor_timing_advance_deg") * 64 / 60; _params.motor_bemf_window_len_denom = config_get("motor_bemf_window_len_denom"); _params.bemf_valid_range_pct128 = config_get("motor_bemf_valid_range_pct") * 128 / 100; _params.zc_failures_max = config_get("motor_zc_failures_to_stop"); _params.zc_detects_min = config_get("motor_zc_detects_to_start"); _params.comm_period_max = config_get("motor_comm_period_max_usec") * HNSEC_PER_USEC; _params.comm_blank_hnsec = config_get("motor_comm_blank_usec") * HNSEC_PER_USEC; _params.spinup_timeout = config_get("motor_spinup_timeout_ms") * HNSEC_PER_MSEC; _params.spinup_start_comm_period = config_get("motor_spinup_start_comm_period_usec") * HNSEC_PER_USEC; _params.spinup_end_comm_period = config_get("motor_spinup_end_comm_period_usec") * HNSEC_PER_USEC; _params.spinup_num_good_comms = config_get("motor_spinup_num_good_comms"); _params.spinup_duty_cycle_increment = config_get("motor_spinup_duty_cycle_inc"); /* * Validation */ if (_params.comm_period_max > motor_timer_get_max_delay_hnsec()) { _params.comm_period_max = motor_timer_get_max_delay_hnsec(); } if (_params.spinup_end_comm_period > _params.comm_period_max) { _params.spinup_end_comm_period = _params.comm_period_max; } _params.adc_sampling_period = motor_adc_sampling_period_hnsec(); lowsyslog("Motor: RTCTL config: Max comm period: %u usec, BEMF window denom: %i\n", (unsigned)(_params.comm_period_max / HNSEC_PER_USEC), _params.motor_bemf_window_len_denom); }
static int init_constants(unsigned frequency) { assert_always(_pwm_top == 0); // Make sure it was not initialized already /* * PWM top, derived from frequency */ if (frequency < MOTOR_PWM_MIN_FREQUENCY || frequency > MOTOR_PWM_MAX_FREQUENCY) { return -1; } const int pwm_steps = PWM_TIMER_FREQUENCY / frequency; if ((pwm_steps < 2) || (pwm_steps > 65536)) { assert(0); return -1; } _pwm_top = pwm_steps - 1; _pwm_half_top = pwm_steps / 2; const int effective_steps = pwm_steps / 2; const float true_frequency = PWM_TIMER_FREQUENCY / (float)pwm_steps; const unsigned adc_period_usec = motor_adc_sampling_period_hnsec() / HNSEC_PER_USEC; lowsyslog("Motor: PWM freq: %f; Effective steps: %i; ADC period: %u usec\n", true_frequency, effective_steps, adc_period_usec); /* * PWM min - Limited by MOTOR_ADC_SAMPLE_WINDOW_NANOSEC */ const float pwm_clock_period = 1.f / PWM_TIMER_FREQUENCY; const float pwm_adc_window_len = (MOTOR_ADC_SAMPLE_WINDOW_NANOSEC / 1e9f) * 2; const float pwm_adc_window_ticks_float = pwm_adc_window_len / pwm_clock_period; assert(pwm_adc_window_ticks_float >= 0); uint16_t pwm_half_adc_window_ticks = (uint16_t)pwm_adc_window_ticks_float; if (pwm_half_adc_window_ticks > _pwm_half_top) { pwm_half_adc_window_ticks = _pwm_half_top; } _pwm_min = pwm_half_adc_window_ticks; assert(_pwm_min <= _pwm_half_top); /* * ADC synchronization. * ADC shall be triggered in the middle of a PWM cycle in order to catch the moment when the instant * winding current matches with average winding current - this helps to eliminate the current ripple * caused by the PWM switching. Thus we trigger ADC at the point ((pwm_value / 2) - adc_advance). * Refer to "Synchronizing the On-Chip Analog-to-Digital Converter on 56F80x Devices" for some explanation. */ const float adc_trigger_advance = MOTOR_ADC_SYNC_ADVANCE_NANOSEC / 1e9f; const float adc_trigger_advance_ticks_float = adc_trigger_advance / pwm_clock_period; assert(adc_trigger_advance_ticks_float >= 0); assert(adc_trigger_advance_ticks_float < (_pwm_top * 0.4f)); _adc_advance_ticks = (uint16_t)adc_trigger_advance_ticks_float; lowsyslog("Motor: PWM range [%u; %u], ADC advance ticks %u\n", (unsigned)_pwm_min, (unsigned)_pwm_top, (unsigned)_adc_advance_ticks); return 0; }
uint32_t motor_rtctl_get_min_comm_period_hnsec(void) { // Ensure some number of ADC samples per comm period uint32_t retval = motor_adc_sampling_period_hnsec() * 5; if (retval < ABS_MIN_COMM_PERIOD_USEC * HNSEC_PER_USEC) { retval = ABS_MIN_COMM_PERIOD_USEC * HNSEC_PER_USEC; } return retval; }