#include #include "bsp/bsp.h" #include "bsp/mc_hall_gpio.h" #include "os/co_task.h" #include "os/timer.h" #include "libs/utils.h" #include "libs/logger.h" #include "math/fast_math.h" #include "foc/motor/hall.h" #include "foc/core/foc_api.h" #include "app/nv_storage.h" #include "bsp/timer_count32.h" #define USE_DETECTED_ANGLE 1 #define HALL_READ_TIMES 3 static void _hall_detect_task(void *args); static void _hall_init_el_angle(void); #define HALL_PLACE_OFFSET (315) //(345) //315 /* 4,5,1,3,2,6,4 */ static hall_sensor_t _sensor_hander; measure_time_t g_meas_hall = {.exec_max_time = 6,}; #define read_hall(h,t) {h = get_hall_stat(HALL_READ_TIMES); t = _hall_table[h];} #define us_2_s(tick) ((float)tick / 1000000.0f) #define rand_angle(a) {if (a >= PHASE_360_DEGREE) a-=PHASE_360_DEGREE;else if (a < 0) a +=PHASE_360_DEGREE;}; static float hall_speed[8]; static float hall_angle[8]; static void __inline _hall_put_sample(u32 ticks, float angle) { hall_sample_t *s = &_sensor_hander.samples; s->ticks_sum -= s->ticks[s->index]; s->angles_sum -= s->angles[s->index]; s->ticks[s->index] = ticks; s->angles[s->index] = angle; s->ticks_sum += s->ticks[s->index]; s->angles_sum += s->angles[s->index]; s->index += 1; if (s->index >= SAMPLE_MAX_COUNT) { s->full = true; s->index = 0; } } static float __inline _hall_angle_speed(void){ hall_sample_t *s = &_sensor_hander.samples; if (s->ticks_sum == 0) { return 0.0f; } if (!s->full) { return s->angles[s->index - 1] / us_2_s(s->ticks[s->index-1]); }else { return s->angles_sum / us_2_s(s->ticks_sum); } } void hall_debug_log(void) { for (int i = 0; i < 8; i++) { if (i != 0 && i != 7) { sys_debug("hall speed: %d, %f - %f, %d\n", i, hall_speed[i], hall_angle[i], _sensor_hander.sensor_error); sys_debug("hall angle %d\n", _sensor_hander.angle_table[i]); } } sys_debug("angle dir %d\n", _sensor_hander.direction); } /* static bool __inline _hall_data_empty(void) { hall_sample_t *s = &_sensor_hander.samples; if ((!s->full) && (s->index == 0)){ return true; } return false; } */ static void hall_sensor_default(void) { memset(&_sensor_hander, 0, sizeof(_sensor_hander)); _sensor_hander.phase_offset = HALL_PLACE_OFFSET;//mc_config_get()->hall_offset; memcpy((char *)_sensor_hander.angle_table, (char *)mc_config_get()->hall_table, sizeof(_sensor_hander.angle_table)); _hall_init_el_angle(); hall_debug_log(); } void hall_sensor_init(void) { mc_hall_init(); hall_sensor_default(); co_task_create(_hall_detect_task, NULL, 512); } void hall_sensor_clear(void) { hall_sensor_default(); } static void _hall_detect_task(void *args) { while(1) { if (_sensor_hander.el_speed != 0) { u32 ticks_now = timer_count32_get(); u32 delta_us = timer_count32_getus(ticks_now, _sensor_hander.hall_ticks); if (delta_us >= (1200*1000)) { hall_sensor_clear(); } } co_task_delay(100); } } float hall_sensor_get_theta(void){ if (_sensor_hander.is_override_angle) { return _sensor_hander.override_el_angle; } u32 us_now = timer_count32_delta_us(_sensor_hander.estimate_time_ticks, &_sensor_hander.estimate_time_ticks); float angle_step = _sensor_hander.estimate_el_speed * us_2_s(us_now); _sensor_hander.estimate_delta_angle += angle_step; if (_sensor_hander.direction == POSITIVE) { _sensor_hander.estimate_el_angle += angle_step; }else { _sensor_hander.estimate_el_angle -= angle_step; } rand_angle(_sensor_hander.estimate_el_angle); //log_chan_value(1, (int)_sensor_hander.estimate_el_angle); return _sensor_hander.estimate_el_angle; } void hall_sensor_set_theta(bool override, float theta){ _sensor_hander.is_override_angle = override; _sensor_hander.override_el_angle = theta; } float hall_sensor_get_speed(void) { return _sensor_hander.rpm; } int hall_offset_increase(int inc) { if (_sensor_hander.phase_offset + inc >= 360) { _sensor_hander.phase_offset = _sensor_hander.phase_offset + inc - 360; }else { _sensor_hander.phase_offset += inc; } return _sensor_hander.phase_offset; } u16 *hall_get_table(void) { return _sensor_hander.angle_table; } int hall_sensor_calibrate(float voltage){ foc_set_controller_mode(FOC_MODE_OPEN_LOOP); hall_sensor_set_theta(true, 0.0f); foc_set_dq_command(0.0f, 0.0f); foc_pwm_start(true); foc_start_adc(true); for (int i = 0;i < 100;i++) { foc_set_dq_command((float)i * voltage / 100.0f, 0.0f); co_task_delay(1); wdog_reload(); } float sin_hall[8]; float cos_hall[8]; int hall_iterations[8]; memset(sin_hall, 0, sizeof(sin_hall)); memset(cos_hall, 0, sizeof(cos_hall)); memset(_sensor_hander.angle_table, 0, sizeof(_sensor_hander.angle_table)); memset(hall_iterations, 0, sizeof(hall_iterations)); co_task_delay(2 * 1000); // Forwards #if 1 for (int i = 0;i < 5;i++) { for (int j = 0;j < 360;j++) { hall_sensor_set_theta(true, j); co_task_delay(5); wdog_reload(); int hall = get_hall_stat(7); float s, c; normal_sincosf(degree_2_pi(j), &s, &c); sin_hall[hall] += s; cos_hall[hall] += c; hall_iterations[hall]++; } } #endif #if 0 //hall_sensor_set_theta(true, 360); //co_task_delay(2 * 1000); sys_debug("Revers\n"); // Reverse for (int i = 0;i < 5;i++) { for (int j = 360;j >= 0;j--) { hall_sensor_set_theta(true, j); co_task_delay(5); wdog_reload(); int hall = get_hall_stat(7); float s, c; normal_sincosf(degree_2_pi(j), &s, &c); sin_hall[hall] += s; cos_hall[hall] += c; hall_iterations[hall]++; } } #endif for (int i = 99;i >= 0;i--) { foc_set_dq_command((float)i * voltage / 100.0f, 0.0f); co_task_delay(1); wdog_reload(); } foc_pwm_start(false); foc_start_adc(false); hall_sensor_set_theta(false, 0.0f); int fails = 0; for(int i = 0;i < 8;i++) { if (hall_iterations[i] > 30) { float ang = pi_2_degree(atan2f(sin_hall[i], cos_hall[i])); fast_norm_angle(&ang); _sensor_hander.angle_table[i] = (u16)ang; sys_debug("%d: %d\n", i, _sensor_hander.angle_table[i]); co_task_delay(10); } else { fails++; _sensor_hander.angle_table[i] = 0xFFFF; } } return fails == 2; } static void _hall_init_el_angle(void) { _sensor_hander.hall_stat = get_hall_stat(HALL_READ_TIMES); #ifdef USE_DETECTED_ANGLE if (_sensor_hander.hall_stat == 0 || _sensor_hander.hall_stat == 7) { _sensor_hander.sensor_error ++; return; } _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + _sensor_hander.angle_table[_sensor_hander.hall_stat]; #else s32 sector_center = PHASE_60_DEGREE/2; switch ( _sensor_hander.hall_stat ) { case STATE_5: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + sector_center; break; case STATE_1: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + PHASE_60_DEGREE + sector_center; break; case STATE_3: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + PHASE_120_DEGREE + sector_center; break; case STATE_2: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + PHASE_180_DEGREE + sector_center; break; case STATE_6: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + PHASE_240_DEGREE + sector_center; break; case STATE_4: _sensor_hander.measured_el_angle = _sensor_hander.phase_offset + PHASE_300_DEGREE + sector_center; break; default: /* Bad hall sensor configutarion so update the speed reliability */ _sensor_hander.sensor_error ++; return; } #endif _sensor_hander.sensor_error = 0; /* Initialize the measured angle */ rand_angle(_sensor_hander.measured_el_angle); _sensor_hander.estimate_el_angle = _sensor_hander.measured_el_angle; _sensor_hander.hall_ticks = timer_count32_get(); _sensor_hander.estimate_time_ticks = timer_count32_get(); } static __inline__ s32 _get_angle(u8 state, s32 added) { #ifdef USE_DETECTED_ANGLE return _sensor_hander.phase_offset + _sensor_hander.angle_table[state]; #else return _sensor_hander.phase_offset + added; #endif } /* 4,5,1,3,2,6,4 */ static s32 _hall_position(u8 state_now, u8 state_prev) { s32 theta_now = 0xFFFFFFFF; switch (state_now) { case STATE_1: if (state_prev == STATE_5) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_60_DEGREE);//_sensor_hander.phase_offset + PHASE_60_DEGREE; }else if (state_prev == STATE_3) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_120_DEGREE);//_sensor_hander.phase_offset + PHASE_120_DEGREE; } break; case STATE_2: if (state_prev == STATE_3) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_180_DEGREE);//_sensor_hander.phase_offset + PHASE_180_DEGREE; }else if (state_prev == STATE_6) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_240_DEGREE);//_sensor_hander.phase_offset + PHASE_240_DEGREE; } break; case STATE_3: if (state_prev == STATE_1) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_120_DEGREE);//_sensor_hander.phase_offset + PHASE_120_DEGREE; }else if (state_prev == STATE_2) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_180_DEGREE);//_sensor_hander.phase_offset + PHASE_180_DEGREE; } break; case STATE_4: if (state_prev == STATE_6) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_300_DEGREE);//_sensor_hander.phase_offset + PHASE_300_DEGREE; }else if (state_prev == STATE_5) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_0_DEGREE);//_sensor_hander.phase_offset + PHASE_0_DEGREE; } break; case STATE_5: if (state_prev == STATE_4) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_0_DEGREE);//_sensor_hander.phase_offset + PHASE_0_DEGREE; }else if (state_prev == STATE_1) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_60_DEGREE);//_sensor_hander.phase_offset + PHASE_60_DEGREE; } break; case STATE_6: if (state_prev == STATE_2) { _sensor_hander.direction = POSITIVE; theta_now = _get_angle(state_now, PHASE_240_DEGREE);//_sensor_hander.phase_offset + PHASE_240_DEGREE; }else if (state_prev == STATE_4) { _sensor_hander.direction = NEGATIVE; theta_now = _get_angle(state_now, PHASE_300_DEGREE);//_sensor_hander.phase_offset + PHASE_300_DEGREE; } break; default: _sensor_hander.sensor_error ++; return 0xFFFFFFFF; } rand_angle(theta_now); return theta_now; } static __inline u8 _next_hall(u8 hall_now) { switch (hall_now) { case STATE_1: if (_sensor_hander.direction == POSITIVE) { return STATE_3; }else { return STATE_5; } case STATE_2: if (_sensor_hander.direction == POSITIVE) { return STATE_6; }else { return STATE_3; } case STATE_3: if (_sensor_hander.direction == POSITIVE) { return STATE_2; }else { return STATE_1; } case STATE_4: if (_sensor_hander.direction == POSITIVE) { return STATE_5; }else { return STATE_6; } case STATE_5: if (_sensor_hander.direction == POSITIVE) { return STATE_1; }else { return STATE_4; } case STATE_6: if (_sensor_hander.direction == POSITIVE) { return STATE_4; }else { return STATE_2; } default: //not reached here return STATE_1; } } #ifdef USE_DETECTED_ANGLE static __inline__ float _get_delta_angle(u8 now, u8 next) { float delta_angle = _sensor_hander.angle_table[next] - _sensor_hander.angle_table[now]; if (_sensor_hander.direction == POSITIVE) { if (delta_angle < 0) { //process cross 360 degree delta_angle += 360.0f; } }else if (_sensor_hander.direction == NEGATIVE) { if (delta_angle > 0) { //process cross 360 degree delta_angle -= 360.0f; } delta_angle = -delta_angle; } return delta_angle; } #endif void hall_sensor_handler(void) { if (_sensor_hander.is_override_angle) { sys_debug("irq: %d:%d\n", (int)get_hall_stat(HALL_READ_TIMES), (int)_sensor_hander.override_el_angle); return; } time_measure_start(&g_meas_hall); u8 hall_stat_now = get_hall_stat(HALL_READ_TIMES); u8 hall_stat_prev = _sensor_hander.hall_stat; u32 hall_ticks_now = timer_count32_get(); /*获取当前转子角度*/ s32 theta_now = _hall_position(hall_stat_now, hall_stat_prev); if (theta_now == 0xFFFFFFFF) { return; } //获取两次中断的时间间隔,估计速度 u32 delta_us = timer_count32_getus(hall_ticks_now, _sensor_hander.hall_ticks); if (delta_us == 0) { return; } //获取两次中断之间转子转过的角度,获取预期的下次hall状态变换转过的角度 #ifdef USE_DETECTED_ANGLE float delta_angle = _get_delta_angle(hall_stat_prev, hall_stat_now); float next_delta_angle = _get_delta_angle(hall_stat_now, _next_hall(hall_stat_now)); #else float delta_angle = (float)PHASE_60_DEGREE; float next_delta_angle = delta_angle; #endif float delta_time = us_2_s(delta_us); float prev_imme_el_speed = _sensor_hander.immediately_el_speed; _sensor_hander.immediately_el_speed = delta_angle/delta_time; float delta_el_speed = fabs(_sensor_hander.immediately_el_speed - prev_imme_el_speed); if (delta_el_speed/prev_imme_el_speed >= 0.1f) { //即时速度增加10%,认为不稳定,需要使用即时速度估计转子位置 _sensor_hander.trns_detect = true; }else { _sensor_hander.trns_detect = false; } _hall_put_sample(delta_us, delta_angle); os_disable_irq(); _sensor_hander.el_speed = _hall_angle_speed(); _sensor_hander.estimate_delta_angle = _sensor_hander.estimate_delta_angle - delta_angle; /*通过上次预估的转子位置,对当前的预估速度进行补偿*/ if (_sensor_hander.trns_detect) { _sensor_hander.estimate_el_speed = (next_delta_angle - _sensor_hander.estimate_delta_angle)/delta_angle * _sensor_hander.immediately_el_speed; }else { _sensor_hander.estimate_el_speed = (next_delta_angle - _sensor_hander.estimate_delta_angle)/delta_angle * _sensor_hander.el_speed; } _sensor_hander.next_delta_angle = next_delta_angle; //_sensor_hander.measured_el_angle = theta_now; os_enable_irq(); _sensor_hander.hall_stat = hall_stat_now; _sensor_hander.hall_ticks = hall_ticks_now; _sensor_hander.rpm = _sensor_hander.el_speed / 360.0f * 60.0f; time_measure_end(&g_meas_hall); }