自学内容网 自学内容网

开源BLHELI-S 代码详细解读(五)

我们继续来看calc_next_comm_timing, 每次操作完换相之后,这里都会调用,同时会设置timer3去等advance timing.

总体思想是根据电机运行状态计算前4次换相时间,然后根据前4次换相时间计算15度和7.5度电角度时间,换相之后延时7.5度电角度开始检测过零点,检测到过零点后延时15度电角度进行换相


;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Calculate next commutation timing routine
;
; No assumptions
;
; Called immediately after each commutation
; Also sets up timer 3 to wait advance timing
; Two entry points are used
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****
calc_next_comm_timing:; Entry point for run phase
; Read commutation time
clrIE_EA
clrTMR2CN0_TR2; Timer 2 disabled
movTemp1, TMR2L; Load timer value
movTemp2, TMR2H    ;  temp1, temp2取timer2当时的计数
movTemp3, Timer2_X     
jnbTMR2CN0_TF2H, ($+4); Check if interrupt is pending, 检查timer2的中断溢出标志要是零的话跳走,temp3不加1
incTemp3; If it is pending, then timer has already wrapped, 已经超时了,Temp3+1
setbTMR2CN0_TR2; Timer 2 enabled, 打开timer.
setbIE_EA ;打开全部中断
IF MCU_48MHZ >= 1
clrC 
movA, Temp3
rrcA          
movTemp3, A   ;Temp3 = Temp3/2
movA, Temp2
rrcA
movTemp2, A   ;Temp2 = Temp2/2
movA, Temp1
rrcA
movTemp1, A    ;Temp1 = Temp1/2
ENDIF
; Calculate this commutation time
movTemp4, Prev_Comm_L      ; temp4/5 赋为上次操作时间
movTemp5, Prev_Comm_H
movPrev_Comm_L, Temp1; Store timestamp as previous commutation
movPrev_Comm_H, Temp2      ; 保存当前时间到上次操作时间到Pre_Comm_L/H
clrC
movA, Temp1
subbA, Temp4; Calculate the new commutation time
movTemp1, A
movA, Temp2
subbA, Temp5             ;当前时间减去上次时间,结果在temp1,和A.
jbFlags1.STARTUP_PHASE, calc_next_comm_startup ;如果启动阶段,跳走。

IF MCU_48MHZ >= 1          
anlA, #7Fh         ;如果48Mhz, 高位 & 7Fh
ENDIF
movTemp2, A         ;保存高位到Temp2
jnbFlags1.HIGH_RPM, ($+5); Branch if high rpm ,
ajmpcalc_next_comm_timing_fast ; 是高rpm,跳到calc_next_comm_timing_fast

ajmpcalc_next_comm_normal  ; 如果不是高rpm,跳到calc_next_comm_normal

calc_next_comm_startup:
movTemp6, Prev_Comm_X
movPrev_Comm_X, Temp3; Store extended timestamp as previous commutation
movTemp2, A
movA, Temp3
subbA, Temp6; Calculate the new extended commutation time
IF MCU_48MHZ >= 1
anlA, #7Fh    ;如果48Mhz, 高位 & 7Fh
ENDIF
movTemp3, A
jzcalc_next_comm_startup_no_X

movTemp1, #0FFh
movTemp2, #0FFh
ajmpcalc_next_comm_startup_average

calc_next_comm_startup_no_X:
movTemp7, Prev_Prev_Comm_L
movTemp8, Prev_Prev_Comm_H
movPrev_Prev_Comm_L, Temp4
movPrev_Prev_Comm_H, Temp5
movTemp1, Prev_Comm_L; Reload this commutation time
movTemp2, Prev_Comm_H
clrC
movA, Temp1
subbA, Temp7; Calculate the new commutation time based upon the two last commutations (to reduce sensitivity to offset)
movTemp1, A
movA, Temp2
subbA, Temp8
movTemp2, A

calc_next_comm_startup_average:
clrC
movA, Comm_Period4x_H; Average with previous and save
rrcA
movTemp4, A
movA, Comm_Period4x_L
rrcA
movTemp3, A
movA, Temp1
addA, Temp3
movComm_Period4x_L, A
movA, Temp2
addcA, Temp4
movComm_Period4x_H, A
jnc($+8)

movComm_Period4x_L, #0FFh
movComm_Period4x_H, #0FFh

ajmpcalc_new_wait_times_setup

calc_next_comm_normal:
; Calculate new commutation time 
movTemp3, Comm_Period4x_L; Comm_Period4x(-l-h) holds the time of 4 commutations
movTemp4, Comm_Period4x_H
movTemp5, Comm_Period4x_L; Copy variables
movTemp6, Comm_Period4x_H
movTemp7, #4; Divide Comm_Period4x 4 times as default
movTemp8, #2; Divide new commutation time 2 times as default
clrC
movA, Temp4
subbA, #04h
jccalc_next_comm_avg_period_div

decTemp7; Reduce averaging time constant for low speeds
decTemp8

clrC
movA, Temp4
subbA, #08h
jccalc_next_comm_avg_period_div

jbFlags1.INITIAL_RUN_PHASE, calc_next_comm_avg_period_div; Do not average very fast during initial run

decTemp7; Reduce averaging time constant more for even lower speeds
decTemp8

calc_next_comm_avg_period_div:
clrC
movA, Temp6
rrcA; Divide by 2
movTemp6, A
movA, Temp5
rrcA
movTemp5, A
djnzTemp7, calc_next_comm_avg_period_div

clrC
movA, Temp3
subbA, Temp5; Subtract a fraction
movTemp3, A
movA, Temp4
subbA, Temp6
movTemp4, A
movA, Temp8; Divide new time
jzcalc_next_comm_new_period_div_done

calc_next_comm_new_period_div:
clrC
movA, Temp2
rrcA; Divide by 2
movTemp2, A
movA, Temp1
rrcA
movTemp1, A
djnzTemp8, calc_next_comm_new_period_div

calc_next_comm_new_period_div_done:
movA, Temp3
addA, Temp1; Add the divided new time
movTemp3, A
movA, Temp4
addcA, Temp2
movTemp4, A
movComm_Period4x_L, Temp3; Store Comm_Period4x_X
movComm_Period4x_H, Temp4
jnccalc_new_wait_times_setup; If period larger than 0xffff - go to slow case

movTemp4, #0FFh
movComm_Period4x_L, Temp4; Set commutation period registers to very slow timing (0xffff)
movComm_Period4x_H, Temp4

calc_new_wait_times_setup:
; Set high rpm bit (if above 156k erpm)
clrC
movA, Temp4
subbA, #2
jnc($+4)

setbFlags1.HIGH_RPM ; Set high rpm bit

; Load programmed commutation timing
jnbFlags1.STARTUP_PHASE, calc_new_wait_per_startup_done; Set dedicated timing during startup

movTemp8, #3
ajmpcalc_new_wait_per_demag_done

calc_new_wait_per_startup_done:
movTemp1, #Pgm_Comm_Timing; Load timing setting
movA, @Temp1
movTemp8, A; Store in Temp8
clrC
movA, Demag_Detected_Metric; Check demag metric
subbA, #130
jccalc_new_wait_per_demag_done

incTemp8; Increase timing

clrC
movA, Demag_Detected_Metric
subbA, #160
jc($+3)

incTemp8; Increase timing again

clrC
movA, Temp8; Limit timing to max
subbA, #6
jc($+4)

movTemp8, #5; Set timing to max

calc_new_wait_per_demag_done:
; Set timing reduction
movTemp7, #2
; Load current commutation timing
movA, Comm_Period4x_H; Divide 4 times
swapA
anlA, #00Fh
movTemp2, A
movA, Comm_Period4x_H
swapA
anlA, #0F0h
movTemp1, A
movA, Comm_Period4x_L
swapA
anlA, #00Fh
addA, Temp1
movTemp1, A

clrC
movA, Temp1
subbA, Temp7
movTemp3, A
movA, Temp2
subbA, #0
movTemp4, A
jcload_min_time; Check that result is still positive

clrC
movA, Temp3
subbA, #1
movA, Temp4
subbA, #0
jnccalc_new_wait_times_exit; Check that result is still above minumum

load_min_time:
movTemp3, #1
clrA
movTemp4, A 

calc_new_wait_times_exit:
ljmpwait_advance_timing


; Fast calculation (Comm_Period4x_H less than 2)
calc_next_comm_timing_fast:
; Calculate new commutation time
movTemp3, Comm_Period4x_L; Comm_Period4x(-l-h) holds the time of 4 commutations
movTemp4, Comm_Period4x_H
movA, Temp4; Divide by 2 4 times
swapA
movTemp7, A
movA, Temp3
swap A
anlA, #0Fh
orlA, Temp7
movTemp5, A
clrC
movA, Temp3; Subtract a fraction
subbA, Temp5
movTemp3, A
movA, Temp4
subbA, #0
movTemp4, A
clrC
movA, Temp1
rrcA; Divide by 2 2 times
clrC
rrcA
movTemp1, A
movA, Temp3; Add the divided new time
addA, Temp1
movTemp3, A
movA, Temp4
addcA, #0
movTemp4, A
movComm_Period4x_L, Temp3; Store Comm_Period4x_X
movComm_Period4x_H, Temp4
clrC
movA, Temp4; If erpm below 156k - go to normal case
subbA, #2
jc($+4)

clrFlags1.HIGH_RPM ; Clear high rpm bit

; Set timing reduction
movTemp1, #2
movA, Temp4; Divide by 2 4 times
swapA
movTemp7, A
movTemp4, #0
movA, Temp3
swap A
anlA, #0Fh
orlA, Temp7
movTemp3, A
clrC
movA, Temp3
subbA, Temp1
movTemp3, A
jcload_min_time_fast; Check that result is still positive

clrC
subbA, #1
jnccalc_new_wait_times_fast_done; Check that result is still above minumum

load_min_time_fast:
movTemp3, #1

calc_new_wait_times_fast_done:
movTemp1, #Pgm_Comm_Timing; Load timing setting
movA, @Temp1
movTemp8, A; Store in Temp8


;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Wait advance timing routine
;
; No assumptions
; NOTE: Be VERY careful if using temp registers. They are passed over this routine
;
; Waits for the advance timing to elapse and sets up the next zero cross wait
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****
wait_advance_timing:
jnbFlags0.T3_PENDING, ($+5)
ajmpwait_advance_timing

; Setup next wait time
movTMR3RLL, Wt_ZC_Tout_Start_L
movTMR3RLH, Wt_ZC_Tout_Start_H
setbFlags0.T3_PENDING
orlEIE1, #80h; Enable timer 3 interrupts


;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Calculate new wait times routine
;
; No assumptions
;
; Calculates new wait times
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****
calc_new_wait_times:
clrC
clrA
subbA, Temp3; Negate
movTemp1, A
clrA
subbA, Temp4
movTemp2, A
IF MCU_48MHZ >= 1
clrC
movA, Temp1; Multiply by 2
rlcA
movTemp1, A
movA, Temp2
rlcA
movTemp2, A
ENDIF
jnbFlags1.HIGH_RPM, ($+6); Branch if high rpm
ljmpcalc_new_wait_times_fast

movA, Temp1; Copy values
movTemp3, A
movA, Temp2
movTemp4, A
setbC; Negative numbers - set carry
movA, Temp2
rrcA; Divide by 2
movTemp6, A
movA, Temp1
rrcA
movTemp5, A
movWt_Zc_Tout_Start_L, Temp1; Set 15deg time for zero cross scan timeout
movWt_Zc_Tout_Start_H, Temp2
clrC
movA, Temp8; (Temp8 has Pgm_Comm_Timing)
subbA, #3; Is timing normal?
jzstore_times_decrease; Yes - branch

movA, Temp8
jbACC.0, adjust_timing_two_steps; If an odd number - branch

movA, Temp1; Add 7.5deg and store in Temp1/2
addA, Temp5
movTemp1, A
movA, Temp2
addcA, Temp6
movTemp2, A
movA, Temp5; Store 7.5deg in Temp3/4
movTemp3, A
movA, Temp6
movTemp4, A
jmpstore_times_up_or_down

adjust_timing_two_steps:
movA, Temp1; Add 15deg and store in Temp1/2
addA, Temp1
movTemp1, A
movA, Temp2
addcA, Temp2
movTemp2, A
clrC
movA, Temp1
addA, #1
movTemp1, A
movA, Temp2
addcA, #0
movTemp2, A
movTemp3, #-1; Store minimum time in Temp3/4
movTemp4, #0FFh

store_times_up_or_down:
clrC
movA, Temp8
subbA, #3; Is timing higher than normal?
jcstore_times_decrease; No - branch

store_times_increase:
movWt_Comm_Start_L, Temp3; Now commutation time (~60deg) divided by 4 (~15deg nominal)
movWt_Comm_Start_H, Temp4
movWt_Adv_Start_L, Temp1; New commutation advance time (~15deg nominal)
movWt_Adv_Start_H, Temp2
movWt_Zc_Scan_Start_L, Temp5; Use this value for zero cross scan delay (7.5deg)
movWt_Zc_Scan_Start_H, Temp6
ljmpwait_before_zc_scan

store_times_decrease:
movWt_Comm_Start_L, Temp1; Now commutation time (~60deg) divided by 4 (~15deg nominal)
movWt_Comm_Start_H, Temp2
movWt_Adv_Start_L, Temp3; New commutation advance time (~15deg nominal)
movWt_Adv_Start_H, Temp4
movWt_Zc_Scan_Start_L, Temp5; Use this value for zero cross scan delay (7.5deg)
movWt_Zc_Scan_Start_H, Temp6
jnbFlags1.STARTUP_PHASE, store_times_exit

