diff --git a/Bluejay.asm b/Bluejay.asm index d355979..9f3d825 100644 --- a/Bluejay.asm +++ b/Bluejay.asm @@ -109,11 +109,6 @@ Z_ EQU 26 ; Bm Cm Am Vn __ RX __ __ Ac Ap Bc Bp Cc Cp __ __ yes no high - Pino PWM_CENTERED EQU DEADTIME > 0 ; Use center aligned pwm on ESCs with dead time -IF MCU_48MHZ < 2 AND PWM_FREQ < 3 - ; Number of bits in pwm high byte - PWM_BITS_H EQU (2 + MCU_48MHZ - PWM_CENTERED - PWM_FREQ) -ENDIF - $include (Common.inc) ; Include common source code for EFM8BBx based ESCs ;**** **** **** **** **** @@ -136,6 +131,7 @@ DEFAULT_PGM_DITHERING EQU 1 ; 0=Disabled, 1=Enabled DEFAULT_PGM_STARTUP_POWER_MAX EQU 25 ; 0..255 => (1000..2000 Throttle): Maximum startup power DEFAULT_PGM_BRAKING_STRENGTH EQU 255 ; 0..255 => 0..100 % Braking +DEFAULT_PGM_PWM_FREQUENCY EQU 24 ; 24, 48, 96 [kHz] ;**** **** **** **** **** ; Temporary register definitions @@ -259,6 +255,10 @@ DShot_GCR_Pulse_Time_3_Tmp: DS 1 DShot_GCR_Start_Delay: DS 1 +Pwm_Bits_H: DS 1 +Pwm_H_Mask: DS 1 +Dithering_Mask: DS 1 + ;**** **** **** **** **** ; Indirect addressing data segments ISEG AT 080h ; The variables below must be in this sequence @@ -269,7 +269,7 @@ Pgm_Dithering: DS 1 ; Enable PWM dithering Pgm_Startup_Power_Max: DS 1 ; Maximum power (limit) during startup (and starting initial run phase) _Pgm_Rampup_Slope: DS 1 ; Pgm_Rpm_Power_Slope: DS 1 ; Low RPM power protection slope (factor) -Pgm_Pwm_Freq: DS 1 ; PWM frequency (temporary method for display) +Pgm_Pwm_Frequency: DS 1 ; PWM frequency [kHz] Pgm_Direction: DS 1 ; Rotation direction _Pgm_Input_Pol: DS 1 ; Input PWM polarity Initialized_L_Dummy: DS 1 ; Place holder @@ -316,7 +316,7 @@ Temp_Storage: DS 48 ; Temporary storage (internal memory) CSEG AT 1A00h EEPROM_FW_MAIN_REVISION EQU 0 ; Main revision of the firmware EEPROM_FW_SUB_REVISION EQU 16 ; Sub revision of the firmware -EEPROM_LAYOUT_REVISION EQU 204 ; Revision of the EEPROM layout +EEPROM_LAYOUT_REVISION EQU 205 ; Revision of the EEPROM layout Eep_FW_Main_Revision: DB EEPROM_FW_MAIN_REVISION ; EEPROM firmware main revision number Eep_FW_Sub_Revision: DB EEPROM_FW_SUB_REVISION ; EEPROM firmware sub revision number @@ -329,7 +329,7 @@ Eep_Pgm_Dithering: DB DEFAULT_PGM_DITHERING Eep_Pgm_Startup_Power_Max: DB DEFAULT_PGM_STARTUP_POWER_MAX _Eep_Pgm_Rampup_Slope: DB 0FFh Eep_Pgm_Rpm_Power_Slope: DB DEFAULT_PGM_RPM_POWER_SLOPE ; EEPROM copy of programmed rpm power slope (formerly startup power) -Eep_Pgm_Pwm_Freq: DB (24 SHL PWM_FREQ) ; Temporary method for display +Eep_Pgm_Pwm_Frequency: DB DEFAULT_PGM_PWM_FREQUENCY Eep_Pgm_Direction: DB DEFAULT_PGM_DIRECTION ; EEPROM copy of programmed rotation direction _Eep__Pgm_Input_Pol: DB 0FFh Eep_Initialized_L: DB 055h ; EEPROM initialized signature (lo byte) @@ -364,7 +364,7 @@ Eep_Pgm_LED_Control: DB DEFAULT_PGM_LED_CONTROL ; EEPROM copy of programmed LE Eep_Dummy: DB 0FFh ; EEPROM address for safety reason CSEG AT 1A60h -Eep_Name: DB "Bluejay " ; Name tag (16 Bytes) +Eep_Name: DB "Bluejay (TEST) " ; Name tag (16 Bytes) CSEG AT 1A70h Eep_Pgm_Beep_Melody: DB 2, 58, 4, 32, 52, 66, 13, 0, 69, 45, 13, 0, 52, 66, 13, 0, 78, 39, 211, 0, 69, 45, 208, 25, 52, 25, 0 @@ -933,22 +933,29 @@ t1_int_zero_rcp_checked: clr C mov A, Temp6 subb A, Temp2 ; 8-bit rc pulse - jnc t1_int_scale_pwm_resolution + jnc t1_int_pwm_scale_resolution -IF PWM_BITS_H == 0 ; 8-bit pwm + mov A, Pwm_Bits_H + jnz t1_int_pwm_limit_not_8bit +;IF PWM_BITS_H == 0 ; 8-bit pwm mov A, Temp6 mov Temp2, A -ELSE + sjmp t1_int_pwm_scale_resolution +;ELSE +t1_int_pwm_limit_not_8bit: mov A, Temp6 ; Multiply limit by 8 for 11-bit pwm mov B, #8 mul AB mov Temp4, A mov Temp5, B -ENDIF +;ENDIF -t1_int_scale_pwm_resolution: +t1_int_pwm_scale_resolution: ; Scale pwm resolution and invert (duty cycle is defined inversely) -IF PWM_BITS_H == 3 ; 11-bit pwm + + mov A, Pwm_Bits_H + cjne A, #3, t1_int_pwm_scale_10_bit +;IF PWM_BITS_H == 3 ; 11-bit pwm mov A, Temp5 cpl A anl A, #7 @@ -956,7 +963,10 @@ IF PWM_BITS_H == 3 ; 11-bit pwm mov A, Temp4 cpl A mov Temp2, A -ELSEIF PWM_BITS_H == 2 ; 10-bit pwm + sjmp t1_int_set_pwm ; No dithering for 11-bit pwm +;ELSEIF PWM_BITS_H == 2 ; 10-bit pwm +t1_int_pwm_scale_10_bit: + cjne A, #2, t1_int_pwm_scale_9_bit clr C mov A, Temp5 rrc A @@ -967,7 +977,10 @@ ELSEIF PWM_BITS_H == 2 ; 10-bit pwm rrc A cpl A mov Temp2, A -ELSEIF PWM_BITS_H == 1 ; 9-bit pwm + sjmp t1_int_pwm_dithering +;ELSEIF PWM_BITS_H == 1 ; 9-bit pwm +t1_int_pwm_scale_9_bit: + cjne A, #1, t1_int_pwm_scale_8_bit mov B, Temp5 mov A, Temp4 mov C, B.0 @@ -982,21 +995,22 @@ ELSEIF PWM_BITS_H == 1 ; 9-bit pwm cpl A anl A, #1 mov Temp3, A -ELSEIF PWM_BITS_H == 0 ; 8-bit pwm + sjmp t1_int_pwm_dithering +;ELSEIF PWM_BITS_H == 0 ; 8-bit pwm +t1_int_pwm_scale_8_bit: mov A, Temp2 ; Temp2 already 8-bit cpl A mov Temp2, A mov Temp3, #0 -ENDIF +;ENDIF +t1_int_pwm_dithering: ; 11-bit effective dithering of 8/9/10-bit pwm -IF PWM_BITS_H < 3 jnb Flag_Dithering, t1_int_set_pwm mov A, Temp4 ; 11-bit low byte cpl A - anl A, #((1 SHL (3 - PWM_BITS_H)) - 1); Get index into dithering pattern table - + anl A, Dithering_Mask ; Get index into dithering pattern table add A, #Dithering_Patterns mov Temp1, A ; Reuse DShot pwm pointer since it is not currently in use. mov A, @Temp1 ; Retrieve pattern @@ -1005,19 +1019,17 @@ IF PWM_BITS_H < 3 jnb ACC.0, t1_int_set_pwm ; Increment if bit is set + inc Temp2 mov A, Temp2 - add A, #1 - mov Temp2, A jnz t1_int_set_pwm -IF PWM_BITS_H != 0 +;IF PWM_BITS_H != 0 ; TODO: 8-bit optimization not applied + inc Temp3 mov A, Temp3 - addc A, #0 - mov Temp3, A - jnb ACC.PWM_BITS_H, t1_int_set_pwm + anl A, Pwm_H_Mask + jnz t1_int_set_pwm dec Temp3 ; Reset on overflow -ENDIF +;ENDIF dec Temp2 -ENDIF t1_int_set_pwm: ; Set pwm registers @@ -1055,26 +1067,30 @@ t1_int_max_braking_set: t1_int_pwm_braking_set: ENDIF - ; Note: Interrupts are not explicitly disabled - ; Assume higher priority interrupts (Int0, Timer0) to be disabled at this point -IF PWM_BITS_H != 0 + ; Note: Interrupts (of higher priority) are not explicitly disabled because + ; int0 is already disabled and timer 0 is assumed to be disabled at this point +;IF PWM_BITS_H != 0 + mov A, Pwm_Bits_H + jz t1_int_set_pwm_8_bit + ; Set power pwm auto-reload registers Set_Power_Pwm_Reg_L Temp2 Set_Power_Pwm_Reg_H Temp3 -ELSE - Set_Power_Pwm_Reg_H Temp2 -ENDIF - IF DEADTIME != 0 ; Set damp pwm auto-reload registers - IF PWM_BITS_H != 0 - Set_Damp_Pwm_Reg_L Temp4 - Set_Damp_Pwm_Reg_H Temp5 - ELSE - Set_Damp_Pwm_Reg_H Temp4 - ENDIF + Set_Damp_Pwm_Reg_L Temp4 + Set_Damp_Pwm_Reg_H Temp5 +ENDIF + sjmp t1_int_set_pwm_done +;ELSE +t1_int_set_pwm_8_bit: + Set_Power_Pwm_Reg_H Temp2 +IF DEADTIME != 0 + Set_Damp_Pwm_Reg_H Temp4 ENDIF +;ENDIF +t1_int_set_pwm_done: mov Rcp_Timeout_Cntd, #10 ; Set timeout count ; Prepare DShot telemetry @@ -3492,7 +3508,7 @@ set_default_parameters: imov Temp1, #DEFAULT_PGM_STARTUP_POWER_MAX ; Pgm_Startup_Power_Max imov Temp1, #0FFh ; _Pgm_Rampup_Slope imov Temp1, #DEFAULT_PGM_RPM_POWER_SLOPE ; Pgm_Rpm_Power_Slope - imov Temp1, #(24 SHL PWM_FREQ) ; Pgm_Pwm_Freq + imov Temp1, #DEFAULT_PGM_PWM_FREQUENCY ; Pgm_Pwm_Frequency imov Temp1, #DEFAULT_PGM_DIRECTION ; Pgm_Direction imov Temp1, #0FFh ; _Pgm_Input_Pol @@ -3593,21 +3609,45 @@ decode_temp_done: mov Temp1, #Pgm_Beep_Strength ; Read programmed beep strength setting mov Beep_Strength, @Temp1 ; Set beep strength - mov Temp1, #Pgm_Braking_Strength ; Read programmed braking strength setting + ; Decode pwm frequency setting + mov Temp1, #Pgm_Pwm_Frequency ; Read programmed pwm frequency setting mov A, @Temp1 -IF PWM_BITS_H == 3 ; Scale braking strength to pwm resolution - ; Note: Added for completeness + mov Temp2, #0 ; 24 kHz by default + cjne A, #48, ($+5) + mov Temp2, #1 ; 48 kHz + cjne A, #96, ($+5) + mov Temp2, #2 ; 96 kHz + + ; TODO: Simplify? + clr C + mov A, #(2 + MCU_48MHZ - PWM_CENTERED) + subb A, Temp2 + mov Pwm_Bits_H, A ; Number of bits in pwm high byte + + ; Decode pwm dithering and braking strength settings + mov Temp1, #Pgm_Dithering ; Read programmed dithering setting + mov A, @Temp1 + add A, #0FFh ; Carry set if A is not zero + mov Flag_Dithering, C ; Set dithering enabled + + mov A, Pwm_Bits_H + cjne A, #3, decode_pwm_h_2 ; Currently 11-bit pwm is only used on targets with built-in dead time insertion - rl A - rl A - rl A - mov Temp2, A - anl A, #07h - mov Pwm_Braking_H, A - mov A, Temp2 - anl A, #0F8h - mov Pwm_Braking_L, A -ELSEIF PWM_BITS_H == 2 + ; Not initializing pwm dithering or braking strength + sjmp decode_pwm_h_done + +decode_pwm_h_2: +;IF PWM_BITS_H == 2 ; Initialize pwm dithering bit patterns + cjne A, #2, decode_pwm_h_1 + mov Pwm_H_Mask, #03h + mov Dithering_Mask, #01h + + mov Temp1, #Dithering_Patterns ; 1-bit dithering (10-bit to 11-bit) + mov @Temp1, #00h ; 00000000 + imov Temp1, #55h ; 01010101 + + mov Temp1, #Pgm_Braking_Strength ; Scale 10-bit braking pwm + mov A, @Temp1 rl A rl A mov Temp2, A @@ -3616,7 +3656,22 @@ ELSEIF PWM_BITS_H == 2 mov A, Temp2 anl A, #0FCh mov Pwm_Braking_L, A -ELSEIF PWM_BITS_H == 1 + + sjmp decode_pwm_h_done +;ELSEIF PWM_BITS_H == 1 +decode_pwm_h_1: + cjne A, #1, decode_pwm_h_0 + mov Pwm_H_Mask, #01h + mov Dithering_Mask, #03h + + mov Temp1, #Dithering_Patterns ; 2-bit dithering (9-bit to 11-bit) + mov @Temp1, #00h ; 00000000 + imov Temp1, #11h ; 00010001 + imov Temp1, #55h ; 01010101 + imov Temp1, #77h ; 01110111 + + mov Temp1, #Pgm_Braking_Strength ; Scale 9-bit braking pwm + mov A, @Temp1 rl A mov Temp2, A anl A, #01h @@ -3624,30 +3679,14 @@ ELSEIF PWM_BITS_H == 1 mov A, Temp2 anl A, #0FEh mov Pwm_Braking_L, A -ELSEIF PWM_BITS_H == 0 - mov Pwm_Braking_H, #0 - mov Pwm_Braking_L, A -ENDIF - cjne @Temp1, #0FFh, decode_pwm_dithering - mov Pwm_Braking_L, #0FFh ; Apply full braking if setting is max -decode_pwm_dithering: - mov Temp1, #Pgm_Dithering ; Read programmed dithering setting - mov A, @Temp1 - add A, #0FFh ; Carry set if A is not zero - mov Flag_Dithering, C ; Set dithering enabled + sjmp decode_pwm_h_done +;ELSEIF PWM_BITS_H == 0 +decode_pwm_h_0: + cjne A, #0, decode_pwm_h_done + mov Pwm_H_Mask, #00h + mov Dithering_Mask, #07h -IF PWM_BITS_H == 2 ; Initialize pwm dithering bit patterns - mov Temp1, #Dithering_Patterns ; 1-bit dithering (10-bit to 11-bit) - mov @Temp1, #00h ; 00000000 - imov Temp1, #55h ; 01010101 -ELSEIF PWM_BITS_H == 1 - mov Temp1, #Dithering_Patterns ; 2-bit dithering (9-bit to 11-bit) - mov @Temp1, #00h ; 00000000 - imov Temp1, #11h ; 00010001 - imov Temp1, #55h ; 01010101 - imov Temp1, #77h ; 01110111 -ELSEIF PWM_BITS_H == 0 mov Temp1, #Dithering_Patterns ; 3-bit dithering (8-bit to 11-bit) mov @Temp1, #00h ; 00000000 imov Temp1, #01h ; 00000001 @@ -3657,7 +3696,18 @@ ELSEIF PWM_BITS_H == 0 imov Temp1, #5Bh ; 01011011 imov Temp1, #77h ; 01110111 imov Temp1, #7fh ; 01111111 -ENDIF + + mov Temp1, #Pgm_Braking_Strength ; Scale 8-bit braking pwm + mov A, @Temp1 + mov Pwm_Braking_H, #0 + mov Pwm_Braking_L, A +;ENDIF + +decode_pwm_h_done: + cjne @Temp1, #0FFh, decode_exit + mov Pwm_Braking_L, #0FFh ; Apply full braking if setting is max + +decode_exit: ret diff --git a/Common.inc b/Common.inc index f833ca5..b278cdc 100644 --- a/Common.inc +++ b/Common.inc @@ -156,7 +156,9 @@ Initialize_PCA MACRO mov PCA0CN0, #40h ;; PCA enabled mov PCA0MD, #08h ;; PCA clock is system clock - mov PCA0PWM, #(80h + PWM_BITS_H) ;; Enable PCA auto-reload registers and set pwm cycle length (8-11 bits) + mov A, #80h ;; Enable PCA auto-reload registers + add A, Pwm_Bits_H ;; Set pwm cycle length (8-11 bits) + mov PCA0PWM, A IF PWM_CENTERED == 1 mov PCA0CENT, #07h ;; Center aligned pwm diff --git a/Makefile b/Makefile index f8a307b..413c0e1 100644 --- a/Makefile +++ b/Makefile @@ -3,16 +3,14 @@ TAG := $(shell git describe --tags --abbrev=0) VERSION ?= $(TAG) # Target parameters -LAYOUTS = A B C D E F G H I J K L M N O P Q R S T U V W Z -MCUS = H L -DEADTIMES = 0 5 10 15 20 25 30 40 50 70 90 120 -PWM_FREQS = 24 48 96 +LAYOUTS = A C F G J M O P Q R S Z +MCUS = H +DEADTIMES = 5 10 15 20 25 30 40 50 70 90 # Example single target LAYOUT ?= A MCU ?= H DEADTIME ?= 5 -PWM ?= 24 # Directory configuration OUTPUT_DIR ?= build @@ -56,14 +54,13 @@ EFM8_LOAD_BAUD ?= 115200 .NOTPARALLEL: define MAKE_OBJ -OBJS += $(1)_$(2)_$(3)_$(4)_$(VERSION).OBJ -$(OUTPUT_DIR)/$(1)_$(2)_$(3)_$(4)_$(VERSION).OBJ : $(ASM_SRC) $(ASM_INC) +OBJS += $(1)_$(2)_$(3)_$(VERSION).OBJ +$(OUTPUT_DIR)/$(1)_$(2)_$(3)_$(VERSION).OBJ : $(ASM_SRC) $(ASM_INC) $(eval _ESC := $(1)) $(eval _ESC_INT := $(shell printf "%d" "'${_ESC}")) $(eval _ESCNO := $(shell echo $$(( $(_ESC_INT) - 65 + 1)))) $(eval _MCU_48MHZ := $(subst L,0,$(subst H,1,$(2)))) $(eval _DEADTIME := $(3)) - $(eval _PWM_FREQ := $(subst 24,0,$(subst 48,1,$(subst 96,2,$(4))))) $$(eval _LST := $$(patsubst %.OBJ,%.LST,$$@)) @mkdir -p $(OUTPUT_DIR) @echo "AX51 : $$@" @@ -71,13 +68,12 @@ $(OUTPUT_DIR)/$(1)_$(2)_$(3)_$(4)_$(VERSION).OBJ : $(ASM_SRC) $(ASM_INC) "DEFINE(ESCNO=$(_ESCNO)) " \ "DEFINE(MCU_48MHZ=$(_MCU_48MHZ)) "\ "DEFINE(DEADTIME=$(_DEADTIME)) "\ - "DEFINE(PWM_FREQ=$(_PWM_FREQ)) "\ "OBJECT($$@) "\ "PRINT($$(_LST)) "\ "$(AX51_FLAGS)" > /dev/null 2>&1 || (grep -B 3 -E "\*\*\* (ERROR|WARNING)" $$(_LST); exit 1) endef -SINGLE_TARGET_HEX = $(HEX_DIR)/$(LAYOUT)_$(MCU)_$(DEADTIME)_$(PWM)_$(VERSION).hex +SINGLE_TARGET_HEX = $(HEX_DIR)/$(LAYOUT)_$(MCU)_$(DEADTIME)_$(VERSION).hex single_target : $(SINGLE_TARGET_HEX) @@ -85,8 +81,7 @@ single_target : $(SINGLE_TARGET_HEX) $(foreach _l, $(LAYOUTS), \ $(foreach _m, $(MCUS), \ $(foreach _d, $(DEADTIMES), \ - $(foreach _p, $(filter-out $(subst L,96,$(_m)), $(PWM_FREQS)), \ - $(eval $(call MAKE_OBJ,$(_l),$(_m),$(_d),$(_p))))))) + $(eval $(call MAKE_OBJ,$(_l),$(_m),$(_d)))))) HEX_TARGETS = $(OBJS:%.OBJ=$(HEX_DIR)/%.hex) @@ -120,9 +115,9 @@ changelog: help: @echo "" @echo "Usage examples" - @echo "================================================================" - @echo "make all # Build all targets" - @echo "make LAYOUT=A MCU=H DEADTIME=5 PWM=24 # Build a single target" + @echo "========================================================" + @echo "make all # Build all targets" + @echo "make LAYOUT=A MCU=H DEADTIME=5 # Build a single target" @echo clean: