#include #include "bsp/bsp.h" #include "bsp/mc_hall_gpio.h" #include "os/os_task.h" #include "libs/utils.h" #include "libs/logger.h" #include "math/fast_math.h" #include "foc/motor/hall.h" #include "app/nv_storage.h" #include "bsp/timer_count32.h" #include "libs/time_measure.h" //#define USE_DETECTED_ANGLE 1 #define HALL_READ_TIMES 3 static u32 _hall_detect_task(void *args); static void _hall_init_el_angle(void); #define HALL_PLACE_OFFSET (315 << 19) //(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) S32Q14((float)tick / 1000000.0f) //s32q14 #define rand_angle(a) {if (a >= PHASE_360_DEGREE) a-=PHASE_360_DEGREE;else if (a < 0) a +=PHASE_360_DEGREE;}; static void __inline _hall_put_sample(u32 ticks, s32q19_t 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 s32q5_t __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) { 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(); shark_task_create(_hall_detect_task, NULL); } void hall_sensor_clear(void) { hall_sensor_default(); } static u32 _hall_detect_task(void *args) { if (_sensor_hander.el_speed != 0) { u32 ticks_now = timer_count32_get(); u32 delta_us = timer_count32_delta(ticks_now, _sensor_hander.hall_ticks); if (delta_us >= (1200*1000)) { hall_sensor_clear(); } } return 0; } s16q5_t hall_sensor_get_theta(void){ u32 us_now = timer_count32_get(); u32 us_delta = timer_count32_delta(us_now, _sensor_hander.estimate_time_ticks); _sensor_hander.estimate_time_ticks = us_now; s32q19_t angle_step = _sensor_hander.estimate_el_speed * us_2_s(us_delta); _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); return (_sensor_hander.estimate_el_angle >> 14); } s32q5_t hall_sensor_get_speed(void) { return _sensor_hander.rpm; } int hall_offset_increase(int inc) { inc = inc << 19; if (_sensor_hander.phase_offset + inc >= PHASE_360_DEGREE) { _sensor_hander.phase_offset = _sensor_hander.phase_offset + inc - PHASE_360_DEGREE; }else { _sensor_hander.phase_offset += inc; } return _sensor_hander.phase_offset; } s32 *hall_get_table(void) { return _sensor_hander.angle_table; } 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; } #ifdef USE_DETECTED_ANGLE 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; } } static __inline__ s32 _get_delta_angle(u8 now, u8 next) { s32 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 += PHASE_360_DEGREE; } }else if (_sensor_hander.direction == NEGATIVE) { if (delta_angle > 0) { //process cross 360 degree delta_angle -= PHASE_360_DEGREE; } delta_angle = -delta_angle; } return delta_angle; } #endif void HALL_IRQHandler(void) { 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_delta(hall_ticks_now, _sensor_hander.hall_ticks); if (delta_us == 0) { return; } //获取两次中断之间转子转过的角度,获取预期的下次hall状态变换转过的角度 #ifdef USE_DETECTED_ANGLE s32 delta_angle = _get_delta_angle(hall_stat_prev, hall_stat_now); s32 next_delta_angle = _get_delta_angle(hall_stat_now, _next_hall(hall_stat_now)); #else s32 delta_angle = PHASE_60_DEGREE; s32 next_delta_angle = delta_angle; #endif s32 delta_time = us_2_s(delta_us); s32 prev_imme_el_speed = _sensor_hander.immediately_el_speed; _sensor_hander.immediately_el_speed = delta_angle/delta_time; //s32q5 s32 delta_el_speed = abs(_sensor_hander.immediately_el_speed - prev_imme_el_speed); if (delta_el_speed*100/prev_imme_el_speed >= 20) { //即时速度增加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(); //s32q5 _sensor_hander.estimate_delta_angle = _sensor_hander.estimate_delta_angle - delta_angle; /*通过上次预估的转子位置,对当前的预估速度进行补偿*/ s32q14_t est_el_speed = ((next_delta_angle - _sensor_hander.estimate_delta_angle)<<9)/delta_angle * _sensor_hander.el_speed; if (_sensor_hander.trns_detect) { //s32q14 est_el_speed = ((next_delta_angle - _sensor_hander.estimate_delta_angle)<<9)/delta_angle * _sensor_hander.immediately_el_speed; } //s32q5 _sensor_hander.estimate_el_speed = est_el_speed >> 9; _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 * 60; //s32q5 time_measure_end(&g_meas_hall); }