movWt_Comm_Start_L, #0F0h; Set very short delays for all but advance time during startup, in order to widen zero cross capture range
movWt_Comm_Start_H, #0FFh
movWt_Zc_Scan_Start_L, #0F0h
movWt_Zc_Scan_Start_H, #0FFh
movWt_Zc_Tout_Start_L, #0F0h
movWt_Zc_Tout_Start_H, #0FFh

store_times_exit:
ljmpwait_before_zc_scan


calc_new_wait_times_fast:
movA, Temp1; Copy values
movTemp3, A
setbC; Negative numbers - set carry
movA, Temp1; Divide by 2
rrcA
movTemp5, A
movWt_Zc_Tout_Start_L, Temp1; Set 15deg time for zero cross scan timeout
clrC
movA, Temp8; (Temp8 has Pgm_Comm_Timing)
subbA, #3; Is timing normal?
jzstore_times_decrease_fast; Yes - branch

movA, Temp8
jbACC.0, adjust_timing_two_steps_fast; If an odd number - branch

movA, Temp1; Add 7.5deg and store in Temp1
addA, Temp5
movTemp1, A
movA, Temp5; Store 7.5deg in Temp3
movTemp3, A
ajmpstore_times_up_or_down_fast

adjust_timing_two_steps_fast:
movA, Temp1; Add 15deg and store in Temp1
addA, Temp1
addA, #1
movTemp1, A
movTemp3, #-1; Store minimum time in Temp3

store_times_up_or_down_fast:
clrC
movA, Temp8
subbA, #3; Is timing higher than normal?
jcstore_times_decrease_fast; No - branch

store_times_increase_fast:
movWt_Comm_Start_L, Temp3; Now commutation time (~60deg) divided by 4 (~15deg nominal)
movWt_Adv_Start_L, Temp1; New commutation advance time (~15deg nominal)
movWt_Zc_Scan_Start_L, Temp5; Use this value for zero cross scan delay (7.5deg)
ljmpwait_before_zc_scan

store_times_decrease_fast:
movWt_Comm_Start_L, Temp1; Now commutation time (~60deg) divided by 4 (~15deg nominal)
movWt_Adv_Start_L, Temp3; New commutation advance time (~15deg nominal)
movWt_Zc_Scan_Start_L, Temp5; Use this value for zero cross scan delay (7.5deg)


;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Wait before zero cross scan routine
;
; No assumptions
;
; Waits for the zero cross scan wait time to elapse
; Also sets up timer 3 for the zero cross scan timeout time
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****
wait_before_zc_scan:
jnbFlags0.T3_PENDING, ($+5)  ;jump if Flags0.T3_PENDING is zero
ajmpwait_before_zc_scan

movStartup_Zc_Timeout_Cntd, #2
setup_zc_scan_timeout:
setbFlags0.T3_PENDING
orlEIE1, #80h; Enable timer 3 interrupts
movA, Flags1
anlA, #((1 SHL STARTUP_PHASE)+(1 SHL INITIAL_RUN_PHASE))
jzwait_before_zc_scan_exit

movTemp1, Comm_Period4x_L; Set long timeout when starting
movTemp2, Comm_Period4x_H
clrC
movA, Temp2
rrcA
movTemp2, A
movA, Temp1
rrcA
movTemp1, A
IF MCU_48MHZ == 0
clrC
movA, Temp2
rrcA
movTemp2, A
movA, Temp1
rrcA
movTemp1, A
ENDIF
jnbFlags1.STARTUP_PHASE, setup_zc_scan_timeout_startup_done

movA, Temp2
addA, #40h; Increase timeout somewhat to avoid false wind up
movTemp2, A

setup_zc_scan_timeout_startup_done:
clrIE_EA
anlEIE1, #7Fh; Disable timer 3 interrupts
movTMR3CN0, #00h; Timer 3 disabled and interrupt flag cleared
clrC
clrA
subbA, Temp1; Set timeout
movTMR3L, A
clrA
subbA, Temp2
movTMR3H, A
movTMR3CN0, #04h; Timer 3 enabled and interrupt flag cleared
setbFlags0.T3_PENDING
orlEIE1, #80h; Enable timer 3 interrupts
setbIE_EA

wait_before_zc_scan_exit:          
ret


原文地址:https://blog.csdn.net/aerror/article/details/136353455

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!