diff --git a/.editorconfig b/.editorconfig
index e4576613..f08cad1b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,16 +1,13 @@
root = true
[*]
-indent_style = tab
+indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-[*.{asm,inc}]
-indent_size = 5
-
-[*.{yml,yaml}]
+[*.{yml,yaml,sh}]
indent_style = space
indent_size = 2
diff --git a/BLHeliBootLoad.inc b/BLHeliBootLoad.inc
deleted file mode 100644
index ce91cc38..00000000
--- a/BLHeliBootLoad.inc
+++ /dev/null
@@ -1,396 +0,0 @@
-; BLHeli bootloader for SiLabs MCUs. Based upon AVRootloader (copyright HR)
-
-XTAL EQU 25000000
-
-; Bootloader segment address
-IF MCU_TYPE < 2
- BOOT_START EQU 1C00h
-ELSEIF MCU_TYPE == 2
- BOOT_START EQU 0F000h
-ENDIF
-
-BOOT_DELAY EQU XTAL/4 ; About 250ms (don't set to fast to avoid connection problems)
-BOOT_BAUDRATE EQU 19200 ; Only used if no baudrate detection activated, XTAL is than important
-BOOT_VERSION EQU 6 ; Version 6 (must be not changed)
-BOOT_PAGES EQU 1 ; Number of flash segments for bootloader
-
-UART_LOOP EQU 26 ; Depends upon timing of putc, getc
-BAUDTIME EQU ((XTAL/BOOT_BAUDRATE)/3)-UART_LOOP
-
-SUCCESS EQU 030h
-ERRORVERIFY EQU 0C0h
-ERRORCOMMAND EQU 0C1h
-ERRORCRC EQU 0C2h
-ERRORPROG EQU 0C5h
-
-POLYNOM EQU 0A001h ; CRC Polynom
-
-Xl EQU R0 ; Temporary X
-Xh EQU R1
-Paral EQU R2 ; Params for UART
-Parah EQU R3
-Cmdl EQU R4 ; Commands
-Cmdh EQU R5
-Cntl EQU R6 ; Baudtime
-Cnth EQU R7
-
-DSEG AT 20h
-Bit_Reg: DS 1 ; Bit storage register
-Byte_Reg: DS 1 ; Byte storage register
-Crcl: DS 1 ; CRC 16Bit
-Crch: DS 1
-Baudl: DS 1 ; Baudtime
-Baudh: DS 1
-Bit_Cnt: DS 1 ; Counter in UART loops
-Byte_Cntl: DS 1 ; Generic counter
-Byte_Cnth: DS 1
-BL_Flash_Key_1: DS 1 ; Flash keys
-BL_Flash_Key_2: DS 1
-
-CSEG AT BOOT_START ; Bootloader start
-init:clr IE_EA
- ; Select register bank 0 for main program routines
- clr PSW.3 ; Select register bank 0 for main program routines
- ; Disable the WDT.
- mov WDTCN, #0DEh ; Disable watchdog
- mov WDTCN, #0ADh
- ; Initialize stack
- mov SP, #0c0h ; Stack = 64 upper bytes of RAM
- ; Initialize clock
- mov CLKSEL, #00h ; Set clock divider to 1
- IF MCU_TYPE < 2
- ; Initialize VDD monitor
- orl VDM0CN, #080h ; Enable the VDD monitor
- ENDIF
- mov Baudl, #38h ; Wait 100us
- mov Baudh, #03h
- acall waitf
- ; Initialize flash keys
- mov BL_Flash_Key_1, #0A5h ; First key code
- mov BL_Flash_Key_2, #0F1h ; Second key code
- ; Initialize ports
- orl RTX_MDIN, #(1 SHL RTX_PIN) ; Set digital
- anl RTX_MDOUT, #NOT(1 SHL RTX_PIN) ; Disable pushpull
- setb RTX_PORT.RTX_PIN ; Set data high
- mov RTX_SKIP, #0FFh
- mov XBR2, #40h; ; Enable crossbar
- ; Set number of connect attempts before exiting bootloader
- mov Cmdh, #250
-
- ; Identifier scanning
-abd: mov Xl, #(low(BOOT_DELAY / 6)+1)
- mov Xh, #(high(BOOT_DELAY / 6)+1)
- mov Cmdl, #(high((BOOT_DELAY / 6) SHR 8)+1)
- mov Crcl, #0
- mov Crch, #0
- mov DPTR, #BOOT_SIGN
- mov Parah, #(BOOT_MSG - BOOT_SIGN)
- mov Baudl, #low(BAUDTIME)
- mov Baudh, #high(BAUDTIME)
-
-wait_for_low:
- jnb RTX_PORT.RTX_PIN, ($+5)
- ajmp wait_for_low
-
- ; Identifier (BOOT_SIGN) scanning with timeout and checksum
-id1: jb RTX_PORT.RTX_PIN, id3 ; Look for high
- djnz Xl, id1 ; Subtract 1 from X (BOOT_DELAY)
- djnz Xh, id1
- djnz Cmdl, id1
-
- ajmp exit
-
-id3: jnb RTX_PORT.RTX_PIN, id4 ; Look for low
- djnz Xl, id3 ; Subtract 1 from X (BOOT_DELAY)
- djnz Xh, id3
- djnz Cmdl, id3
-
- ajmp exit
-
-id4: acall getx ; Read character
- clr A
- movc A, @A+DPTR ; Load BOOT_SIGN character
- inc DPTR
- clr C
- subb A, Paral ; Compare with read character
- jz id5
- djnz Cmdh, abd ; Retry if not last connect attempt
- ajmp exit
-
-id5:
- djnz Parah, id1
-
- acall getw ; Read CRC
- jz ($+4) ; Check CRC
- ajmp abd
-
- ; Send info about chip/bootloader (BOOT_MSG + BOOT_INFO)
- mov Parah, #((BOOT_INFO - BOOT_MSG) + 4)
-in1: clr A
- movc A, @A+DPTR ; Load character
- mov Paral, A
- inc DPTR
- acall putc
- djnz Parah, in1
-
-
- ; Main commandloop
- ; 0=Run/restart
- ; 1=Program flash, 2=Erase flash, 3=Read flash
- ; 0xFF=Set address, 0xFE=Set buffer, 0xFD=Keep alive
-main:mov Paral, #SUCCESS
-mai1:acall putc
- mov Crcl, #0 ; Reset CRC
- mov Crch, #0
- acall getw ; Get command
- mov A, Paral
- mov Cmdl, A
- mov A, Parah
- mov Cmdh, A
- clr C
- mov A, Cmdh
- subb A, #0FEh
- jc mai2 ; Jump if not set address or set buffer
-
- acall getw ; Address or number of bytes
- mov Byte_Cntl, Paral ; Store number of bytes for set buffer
- mov Byte_Cnth, Parah
- mov A, Cmdh
- jnb ACC.0, mai2 ; Jump if set buffer
-
- mov DPL, Paral ; Store flash address (for set address)
- mov DPH, Parah
-
-mai2:acall getw ; Get CRC
- mov Paral, #ERRORCRC
- jnz mai1
- clr C
- mov A, Cmdh
- subb A, #0FEh
- jz setbuf ; If command is set buffer, receive data
- jnc main
-
- cjne Cmdh, #0, mai4 ; Jump if command != 0 (and not set buffer)
-
- ; Run application/restart bootloader
- mov A, Cmdl
- jz rst
-exit:mov Bit_Access, #0 ; Clear variable used by flash lock detect
- mov Bit_Access_Int, #0FFh ; Set variable to indicate that program execution came from bootloader
- mov BL_Flash_Key_1, #0 ; Set flash keys to invalid values
- mov BL_Flash_Key_2, #0
- ljmp 0000h
-rst: ajmp init
-
- ; Set buffer
-setbuf:mov Xl, Byte_Cntl ; Set number of bytes
- mov Xh, Byte_Cnth
- inc Xl
- inc Xh
-set4:djnz Xl, set5
- djnz Xh, set5
- ajmp set6
-
-set5:acall getc ; Receive data
- mov A, Paral
- movx @Xl, A ; Store data in XRAM
- ajmp set4
-
-set6:inc Cmdh
- ajmp mai2
-
-mai4:clr C
- mov A, Cmdh
- subb A, #3
- jnc mai5 ; Jump if command >= 3
-
- ; Program/erase
- mov A, Cmdh
- mov C, ACC.0
- mov Bit_Reg.0, C
- mov Paral, #ERRORPROG
- clr C
- mov A, DPL
- subb A, #low(BOOT_START)
- mov A, DPH
- subb A, #high(BOOT_START)
- jnc mai1 ; Jump if in bootloader segment
- jb Bit_Reg.0, pro3 ; Jump if program command
-
- ; Erase flash
- orl PSCTL, #02h ; Set the PSEE bit
- orl PSCTL, #01h ; Set the PSWE bit
- mov FLKEY, BL_Flash_Key_1 ; First key code
- mov FLKEY, BL_Flash_Key_2 ; Second key code
- movx @DPTR, A
- jnb Bit_Reg.0, pro6 ; Jump if erase command
-
- ; Program flash
-pro3:mov Xl, Byte_Cntl ; Set number of bytes
- mov Xh, Byte_Cnth
- inc Xl
- inc Xh
- orl PSCTL, #01h ; Set the PSWE bit
- anl PSCTL, #0FDh ; Clear the PSEE bit
-pro4:djnz Xl, pro5
- djnz Xh, pro5
- ajmp pro6
-
-pro5:
- clr C
- mov A, DPH ; Check that address is not in bootloader area
- IF MCU_TYPE < 2
- subb A, #1Ch
- ELSEIF MCU_TYPE == 2
- subb A, #0F0h
- ENDIF
- jc ($+5)
-
- inc DPTR ; Increment flash address
- ajmp pro4
-
- movx A, @Xl ; Read from XRAM
- mov FLKEY, BL_Flash_Key_1 ; First key code
- mov FLKEY, BL_Flash_Key_2 ; Second key code
- movx @DPTR, A ; Write to flash
- inc DPTR ; Increment flash address
- ajmp pro4
-
-pro6:anl PSCTL, #0FCh ; Clear the PSEE and PSWE bits
- ajmp main ; Successfully done erase or program
-
- ; Read flash
-mai5:mov Paral, #ERRORCOMMAND ; Illegal command
- cjne Cmdh, #3, mai6 ; Jump if not read flash command
-
-rd1: clr A
- movc A, @A+DPTR ; Read from flash
- inc DPTR ; Increment flash address
- mov Paral, A
- acall putp
- djnz Cmdl, rd1 ; Decrement bytes to read
-
- acall putw ; CRC
- ajmp main
-
-mai6:ajmp mai1
-
-
-
-
- ; Send char with crc
-putw:mov Paral, Crcl
- mov Parah, Crch
- acall putc
- mov A, Parah
- mov Paral, A
-putp:mov A, Paral
- xrl Crcl, A
- mov Bit_Cnt, #8
-put1:clr C
- mov A, Crch
- rrc A
- mov Crch, A
- mov A, Crcl
- rrc A
- mov Crcl, A
- jnc put2
-
- xrl Crch, #high(POLYNOM)
- xrl Crcl, #low(POLYNOM)
-
-put2:djnz Bit_Cnt, put1
-
-
- ; Send char
-putc:acall waitf
- acall waitf
- mov Bit_Cnt, #10
- mov A, Paral
- cpl A
-put3:jb Bit_Reg.1, ($+5)
- setb RTX_PORT.RTX_PIN ; Set pin high
- jnb Bit_Reg.1, ($+5)
- clr RTX_PORT.RTX_PIN ; Set pin low
- acall waitf
- clr C
- rrc A
- jc put4
-
- clr Bit_Reg.1
-
-put4:djnz Bit_Cnt, put3
-
- ret
-
-
- ; Receive char/word
-getw:acall getc
- mov A, Paral
- mov Parah, A
-getc:jb RTX_PORT.RTX_PIN, ($+5) ; Wait for high
- ajmp getc
-
-get1:jnb RTX_PORT.RTX_PIN, ($+5) ; Wait for low
- ajmp get1
-
-getx:mov Bit_Cnt, #8
- mov Cntl, Baudl
- mov Cnth, Baudh
- clr C
- mov A, Cnth ; Wait half a baud
- rrc A
- mov Cnth, A
- mov A, Cntl
- rrc A
- mov Cntl, A
- acall waith
-get2:acall waitf ; Wait one baud
- clr C
- mov A, Paral
- rrc A
- jnb RTX_PORT.RTX_PIN, ($+5)
- orl A, #080h
-
- mov Paral, A
- jnb ACC.7, ($+6)
- xrl Crcl, #low(POLYNOM)
-
- clr C
- mov A, Crch
- rrc A
- mov Crch, A
- mov A, Crcl
- rrc A
- mov Crcl, A
- jnc get3
-
- xrl Crch, #high(POLYNOM)
- xrl Crcl, #low(POLYNOM)
-
-get3:djnz Bit_Cnt, get2
-
- mov A, Crcl
- xrl A, Crch
- xrl A, Crch
- mov Crcl, A
- ret
-
-
- ; UART delays
-waitf:mov Cntl, Baudl
- mov Cnth, Baudh
-waith:inc Cntl
- inc Cnth
-wait1:djnz Cntl, wait1
- djnz Cnth, wait1
-
- setb Bit_Reg.1
- ret
-
-
-BOOT_SIGN: DB "BLHeli"
-
-BOOT_MSG: DB "471d" ; Interface-MCU_BootlaoderRevision
-
-BOOT_INFO: DB SIGNATURE_001, SIGNATURE_002, BOOT_VERSION, BOOT_PAGES
diff --git a/Bluejay.asm b/Bluejay.asm
deleted file mode 100644
index 05533698..00000000
--- a/Bluejay.asm
+++ /dev/null
@@ -1,4676 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Bluejay is a fork of BLHeli_S by Steffen Skaug.
-;
-; The input signal can be DShot with rates: DShot150, DShot300 and DShot600.
-;
-; This file is best viewed with tab width set to 5.
-;
-;**** **** **** **** ****
-; Master clock is internal 24MHz oscillator (or 48MHz, for which the times below are halved)
-; Although 24/48 are used in the code, the exact clock frequencies are 24.5MHz or 49.0 MHz
-; Timer0 (41.67ns counts) always counts up and is used for
-; - RC pulse measurement
-; - DShot telemetry pulse timing
-; Timer1 (41.67ns counts) always counts up and is used for
-; - DShot frame sync detection
-; Timer2 (500ns counts) always counts up and is used for
-; - RC pulse timeout counts and commutation times
-; Timer3 (500ns counts) always counts up and is used for
-; - Commutation timeouts
-; PCA0 (41.67ns counts) always counts up and is used for
-; - Hardware PWM generation
-;
-;**** **** **** **** ****
-; Motor control:
-; - Brushless motor control with 6 states for each electrical 360 degrees
-; - An advance timing of 0deg has zero cross 30deg after one commutation and 30deg before the next
-; - Timing advance in this implementation is set to 15deg nominally
-; - Motor pwm is always damped light (aka complementary pwm, regenerative braking)
-; Motor sequence starting from zero crossing:
-; - Timer wait: Wt_Comm 15deg ; Time to wait from zero cross to actual commutation
-; - Timer wait: Wt_Advance 15deg ; Time to wait for timing advance. Nominal commutation point is after this
-; - Timer wait: Wt_Zc_Scan 7.5deg ; Time to wait before looking for zero cross
-; - Scan for zero cross 22.5deg ; Nominal, with some motor variations
-;
-; Motor startup:
-; There is a startup phase and an initial run phase, before normal bemf commutation run begins.
-;
-;**** **** **** **** ****
-; Legend:
-; RX Receive/transmit pin
-; Am, Bm, Cm Comparator inputs for BEMF
-; Vn Common Comparator input
-; Ap, Bp, Cp PWM pins
-; Ac, Bc, Cc Complementary PWM pins
-;
-;**** **** **** **** ****
-; List of enumerated supported ESCs
- ; PORT 0 PORT 1 PWM COM PWM LED
- ; P0 P1 P2 P3 P4 P5 P6 P7 P0 P1 P2 P3 P4 P5 P6 P7 inv inv side n
- ; ----------------------- ----------------------- ------------------
-IF MCU_TYPE < 2
-A_ EQU 1 ; Vn Am Bm Cm __ RX __ __ Ap Ac Bp Bc Cp Cc __ __ no no high _
-B_ EQU 2 ; Vn Am Bm Cm __ RX __ __ Cc Cp Bc Bp Ac Ap __ __ no no high _
-C_ EQU 3 ; RX __ Vn Am Bm Cm Ap Ac Bp Bc Cp Cc __ __ __ __ no no high _
-D_ EQU 4 ; Bm Cm Am Vn __ RX __ __ Ap Ac Bp Bc Cp Cc __ __ no yes high _
-E_ EQU 5 ; Vn Am Bm Cm __ RX L0 L1 Ap Ac Bp Bc Cp Cc L2 __ no no high 3 Pinout like A, with LEDs
-F_ EQU 6 ; Vn Cm Bm Am __ RX __ __ Ap Ac Bp Bc Cp Cc __ __ no no high _
-G_ EQU 7 ; Bm Cm Am Vn __ RX __ __ Ap Ac Bp Bc Cp Cc __ __ no no high _ Pinout like D, but non-inverted com FETs
-H_ EQU 8 ; Cm Vn Bm Am __ __ __ RX Cc Bc Ac __ Cp Bp Ap __ no no high _
-I_ EQU 9 ; Vn Am Bm Cm __ RX __ __ Cp Bp Ap Cc Bc Ac __ __ no no high _
-J_ EQU 10 ; Am Cm Bm Vn RX L0 L1 L2 Ap Bp Cp Ac Bc Cc __ __ no no high 3
-K_ EQU 11 ; RX Am Vn Bm __ Cm __ __ Ac Bc Cc Cp Bp Ap __ __ no yes high _
-L_ EQU 12 ; Cm Bm Am Vn __ RX __ __ Cp Bp Ap Cc Bc Ac __ __ no no high _
-M_ EQU 13 ; __ __ L0 RX Bm Vn Cm Am __ Ap Bp Cp Ac Bc Cc __ no no high 1
-N_ EQU 14 ; Vn Am Bm Cm __ RX __ __ Ac Ap Bc Bp Cc Cp __ __ no no high _
-O_ EQU 15 ; Bm Cm Am Vn __ RX __ __ Ap Ac Bp Bc Cp Cc __ __ no yes low _ Pinout Like D, but low side pwm
-P_ EQU 16 ; __ Cm Bm Vn Am RX __ __ __ Ap Bp Cp Ac Bc Cc __ no no high _
-Q_ EQU 17 ; __ RX __ L0 L1 Ap Bp Cp Ac Bc Cc Vn Cm Bm Am __ no no high 2
-R_ EQU 18 ; Vn Am Bm Cm __ RX __ __ Cp Bp Ap Cc Bc Ac __ __ no no high _ Same as I
-S_ EQU 19 ; Bm Cm Am Vn __ RX __ __ Ac Ap Bc Bp Cc Cp __ __ no no high _
-T_ EQU 20 ; __ Cm Vn Bm __ Am __ RX Cc Bc Ac Ap Bp Cp __ __ no no high _
-U_ EQU 21 ; L2 L1 L0 RX Bm Vn Cm Am __ Ap Bp Cp Ac Bc Cc __ no no high 3 Pinout like M, with 3 LEDs
-V_ EQU 22 ; Am Bm Vn Cm __ RX __ Cc Cp Bc __ __ Bp Ac Ap __ no no high _
-W_ EQU 23 ; __ __ Am Vn __ Bm Cm RX __ __ __ __ Cp Bp Ap __ n/a n/a high _ Tristate gate driver
-X_ EQU 24
-Y_ EQU 25
-Z_ EQU 26 ; Bm Cm Am Vn __ RX __ __ Ac Ap Bc Bp Cc Cp __ __ yes no high _ Pinout like S, but inverted pwm FETs
-ENDIF
-
-; BB51 - Required
-IF MCU_TYPE = 2
-A_ EQU 1 ; __ Bm Cm Am Vn RX __ __ Ap Ac Bp Bc Cp Cc __ __ no no low _
-B_ EQU 2 ; __ Bm Cm Am Vn RX __ __ Ac Ap Bc Bp Cc Cp __ __ no yes high _
-C_ EQU 3 ; __ Bm Cm Am Vn RX __ __ Ac Ap Bc Bp Cc Cp __ __ yes yes high _
-ENDIF
-
-;**** **** **** **** ****
-; Select the port mapping to use (or unselect all for use with external batch compile file)
-;ESCNO EQU A_
-
-;**** **** **** **** ****
-; Select the MCU type (or unselect for use with external batch compile file)
-;MCU_TYPE EQU 0 ; BB1
-;MCU_TYPE EQU 1 ; BB2
-;MCU_TYPE EQU 2 ; BB51
-
-;**** **** **** **** ****
-; Select the FET dead time (or unselect for use with external batch compile file)
-;DEADTIME EQU 15 ; 20.4ns per step
-
-;**** **** **** **** ****
-; Select the pwm frequency (or unselect for use with external batch compile file)
-;PWM_FREQ EQU 0 ; 0=24, 1=48, 2=96 kHz
-
-PWM_CENTERED EQU DEADTIME > 0 ; Use center aligned pwm on ESCs with dead time
-
-IF MCU_TYPE == 0
- IS_MCU_48MHZ EQU 0
-ELSE
- IS_MCU_48MHZ EQU 1
-ENDIF
-
-IF MCU_TYPE < 3 AND PWM_FREQ < 3
- ; Number of bits in pwm high byte
- PWM_BITS_H EQU (2 + IS_MCU_48MHZ - PWM_CENTERED - PWM_FREQ)
-ENDIF
-
-$include (Common.inc) ; Include common source code for EFM8BBx based ESCs
-
-;**** **** **** **** ****
-; Programming defaults
-DEFAULT_PGM_RPM_POWER_SLOPE EQU 9 ; 0=Off, 1..13 (Power limit factor in relation to rpm)
-DEFAULT_PGM_COMM_TIMING EQU 4 ; 1=Low 2=MediumLow 3=Medium 4=MediumHigh 5=High
-DEFAULT_PGM_DEMAG_COMP EQU 2 ; 1=Disabled 2=Low 3=High
-DEFAULT_PGM_DIRECTION EQU 1 ; 1=Normal 2=Reversed 3=Bidir 4=Bidir rev
-DEFAULT_PGM_BEEP_STRENGTH EQU 40 ; 0..255 (BLHeli_S is 1..255)
-DEFAULT_PGM_BEACON_STRENGTH EQU 80 ; 0..255
-DEFAULT_PGM_BEACON_DELAY EQU 4 ; 1=1m 2=2m 3=5m 4=10m 5=Infinite
-DEFAULT_PGM_ENABLE_TEMP_PROT EQU 7 ; 0=Disabled 1=80C 2=90C 3=100C 4=110C 5=120C 6=130C 7=140C
-
-DEFAULT_PGM_POWER_RATING EQU 2 ; 1=1S, 2=2S+
-
-DEFAULT_PGM_BRAKE_ON_STOP EQU 0 ; 1=Enabled 0=Disabled
-DEFAULT_PGM_LED_CONTROL EQU 0 ; Byte for LED control. 2 bits per LED, 0=Off, 1=On
-
-DEFAULT_PGM_STARTUP_POWER_MIN EQU 51 ; 0..255 => (1000..1125 Throttle): value * (1000 / 2047) + 1000
-DEFAULT_PGM_STARTUP_BEEP EQU 1 ; 0=Short beep, 1=Melody
-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
-
-;**** **** **** **** ****
-; Temporary register definitions
-Temp1 EQU R0
-Temp2 EQU R1
-Temp3 EQU R2
-Temp4 EQU R3
-Temp5 EQU R4
-Temp6 EQU R5
-Temp7 EQU R6
-Temp8 EQU R7
-
-;**** **** **** **** ****
-; RAM definitions
-; Bit-addressable data segment
-DSEG AT 20h
-Bit_Access: DS 1 ; MUST BE AT THIS ADDRESS. Variable at bit accessible address (for non interrupt routines)
-Bit_Access_Int: DS 1 ; Variable at bit accessible address (for interrupts)
-
-Flags0: DS 1 ; State flags. Reset upon motor_start
-Flag_Startup_Phase BIT Flags0.0 ; Set when in startup phase
-Flag_Initial_Run_Phase BIT Flags0.1 ; Set when in initial run phase (or startup phase), before synchronized run is achieved.
-Flag_Motor_Dir_Rev BIT Flags0.2 ; Set if the current spinning direction is reversed
-Flag_Demag_Notify BIT Flags0.3 ; Set when motor demag has been detected but still not notified
-Flag_Desync_Notify BIT Flags0.4 ; Set when motor desync has been detected but still not notified
-Flag_Stall_Notify BIT Flags0.5 ; Set when motor stall detected but still not notified
-
-Flags1: DS 1 ; State flags. Reset upon motor_start
-Flag_Timer3_Pending BIT Flags1.0 ; Timer3 pending flag
-Flag_Demag_Detected BIT Flags1.1 ; Set when excessive demag time is detected
-Flag_Comp_Timed_Out BIT Flags1.2 ; Set when comparator reading timed out
-Flag_Motor_Running BIT Flags1.3
-Flag_Motor_Started BIT Flags1.4 ; Set when motor is started
-Flag_Dir_Change_Brake BIT Flags1.5 ; Set when braking before direction change in case of bidirectional operation
-Flag_High_Rpm BIT Flags1.6 ; Set when motor rpm is high (Comm_Period4x_H less than 2)
-
-Flags2: DS 1 ; State flags. NOT reset upon motor_start
-; BIT Flags2.0
-Flag_Pgm_Dir_Rev BIT Flags2.1 ; Set if the programmed direction is reversed
-Flag_Pgm_Bidir BIT Flags2.2 ; Set if the programmed control mode is bidirectional operation
-Flag_32ms_Elapsed BIT Flags2.3 ; Set when timer2 interrupt is triggered
-Flag_Ext_Tele BIT Flags2.4 ; Set if Extended DHOT telemetry is enabled
-Flag_Rcp_Stop BIT Flags2.5 ; Set if the RC pulse value is zero or if timeout occurs
-Flag_Rcp_Dir_Rev BIT Flags2.6 ; RC pulse direction in bidirectional mode
-Flag_Rcp_DShot_Inverted BIT Flags2.7 ; DShot RC pulse input is inverted (and supports telemetry)
-
-Flags3: DS 1 ; State flags. NOT reset upon motor_start
-Flag_Telemetry_Pending BIT Flags3.0 ; DShot telemetry data packet is ready to be sent
-Flag_Dithering BIT Flags3.1 ; PWM dithering enabled
-Flag_Had_Signal BIT Flags3.2 ; Used to detect reset after having had a valid signal
-
-Tlm_Data_L: DS 1 ; DShot telemetry data (lo byte)
-Tlm_Data_H: DS 1 ; DShot telemetry data (hi byte)
-
-;**** **** **** **** ****
-; Direct addressing data segment
-DSEG AT 30h
-Rcp_Outside_Range_Cnt: DS 1 ; RC pulse outside range counter (incrementing)
-Rcp_Timeout_Cntd: DS 1 ; RC pulse timeout counter (decrementing)
-Rcp_Stop_Cnt: DS 1 ; Counter for RC pulses below stop value
-
-Beacon_Delay_Cnt: DS 1 ; Counter to trigger beacon during wait for start
-
-Startup_Cnt: DS 1 ; Startup phase commutations counter (incrementing)
-Startup_Zc_Timeout_Cntd: DS 1 ; Startup zero cross timeout counter (decrementing)
-Initial_Run_Rot_Cntd: DS 1 ; Initial run rotations counter (decrementing)
-Startup_Stall_Cnt: DS 1 ; Counts start/run attempts that resulted in stall. Reset upon a proper stop
-Demag_Detected_Metric: DS 1 ; Metric used to gauge demag event frequency
-Demag_Detected_Metric_Max: DS 1 ; Metric used to gauge demag event frequency
-Demag_Pwr_Off_Thresh: DS 1 ; Metric threshold above which power is cut
-Low_Rpm_Pwr_Slope: DS 1 ; Sets the slope of power increase for low rpm
-
-Timer2_X: DS 1 ; Timer2 extended byte
-Prev_Comm_L: DS 1 ; Previous commutation Timer2 timestamp (lo byte)
-Prev_Comm_H: DS 1 ; Previous commutation Timer2 timestamp (hi byte)
-Prev_Comm_X: DS 1 ; Previous commutation Timer2 timestamp (ext byte)
-Prev_Prev_Comm_L: DS 1 ; Pre-previous commutation Timer2 timestamp (lo byte)
-Prev_Prev_Comm_H: DS 1 ; Pre-previous commutation Timer2 timestamp (hi byte)
-Comm_Period4x_L: DS 1 ; Timer2 ticks between the last 4 commutations (lo byte)
-Comm_Period4x_H: DS 1 ; Timer2 ticks between the last 4 commutations (hi byte)
-Comparator_Read_Cnt: DS 1 ; Number of comparator reads done
-
-Wt_Adv_Start_L: DS 1 ; Timer3 start point for commutation advance timing (lo byte)
-Wt_Adv_Start_H: DS 1 ; Timer3 start point for commutation advance timing (hi byte)
-Wt_Zc_Scan_Start_L: DS 1 ; Timer3 start point from commutation to zero cross scan (lo byte)
-Wt_Zc_Scan_Start_H: DS 1 ; Timer3 start point from commutation to zero cross scan (hi byte)
-Wt_Zc_Tout_Start_L: DS 1 ; Timer3 start point for zero cross scan timeout (lo byte)
-Wt_Zc_Tout_Start_H: DS 1 ; Timer3 start point for zero cross scan timeout (hi byte)
-Wt_Comm_Start_L: DS 1 ; Timer3 start point from zero cross to commutation (lo byte)
-Wt_Comm_Start_H: DS 1 ; Timer3 start point from zero cross to commutation (hi byte)
-
-Pwm_Limit: DS 1 ; Maximum allowed pwm (8-bit)
-Pwm_Limit_By_Rpm: DS 1 ; Maximum allowed pwm for low or high rpm (8-bit)
-Pwm_Limit_Beg: DS 1 ; Initial pwm limit (8-bit)
-
-Pwm_Braking_L: DS 1 ; Max Braking pwm (lo byte)
-Pwm_Braking_H: DS 1 ; Max Braking pwm (hi byte)
-
-Temp_Prot_Limit: DS 1 ; Temperature protection limit
-Temp_Pwm_Level_Setpoint: DS 1 ; PWM level setpoint
-
-Beep_Strength: DS 1 ; Strength of beeps
-
-Flash_Key_1: DS 1 ; Flash key one
-Flash_Key_2: DS 1 ; Flash key two
-
-DShot_Pwm_Thr: DS 1 ; DShot pulse width threshold value (Timer0 ticks)
-DShot_Timer_Preset: DS 1 ; DShot timer preset for frame sync detection (Timer1 lo byte)
-DShot_Frame_Start_L: DS 1 ; DShot frame start timestamp (Timer2 lo byte)
-DShot_Frame_Start_H: DS 1 ; DShot frame start timestamp (Timer2 hi byte)
-DShot_Frame_Length_Thr: DS 1 ; DShot frame length criteria (Timer2 ticks)
-
-DShot_Cmd: DS 1 ; DShot command
-DShot_Cmd_Cnt: DS 1 ; DShot command count
-
-; Pulse durations for GCR encoding DShot telemetry data
-DShot_GCR_Pulse_Time_1: DS 1 ; Encodes binary: 1
-DShot_GCR_Pulse_Time_2: DS 1 ; Encodes binary: 01
-DShot_GCR_Pulse_Time_3: DS 1 ; Encodes binary: 001
-
-DShot_GCR_Pulse_Time_1_Tmp: DS 1
-DShot_GCR_Pulse_Time_2_Tmp: DS 1
-DShot_GCR_Pulse_Time_3_Tmp: DS 1
-
-DShot_GCR_Start_Delay: DS 1
-
-Ext_Telemetry_L: DS 1 ; Extended telemetry data to be sent
-Ext_Telemetry_H: DS 1
-Scheduler_Counter: DS 1 ; Scheduler Heartbeat
-
-;**** **** **** **** ****
-; Indirect addressing data segments
-ISEG AT 080h ; The variables below must be in this sequence
-_Pgm_Gov_P_Gain: DS 1 ;
-Pgm_Startup_Power_Min: DS 1 ; Minimum power during startup phase
-Pgm_Startup_Beep: DS 1 ; Startup beep melody on/off
-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_Direction: DS 1 ; Rotation direction
-_Pgm_Input_Pol: DS 1 ; Input PWM polarity
-Initialized_L_Dummy: DS 1 ; Place holder
-Initialized_H_Dummy: DS 1 ; Place holder
-_Pgm_Enable_TX_Program: DS 1 ; Enable/disable value for TX programming
-Pgm_Braking_Strength: DS 1 ; Set maximum braking strength (complementary pwm)
-_Pgm_Gov_Setup_Target: DS 1 ; Main governor setup target
-_Pgm_Startup_Rpm: DS 1 ; Startup RPM
-_Pgm_Startup_Accel: DS 1 ; Startup acceleration
-_Pgm_Volt_Comp: DS 1 ; Voltage comp
-Pgm_Comm_Timing: DS 1 ; Commutation timing
-_Pgm_Damping_Force: DS 1 ; Damping force
-_Pgm_Gov_Range: DS 1 ; Governor range
-_Pgm_Startup_Method: DS 1 ; Startup method
-_Pgm_Min_Throttle: DS 1 ; Minimum throttle
-_Pgm_Max_Throttle: DS 1 ; Maximum throttle
-Pgm_Beep_Strength: DS 1 ; Beep strength
-Pgm_Beacon_Strength: DS 1 ; Beacon strength
-Pgm_Beacon_Delay: DS 1 ; Beacon delay
-_Pgm_Throttle_Rate: DS 1 ; Throttle rate
-Pgm_Demag_Comp: DS 1 ; Demag compensation
-_Pgm_BEC_Voltage_High: DS 1 ; BEC voltage
-_Pgm_Center_Throttle: DS 1 ; Center throttle (in bidirectional mode)
-_Pgm_Main_Spoolup_Time: DS 1 ; Main spoolup time
-Pgm_Enable_Temp_Prot: DS 1 ; Temperature protection enable
-_Pgm_Enable_Power_Prot: DS 1 ; Low RPM power protection enable
-_Pgm_Enable_Pwm_Input: DS 1 ; Enable PWM input signal
-_Pgm_Pwm_Dither: DS 1 ; Output PWM dither
-Pgm_Brake_On_Stop: DS 1 ; Braking when throttle is zero
-Pgm_LED_Control: DS 1 ; LED control
-Pgm_Power_Rating: DS 1 ; Power rating
-
-ISEG AT 0B0h
-Stack: DS 16 ; Reserved stack space
-
-ISEG AT 0C0h
-Dithering_Patterns: DS 16 ; Bit patterns for pwm dithering
-
-ISEG AT 0D0h
-Temp_Storage: DS 48 ; Temporary storage (internal memory)
-
-;**** **** **** **** ****
-; EEPROM code segments
-; A segment of the flash is used as "EEPROM", which is not available in SiLabs MCUs
-IF MCU_TYPE == 2
- CSEG AT 3000h
-ELSE
- CSEG AT 1A00h
-ENDIF
-EEPROM_FW_MAIN_REVISION EQU 0 ; Main revision of the firmware
-EEPROM_FW_SUB_REVISION EQU 19 ; Sub revision of the firmware
-EEPROM_LAYOUT_REVISION EQU 206 ; Revision of the EEPROM layout
-EEPROM_B2_PARAMETERS_COUNT EQU 27 ; Number of parameters
-
-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
-Eep_Layout_Revision: DB EEPROM_LAYOUT_REVISION ; EEPROM layout revision number
-
-_Eep_Pgm_Gov_P_Gain: DB 0FFh
-Eep_Pgm_Startup_Power_Min: DB DEFAULT_PGM_STARTUP_POWER_MIN
-Eep_Pgm_Startup_Beep: DB DEFAULT_PGM_STARTUP_BEEP
-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_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)
-Eep_Initialized_H: DB 0AAh ; EEPROM initialized signature (hi byte)
-
-; EEPROM parameters block 2 (B2)
-_Eep_Enable_TX_Program: DB 0FFh ; EEPROM TX programming enable
-Eep_Pgm_Braking_Strength: DB DEFAULT_PGM_BRAKING_STRENGTH
-_Eep_Pgm_Gov_Setup_Target: DB 0FFh
-_Eep_Pgm_Startup_Rpm: DB 0FFh
-_Eep_Pgm_Startup_Accel: DB 0FFh
-_Eep_Pgm_Volt_Comp: DB 0FFh
-Eep_Pgm_Comm_Timing: DB DEFAULT_PGM_COMM_TIMING ; EEPROM copy of programmed commutation timing
-_Eep_Pgm_Damping_Force: DB 0FFh
-_Eep_Pgm_Gov_Range: DB 0FFh
-_Eep_Pgm_Startup_Method: DB 0FFh
-_Eep_Pgm_Min_Throttle: DB 0FFh ; EEPROM copy of programmed minimum throttle
-_Eep_Pgm_Max_Throttle: DB 0FFh ; EEPROM copy of programmed minimum throttle
-Eep_Pgm_Beep_Strength: DB DEFAULT_PGM_BEEP_STRENGTH ; EEPROM copy of programmed beep strength
-Eep_Pgm_Beacon_Strength: DB DEFAULT_PGM_BEACON_STRENGTH ; EEPROM copy of programmed beacon strength
-Eep_Pgm_Beacon_Delay: DB DEFAULT_PGM_BEACON_DELAY ; EEPROM copy of programmed beacon delay
-_Eep_Pgm_Throttle_Rate: DB 0FFh
-Eep_Pgm_Demag_Comp: DB DEFAULT_PGM_DEMAG_COMP ; EEPROM copy of programmed demag compensation
-_Eep_Pgm_BEC_Voltage_High: DB 0FFh
-_Eep_Pgm_Center_Throttle: DB 0FFh ; EEPROM copy of programmed center throttle
-_Eep_Pgm_Main_Spoolup_Time: DB 0FFh
-Eep_Pgm_Temp_Prot_Enable: DB DEFAULT_PGM_ENABLE_TEMP_PROT ; EEPROM copy of programmed temperature protection enable
-_Eep_Pgm_Enable_Power_Prot: DB 0FFh ; EEPROM copy of programmed low rpm power protection enable
-_Eep_Pgm_Enable_Pwm_Input: DB 0FFh
-_Eep_Pgm_Pwm_Dither: DB 0FFh
-Eep_Pgm_Brake_On_Stop: DB DEFAULT_PGM_BRAKE_ON_STOP ; EEPROM copy of programmed braking when throttle is zero
-Eep_Pgm_LED_Control: DB DEFAULT_PGM_LED_CONTROL ; EEPROM copy of programmed LED control
-Eep_Pgm_Power_Rating: DB DEFAULT_PGM_POWER_RATING ; EEPROM copy of programmed power rating
-
-Eep_Dummy: DB 0FFh ; EEPROM address for safety reason
-
-IF MCU_TYPE == 2
- CSEG AT 3060h
-ELSE
- CSEG AT 1A60h
-ENDIF
-Eep_Name: DB "Bluejay " ; Name tag (16 Bytes)
-
-IF MCU_TYPE == 2
- CSEG AT 3070h
-ELSE
- CSEG AT 1A70h
-ENDIF
-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
-
-;**** **** **** **** ****
-Interrupt_Table_Definition ; SiLabs interrupts
-CSEG AT 80h ; Code segment after interrupt vectors
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Macros
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-DSHOT_TLM_CLOCK EQU 24500000 ; 24.5MHz
-DSHOT_TLM_START_DELAY EQU -(5 * 25 / 4) ; Start telemetry after 5 us (~30 us after receiving DShot cmd)
-IF MCU_TYPE == 0
-DSHOT_TLM_PREDELAY EQU 9 ; 9 Timer0 ticks inherent delay
-ELSE
-DSHOT_TLM_PREDELAY EQU 7 ; 7 Timer0 ticks inherent delay
-ENDIF
-
-IF MCU_TYPE >= 1
- DSHOT_TLM_CLOCK_48 EQU 49000000 ; 49MHz
- DSHOT_TLM_START_DELAY_48 EQU -(16 * 49 / 4) ; Start telemetry after 16 us (~30 us after receiving DShot cmd)
- DSHOT_TLM_PREDELAY_48 EQU 11 ; 11 Timer0 ticks inherent delay
-ENDIF
-
-Set_DShot_Tlm_Bitrate MACRO rate
- mov DShot_GCR_Pulse_Time_1, #(DSHOT_TLM_PREDELAY - (1 * DSHOT_TLM_CLOCK / 4 / rate))
- mov DShot_GCR_Pulse_Time_2, #(DSHOT_TLM_PREDELAY - (2 * DSHOT_TLM_CLOCK / 4 / rate))
- mov DShot_GCR_Pulse_Time_3, #(DSHOT_TLM_PREDELAY - (3 * DSHOT_TLM_CLOCK / 4 / rate))
-
- mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY
-
-IF MCU_TYPE >= 1
- mov DShot_GCR_Pulse_Time_1_Tmp, #(DSHOT_TLM_PREDELAY_48 - (1 * DSHOT_TLM_CLOCK_48 / 4 / rate))
- mov DShot_GCR_Pulse_Time_2_Tmp, #(DSHOT_TLM_PREDELAY_48 - (2 * DSHOT_TLM_CLOCK_48 / 4 / rate))
- mov DShot_GCR_Pulse_Time_3_Tmp, #(DSHOT_TLM_PREDELAY_48 - (3 * DSHOT_TLM_CLOCK_48 / 4 / rate))
-ENDIF
-ENDM
-
-; DShot GCR encoding, adjust time by adding to previous item
-GCR_Add_Time MACRO reg
- mov B, @reg
- mov A, DShot_GCR_Pulse_Time_2
- cjne A, B, ($+5)
- mov A, DShot_GCR_Pulse_Time_3
- mov @reg, A
-ENDM
-
-; Prepare telemetry packet while waiting for Timer3 to wrap
-Wait_For_Timer3 MACRO
-LOCAL wait_for_t3 done_waiting
- jb Flag_Telemetry_Pending, wait_for_t3
-
- jnb Flag_Timer3_Pending, done_waiting
- call dshot_tlm_create_packet
-
-wait_for_t3:
- jnb Flag_Timer3_Pending, done_waiting
- sjmp wait_for_t3
-
-done_waiting:
-ENDM
-
-; Used for subdividing the DShot telemetry routine into chunks,
-; that will return if Timer3 has wrapped
-Early_Return_Packet_Stage MACRO num
- Early_Return_Packet_Stage_ num, %(num + 1)
-ENDM
-
-Early_Return_Packet_Stage_ MACRO num next
-IF num > 0
- inc Temp7 ;; Increment current packet stage
- jb Flag_Timer3_Pending, dshot_packet_stage_&num ;; Return early if Timer3 has wrapped
- pop PSW
- ret
-dshot_packet_stage_&num:
-ENDIF
-IF num < 5
- cjne Temp7, #(num), dshot_packet_stage_&next ;; If this is not current stage, skip to next
-ENDIF
-ENDM
-
-Decode_DShot_2Bit MACRO dest, decode_fail
- movx A, @Temp1
- mov Temp7, A
- clr C
- subb A, Temp6 ;; Subtract previous timestamp
- clr C
- subb A, Temp2
- jc decode_fail ;; Check that bit is longer than minimum
-
- subb A, Temp2 ;; Check if bit is zero or one
- rlca dest ;; Shift bit into data byte
- inc Temp1 ;; Next bit
-
- movx A, @Temp1
- mov Temp6, A
- clr C
- subb A, Temp7
- clr C
- subb A, Temp2
- jc decode_fail
-
- subb A, Temp2
- rlca dest
- inc Temp1
-ENDM
-
-;**** **** **** **** ****
-; Compound instructions for convenience
-xcha MACRO var1, var2 ;; Exchange via accumulator
- mov A, var1
- xch A, var2
- mov var1, A
-ENDM
-
-rrca MACRO var ;; Rotate right through carry via accumulator
- mov A, var
- rrc A
- mov var, A
-ENDM
-
-rlca MACRO var ;; Rotate left through carry via accumulator
- mov A, var
- rlc A
- mov var, A
-ENDM
-
-rla MACRO var ;; Rotate left via accumulator
- mov A, var
- rl A
- mov var, A
-ENDM
-
-ljc MACRO label ;; Long jump if carry set
-LOCAL skip
- jnc skip
- jmp label
-skip:
-ENDM
-
-ljz MACRO label ;; Long jump if accumulator is zero
-LOCAL skip
- jnz skip
- jmp label
-skip:
-ENDM
-
-imov MACRO reg, val ;; Increment pointer register and move
- inc reg
- mov @reg, val ;; Write value to memory address pointed to by register
-ENDM
-
-;**** **** **** **** ****
-; Division
-;
-; ih, il: input (hi byte, lo byte)
-; oh, ol: output (hi byte, lo byte)
-;
-Divide_By_16 MACRO ih, il, oh, ol
- mov A, ih
- swap A
- mov ol, A
- anl A, #00Fh
- mov oh, A
- mov A, ol
- anl A, #0F0h
- mov ol, A
- mov A, il
- swap A
- anl A, #00Fh
- orl A, ol
- mov ol, A
-ENDM
-
-Divide_12Bit_By_16 MACRO ih, il, ol ;; Only if ih < 16
- mov A, ih
- swap A
- mov ol, A
- mov A, il
- swap A
- anl A, #00Fh
- orl A, ol
- mov ol, A
-ENDM
-
-Divide_By_8 MACRO ih, il, oh, ol
- mov A, ih
- swap A
- rl A
- mov ol, A
- anl A, #01Fh
- mov oh, A
- mov A, ol
- anl A, #0E0h
- mov ol, A
- mov A, il
- swap A
- rl A
- anl A, #01Fh
- orl A, ol
- mov ol, A
-ENDM
-
-Divide_11Bit_By_8 MACRO ih, il, ol ;; Only if ih < 8
- mov A, ih
- swap A
- rl A
- mov ol, A
- mov A, il
- swap A
- rl A
- anl A, #01Fh
- orl A, ol
- mov ol, A
-ENDM
-
-Divide_By_4 MACRO ih, il, oh, ol
- clr C
- mov A, ih
- rrc A
- mov oh, A
- mov A, il
- rrc A
- mov ol, A
-
- clr C
- mov A, oh
- rrc A
- mov oh, A
- mov A, ol
- rrc A
- mov ol, A
-ENDM
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Interrupt handlers
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Timer0 interrupt routine (High priority)
-;
-; Generate DShot telemetry signal
-;
-; Requirements:
-; - Must NOT be called while Flag_Telemetry_Pending is cleared
-; - Must NOT write to Temp7, Temp8
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-t0_int:
- push PSW
- mov PSW, #10h ; Select register bank 2 for this interrupt
-
- dec Temp1
- cjne Temp1, #(Temp_Storage - 1), t0_int_dshot_tlm_transition
-
- inc Temp1 ; Set pointer to uncritical position
-
- ; If last pulse is high, telemetry is finished,
- ; otherwise wait for it to return to high
- jb RTX_BIT, t0_int_dshot_tlm_finish
-
-t0_int_dshot_tlm_transition:
- cpl RTX_BIT ; Invert signal level
-
- mov TL0, @Temp1 ; Schedule next update
-
- pop PSW
- reti
-
-t0_int_dshot_tlm_finish:
- ; Configure RTX_PIN for digital input
- anl RTX_MDOUT, #(NOT (1 SHL RTX_PIN)) ; Set RTX_PIN output mode to open-drain
- setb RTX_BIT ; Float high
-
- clr IE_ET0 ; Disable Timer0 interrupts
-
- mov CKCON0, Temp8 ; Restore regular DShot Timer0/1 clock settings
- mov TMOD, #0AAh ; Timer0/1 gated by Int0/1
-
- clr TCON_IE0 ; Clear Int0 pending flag
- clr TCON_IE1 ; Clear Int1 pending flag
-
- mov TL0, #0 ; Reset Timer0 count
- setb IE_EX0 ; Enable Int0 interrupts
- setb IE_EX1 ; Enable Int1 interrupts
-
- clr Flag_Telemetry_Pending ; Mark that new telemetry packet may be created
-
- pop PSW
- reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Timer1 interrupt routine
-;
-; Decode DShot frame
-; Process new throttle value and update pwm registers
-; Schedule DShot telemetry
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-t1_int:
- clr IE_EX0 ; Disable Int0 interrupts
- clr TCON_TR1 ; Stop Timer1
- mov TL1, DShot_Timer_Preset ; Reset sync timer
-
- push PSW
- mov PSW, #8h ; Select register bank 1 for this interrupt
- push ACC
- push B
-
- ; Note: Interrupts are not explicitly disabled
- ; Assume higher priority interrupts (Int0, Timer0) to be disabled at this point
- clr TMR2CN0_TR2 ; Timer2 disabled
- mov Temp2, TMR2L ; Read timer value
- mov Temp3, TMR2H
- setb TMR2CN0_TR2 ; Timer2 enabled
-
- ; Check frame time length
- clr C
- mov A, Temp2
- subb A, DShot_Frame_Start_L
- mov Temp2, A
- mov A, Temp3
- subb A, DShot_Frame_Start_H
- jnz t1_int_frame_fail ; Frame too long
-
- clr C
- mov A, Temp2
- subb A, DShot_Frame_Length_Thr
- jc t1_int_frame_fail ; Frame too short
- subb A, DShot_Frame_Length_Thr
- jnc t1_int_frame_fail ; Frame too long
-
- ; Check that correct number of pulses is received
- cjne Temp1, #16, t1_int_frame_fail ; Read current pointer
-
- ; Decode transmitted data
- mov Temp1, #0 ; Set pointer
- mov Temp2, DShot_Pwm_Thr ; DShot pulse width criteria
- mov Temp6, #0 ; Reset timestamp
-
- ; Decode DShot data Msb. Use more code space to save time (by not using loop)
- Decode_DShot_2Bit Temp5, t1_int_frame_fail
- Decode_DShot_2Bit Temp5, t1_int_frame_fail
- sjmp t1_int_decode_lsb
-
-t1_int_frame_fail:
- sjmp t1_int_outside_range
-
-t1_int_decode_lsb:
- ; Decode DShot data Lsb
- Decode_DShot_2Bit Temp4, t1_int_outside_range
- Decode_DShot_2Bit Temp4, t1_int_outside_range
- Decode_DShot_2Bit Temp4, t1_int_outside_range
- Decode_DShot_2Bit Temp4, t1_int_outside_range
- sjmp t1_int_decode_checksum
-
-t1_int_outside_range:
- inc Rcp_Outside_Range_Cnt
- mov A, Rcp_Outside_Range_Cnt
- jnz ($+4)
- dec Rcp_Outside_Range_Cnt
-
- clr C
- mov A, Rcp_Outside_Range_Cnt
- subb A, #50 ; Allow a given number of outside pulses
- jc t1_int_exit_timeout ; If outside limits - ignore first pulses
-
- ; RCP signal has not timed out, but pulses are not recognized as DShot
- setb Flag_Rcp_Stop ; Set pulse length to zero
- mov DShot_Cmd, #0 ; Reset DShot command
- mov DShot_Cmd_Cnt, #0
-
- ajmp t1_int_exit_no_tlm ; Exit without resetting timeout
-
-t1_int_exit_timeout:
- mov Rcp_Timeout_Cntd, #10 ; Set timeout count
- ajmp t1_int_exit_no_tlm
-
-t1_int_decode_checksum:
- ; Decode DShot data checksum
- Decode_DShot_2Bit Temp3, t1_int_outside_range
- Decode_DShot_2Bit Temp3, t1_int_outside_range
-
- ; XOR check (in inverted data, which is ok), only low nibble is considered
- mov A, Temp4
- swap A
- xrl A, Temp4
- xrl A, Temp5
- xrl A, Temp3
- jnb Flag_Rcp_DShot_Inverted, ($+4)
- cpl A ; Invert checksum if using inverted DShot
- anl A, #0Fh
- jnz t1_int_outside_range ; XOR check
-
- ; Invert DShot data and subtract 96 (still 12 bits)
- clr C
- mov A, Temp4
- cpl A
- mov Temp3, A ; Store in case it is a DShot command
- subb A, #96
- mov Temp4, A
- mov A, Temp5
- cpl A
- anl A, #0Fh
- subb A, #0
- mov Temp5, A
- jnc t1_int_normal_range
-
- mov A, Temp3 ; Check for 0 or DShot command
- mov Temp5, #0
- mov Temp4, #0
- jz t1_int_dshot_set_cmd ; Clear DShot command when RCP is zero
-
- clr C ; We are in the special DShot range
- rrc A ; Shift tlm bit into carry
- jnc t1_int_dshot_clear_cmd ; Check for tlm bit set (if not telemetry, invalid command)
-
- cjne A, DShot_Cmd, t1_int_dshot_set_cmd
-
- inc DShot_Cmd_Cnt
- sjmp t1_int_normal_range
-
-t1_int_dshot_clear_cmd:
- clr A
-
-t1_int_dshot_set_cmd:
- mov DShot_Cmd, A
- mov DShot_Cmd_Cnt, #0
-
-t1_int_normal_range:
- ; Check for bidirectional operation (0=stop, 96-2095->fwd, 2096-4095->rev)
- jnb Flag_Pgm_Bidir, t1_int_not_bidir ; If not bidirectional operation - branch
-
- ; Subtract 2000 (still 12 bits)
- clr C
- mov A, Temp4
- subb A, #0D0h
- mov B, A
- mov A, Temp5
- subb A, #07h
- jc t1_int_bidir_set ; Is result is positive?
- mov Temp4, B ; Yes - Use the subtracted value
- mov Temp5, A
-
-t1_int_bidir_set:
- jnb Flag_Pgm_Dir_Rev, ($+4) ; Check programmed direction
- cpl C ; Reverse direction
- mov Flag_Rcp_Dir_Rev, C ; Set rcp direction
-
- clr C ; Multiply throttle value by 2
- rlca Temp4
- rlca Temp5
-
-t1_int_not_bidir:
- ; From here Temp5/Temp4 should be at most 3999 (4095-96)
- mov A, Temp4 ; Divide by 16 (12 to 8-bit)
- anl A, #0F0h
- orl A, Temp5 ; Note: Assumes Temp5 to be 4-bit
- swap A
- mov B, #5 ; Divide by 5 (80 in total)
- div AB
- mov Temp3, A
- ; Align to 11 bits
- ;clr C ; Note: Cleared by div
- rrca Temp5
- mov A, Temp4
- rrc A
- ; Scale from 2000 to 2048
- add A, Temp3
- mov Temp4, A
- mov A, Temp5
- addc A, #0
- mov Temp5, A
- jnb ACC.3, ($+7) ; Limit to 11-bit maximum
- mov Temp4, #0FFh
- mov Temp5, #07h
-
- ; Do not boost when changing direction in bidirectional mode
- jb Flag_Motor_Started, t1_int_startup_boosted
-
- ; Boost pwm during direct start
- jnb Flag_Initial_Run_Phase, t1_int_startup_boosted
-
- mov A, Temp5
- jnz t1_int_stall_boost ; Already more power than minimum at startup
-
- mov Temp2, #Pgm_Startup_Power_Min ; Read minimum startup power setting
- mov B, @Temp2
-
- clr C ; Set power to at least be minimum startup power
- mov A, Temp4
- subb A, B
- jnc t1_int_stall_boost
- mov Temp4, B
-
-t1_int_stall_boost:
- mov A, Startup_Stall_Cnt ; Check stall count
- jz t1_int_startup_boosted
- mov B, #40 ; Note: Stall count should be less than 6
- mul AB
-
- add A, Temp4 ; Add more power when failing to start motor (stalling)
- mov Temp4, A
- mov A, Temp5
- addc A, #0
- mov Temp5, A
- jnb ACC.3, ($+7) ; Limit to 11-bit maximum
- mov Temp4, #0FFh
- mov Temp5, #07h
-
-t1_int_startup_boosted:
- ; Set 8-bit value
- mov A, Temp4
- anl A, #0F8h
- orl A, Temp5 ; Assumes Temp5 to be 3-bit (11-bit rcp)
- swap A
- rl A
- mov Temp2, A
-
- jnz t1_int_rcp_not_zero
-
- mov A, Temp4 ; Only set Rcp_Stop if all all 11 bits are zero
- jnz t1_int_rcp_not_zero
-
- setb Flag_Rcp_Stop
- sjmp t1_int_zero_rcp_checked
-
-t1_int_rcp_not_zero:
- mov Rcp_Stop_Cnt, #0 ; Reset rcp stop counter
- clr Flag_Rcp_Stop ; Pulse ready
-
-t1_int_zero_rcp_checked:
- ; Decrement outside range counter
- mov A, Rcp_Outside_Range_Cnt
- jz ($+4)
- dec Rcp_Outside_Range_Cnt
-
- ; Set pwm limit
- clr C
- mov A, Pwm_Limit ; Limit to the smallest
- mov Temp6, A ; Store limit in Temp6
- subb A, Pwm_Limit_By_Rpm
- jc ($+4)
- mov Temp6, Pwm_Limit_By_Rpm
-
- ; Check against limit
- clr C
- mov A, Temp6
- subb A, Temp2 ; 8-bit rc pulse
- jnc t1_int_scale_pwm_resolution
-
-IF PWM_BITS_H == 0 ; 8-bit pwm
- mov A, Temp6
- mov Temp2, A
-ELSE
- mov A, Temp6 ; Multiply limit by 8 for 11-bit pwm
- mov B, #8
- mul AB
- mov Temp4, A
- mov Temp5, B
-ENDIF
-
-t1_int_scale_pwm_resolution:
-; Scale pwm resolution and invert (duty cycle is defined inversely)
-IF PWM_BITS_H == 3 ; 11-bit pwm
- mov A, Temp5
- cpl A
- anl A, #7
- mov Temp3, A
- mov A, Temp4
- cpl A
- mov Temp2, A
-ELSEIF PWM_BITS_H == 2 ; 10-bit pwm
- clr C
- mov A, Temp5
- rrc A
- cpl A
- anl A, #3
- mov Temp3, A
- mov A, Temp4
- rrc A
- cpl A
- mov Temp2, A
-ELSEIF PWM_BITS_H == 1 ; 9-bit pwm
- mov B, Temp5
- mov A, Temp4
- mov C, B.0
- rrc A
- mov C, B.1
- rrc A
- cpl A
- mov Temp2, A
- mov A, Temp5
- rr A
- rr A
- cpl A
- anl A, #1
- mov Temp3, A
-ELSEIF PWM_BITS_H == 0 ; 8-bit pwm
- mov A, Temp2 ; Temp2 already 8-bit
- cpl A
- mov Temp2, A
- mov Temp3, #0
-ENDIF
-
-; 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
-
- add A, #Dithering_Patterns
- mov Temp1, A ; Reuse DShot pwm pointer since it is not currently in use.
- mov A, @Temp1 ; Retrieve pattern
- rl A ; Rotate pattern
- mov @Temp1, A ; Store pattern
-
- jnb ACC.0, t1_int_set_pwm ; Increment if bit is set
-
- mov A, Temp2
- add A, #1
- mov Temp2, A
- jnz t1_int_set_pwm
-IF PWM_BITS_H != 0
- mov A, Temp3
- addc A, #0
- mov Temp3, A
- jnb ACC.PWM_BITS_H, t1_int_set_pwm
- dec Temp3 ; Reset on overflow
-ENDIF
- dec Temp2
-ENDIF
-
-t1_int_set_pwm:
-; Set pwm registers
-IF DEADTIME != 0
- ; Subtract dead time from normal pwm and store as damping pwm
- ; Damping pwm duty cycle will be higher because numbers are inverted
- clr C
- mov A, Temp2 ; Skew damping FET timing
-IF MCU_TYPE == 0
- subb A, #((DEADTIME + 1) SHR 1)
-ELSE
- subb A, #(DEADTIME)
-ENDIF
- mov Temp4, A
- mov A, Temp3
- subb A, #0
- mov Temp5, A
- jnc t1_int_max_braking_set
-
- clr A ; Set to minimum value
- mov Temp4, A
- mov Temp5, A
- sjmp t1_int_pwm_braking_set ; Max braking is already zero - branch
-
-t1_int_max_braking_set:
- clr C
- mov A, Temp4
- subb A, Pwm_Braking_L
- mov A, Temp5
- subb A, Pwm_Braking_H ; Is braking pwm more than maximum allowed braking?
- jc t1_int_pwm_braking_set ; Yes - branch
- mov Temp4, Pwm_Braking_L ; No - set desired braking instead
- mov Temp5, Pwm_Braking_H
-
-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
- ; 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
-ENDIF
-
- mov Rcp_Timeout_Cntd, #10 ; Set timeout count
-
- ; Prepare DShot telemetry
- jnb Flag_Rcp_DShot_Inverted, t1_int_exit_no_tlm ; Only send telemetry for inverted DShot
- jnb Flag_Telemetry_Pending, t1_int_exit_no_tlm ; Check if telemetry packet is ready
-
- ; Prepare Timer0 for sending telemetry data
- mov CKCON0, #01h ; Timer0 is system clock divided by 4
- mov TMOD, #0A2h ; Timer0 runs free not gated by Int0
-
- ; Configure RTX_PIN for digital output
- setb RTX_BIT ; Default to high level
- orl RTX_MDOUT, #(1 SHL RTX_PIN) ; Set output mode to push-pull
-
- mov Temp1, #0 ; Set pointer to start
-
- ; Note: Delay must be large enough to ensure port is ready for output
- mov TL0, DShot_GCR_Start_Delay ; Telemetry will begin after this delay
- clr TCON_TF0 ; Clear Timer0 overflow flag
- setb IE_ET0 ; Enable Timer0 interrupts
-
- sjmp t1_int_exit_no_int
-
-t1_int_exit_no_tlm:
- mov Temp1, #0 ; Set pointer to start
- mov TL0, #0 ; Reset Timer0
- setb IE_EX0 ; Enable Int0 interrupts
- setb IE_EX1 ; Enable Int1 interrupts
-
-t1_int_exit_no_int:
- pop B ; Restore preserved registers
- pop ACC
- pop PSW
- reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Timer2 interrupt routine
-;
-; Update RC pulse timeout and stop counters
-; Happens every 32ms
-;
-; Requirements: No PSW instructions or Temp registers
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-t2_int:
- push ACC
- clr TMR2CN0_TF2H ; Clear interrupt flag
- inc Timer2_X ; Increment extended byte
- setb Flag_32ms_Elapsed ; Set 32ms elapsed flag
-
- ; Check RC pulse timeout counter
- mov A, Rcp_Timeout_Cntd ; RC pulse timeout count zero?
- jnz t2_int_rcp_timeout_decrement
- setb Flag_Rcp_Stop ; If zero -> Set rcp stop in case of timeout
- sjmp t2_int_flag_rcp_stop_check
-
-t2_int_rcp_timeout_decrement:
- dec Rcp_Timeout_Cntd ; No - decrement
-
-t2_int_flag_rcp_stop_check:
- ; If rc pulse is not zero
- jnb Flag_Rcp_Stop, t2_int_exit ; If rc pulse is not zero don't increment rcp stop counter
-
- ; Increment Rcp_Stop_Cnt clipping it to 255
- mov A, Rcp_Stop_Cnt
- inc A
- jz ($+4)
- inc Rcp_Stop_Cnt
-
-; ************** Return from timer2 **********
-t2_int_exit:
- pop ACC ; Restore preserved registers
- reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Timer3 interrupt routine
-;
-; Used for commutation timing
-;
-; Requirements: No PSW instructions or Temp/Acc/B registers
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-t3_int:
- clr IE_EA ; Disable all interrupts
- anl EIE1, #7Fh ; Disable Timer3 interrupts
- anl TMR3CN0, #07Fh ; Clear Timer3 interrupt flag
- mov TMR3RLL, #0FAh ; Short delay to avoid re-loading regular delay
- mov TMR3RLH, #0FFh
- clr Flag_Timer3_Pending ; Flag that timer has wrapped
- setb IE_EA ; Enable all interrupts
- reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Int0 interrupt routine (High priority)
-;
-; Read and store DShot pwm signal for decoding
-;
-; Requirements: No PSW instructions
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-int0_int:
- push ACC
- mov A, TL0 ; Read pwm for DShot immediately
- mov TL1, DShot_Timer_Preset ; Reset sync timer
-
- ; Temp1 in register bank 1 points to pwm timings
- push PSW
- mov PSW, #8h
- movx @Temp1, A ; Store pwm in external memory
- inc Temp1
- pop PSW
-
- pop ACC
- reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Int1 interrupt routine
-;
-; Used for RC pulse timing
-;
-; Requirements: No PSW instructions or Temp/Acc registers
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-int1_int:
- clr IE_EX1 ; Disable Int1 interrupts
- setb TCON_TR1 ; Start Timer1
-
- ; Note: Interrupts are not explicitly disabled, assuming higher priority interrupts:
- ; - Timer0 to be disabled at this point
- ; - Int0 to not trigger for valid DShot signal
- clr TMR2CN0_TR2 ; Timer2 disabled
- mov DShot_Frame_Start_L, TMR2L ; Read timer value
- mov DShot_Frame_Start_H, TMR2H
- setb TMR2CN0_TR2 ; Timer2 enabled
-reti
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; PCA interrupt routine
-;
-; Update pwm registers according to PCA clock signal
-;
-; Requirements: No PSW instructions or Temp registers
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-pca_int:
- reti
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Misc utility functions
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Wait a number of milliseconds (Multiple entry points)
-;
-; Requirements:
-; - System clock should be set to 24MHz
-; - Interrupts should be disabled for precision
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-wait1ms:
- mov Temp3, #0 ; Milliseconds (hi byte)
- mov Temp2, #1 ; Milliseconds (lo byte)
- sjmp wait_ms
-
-wait5ms:
- mov Temp3, #0
- mov Temp2, #5
- sjmp wait_ms
-
-wait10ms:
- mov Temp3, #0
- mov Temp2, #10
- sjmp wait_ms
-
-wait100ms:
- mov Temp3, #0
- mov Temp2, #100
- sjmp wait_ms
-
-wait200ms:
- mov Temp3, #0
- mov Temp2, #200
- sjmp wait_ms
-
-wait250ms:
- mov Temp3, #0
- mov Temp2, #250
- sjmp wait_ms
-
-wait_ms:
- inc Temp2 ; Increment for use with djnz
- inc Temp3
- sjmp wait_ms_start
-
-wait_ms_o: ; Outer loop
- mov Temp1, #24
-
-wait_ms_m: ; Middle loop
- mov A, #255
- djnz ACC, $ ; Inner loop (41.6us - 1020 cycles)
- djnz Temp1, wait_ms_m
-
-wait_ms_start:
- djnz Temp2, wait_ms_o
- djnz Temp3, wait_ms_o
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Beeper routines (Multiple entry points)
-;
-; Requirements: Interrupts must be disabled and FETs turned off
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-beep_f1:
- mov Temp3, #66 ; Off wait loop length (Tone)
- mov Temp4, #(3500 / 66) ; Number of beep pulses (Duration)
- sjmp beep
-
-beep_f2:
- mov Temp3, #45
- mov Temp4, #(3500 / 45)
- sjmp beep
-
-beep_f3:
- mov Temp3, #38
- mov Temp4, #(3500 / 38)
- sjmp beep
-
-beep_f4:
- mov Temp3, #25
- mov Temp4, #(3500 / 25)
- sjmp beep
-
-beep_f5:
- mov Temp3, #20
- mov Temp4, #(3500 / 20)
- sjmp beep
-
-beep_f1_short:
- mov Temp3, #66
- mov Temp4, #(2000 / 66)
- sjmp beep
-
-beep_f2_short:
- mov Temp3, #45
- mov Temp4, #(2000 / 45)
- sjmp beep
-
-beep:
- mov A, Beep_Strength
- jnz beep_start ; Start if beep strength is not 0
- ret
-
-beep_start:
- mov Temp2, #2
-
-beep_on_off:
- clr A
- B_Com_Fet_Off ; B com FET off
- djnz ACC, $ ; Allow some time after com FET is turned off
- B_Pwm_Fet_On ; B pwm FET on (in order to charge the driver of the B com FET)
- djnz ACC, $ ; Let the pwm FET be turned on a while
- B_Pwm_Fet_Off ; B pwm FET off again
- djnz ACC, $ ; Allow some time after pwm FET is turned off
- B_Com_Fet_On ; B com FET on
- djnz ACC, $ ; Allow some time after com FET is turned on
-
- mov A, Temp2 ; Turn on pwm FET
- jb ACC.0, beep_a_pwm_on
- A_Pwm_Fet_On
-beep_a_pwm_on:
- jnb ACC.0, beep_c_pwm_on
- C_Pwm_Fet_On
-beep_c_pwm_on:
-
- mov A, Beep_Strength ; On time according to beep strength
- djnz ACC, $
-
- mov A, Temp2 ; Turn off pwm FET
- jb ACC.0, beep_a_pwm_off
- A_Pwm_Fet_Off
-beep_a_pwm_off:
- jnb ACC.0, beep_c_pwm_off
- C_Pwm_Fet_Off
-beep_c_pwm_off:
-
- mov A, #150 ; Off for 25 us
- djnz ACC, $
-
- djnz Temp2, beep_on_off ; Toggle next pwm FET
-
- mov A, Temp3
-beep_off: ; Fets off loop
- mov Temp1, #200
- djnz Temp1, $
- djnz ACC, beep_off ; Off time according to beep frequency
-
- djnz Temp4, beep_start ; Number of beep pulses (duration)
-
- B_Com_Fet_Off
- ret
-
-; Beep sequences
-beep_signal_lost:
- call beep_f1
- call beep_f2
- call beep_f3
- ret
-
-beep_enter_bootloader:
- call beep_f2_short
- call beep_f1
- ret
-
-beep_motor_stalled:
- call beep_f3
- call beep_f2
- call beep_f1
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Beacon beep
-;
-; Beep with beacon strength
-; Beep tone 1-5 in Temp1
-;
-; Requirements: Interrupts must be disabled and FETs turned off
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-beacon_beep:
- mov Temp2, #Pgm_Beacon_Strength ; Set beacon beep strength
- mov Beep_Strength, @Temp2
-
- cjne Temp1, #1, beacon_beep2
- call beep_f1
- sjmp beacon_beep_exit
-
-beacon_beep2:
- cjne Temp1, #2, beacon_beep3
- call beep_f2
- sjmp beacon_beep_exit
-
-beacon_beep3:
- cjne Temp1, #3, beacon_beep4
- call beep_f3
- sjmp beacon_beep_exit
-
-beacon_beep4:
- cjne Temp1, #4, beacon_beep5
- call beep_f4
- sjmp beacon_beep_exit
-
-beacon_beep5:
- call beep_f5
-
-beacon_beep_exit:
- mov Temp2, #Pgm_Beep_Strength ; Set normal beep strength
- mov Beep_Strength, @Temp2
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Play beep melody
-;
-; Plays a beep melody from eeprom storage
-;
-; A melody has 64 pairs of (item1, item2) - a total of 128 items.
-; the first 4 values of the 128 items are metadata
-; item2 - is the duration of each pulse of the musical note, lower the value, higher the pitch
-; item1 - if item2 is zero, it is the number of milliseconds of wait time, else it is the number of pulses of item2
-;
-; Requirements: Interrupts must be disabled and FETs turned off
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-play_beep_melody:
- mov DPTR, #(Eep_Pgm_Beep_Melody)
- clr A
- movc A, @A+DPTR
- cpl A
- jz play_beep_melody_exit ; If first byte is 255, skip startup melody (settings may be invalid)
-
- mov Temp5, #62
- mov DPTR, #(Eep_Pgm_Beep_Melody + 04h)
-
-play_beep_melody_loop:
- ; Read current location at Eep_Pgm_Beep_Melody to Temp4 and increment DPTR. If the value is 0, no point trying to play this note
- clr A
- movc A, @A+DPTR
- inc DPTR
- mov Temp4, A
- jz play_beep_melody_exit
-
- ; Read current location at Eep_Pgm_Beep_Melody to Temp3. If the value zero, that means this is a silent note
- clr A
- movc A, @A+DPTR
- mov Temp3, A
- jz play_beep_melody_item_wait_ms
- call beep
- sjmp play_beep_melody_loop_next_item
-
-play_beep_melody_item_wait_ms:
- mov A, Temp4
- mov Temp2, A
- mov Temp3, #0
- call wait_ms
-
-play_beep_melody_loop_next_item:
- inc DPTR
- djnz Temp5, play_beep_melody_loop
-
-play_beep_melody_exit:
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; LED control
-;
-; Controls LEDs
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-led_control:
- mov Temp1, #Pgm_LED_Control
- mov A, @Temp1
- mov Temp2, A
- anl A, #03h
- Set_LED_0
- jnz led_0_done
- Clear_LED_0
-
-led_0_done:
- mov A, Temp2
- anl A, #0Ch
- Set_LED_1
- jnz led_1_done
- Clear_LED_1
-
-led_1_done:
- mov A, Temp2
- anl A, #030h
- Set_LED_2
- jnz led_2_done
- Clear_LED_2
-
-led_2_done:
- mov A, Temp2
- anl A, #0C0h
- Set_LED_3
- jnz led_3_done
- Clear_LED_3
-
-led_3_done:
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Power and temperature control
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Switch power off
-;
-; Switches all FETs off
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-switch_power_off:
- All_Pwm_Fets_Off ; Turn off all pwm FETs
- All_Com_Fets_Off ; Turn off all commutation FETs
- Set_All_Pwm_Phases_Off
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Set pwm limit low rpm
-;
-; Sets power limit for low rpm
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-set_pwm_limit:
- jb Flag_High_Rpm, set_pwm_limit_high_rpm ; If high rpm, limit pwm by rpm instead
-
-;set_pwm_limit_low_rpm:
- ; Set pwm limit
- mov Temp1, #0FFh ; Default full power
- jb Flag_Startup_Phase, set_pwm_limit_low_rpm_exit ; Exit if startup phase set
-
- mov A, Low_Rpm_Pwr_Slope ; Check if low RPM power protection is enabled
- jz set_pwm_limit_low_rpm_exit ; Exit if disabled (zero)
-
- mov A, Comm_Period4x_H
- jz set_pwm_limit_low_rpm_exit ; Avoid divide by zero
-
- mov A, #255 ; Divide 255 by Comm_Period4x_H
- jnb Flag_Initial_Run_Phase, ($+5) ; More protection for initial run phase
- mov A, #127
- mov B, Comm_Period4x_H
- div AB
- mov B, Low_Rpm_Pwr_Slope ; Multiply by slope
- mul AB
- mov Temp1, A ; Set new limit
- xch A, B
- jz ($+4) ; Limit to max
-
- mov Temp1, #0FFh
-
- clr C
- mov A, Temp1 ; Limit to min
- subb A, Pwm_Limit_Beg
- jnc set_pwm_limit_low_rpm_exit
-
- mov Temp1, Pwm_Limit_Beg
-
-set_pwm_limit_low_rpm_exit:
- mov Pwm_Limit_By_Rpm, Temp1
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Set pwm limit high rpm
-;
-; Sets power limit for high rpm
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-set_pwm_limit_high_rpm:
- clr C
- mov A, Comm_Period4x_L
-IF MCU_TYPE >= 1
- subb A, #0A0h ; Limit Comm_Period4x to 160, which is ~510k erpm
-ELSE
- subb A, #0E4h ; Limit Comm_Period4x to 228, which is ~358k erpm
-ENDIF
- mov A, Comm_Period4x_H
- subb A, #00h
-
- mov A, Pwm_Limit_By_Rpm
- jnc set_pwm_limit_high_rpm_inc_limit
-
- dec A
- sjmp set_pwm_limit_high_rpm_store
-
-set_pwm_limit_high_rpm_inc_limit:
- inc A
-
-set_pwm_limit_high_rpm_store:
- jz ($+4)
- mov Pwm_Limit_By_Rpm, A
-
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Scheduler
-; Each step 32ms, cycle 256ms (8 steps)
-;
-; ReqSch00: - Steps even [0, 2, 4, 6]
-; ReqSch01: - Update temperature setpoint
-; ReqSch02: - [TELEMETRY] Send demag metric frame
-; ReqSch03: - Steps odd [1, 3, 5, 7]
-; ReqSch04: - Update temperature PWM limit
-; ReqSch06: - Case step 1
-; ReqSch07: - [TELEMETRY] Send status frame
-; ReqSch08: - Case step 3
-; ReqSch09: - [TELEMETRY] Send debug1 frame
-; ReqSch10: - Case step 5
-; ReqSch11: - [TELEMETRY] Send debug2 frame
-; ReqSch12: - Case step 7
-; ReqSch13: - [TELEMETRY] Send temperature frame
-; ReqSch14: - Start new ADC conversion
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-scheduler_run:
- ; Exit if not 32ms elapsed, otherwise start schedule
- jbc Flag_32ms_Elapsed, scheduler_start
- ret
-
-scheduler_start:
- ; Increment Scheduler Counter
- inc Scheduler_Counter
-
- ; Choose between odd or even steps
- mov A, Scheduler_Counter
- jb ACC.0, scheduler_steps_odd
-
-scheduler_steps_even:
- ; ********************* UPDATE TEMPERATURE SETPOINT *****************
-
- ; Check temp protection enabled, and skip when protection is disabled
- mov A, Temp_Prot_Limit
- jz scheduler_steps_even_demag_metric_frame
-
- ; Set setpoint maximum value
- mov Temp_Pwm_Level_Setpoint, #255
-
- ; Check TEMP_LIMIT in Base.inc and make calculations to understand temperature readings
- ; Is temperature reading below 256?
- ; On BB1 & BB21
- ; - Using external voltage regulator and vdd 3.3V as ADC reference -> ADC 10bit value corresponding to about 25ºC
- ; - Using external voltage regulator and internal 1.65V as ADC reference -> ADC 10bit value corresponding to about 0ºC
- ; On BB51
- ; - Using external voltage regulator and internal 1.65V as ADC reference -> ADC 10bit value corresponding to about 0ºC
- mov A, ADC0H ; Load temp hi
- jz scheduler_steps_even_demag_metric_frame ; Temperature below 25ºC (on 2S+ (BB1, BB2)) and below 0ºC (on 1S (BB1, BB21), BB51) do not update setpoint
-
- mov A, ADC0L ; Load temp lo
-
- clr C
- subb A, Temp_Prot_Limit ; Is temperature below first limit?
- jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
-
- mov Temp_Pwm_Level_Setpoint, #200 ; No - update pwm limit (about 80%)
-
- subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below second limit
- jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
-
- mov Temp_Pwm_Level_Setpoint, #150 ; No - update pwm limit (about 60%)
-
- subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below third limit
- jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
-
- mov Temp_Pwm_Level_Setpoint, #100 ; No - update pwm limit (about 40% allowing landing)
-
- subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below final limit
- jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
-
- mov Temp_Pwm_Level_Setpoint, #50 ; No - update pwm limit (about 20% forced landing)
- ; Zero pwm cannot be set because of set_pwm_limit algo restrictions
- ; Otherwise hard stuttering is produced
-
-scheduler_steps_even_demag_metric_frame:
- ; Check telemetry is enable to produce telemetry frames
- jb Flag_Ext_Tele, scheduler_steps_even_demag_metric_frame_prepare
- jmp scheduler_exit
-
-scheduler_steps_even_demag_metric_frame_prepare:
- ; ********************* [TELEMETRY] SEND DEMAG METRIC FRAME *****************
- mov Ext_Telemetry_L, Demag_Detected_Metric ; Set telemetry low value to demag metric data
- mov Ext_Telemetry_H, #0Ch ; Set telemetry high value to demag metric frame ID
-
- ; No more work to do
- jmp scheduler_exit
-
-scheduler_steps_odd:
- ; ********************* UPDATE TEMPERATURE PWM LIMIT *****************
-
- ; Check temp protection enabled, and exit when protection is disabled
- mov A, Temp_Prot_Limit
- jz scheduler_steps_odd_choose_step
-
- ; pwm limit is updated one unit at a time to avoid abrupt pwm changes
- ; resulting in current spikes, that may damage motor/esc
- ; Compare pwm limit to setpoint
- clr C
- mov A, Pwm_Limit
- subb A, Temp_Pwm_Level_Setpoint
- jz scheduler_steps_odd_choose_step ; pwm limit == setpoint -> next
- jc scheduler_steps_odd_temp_pwm_limit_inc ; pwm limit < setpoint -> increase pwm limit
-
-scheduler_steps_odd_temp_pwm_limit_dec:
- ; Decrease pwm limit
- dec Pwm_Limit
-
- ; Now run speciffic odd scheduler step
- sjmp scheduler_steps_odd_choose_step
-
-scheduler_steps_odd_temp_pwm_limit_inc:
- ; Increase pwm limit
- inc Pwm_Limit
-
- ; Now run speciffic odd scheduler step
-
-scheduler_steps_odd_choose_step:
- ; Check telemetry is enable to produce telemetry frames
- jnb Flag_Ext_Tele, scheduler_steps_odd_restart_ADC
-
- ; Let A = Scheduler_Counter % 8, so A = [0 - 7] value
- mov A, Scheduler_Counter
- anl A, #07h
-
-scheduler_steps_odd_status_frame:
- ; ********************* [TELEMETRY] SEND STATUS FRAME *****************
- cjne A, #1, scheduler_steps_odd_debug1_frame
-
- ; if (Demag_Detected_Metric_Max >= 120)
- ; stat.demagMetricMax = (Demag_Detected_Metric_Max - 120) / 9
- ; else
- ; stat.demagMetricMax = 0
- clr C
- mov A, Demag_Detected_Metric_Max
- subb A, #120 ; 120: substract the minimum
- jnc scheduler_steps_odd_status_frame_max_load
- clr A
- sjmp scheduler_steps_odd_status_frame_max_loaded
-
-scheduler_steps_odd_status_frame_max_load:
- mov B, #9
- div AB ; Ranges: [0 - 135] / 9 == [0 - 15]
-
-scheduler_steps_odd_status_frame_max_loaded:
- ; Load flags
- mov C, Flag_Demag_Notify
- mov ACC.7, C
- mov C, Flag_Desync_Notify
- mov ACC.6, C
- mov C, Flag_Stall_Notify
- mov ACC.5, C
-
- ; Data loaded clear flags
- clr Flag_Demag_Notify
- clr Flag_Desync_Notify
- clr Flag_Stall_Notify
-
- ; Load status frame
- mov Ext_Telemetry_L, A ; Set telemetry low value to status data
- mov Ext_Telemetry_H, #0Eh ; Set telemetry high value to status frame ID
-
- ; Now restart ADC conversion
- sjmp scheduler_steps_odd_restart_ADC
-
-scheduler_steps_odd_debug1_frame:
- ; ********************* [TELEMETRY] SEND DEBUG1 FRAME *****************
- cjne A, #3, scheduler_steps_odd_debug2_frame
-
- ; Stub for debug 1
- mov Ext_Telemetry_L, #088h ; Set telemetry low value
- mov Ext_Telemetry_H, #08h ; Set telemetry high value to debug1 frame ID
-
- ; Now restart ADC conversion
- sjmp scheduler_steps_odd_restart_ADC
-
-scheduler_steps_odd_debug2_frame:
- ; ********************* [TELEMETRY] SEND DEBUG2 FRAME *****************
- cjne A, #5, scheduler_steps_odd_temperature_frame
-
- ; Stub for debug 2
- mov Ext_Telemetry_L, #0AAh ; Set telemetry low value
- mov Ext_Telemetry_H, #0Ah ; Set telemetry high value to debug2 frame ID
-
- ; Now restart ADC conversion
- sjmp scheduler_steps_odd_restart_ADC
-
-scheduler_steps_odd_temperature_frame:
- ; ********************* [TELEMETRY] SEND TEMPERATURE FRAME *****************
- cjne A, #7, scheduler_steps_odd_restart_ADC
-
- ; ******************************************************************
- ; Power rating only applies to BB21 because voltage references behave diferently
- ; depending on an external voltage regulator is used or not.
- ; For BB51 (MCU_TYPE == 2) 1s power rating code path is mandatory
- ; ******************************************************************
-IF MCU_TYPE < 2
- mov Temp1, #Pgm_Power_Rating
- cjne @Temp1, #01h, scheduler_steps_odd_temperature_frame_power_rating_2s
-ENDIF
-
-scheduler_steps_odd_temperature_frame_power_rating_1s:
- ; ******************************************************************
- ; ON BB51 and BB1, BB2 at 1S, all using internal 1.65V ADC reference
- ; ******************************************************************
- mov A, ADC0H
- jnz scheduler_steps_odd_temperature_frame_pr1s_temperature_above_0
-
-scheduler_steps_odd_temperature_frame_pr1s_temperature_below_0:
- ; If Hi Byte is not 0x01 we are definetly below 0, thus
- ; clamp to 0.
- clr A
- sjmp scheduler_steps_odd_temperature_frame_temp_load
-
-scheduler_steps_odd_temperature_frame_pr1s_temperature_above_0:
- ; Prepare extended telemetry temperature value for next telemetry transmission
- ; On BB51 they hi byte is always 1 if the temperature is above 0ºC.
- ; In fact the value is 0x0114 at 0ºC, thus we ignore the hi byte and normalize
- ; the low byte to
- mov A, ADC0L
- subb A, #14h
- sjmp scheduler_steps_odd_temperature_frame_temp_load
-
-scheduler_steps_odd_temperature_frame_power_rating_2s:
- ; *****************************************************
- ; ON BB1, BB2 at more than 1S, using vdd V3.3 ADC reference
- ; *****************************************************
- ; Prepare extended telemetry temperature value for next telemetry transmission
- ; Check value above or below 20ºC - this is an approximation ADCOH having a value
- ; of 0x01 equals to around 22.5ºC.
- mov A, ADC0H
- jnz scheduler_steps_odd_temperature_frame_pr2s_temperature_above_20
-
-scheduler_steps_odd_temperature_frame_pr2s_temperature_below_20:
- ; Value below 20ºC -> to code between 0-20
- mov A, ADC0L
- clr C
- subb A, #(255 - 20)
- jnc scheduler_steps_odd_temperature_frame_temp_load
-
- ; Value below 0ºC -> clamp to 0
- clr A
- sjmp scheduler_steps_odd_temperature_frame_temp_load
-
-scheduler_steps_odd_temperature_frame_pr2s_temperature_above_20:
- ; Value above 20ºC -> to code between 20-255
- mov A, ADC0L ; This is an approximation: 9 ADC steps @10 Bit are 10 degrees
- add A, #20
-
-scheduler_steps_odd_temperature_frame_temp_load:
- mov Ext_Telemetry_L, A ; Set telemetry low value with temperature data
- mov Ext_Telemetry_H, #02h ; Set telemetry high value on first repeated dshot coding partition
-
- ; Now restart ADC conversion
-
-scheduler_steps_odd_restart_ADC:
- ; ********************* START NEW ADC CONVERSION *****************
-
- ; Start a new ADC conversion so after 64ms it will be ready for stage 2 og 128ms scheduler
- Stop_Adc
- Start_Adc
-
- ; Nothing else to do
-
-scheduler_exit:
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Commutation and timing
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Initialize timing
-;
-; Part of initialization before motor start
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-initialize_timing:
- ; Initialize commutation period to 7.5ms (~1330 erpm)
- mov Comm_Period4x_L, #00h
- mov Comm_Period4x_H, #0F0h
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Calculate next commutation period
-;
-; Measure the duration of current commutation period,
-; and update Comm_Period4x by averaging a fraction of it.
-;
-; Called immediately after each commutation
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-calc_next_comm_period:
- ; Read commutation time
- clr IE_EA
- clr TMR2CN0_TR2 ; Timer2 disabled
- mov Temp1, TMR2L ; Load Timer2 value
- mov Temp2, TMR2H
- mov Temp3, Timer2_X
- jnb TMR2CN0_TF2H, ($+4) ; Check if interrupt is pending
- inc Temp3 ; If it is pending, then timer has already wrapped
- setb TMR2CN0_TR2 ; Timer2 enabled
- setb IE_EA
-
-IF MCU_TYPE >= 1
- clr C ; Divide time by 2 on 48MHz
- rrca Temp3
- rrca Temp2
- rrca Temp1
-ENDIF
-
- jb Flag_Startup_Phase, calc_next_comm_startup
-
- ; Calculate this commutation time
- clr C
- mov A, Temp1
- subb A, Prev_Comm_L ; Calculate the new commutation time
- mov Prev_Comm_L, Temp1 ; Save timestamp as previous commutation
- mov Temp1, A ; Store commutation period in Temp1 (lo byte)
- mov A, Temp2
- subb A, Prev_Comm_H
- mov Prev_Comm_H, Temp2 ; Save timestamp as previous commutation
-IF MCU_TYPE >= 1
- anl A, #7Fh
-ENDIF
- mov Temp2, A ; Store commutation period in Temp2 (hi byte)
-
- jnb Flag_High_Rpm, calc_next_comm_normal ; Branch normal rpm
- ajmp calc_next_comm_period_fast ; Branch high rpm
-
-calc_next_comm_startup:
- ; Calculate this commutation time
- mov Temp4, Prev_Comm_L
- mov Temp5, Prev_Comm_H
- mov Temp6, Prev_Comm_X
- mov Prev_Comm_L, Temp1 ; Store timestamp as previous commutation
- mov Prev_Comm_H, Temp2
- mov Prev_Comm_X, Temp3 ; Store extended timestamp as previous commutation
-
- clr C
- mov A, Temp1
- subb A, Temp4 ; Calculate the new commutation time
- mov A, Temp2
- subb A, Temp5
- mov A, Temp3
- subb A, Temp6 ; Calculate the new extended commutation time
-IF MCU_TYPE >= 1
- anl A, #7Fh
-ENDIF
- jz calc_next_comm_startup_no_X
-
- ; Extended byte is not zero, so commutation time is above 0xFFFF
- mov Comm_Period4x_L, #0FFh
- mov Comm_Period4x_H, #0FFh
- ajmp calc_next_comm_done
-
-calc_next_comm_startup_no_X:
- ; Extended byte = 0, so commutation time fits within two bytes
- mov Temp7, Prev_Prev_Comm_L
- mov Temp8, Prev_Prev_Comm_H
- mov Prev_Prev_Comm_L, Temp4
- mov Prev_Prev_Comm_H, Temp5
-
- ; Calculate the new commutation time based upon the two last commutations (to reduce sensitivity to offset)
- clr C
- mov A, Temp1
- subb A, Temp7
- mov Temp1, A
- mov A, Temp2
- subb A, Temp8
- mov Temp2, A
-
- mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
- mov Temp4, Comm_Period4x_H
-
- sjmp calc_next_comm_div_4_1
-
-calc_next_comm_normal:
- ; Prepare averaging by dividing Comm_Period4x and current commutation period (Temp2/1) according to speed.
- mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
- mov Temp4, Comm_Period4x_H
-
- clr C
- mov A, Temp4 ; Is Comm_Period4x_H below 4? (above ~80k erpm)
- subb A, #4
- jc calc_next_comm_div_16_4 ; Yes - Use averaging for high speeds
-
- subb A, #4 ; Is Comm_Period4x_H below 8? (above ~40k erpm)
- jc calc_next_comm_div_8_2 ; Yes - Use averaging for low speeds
-
- ; No - Use averaging for even lower speeds
-
- ; Do not average very fast during initial run
- jb Flag_Initial_Run_Phase, calc_next_comm_div_8_2_slow
-
-calc_next_comm_div_4_1:
- ; Update Comm_Period4x from 1 new commutation period
-
- ; Divide Temp4/3 by 4 and store in Temp6/5
- Divide_By_4 Temp4, Temp3, Temp6, Temp5
-
- sjmp calc_next_comm_average_and_update
-
-calc_next_comm_div_8_2:
- ; Update Comm_Period4x from 1/2 new commutation period
-
- ; Divide Temp4/3 by 8 and store in Temp5
- Divide_11Bit_By_8 Temp4, Temp3, Temp5
- mov Temp6, #0
-
- clr C ; Divide by 2
- rrca Temp2
- rrca Temp1
-
- sjmp calc_next_comm_average_and_update
-
-calc_next_comm_div_8_2_slow:
- ; Update Comm_Period4x from 1/2 new commutation period
-
- ; Divide Temp4/3 by 8 and store in Temp6/5
- Divide_By_8 Temp4, Temp3, Temp6, Temp5
-
- clr C ; Divide by 2
- rrca Temp2
- rrca Temp1
-
- sjmp calc_next_comm_average_and_update
-
-calc_next_comm_div_16_4:
- ; Update Comm_Period4x from 1/4 new commutation period
-
- ; Divide Temp4/3 by 16 and store in Temp5
- Divide_12Bit_By_16 Temp4, Temp3, Temp5
- mov Temp6, #0
-
- ; Divide Temp2/1 by 4 and store in Temp2/1
- Divide_By_4 Temp2, Temp1, Temp2, Temp1
-
-calc_next_comm_average_and_update:
- ; Comm_Period4x = Comm_Period4x - (Comm_Period4x / (16, 8 or 4)) + (Comm_Period / (4, 2 or 1))
-
- ; Temp6/5: Comm_Period4x divided by (16, 8 or 4)
- clr C ; Subtract a fraction
- mov A, Temp3 ; Comm_Period4x_L
- subb A, Temp5
- mov Temp3, A
- mov A, Temp4 ; Comm_Period4x_H
- subb A, Temp6
- mov Temp4, A
-
- ; Temp2/1: This commutation period divided by (4, 2 or 1)
- mov A, Temp3 ; Add the divided new time
- add A, Temp1
- mov Comm_Period4x_L, A
- mov A, Temp4
- addc A, Temp2
- mov Comm_Period4x_H, A
-
- jnc calc_next_comm_done ; Is period larger than 0xffff?
- mov Comm_Period4x_L, #0FFh ; Yes - Set commutation period registers to very slow timing (0xffff)
- mov Comm_Period4x_H, #0FFh
-
-calc_next_comm_done:
- clr C
- mov A, Comm_Period4x_H
- subb A, #2 ; Is Comm_Period4x_H below 2? (above ~160k erpm)
- jnc ($+4)
- setb Flag_High_Rpm ; Yes - Set high rpm flag
-
-calc_next_comm_15deg:
- ; Commutation period: 360 deg / 6 runs = 60 deg
- ; 60 deg / 4 = 15 deg
-
- ; Load current commutation timing and compute 15 deg timing
- ; Divide Comm_Period4x by 16 (Comm_Period1x divided by 4) and store in Temp4/3
- Divide_By_16 Comm_Period4x_H, Comm_Period4x_L, Temp4, Temp3
-
- ; Subtract timing reduction
- clr C
- mov A, Temp3
- subb A, #2 ; Set timing reduction
- mov Temp3, A
- mov A, Temp4
- subb A, #0
- mov Temp4, A
-
- jc calc_next_comm_15deg_set_min ; Check that result is still positive
- jnz calc_next_comm_period_exit ; Check that result is still above minimum
- mov A, Temp3
- jnz calc_next_comm_period_exit
-
-calc_next_comm_15deg_set_min:
- mov Temp3, #1 ; Set minimum waiting time (Timers cannot wait for a delay of 0)
- mov Temp4, #0
-
- sjmp calc_next_comm_period_exit
-
-;**** **** **** **** ****
-; Calculate next commutation period (fast)
-; Fast calculation (Comm_Period4x_H less than 2)
-calc_next_comm_period_fast:
- ; Calculate new commutation time
- mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
- mov Temp4, Comm_Period4x_H
-
- ; Divide by 16 and store in Temp5
- Divide_12Bit_By_16 Temp4, Temp3, Temp5
-
- clr C
- mov A, Temp3 ; Subtract a fraction
- subb A, Temp5
- mov Temp3, A
- mov A, Temp4
- subb A, #0
- mov Temp4, A
-
- ; Note: Temp2 is assumed to be zero (approx. Comm_Period4x_H / 4)
- mov A, Temp1 ; Divide by 4
- rr A
- rr A
- anl A, #03Fh
-
- add A, Temp3 ; Add the divided new time
- mov Temp3, A
- mov A, Temp4
- addc A, #0
- mov Temp4, A
-
- mov Comm_Period4x_L, Temp3 ; Store Comm_Period4x
- mov Comm_Period4x_H, Temp4
-
- clr C
- subb A, #2 ; Is Comm_Period4x_H 2 or more? (below ~160k erpm)
- jc ($+4)
- clr Flag_High_Rpm ; Yes - Clear high rpm bit
-
- mov A, Temp4 ; Divide Comm_Period4x by 16 and store in Temp4/3
- swap A
- mov Temp7, A
- mov Temp4, #0 ; Clear waiting time high byte
- mov A, Temp3
- swap A
- anl A, #0Fh
- orl A, Temp7
- clr C
- subb A, #2 ; Timing reduction
- mov Temp3, A
- jc calc_next_comm_fast_set_min ; Check that result is still positive
- jnz calc_next_comm_period_exit ; Check that result is still above minimum
-
-calc_next_comm_fast_set_min:
- mov Temp3, #1 ; Set minimum waiting time (Timers cannot wait for a delay of 0)
-
-calc_next_comm_period_exit:
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Wait advance timing
-;
-; Waits for the advance timing to elapse
-;
-; NOTE: Be VERY careful if using temp registers. They are passed over this routine
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-wait_advance_timing:
- ; If it has not already, we wait here for the Wt_Adv_Start_ delay to elapse.
- Wait_For_Timer3
-
- ; At this point Timer3 has (already) wrapped and been reloaded with the Wt_Zc_Scan_Start_ delay.
- ; In case this delay has also elapsed, Timer3 has been reloaded with a short delay any number of times.
- ; - The interrupt flag is set and the pending flag will clear immediately after enabling the interrupt.
-
- mov TMR3RLL, Wt_ZC_Tout_Start_L ; Setup next wait time
- mov TMR3RLH, Wt_ZC_Tout_Start_H
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Calculate new wait times
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-calc_new_wait_times:
- mov Temp1, #Pgm_Comm_Timing ; Load commutation timing setting
- mov A, @Temp1
- mov Temp8, A ; Store in Temp8
-
- clr C
- clr A
- subb A, Temp3 ; Negate
- mov Temp1, A
- clr A
- subb A, Temp4
- mov Temp2, A
-IF MCU_TYPE >= 1
- clr C
- rlca Temp1 ; Multiply by 2
- rlca Temp2
-ENDIF
-
- ; Temp2/1 = 15deg Timer2 period
-
- jb Flag_High_Rpm, calc_new_wait_times_fast ; Branch if high rpm
-
- ; Load programmed commutation timing
- jnb Flag_Startup_Phase, adjust_comm_timing
-
- mov Temp8, #3 ; Set dedicated timing during startup
- sjmp load_comm_timing_done
-
-adjust_comm_timing:
- ; Adjust commutation timing according to demag metric
- clr C
- mov A, Demag_Detected_Metric ; Check demag metric
- subb A, #130
- jc load_comm_timing_done
-
- inc Temp8 ; Increase timing (if metric 130 or above)
-
- subb A, #30
- jc ($+3)
-
- inc Temp8 ; Increase timing again (if metric 160 or above)
-
- clr C
- mov A, Temp8 ; Limit timing to max
- subb A, #6
- jc ($+4)
-
- mov Temp8, #5 ; Set timing to max (if timing 6 or above)
-
-load_comm_timing_done:
- mov A, Temp1 ; Copy values
- mov Temp3, A
- mov A, Temp2
- mov Temp4, A
-
- setb C ; Negative numbers - set carry
- mov A, Temp2 ; Store 7.5deg in Temp5/6 (15deg / 2)
- rrc A
- mov Temp6, A
- mov A, Temp1
- rrc A
- mov Temp5, A
-
- mov Wt_Zc_Scan_Start_L, Temp5 ; Set 7.5deg time for zero cross scan delay
- mov Wt_Zc_Scan_Start_H, Temp6
- mov Wt_Zc_Tout_Start_L, Temp1 ; Set 15deg time for zero cross scan timeout
- mov Wt_Zc_Tout_Start_H, Temp2
-
- clr C
- mov A, Temp8 ; (Temp8 has Pgm_Comm_Timing)
- subb A, #3 ; Is timing normal?
- jz store_times_decrease ; Yes - branch
-
- mov A, Temp8
- jb ACC.0, adjust_timing_two_steps; If an odd number - branch
-
- ; Commutation timing setting is 2 or 4
- mov A, Temp1 ; Store 22.5deg in Temp1/2 (15deg + 7.5deg)
- add A, Temp5
- mov Temp1, A
- mov A, Temp2
- addc A, Temp6
- mov Temp2, A
-
- mov A, Temp5 ; Store 7.5deg in Temp3/4
- mov Temp3, A
- mov A, Temp6
- mov Temp4, A
-
- sjmp store_times_up_or_down
-
-adjust_timing_two_steps:
- ; Commutation timing setting is 1 or 5
- mov A, Temp1 ; Store 30deg in Temp1/2 (15deg + 15deg)
- setb C ; Add 1 to final result (Temp1/2 * 2 + 1)
- addc A, Temp1
- mov Temp1, A
- mov A, Temp2
- addc A, Temp2
- mov Temp2, A
-
- mov Temp3, #-1 ; Store minimum time (0deg) in Temp3/4
- mov Temp4, #-1
-
-store_times_up_or_down:
- clr C
- mov A, Temp8
- subb A, #3 ; Is timing higher than normal?
- jc store_times_decrease ; No - branch
-
-store_times_increase:
- mov Wt_Comm_Start_L, Temp3 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
- mov Wt_Comm_Start_H, Temp4
- mov Wt_Adv_Start_L, Temp1 ; New commutation advance time (~15deg nominal)
- mov Wt_Adv_Start_H, Temp2
- sjmp calc_new_wait_times_exit
-
-store_times_decrease:
- mov Wt_Comm_Start_L, Temp1 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
- mov Wt_Comm_Start_H, Temp2
- mov Wt_Adv_Start_L, Temp3 ; New commutation advance time (~15deg nominal)
- mov Wt_Adv_Start_H, Temp4
-
- ; Set very short delays for all but advance time during startup, in order to widen zero cross capture range
- jnb Flag_Startup_Phase, calc_new_wait_times_exit
- mov Wt_Comm_Start_L, #-16
- mov Wt_Comm_Start_H, #-1
- mov Wt_Zc_Scan_Start_L, #-16
- mov Wt_Zc_Scan_Start_H, #-1
- mov Wt_Zc_Tout_Start_L, #-16
- mov Wt_Zc_Tout_Start_H, #-1
-
- sjmp calc_new_wait_times_exit
-
-;**** **** **** **** ****
-; Calculate new wait times fast routine
-calc_new_wait_times_fast:
- mov A, Temp1 ; Copy values
- mov Temp3, A
- setb C ; Negative numbers - set carry
- rrc A ; Divide by 2
- mov Temp5, A
-
- mov Wt_Zc_Scan_Start_L, Temp5 ; Use this value for zero cross scan delay (7.5deg)
- mov Wt_Zc_Tout_Start_L, Temp1 ; Set 15deg time for zero cross scan timeout
-
- clr C
- mov A, Temp8 ; (Temp8 has Pgm_Comm_Timing)
- subb A, #3 ; Is timing normal?
- jz store_times_decrease_fast ; Yes - branch
-
- mov A, Temp8
- jb ACC.0, adjust_timing_two_steps_fast ; If an odd number - branch
-
- mov A, Temp1 ; Add 7.5deg and store in Temp1
- add A, Temp5
- mov Temp1, A
- mov A, Temp5 ; Store 7.5deg in Temp3
- mov Temp3, A
- sjmp store_times_up_or_down_fast
-
-adjust_timing_two_steps_fast:
- mov A, Temp1 ; Add 15deg and store in Temp1
- add A, Temp1
- add A, #1
- mov Temp1, A
- mov Temp3, #-1 ; Store minimum time in Temp3
-
-store_times_up_or_down_fast:
- clr C
- mov A, Temp8
- subb A, #3 ; Is timing higher than normal?
- jc store_times_decrease_fast ; No - branch
-
-store_times_increase_fast:
- mov Wt_Comm_Start_L, Temp3 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
- mov Wt_Adv_Start_L, Temp1 ; New commutation advance time (~15deg nominal)
- sjmp calc_new_wait_times_exit
-
-store_times_decrease_fast:
- mov Wt_Comm_Start_L, Temp1 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
- mov Wt_Adv_Start_L, Temp3 ; New commutation advance time (~15deg nominal)
-
-calc_new_wait_times_exit:
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Wait before zero cross scan
-;
-; Waits for the zero cross scan wait time to elapse
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-wait_before_zc_scan:
- ; If it has not already, we wait here for the Wt_Zc_Scan_Start_ delay to elapse.
- Wait_For_Timer3
-
- ; At this point Timer3 has (already) wrapped and been reloaded with the Wt_ZC_Tout_Start_ delay.
- ; In case this delay has also elapsed, Timer3 has been reloaded with a short delay any number of times.
- ; - The interrupt flag is set and the pending flag will clear immediately after enabling the interrupt.
-
- mov Startup_Zc_Timeout_Cntd, #2
-
-setup_zc_scan_timeout:
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
-
- jnb Flag_Initial_Run_Phase, wait_before_zc_scan_exit
-
- mov Temp1, Comm_Period4x_L ; Set long timeout when starting
- mov Temp2, Comm_Period4x_H
- clr C
- rrca Temp2
- rrca Temp1
-IF MCU_TYPE == 0
- clr C
- rrca Temp2
- rrca Temp1
-ENDIF
- jnb Flag_Startup_Phase, setup_zc_scan_timeout_startup_done
-
- mov A, Temp2
- add A, #40h ; Increase timeout somewhat to avoid false wind up
- mov Temp2, A
-
-setup_zc_scan_timeout_startup_done:
- clr IE_EA
- anl EIE1, #7Fh ; Disable Timer3 interrupts
- mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
- clr C
- clr A
- subb A, Temp1 ; Set timeout
- mov TMR3L, A
- clr A
- subb A, Temp2
- mov TMR3H, A
- mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
- setb IE_EA
-
-wait_before_zc_scan_exit:
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Wait for comparator to go low/high
-;
-; Scans for comparator going low/high
-; Exit if zero cross timeout has elapsed
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-wait_for_comp_out_low:
- mov B, #00h ; Desired comparator output
- jnb Flag_Dir_Change_Brake, comp_init
- mov B, #40h
- sjmp comp_init
-
-wait_for_comp_out_high:
- mov B, #40h ; Desired comparator output
- jnb Flag_Dir_Change_Brake, comp_init
- mov B, #00h
-
-comp_init:
- setb Flag_Demag_Detected ; Set demag detected flag as default
- mov Comparator_Read_Cnt, #0 ; Reset number of comparator reads
-
-comp_start:
- ; Set number of comparator readings required
- mov Temp3, #(1 SHL IS_MCU_48MHZ) ; Number of OK readings required
- mov Temp4, #(1 SHL IS_MCU_48MHZ) ; Max number of readings required
- jb Flag_High_Rpm, comp_check_timeout ; Branch if high rpm
-
- jnb Flag_Initial_Run_Phase, ($+5)
- clr Flag_Demag_Detected ; Clear demag detected flag if start phases
-
- jnb Flag_Startup_Phase, comp_not_startup
- mov Temp3, #(27 SHL IS_MCU_48MHZ) ; Set many samples during startup, approximately one pwm period
- mov Temp4, #(27 SHL IS_MCU_48MHZ)
- sjmp comp_check_timeout
-
-comp_not_startup:
- ; Too low value (~<15) causes rough running at pwm harmonics.
- ; Too high a value (~>35) causes the RCT4215 630 to run rough on full throttle
- mov Temp4, #(20 SHL IS_MCU_48MHZ)
- mov A, Comm_Period4x_H ; Set number of readings higher for lower speeds
-IF MCU_TYPE == 0
- clr C
- rrc A
-ENDIF
- jnz ($+3)
- inc A ; Minimum 1
- mov Temp3, A
- clr C
- subb A, #(20 SHL IS_MCU_48MHZ)
- jc ($+4)
- mov Temp3, #(20 SHL IS_MCU_48MHZ) ; Maximum 20
-
-comp_check_timeout:
- jb Flag_Timer3_Pending, comp_check_timeout_not_timed_out ; Has zero cross scan timeout elapsed?
-
- mov A, Comparator_Read_Cnt ; Check that comparator has been read
- jz comp_check_timeout_not_timed_out ; If not yet read - ignore zero cross timeout
-
- jnb Flag_Startup_Phase, comp_check_timeout_timeout_extended
-
- ; Extend timeout during startup
- djnz Startup_Zc_Timeout_Cntd, comp_check_timeout_extend_timeout
-
-comp_check_timeout_timeout_extended:
- setb Flag_Comp_Timed_Out
- sjmp comp_exit
-
-comp_check_timeout_extend_timeout:
- call setup_zc_scan_timeout
-
-comp_check_timeout_not_timed_out:
- inc Comparator_Read_Cnt ; Increment comparator read count
- Read_Comparator_Output
- anl A, #40h
- cjne A, B, comp_read_wrong
-
- ; Comp read ok
- mov A, Startup_Cnt ; Force a timeout for the first commutation
- jz comp_start
-
- jb Flag_Demag_Detected, comp_start ; Do not accept correct comparator output if it is demag
-
- djnz Temp3, comp_check_timeout ; Decrement readings counter - repeat comparator reading if not zero
-
- clr Flag_Comp_Timed_Out
- sjmp comp_exit
-
-comp_read_wrong:
- jb Flag_Startup_Phase, comp_read_wrong_startup
- jb Flag_Demag_Detected, comp_read_wrong_extend_timeout
-
- inc Temp3 ; Increment number of OK readings required
- clr C
- mov A, Temp3
- subb A, Temp4
- jc comp_check_timeout ; If below initial requirement - take another reading
- sjmp comp_start ; Otherwise - go back and restart
-
-comp_read_wrong_startup:
- inc Temp3 ; Increment number of OK readings required
- clr C
- mov A, Temp3
- subb A, Temp4 ; If above initial requirement - do not increment further
- jc ($+3)
- dec Temp3
-
- sjmp comp_check_timeout ; Continue to look for good ones
-
-comp_read_wrong_extend_timeout:
- clr Flag_Demag_Detected ; Clear demag detected flag
- anl EIE1, #7Fh ; Disable Timer3 interrupts
- mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
- jnb Flag_High_Rpm, comp_read_wrong_low_rpm ; Branch if not high rpm
-
- mov TMR3L, #0 ; Set timeout to ~1ms
- mov TMR3H, #-(8 SHL IS_MCU_48MHZ)
-
-comp_read_wrong_timeout_set:
- mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
- ljmp comp_start ; If comparator output is not correct - go back and restart
-
-comp_read_wrong_low_rpm:
- mov A, Comm_Period4x_H ; Set timeout to ~4x comm period 4x value
- mov Temp7, #0FFh ; Default to long timeout
-
-IF MCU_TYPE >= 1
- clr C
- rlc A
- jc comp_read_wrong_load_timeout
-ENDIF
-
- clr C
- rlc A
- jc comp_read_wrong_load_timeout
-
- clr C
- rlc A
- jc comp_read_wrong_load_timeout
-
- mov Temp7, A
-
-comp_read_wrong_load_timeout:
- clr C
- clr A
- subb A, Temp7
- mov TMR3L, #0
- mov TMR3H, A
- sjmp comp_read_wrong_timeout_set
-
-comp_exit:
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Setup commutation timing
-;
-; Clear the zero cross timeout and sets up wait from zero cross to commutation
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-setup_comm_wait:
- clr IE_EA
- anl EIE1, #7Fh ; Disable Timer3 interrupts
-
- ; It is necessary to update the timer reload registers before the timer registers,
- ; to avoid a reload of the previous values in case of a short Wt_Comm_Start delay.
-
- ; Advance wait time will be loaded by Timer3 immediately after the commutation wait elapses
- mov TMR3RLL, Wt_Adv_Start_L ; Setup next wait time
- mov TMR3RLH, Wt_Adv_Start_H
- mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
- mov TMR3L, Wt_Comm_Start_L
- mov TMR3H, Wt_Comm_Start_H
- mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
-
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
- setb IE_EA ; Enable interrupts again
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Evaluate comparator integrity
-;
-; Checks comparator signal behavior versus expected behavior
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-evaluate_comparator_integrity:
- jb Flag_Startup_Phase, eval_comp_startup ; Do not exit run mode during startup phases
-
- jnb Flag_Comp_Timed_Out, eval_comp_exit ; Has timeout elapsed?
- jb Flag_Initial_Run_Phase, eval_comp_exit ; Do not exit run mode if initial run phase
- jb Flag_Dir_Change_Brake, eval_comp_exit ; Do not exit run mode if braking
- jb Flag_Demag_Detected, eval_comp_exit ; Do not exit run mode if it is a demag situation
-
- dec SP ; Routine exit without "ret" command
- dec SP
- ljmp exit_run_mode_on_timeout ; Exit run mode if timeout has elapsed
-
-eval_comp_startup:
- inc Startup_Cnt ; Increment startup counter
-
-eval_comp_exit:
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Wait for commutation
-;
-; Waits from zero cross to commutation
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-wait_for_comm:
- ; Update demag metric
- mov A, Demag_Detected_Metric ; Sliding average of 8, 256 when demag and 0 when not. Limited to minimum 120
- mov B, #7
- mul AB ; Multiply by 7
-
- jnb Flag_Demag_Detected, wait_for_comm_demag_event_added
- ; Add new value for current demag status
- inc B
- ; Signal demag
- setb Flag_Demag_Notify
-
-wait_for_comm_demag_event_added:
- mov C, B.0 ; Divide by 8
- rrc A
- mov C, B.1
- rrc A
- mov C, B.2
- rrc A
- mov Demag_Detected_Metric, A
- clr C
- subb A, #120 ; Limit to minimum 120
- jnc ($+5)
- mov Demag_Detected_Metric, #120
-
- ; Update demag metric max
- clr C
- mov A, Demag_Detected_Metric
- subb A, Demag_Detected_Metric_Max
- jc wait_for_comm_demag_metric_max_updated
- mov Demag_Detected_Metric_Max, Demag_Detected_Metric
-
-wait_for_comm_demag_metric_max_updated:
- ; Check demag metric
- clr C
- mov A, Demag_Detected_Metric
- subb A, Demag_Pwr_Off_Thresh
- jc wait_for_comm_wait
-
- ; Signal desync
- setb Flag_Desync_Notify;
-
- ; Cut power if many consecutive demags. This will help retain sync during hard accelerations
- All_Pwm_Fets_Off
- Set_All_Pwm_Phases_Off
-
-wait_for_comm_wait:
- ; If it has not already, we wait here for the Wt_Comm_Start_ delay to elapse.
- Wait_For_Timer3
-
- ; At this point Timer3 has (already) wrapped and been reloaded with the Wt_Adv_Start_ delay.
- ; In case this delay has also elapsed, Timer3 has been reloaded with a short delay any number of times.
- ; - The interrupt flag is set and the pending flag will clear immediately after enabling the interrupt.
-
- mov TMR3RLL, Wt_Zc_Scan_Start_L ; Setup next wait time
- mov TMR3RLH, Wt_Zc_Scan_Start_H
- setb Flag_Timer3_Pending
- orl EIE1, #80h ; Enable Timer3 interrupts
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Commutation routines
-;
-; Performs commutation switching
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-; Comm phase 1 to comm phase 2
-comm1_comm2: ; C->A
- jb Flag_Motor_Dir_Rev, comm1_comm2_rev
-
- clr IE_EA
- B_Com_Fet_Off
- A_Com_Fet_On
- Set_Pwm_Phase_C ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_B
- ret
-
-comm1_comm2_rev: ; A->C
- clr IE_EA
- B_Com_Fet_Off
- C_Com_Fet_On
- Set_Pwm_Phase_A ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_B
- ret
-
-; Comm phase 2 to comm phase 3
-comm2_comm3: ; B->A
- jb Flag_Motor_Dir_Rev, comm2_comm3_rev
-
- clr IE_EA
- C_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_B
- A_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_C
- ret
-
-comm2_comm3_rev: ; B->C
- clr IE_EA
- A_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_B
- C_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_A
- ret
-
-; Comm phase 3 to comm phase 4
-comm3_comm4: ; B->C
- jb Flag_Motor_Dir_Rev, comm3_comm4_rev
-
- clr IE_EA
- A_Com_Fet_Off
- C_Com_Fet_On
- Set_Pwm_Phase_B ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_A
- ret
-
-comm3_comm4_rev: ; B->A
- clr IE_EA
- C_Com_Fet_Off
- A_Com_Fet_On
- Set_Pwm_Phase_B ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_C
- ret
-
-; Comm phase 4 to comm phase 5
-comm4_comm5: ; A->C
- jb Flag_Motor_Dir_Rev, comm4_comm5_rev
-
- clr IE_EA
- B_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_A
- C_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_B
- ret
-
-comm4_comm5_rev: ; C->A
- clr IE_EA
- B_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_C
- A_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_B
- ret
-
-; Comm phase 5 to comm phase 6
-comm5_comm6: ; A->B
- jb Flag_Motor_Dir_Rev, comm5_comm6_rev
-
- clr IE_EA
- C_Com_Fet_Off
- B_Com_Fet_On
- Set_Pwm_Phase_A ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_C
- ret
-
-comm5_comm6_rev: ; C->B
- clr IE_EA
- A_Com_Fet_Off
- B_Com_Fet_On
- Set_Pwm_Phase_C ; Reapply power after a demag cut
- setb IE_EA
- Set_Comparator_Phase_A
- ret
-
-; Comm phase 6 to comm phase 1
-comm6_comm1: ; C->B
- jb Flag_Motor_Dir_Rev, comm6_comm1_rev
-
- clr IE_EA
- A_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_C
- B_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_A
- ret
-
-comm6_comm1_rev: ; A->B
- clr IE_EA
- C_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
- Set_Pwm_Phase_A
- B_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
- setb IE_EA
- Set_Comparator_Phase_C
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; DShot
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Detect DShot RCP level
-;
-; Determine if RCP signal level is normal or inverted DShot
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-detect_rcp_level:
- mov A, #50 ; Must detect the same level 50 times (25 us)
- mov C, RTX_BIT
-
-detect_rcp_level_read:
- jc ($+5)
- jb RTX_BIT, detect_rcp_level ; Level changed from low to high - start over
- jnc ($+5)
- jnb RTX_BIT, detect_rcp_level ; Level changed from high to low - start over
- djnz ACC, detect_rcp_level_read
-
- mov Flag_Rcp_DShot_Inverted, C
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Check DShot command
-;
-; Determine received DShot command and perform action
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-dshot_cmd_check:
- mov A, DShot_Cmd
- jnz dshot_cmd_beeps_check
- ret
-
-dshot_cmd_beeps_check:
- mov Temp1, A
- clr C
- subb A, #6 ; Beacon beeps for command 1-5
- jnc dshot_cmd_check_count
-
- clr IE_EA ; Disable all interrupts
- call switch_power_off ; Switch power off in case braking is set
- call beacon_beep
- call wait200ms ; Wait a bit for next beep
- setb IE_EA ; Enable all interrupts
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_check_count:
- ; Remaining commands must be received 6 times in a row
- clr C
- mov A, DShot_Cmd_Cnt
- subb A, #6
- jc dshot_cmd_exit_no_clear
-
-dshot_cmd_direction_normal:
- ; Set motor spinning direction to normal
- cjne Temp1, #7, dshot_cmd_direction_reverse
-
- clr Flag_Pgm_Dir_Rev
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_direction_reverse:
- ; Set motor spinning direction to reversed
- cjne Temp1, #8, dshot_cmd_direction_bidir_off
-
- setb Flag_Pgm_Dir_Rev
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_direction_bidir_off:
- ; Set motor control mode to normal (not bidirectional)
- cjne Temp1, #9, dshot_cmd_direction_bidir_on
-
- clr Flag_Pgm_Bidir
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_direction_bidir_on:
- ; Set motor control mode to bidirectional
- cjne Temp1, #10, dshot_cmd_extended_telemetry_enable
-
- setb Flag_Pgm_Bidir
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_extended_telemetry_enable:
- ; Enable extended telemetry
- cjne Temp1, #13, dshot_cmd_extended_telemetry_disable
-
- mov Ext_Telemetry_L, #00h
- mov Ext_Telemetry_H, #0Eh ; Send state/event 0 frame to signal telemetry enable
-
- setb Flag_Ext_Tele
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_extended_telemetry_disable:
- ; Disable extended telemetry
- cjne Temp1, #14, dshot_cmd_direction_user_normal
-
- mov Ext_Telemetry_L, #0FFh
- mov Ext_Telemetry_H, #0Eh ; Send state/event 0xff frame to signal telemetry disable
-
- clr Flag_Ext_Tele
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_direction_user_normal:
- ; Set motor spinning direction to user programmed direction
- cjne Temp1, #20, dshot_cmd_direction_user_reverse
-
- mov Temp2, #Pgm_Direction ; Read programmed direction
- mov A, @Temp2
- dec A
- mov C, ACC.0 ; Set direction
- mov Flag_Pgm_Dir_Rev, C
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_direction_user_reverse: ; Temporary reverse
- ; Set motor spinning direction to reverse of user programmed direction
- cjne Temp1, #21, dshot_cmd_save_settings
-
- mov Temp2, #Pgm_Direction ; Read programmed direction
- mov A, @Temp2
- dec A
- mov C, ACC.0
- cpl C ; Set reverse direction
- mov Flag_Pgm_Dir_Rev, C
-
- sjmp dshot_cmd_exit
-
-dshot_cmd_save_settings:
- cjne Temp1, #12, dshot_cmd_exit
-
- clr A ; Set programmed direction from flags
- mov C, Flag_Pgm_Dir_Rev
- mov ACC.0, C
- mov C, Flag_Pgm_Bidir
- mov ACC.1, C
- inc A
- mov Temp2, #Pgm_Direction ; Store programmed direction
- mov @Temp2, A
-
- mov Flash_Key_1, #0A5h ; Initialize flash keys to valid values
- mov Flash_Key_2, #0F1h
-
- call erase_and_store_all_in_eeprom
-
- mov Flash_Key_1, #0 ; Reset flash keys to invalid values
- mov Flash_Key_2, #0
-
- setb IE_EA
-
-dshot_cmd_exit:
- mov DShot_Cmd, #0 ; Clear DShot command and exit
- mov DShot_Cmd_Cnt, #0
-
-dshot_cmd_exit_no_clear:
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; DShot telemetry create packet
-;
-; Create DShot telemetry packet and prepare it for being sent
-; The routine is divided into 6 sections that can return early
-; in order to reduce commutation interference
-;
-; Requirements:
-; - Must NOT be called while Flag_Telemetry_Pending is set
-; - Must NOT write to Temp7, Temp8
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-dshot_tlm_create_packet:
- push PSW
- mov PSW, #10h ; Select register bank 2
-
- Early_Return_Packet_Stage 0
-
- ; If coded telemetry ready jump to telemetry ready
- mov A, Ext_Telemetry_H
- jnz dshot_tlm_ready
-
- clr IE_EA
- mov A, Comm_Period4x_L ; Read commutation period
- mov Tlm_Data_H, Comm_Period4x_H
- setb IE_EA
-
- ; Calculate e-period (6 commutations) in microseconds
- ; Comm_Period * 6 * 0.5 = Comm_Period4x * 3/4 (1/2 + 1/4)
- mov C, Tlm_Data_H.0
- rrc A
- mov Temp2, A
- mov C, Tlm_Data_H.1
- rrc A
- add A, Temp2
- mov Temp3, A ; Comm_Period3x_L
-
- mov A, Tlm_Data_H
- rr A
- clr ACC.7
- mov Temp2, A
- rr A
- clr ACC.7
- addc A, Temp2
- mov Temp4, A ; Comm_Period3x_H
-
- ; Timer2 ticks are ~489ns (not 500ns), so use approximation for better accuracy:
- ; E-period = Comm_Period3x - 4 * Comm_Period4x_H
-
- ; Note: For better performance assume Comm_Period4x_H < 64 (6-bit, above ~5k erpm)
- ; At lower speed result will be less precise
- mov A, Tlm_Data_H ; Comm_Period4x_H
- rl A ; Multiply by 4
- rl A
- anl A, #0FCh
- mov Temp5, A
-
- clr C
- mov A, Temp3 ; Comm_Period3x_L
- subb A, Temp5
- mov Tlm_Data_L, A
- mov A, Temp4 ; Comm_Period3x_H
- subb A, #0
- mov Tlm_Data_H, A
-
-dshot_tlm_ready:
- Early_Return_Packet_Stage 1
-
- ; If extended telemetry ready jump to extended telemetry coded
- mov A, Ext_Telemetry_H
- jnz dshot_tlm_ext_coded
-
- ; 12-bit encode telemetry data
- mov A, Tlm_Data_H
- jnz dshot_12bit_encode
- mov A, Tlm_Data_L ; Already 12-bit
- jnz dshot_tlm_12bit_encoded
-
- ; If period is zero then reset to FFFFh (FFFh for 12-bit)
- mov Tlm_Data_H, #0Fh
- mov Tlm_Data_L, #0FFh
- sjmp dshot_tlm_12bit_encoded
-
-dshot_tlm_ext_coded:
- ; Move extended telemetry data to telemetry data to send
- mov Tlm_Data_L, Ext_Telemetry_L
- mov Tlm_Data_H, Ext_Telemetry_H
- ; Clear extended telemetry data
- mov Ext_Telemetry_H, #0
-
-dshot_tlm_12bit_encoded:
- Early_Return_Packet_Stage 2
- mov A, Tlm_Data_L
-
- ; Compute inverted xor checksum (4-bit)
- swap A
- xrl A, Tlm_Data_L
- xrl A, Tlm_Data_H
- cpl A
-
- ; GCR encode the telemetry data (16-bit)
- mov Temp1, #Temp_Storage ; Store pulse timings in Temp_Storage
- mov @Temp1, DShot_GCR_Pulse_Time_1; Final transition time
-
- call dshot_gcr_encode ; GCR encode lowest 4-bit of A (store through Temp1)
-
- Early_Return_Packet_Stage 3
-
- mov A, Tlm_Data_L
- call dshot_gcr_encode
-
- Early_Return_Packet_Stage 4
-
- mov A, Tlm_Data_L
- swap A
- call dshot_gcr_encode
-
- Early_Return_Packet_Stage 5
-
- mov A, Tlm_Data_H
- call dshot_gcr_encode
-
- inc Temp1
- mov Temp7, #0 ; Reset current packet stage
-
- pop PSW
- setb Flag_Telemetry_Pending ; Mark that packet is ready to be sent
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; DShot 12-bit encode
-;
-; Encodes 16-bit e-period as a 12-bit value of the form:
-; where M SHL E ~ e-period [us]
-;
-; Note: Not callable to improve performance
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-dshot_12bit_encode:
- ; Encode 16-bit e-period as a 12-bit value
- jb ACC.7, dshot_12bit_7 ; ACC = Tlm_Data_H
- jb ACC.6, dshot_12bit_6
- jb ACC.5, dshot_12bit_5
- jb ACC.4, dshot_12bit_4
- jb ACC.3, dshot_12bit_3
- jb ACC.2, dshot_12bit_2
- jb ACC.1, dshot_12bit_1
- mov A, Tlm_Data_L ; Already 12-bit (E=0)
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_7:
- ;mov A, Tlm_Data_H
- mov C, Tlm_Data_L.7
- rlc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #0fh
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_6:
- ;mov A, Tlm_Data_H
- mov C, Tlm_Data_L.7
- rlc A
- mov C, Tlm_Data_L.6
- rlc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #0dh
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_5:
- ;mov A, Tlm_Data_H
- mov C, Tlm_Data_L.7
- rlc A
- mov C, Tlm_Data_L.6
- rlc A
- mov C, Tlm_Data_L.5
- rlc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #0bh
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_4:
- mov A, Tlm_Data_L
- anl A, #0f0h
- clr Tlm_Data_H.4
- orl A, Tlm_Data_H
- swap A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #09h
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_3:
- mov A, Tlm_Data_L
- mov C, Tlm_Data_H.0
- rrc A
- mov C, Tlm_Data_H.1
- rrc A
- mov C, Tlm_Data_H.2
- rrc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #07h
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_2:
- mov A, Tlm_Data_L
- mov C, Tlm_Data_H.0
- rrc A
- mov C, Tlm_Data_H.1
- rrc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #05h
- ajmp dshot_tlm_12bit_encoded
-
-dshot_12bit_1:
- mov A, Tlm_Data_L
- mov C, Tlm_Data_H.0
- rrc A
- mov Tlm_Data_L, A
- mov Tlm_Data_H, #03h
- ajmp dshot_tlm_12bit_encoded
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; DShot GCR encode
-;
-; GCR encode e-period data for DShot telemetry
-;
-; Input
-; - Temp1: Data pointer for storing pulse timings
-; - A: 4-bit value to GCR encode
-; - B: Time that must be added to transition
-; Output
-; - B: Time remaining to be added to next transition
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-dshot_gcr_encode:
- anl A, #0Fh
- rl A ; Multiply by 2 to match jump offsets
- mov DPTR, #dshot_gcr_encode_jump_table
- jmp @A+DPTR
-
-dshot_gcr_encode_jump_table:
- ajmp dshot_gcr_encode_0_11001
- ajmp dshot_gcr_encode_1_11011
- ajmp dshot_gcr_encode_2_10010
- ajmp dshot_gcr_encode_3_10011
- ajmp dshot_gcr_encode_4_11101
- ajmp dshot_gcr_encode_5_10101
- ajmp dshot_gcr_encode_6_10110
- ajmp dshot_gcr_encode_7_10111
- ajmp dshot_gcr_encode_8_11010
- ajmp dshot_gcr_encode_9_01001
- ajmp dshot_gcr_encode_A_01010
- ajmp dshot_gcr_encode_B_01011
- ajmp dshot_gcr_encode_C_11110
- ajmp dshot_gcr_encode_D_01101
- ajmp dshot_gcr_encode_E_01110
- ajmp dshot_gcr_encode_F_01111
-
-; GCR encoding is ordered by least significant bit first,
-; and represented as pulse durations.
-dshot_gcr_encode_0_11001:
- imov Temp1, DShot_GCR_Pulse_Time_3
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_1_11011:
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_2_10010:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_3
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_3_10011:
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_3
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_4_11101:
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_5_10101:
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_6_10110:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_7_10111:
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_8_11010:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_9_01001:
- imov Temp1, DShot_GCR_Pulse_Time_3
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-dshot_gcr_encode_A_01010:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-dshot_gcr_encode_B_01011:
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-dshot_gcr_encode_C_11110:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- ret
-
-dshot_gcr_encode_D_01101:
- imov Temp1, DShot_GCR_Pulse_Time_2
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-dshot_gcr_encode_E_01110:
- GCR_Add_Time Temp1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-dshot_gcr_encode_F_01111:
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_1
- imov Temp1, DShot_GCR_Pulse_Time_2
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; ESC programming (EEPROM emulation)
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Read all eeprom parameters
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-read_all_eeprom_parameters:
- ; Check initialized signature
- mov DPTR, #Eep_Initialized_L
- mov Temp1, #Bit_Access
- call read_eeprom_byte
- mov A, Bit_Access
- cjne A, #055h, read_eeprom_store_defaults
- inc DPTR ; Now Eep_Initialized_H
- call read_eeprom_byte
- mov A, Bit_Access
- cjne A, #0AAh, read_eeprom_store_defaults
- sjmp read_eeprom_read
-
-read_eeprom_store_defaults:
- mov Flash_Key_1, #0A5h
- mov Flash_Key_2, #0F1h
- call set_default_parameters
- call erase_and_store_all_in_eeprom
- mov Flash_Key_1, #0
- mov Flash_Key_2, #0
- sjmp read_eeprom_exit
-
-read_eeprom_read:
- ; Read eeprom
- mov DPTR, #_Eep_Pgm_Gov_P_Gain
- mov Temp1, #_Pgm_Gov_P_Gain
- mov Temp4, #10 ; 10 parameters
-read_eeprom_block1:
- call read_eeprom_byte
- inc DPTR
- inc Temp1
- djnz Temp4, read_eeprom_block1
-
- ; Read eeprom after Eep_Initialized_x flags
- ; Temp4 = EEPROM_B2_PARAMETERS_COUNT parameters: [_Eep_Enable_TX_Program - Eep_Pgm_Power_Rating]
- mov DPTR, #_Eep_Enable_TX_Program
- mov Temp1, #_Pgm_Enable_TX_Program
- mov Temp4, #EEPROM_B2_PARAMETERS_COUNT
-read_eeprom_block2:
- call read_eeprom_byte
- inc DPTR
- inc Temp1
- djnz Temp4, read_eeprom_block2
-
- mov DPTR, #Eep_Dummy ; Set pointer to uncritical area
-
-read_eeprom_exit:
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Erase flash and store all parameter values in EEPROM
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-erase_and_store_all_in_eeprom:
- clr IE_EA ; Disable interrupts
- call read_tags
- call read_melody
- call erase_flash ; Erase flash
-
- mov DPTR, #Eep_FW_Main_Revision ; Store firmware main revision
- mov A, #EEPROM_FW_MAIN_REVISION
- call write_eeprom_byte_from_acc
-
- inc DPTR ; Now firmware sub revision
- mov A, #EEPROM_FW_SUB_REVISION
- call write_eeprom_byte_from_acc
-
- inc DPTR ; Now layout revision
- mov A, #EEPROM_LAYOUT_REVISION
- call write_eeprom_byte_from_acc
-
- ; Write eeprom before Eep_Initialized_x flags
- ; Temp4 = 10 parameters [_Eep_Pgm_Gov_P_Gain - Eep_Initialized_x]
- mov DPTR, #_Eep_Pgm_Gov_P_Gain
- mov Temp1, #_Pgm_Gov_P_Gain
- mov Temp4, #10
-write_eeprom_block1:
- call write_eeprom_byte
- inc DPTR
- inc Temp1
- djnz Temp4, write_eeprom_block1
-
- ; Write eeprom after Eep_Initialized_x flags
- ; Temp4 = EEPROM_B2_PARAMETERS_COUNT parameters: [_Eep_Enable_TX_Program - Eep_Pgm_Power_Rating]
- mov DPTR, #_Eep_Enable_TX_Program
- mov Temp1, #_Pgm_Enable_TX_Program
- mov Temp4, #EEPROM_B2_PARAMETERS_COUNT
-write_eeprom_block2:
- call write_eeprom_byte
- inc DPTR
- inc Temp1
- djnz Temp4, write_eeprom_block2
-
- ; Now write tags, melogy and signature
- call write_tags
- call write_melody
- call write_eeprom_signature
- mov DPTR, #Eep_Dummy ; Set pointer to uncritical area
-
- ; Give time to flash controller to settle data down
- call wait200ms
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Read eeprom byte
-;
-; Gives data in A and in address given by Temp1
-; Assumes address in DPTR
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-read_eeprom_byte:
- clr A
- movc A, @A+DPTR ; Read from flash
- mov @Temp1, A
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Write eeprom byte
-;
-; Assumes data in address given by Temp1, or in accumulator
-; Assumes address in DPTR
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-write_eeprom_byte:
- mov A, @Temp1
-write_eeprom_byte_from_acc:
- orl PSCTL, #01h ; Set the PSWE bit
- anl PSCTL, #0FDh ; Clear the PSEE bit
- mov Temp8, A
- clr C
- mov A, DPH ; Check that address is not in bootloader area
- IF MCU_TYPE == 2
- subb A, #0F0h
- ELSE
- subb A, #1Ch
- ENDIF
- jc ($+3)
-
- ret
-
- mov A, Temp8
- mov FLKEY, Flash_Key_1 ; First key code
- mov FLKEY, Flash_Key_2 ; Second key code
- movx @DPTR, A ; Write to flash
- anl PSCTL, #0FEh ; Clear the PSWE bit
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Erase flash (erases the flash segment used for "eeprom" variables)
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-erase_flash:
- orl PSCTL, #02h ; Set the PSEE bit
- orl PSCTL, #01h ; Set the PSWE bit
- mov FLKEY, Flash_Key_1 ; First key code
- mov FLKEY, Flash_Key_2 ; Second key code
- mov DPTR, #Eep_Initialized_L
- movx @DPTR, A
- anl PSCTL, #0FCh ; Clear the PSEE and PSWE bits
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Write eeprom signature
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-write_eeprom_signature:
- mov DPTR, #Eep_Initialized_L
- mov A, #055h
- call write_eeprom_byte_from_acc
-
- mov DPTR, #Eep_Initialized_H
- mov A, #0AAh
- call write_eeprom_byte_from_acc
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Read all tags from flash and store in temporary storage
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-read_tags:
- mov Temp3, #48 ; Number of tags
- mov Temp2, #Temp_Storage ; Set RAM address
- mov Temp1, #Bit_Access
- mov DPTR, #Eep_ESC_Layout ; Set flash address
-read_tag:
- call read_eeprom_byte
- mov A, Bit_Access
- mov @Temp2, A ; Write to RAM
- inc Temp2
- inc DPTR
- djnz Temp3, read_tag
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Write all tags from temporary storage and store in flash
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-write_tags:
- mov Temp3, #48 ; Number of tags
- mov Temp2, #Temp_Storage ; Set RAM address
- mov DPTR, #Eep_ESC_Layout ; Set flash address
-write_tag:
- mov A, @Temp2 ; Read from RAM
- call write_eeprom_byte_from_acc
- inc Temp2
- inc DPTR
- djnz Temp3, write_tag
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Read bytes from flash and store in external memory
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-read_melody:
- mov Temp3, #140 ; Number of bytes
- mov Temp2, #0 ; Set XRAM address
- mov Temp1, #Bit_Access
- mov DPTR, #Eep_Pgm_Beep_Melody ; Set flash address
-read_melody_byte:
- call read_eeprom_byte
- mov A, Bit_Access
- movx @Temp2, A ; Write to XRAM
- inc Temp2
- inc DPTR
- djnz Temp3, read_melody_byte
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Write bytes from external memory and store in flash
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-write_melody:
- mov Temp3, #140 ; Number of bytes
- mov Temp2, #0 ; Set XRAM address
- mov DPTR, #Eep_Pgm_Beep_Melody ; Set flash address
-write_melody_byte:
- movx A, @Temp2 ; Read from XRAM
- call write_eeprom_byte_from_acc
- inc Temp2
- inc DPTR
- djnz Temp3, write_melody_byte
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Settings
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Set default parameters
-;
-; Sets default programming parameters
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-set_default_parameters:
- mov Temp1, #_Pgm_Gov_P_Gain
- mov @Temp1, #0FFh ; _Pgm_Gov_P_Gain
- imov Temp1, #DEFAULT_PGM_STARTUP_POWER_MIN ; Pgm_Startup_Power_Min
- imov Temp1, #DEFAULT_PGM_STARTUP_BEEP ; Pgm_Startup_Beep
- imov Temp1, #DEFAULT_PGM_DITHERING ; Pgm_Dithering
- 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_DIRECTION ; Pgm_Direction
- imov Temp1, #0FFh ; _Pgm_Input_Pol
-
- inc Temp1 ; Skip Initialized_L_Dummy
- inc Temp1 ; Skip Initialized_H_Dummy
-
- imov Temp1, #0FFh ; _Pgm_Enable_TX_Program
- imov Temp1, #DEFAULT_PGM_BRAKING_STRENGTH ; Pgm_Braking_Strength
- imov Temp1, #0FFh ; _Pgm_Gov_Setup_Target
- imov Temp1, #0FFh ; _Pgm_Startup_Rpm
- imov Temp1, #0FFh ; _Pgm_Startup_Accel
- imov Temp1, #0FFh ; _Pgm_Volt_Comp
- imov Temp1, #DEFAULT_PGM_COMM_TIMING ; Pgm_Comm_Timing
- imov Temp1, #0FFh ; _Pgm_Damping_Force
- imov Temp1, #0FFh ; _Pgm_Gov_Range
- imov Temp1, #0FFh ; _Pgm_Startup_Method
- imov Temp1, #0FFh ; _Pgm_Min_Throttle
- imov Temp1, #0FFh ; _Pgm_Max_Throttle
- imov Temp1, #DEFAULT_PGM_BEEP_STRENGTH ; Pgm_Beep_Strength
- imov Temp1, #DEFAULT_PGM_BEACON_STRENGTH ; Pgm_Beacon_Strength
- imov Temp1, #DEFAULT_PGM_BEACON_DELAY ; Pgm_Beacon_Delay
- imov Temp1, #0FFh ; _Pgm_Throttle_Rate
- imov Temp1, #DEFAULT_PGM_DEMAG_COMP ; Pgm_Demag_Comp
- imov Temp1, #0FFh ; _Pgm_BEC_Voltage_High
- imov Temp1, #0FFh ; _Pgm_Center_Throttle
- imov Temp1, #0FFh ; _Pgm_Main_Spoolup_Time
- imov Temp1, #DEFAULT_PGM_ENABLE_TEMP_PROT ; Pgm_Enable_Temp_Prot
- imov Temp1, #0FFh ; _Pgm_Enable_Power_Prot
- imov Temp1, #0FFh ; _Pgm_Enable_Pwm_Input
- imov Temp1, #0FFh ; _Pgm_Pwm_Dither
- imov Temp1, #DEFAULT_PGM_BRAKE_ON_STOP ; Pgm_Brake_On_Stop
- imov Temp1, #DEFAULT_PGM_LED_CONTROL ; Pgm_LED_Control
- imov Temp1, #DEFAULT_PGM_POWER_RATING ; Pgm_Power_Rating
-
- ret
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Decode settings
-;
-; Decodes programmed settings and set RAM variables accordingly
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-decode_settings:
- mov Temp1, #Pgm_Direction ; Load programmed direction
- mov A, @Temp1
- dec A
- mov C, ACC.1 ; Set bidirectional mode
- mov Flag_Pgm_Bidir, C
- mov C, ACC.0 ; Set direction (Normal / Reversed)
- mov Flag_Pgm_Dir_Rev, C
-
- ; Check startup power
- mov Temp1, #Pgm_Startup_Power_Max
- mov A, #80 ; Limit to at most 80
- subb A, @Temp1
- jnc ($+4)
- mov @Temp1, #80
-
- ; Check low rpm power slope
- mov Temp1, #Pgm_Rpm_Power_Slope
- mov A, #13 ; Limit to at most 13
- subb A, @Temp1
- jnc ($+4)
- mov @Temp1, #13
-
- mov Low_Rpm_Pwr_Slope, @Temp1
-
- ; Decode demag compensation
- mov Temp1, #Pgm_Demag_Comp
- mov A, @Temp1
- mov Demag_Pwr_Off_Thresh, #255 ; Set default
-
- cjne A, #2, decode_demag_high
-
- mov Demag_Pwr_Off_Thresh, #160 ; Settings for demag comp low
-
-decode_demag_high:
- cjne A, #3, decode_demag_done
-
- mov Demag_Pwr_Off_Thresh, #130 ; Settings for demag comp high
-
-decode_demag_done:
- ; Decode temperature protection limit
- mov Temp_Prot_Limit, #0
- mov Temp1, #Pgm_Enable_Temp_Prot
- mov A, @Temp1
- mov Temp2, A ; Temp2 = *Pgm_Enable_Temp_Prot;
- jz decode_temp_done
-
- ; ******************************************************************
- ; Power rating only applies to BB21 because voltage references behave diferently
- ; depending on an external voltage regulator is used or not.
- ; For BB51 (MCU_TYPE == 2) 1s power rating code path is mandatory
- ; ******************************************************************
-IF MCU_TYPE < 2
- ; Read power rating and decode temperature limit
- mov Temp1, #Pgm_Power_Rating
- cjne @Temp1, #01h, decode_temp_use_adc_use_vdd_3V3_vref
-ENDIF
-
- ; Set A to temperature limit depending on power rating
-decode_temp_use_adc_use_internal_1V65_vref:
- mov A, #(TEMP_LIMIT_1S - TEMP_LIMIT_STEP)
- sjmp decode_temp_step
-decode_temp_use_adc_use_vdd_3V3_vref:
- mov A, #(TEMP_LIMIT_2S - TEMP_LIMIT_STEP)
-
- ; Increase A while Temp2-- != 0;
-decode_temp_step:
- add A, #TEMP_LIMIT_STEP
- djnz Temp2, decode_temp_step
-
- ; Set Temp_Prot_Limit to the temperature limit calculated in A
-decode_temp_done:
- mov Temp_Prot_Limit, A
-
- 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
- mov A, @Temp1
-IF PWM_BITS_H == 3 ; Scale braking strength to pwm resolution
- ; Note: Added for completeness
- ; 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
- rl A
- rl A
- mov Temp2, A
- anl A, #03h
- mov Pwm_Braking_H, A
- mov A, Temp2
- anl A, #0FCh
- mov Pwm_Braking_L, A
-ELSEIF PWM_BITS_H == 1
- rl A
- mov Temp2, A
- anl A, #01h
- mov Pwm_Braking_H, A
- 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
-
-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
- imov Temp1, #11h ; 00010001
- imov Temp1, #25h ; 00100101
- imov Temp1, #55h ; 01010101
- imov Temp1, #5Bh ; 01011011
- imov Temp1, #77h ; 01110111
- imov Temp1, #7fh ; 01111111
-ENDIF
- ret
-
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Main program
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Main program entry point
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-pgm_start:
- mov Flash_Key_1, #0 ; Initialize flash keys to invalid values
- mov Flash_Key_2, #0
- mov WDTCN, #0DEh ; Disable watchdog (WDT)
- mov WDTCN, #0ADh
- mov SP, #Stack ; Initialize stack (16 bytes of indirect RAM)
- IF MCU_TYPE < 2
- orl VDM0CN, #080h ; Enable the VDD monitor
- ENDIF
- mov RSTSRC, #06h ; Set missing clock and VDD monitor as a reset source if not 1S capable
- mov CLKSEL, #00h ; Set clock divider to 1 (Oscillator 0 at 24MHz)
- call switch_power_off
- ; Ports initialization
- mov P0, #P0_INIT
- mov P0MDIN, #P0_DIGITAL
- mov P0MDOUT, #P0_PUSHPULL
- mov P0, #P0_INIT
- mov P0SKIP, #P0_SKIP
- mov P1, #P1_INIT
- mov P1MDIN, #P1_DIGITAL
- mov P1MDOUT, #P1_PUSHPULL
- mov P1, #P1_INIT
- mov P1SKIP, #P1_SKIP
- mov P2MDOUT, #P2_PUSHPULL
-IF MCU_TYPE >= 1
- ; Not available on BB1
- mov SFRPAGE, #20h
- mov P2MDIN, #P2_DIGITAL
- IF MCU_TYPE == 1
- ; Not available on BB51
- mov P2SKIP, #P2_SKIP
- ENDIF
- mov SFRPAGE, #00h
-ENDIF
- Initialize_Crossbar ; Initialize the crossbar and related functionality
- call switch_power_off ; Switch power off again, after initializing ports
-
- ; Clear RAM
- clr A ; Clear accumulator
- mov Temp1, A ; Clear Temp1
- clear_ram:
- mov @Temp1, A ; Clear RAM address
- djnz Temp1, clear_ram ; Decrement address and repeat
-
- call set_default_parameters ; Set default programmed parameters
- call read_all_eeprom_parameters ; Read all programmed parameters
- call decode_settings ; Decode programmed settings
-
- ; Initializing beeps
- clr IE_EA ; Disable interrupts explicitly
- call wait100ms ; Wait a bit to avoid audible resets if not properly powered
- call play_beep_melody ; Play startup beep melody
- call led_control ; Set LEDs to programmed values
-
- call wait100ms ; Wait for flight controller to get ready
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; No signal entry point
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-init_no_signal:
- clr IE_EA ; Disable interrupts explicitly
- mov Flash_Key_1, #0 ; Initialize flash keys to invalid values
- mov Flash_Key_2, #0
- call switch_power_off
-
-IF MCU_TYPE >= 1
- Set_MCU_Clk_24MHz ; Set clock frequency
-ENDIF
-
- mov Temp1, #9 ; Check if input signal is high for ~150ms
- mov Temp2, #0
- mov Temp3, #0
-input_high_check:
- jnb RTX_BIT, bootloader_done ; Look for low
- djnz Temp3, input_high_check
- djnz Temp2, input_high_check
- djnz Temp1, input_high_check
-
- call beep_enter_bootloader
-
- IF MCU_TYPE == 2
- ljmp 0F000h ; Jump to bootloader
- ELSE
- ljmp 1C00h ; Jump to bootloader
- ENDIF
-
-bootloader_done:
- jnb Flag_Had_Signal, setup_dshot ; Check if DShot signal was lost
- call beep_signal_lost
- call wait250ms ; Wait for flight controller to get ready
- call wait250ms
- call wait250ms
- clr Flag_Had_Signal
-
-setup_dshot:
- ; Setup timers for DShot
- mov TCON, #51h ; Timer0/1 run and Int0 edge triggered
- mov CKCON0, #01h ; Timer0/1 clock is system clock divided by 4 (for DShot150)
- mov TMOD, #0AAh ; Timer0/1 set to 8-bits auto reload and gated by Int0/1
- mov TH0, #0 ; Auto reload value zero
- mov TH1, #0
-
- mov TMR2CN0, #04h ; Timer2 enabled (system clock divided by 12)
- mov TMR3CN0, #04h ; Timer3 enabled (system clock divided by 12)
-
- Initialize_PCA ; Initialize PCA
- Set_Pwm_Polarity ; Set pwm polarity
- Enable_Power_Pwm_Module ; Enable power pwm module
- Enable_Damp_Pwm_Module ; Enable damping pwm module
- Initialize_Comparator ; Initialize comparator
- Initialize_Adc ; Initialize ADC operation
- call wait1ms
-
- call detect_rcp_level ; Detect RCP level (normal or inverted DShot)
-
- ; Route RCP according to detected DShot signal (normal or inverted)
- mov IT01CF, #(80h + (RTX_PIN SHL 4) + RTX_PIN) ; Route RCP input to Int0/1, with Int1 inverted
- jnb Flag_Rcp_DShot_Inverted, ($+6)
- mov IT01CF, #(08h + (RTX_PIN SHL 4) + RTX_PIN) ; Route RCP input to Int0/1, with Int0 inverted
-
- clr Flag_Demag_Notify ; Clear motor events
- clr Flag_Desync_Notify
- clr Flag_Stall_Notify
- clr Flag_Telemetry_Pending ; Clear DShot telemetry flag
- clr Flag_Ext_Tele ; Clear extended telemetry enabled flag
-
- ; Setup interrupts
- mov IE, #2Dh ; Enable Timer1/2 interrupts and Int0/1 interrupts
- mov EIE1, #80h ; Enable Timer3 interrupts
- mov IP, #03h ; High priority to Timer0 and Int0 interrupts
-
- setb IE_EA ; Enable all interrupts
-
- ; Setup variables for DShot150 (Only on 24MHz because frame length threshold cannot be scaled up)
-IF MCU_TYPE == 0
- mov DShot_Timer_Preset, #-64 ; Load DShot sync timer preset (for DShot150)
- mov DShot_Pwm_Thr, #8 ; Load DShot qualification pwm threshold (for DShot150)
- mov DShot_Frame_Length_Thr, #160 ; Load DShot frame length criteria
-
- Set_DShot_Tlm_Bitrate 187500 ; = 5/4 * 150000
-
- ; Test whether signal is DShot150
- mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
- call wait100ms ; Wait for new RC pulse
- mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
- jz arming_begin
-ENDIF
-
- mov CKCON0, #0Ch ; Timer0/1 clock is system clock (for DShot300/600)
-
- ; Setup variables for DShot300
- mov DShot_Timer_Preset, #-128 ; Load DShot sync timer preset (for DShot300)
- mov DShot_Pwm_Thr, #16 ; Load DShot pwm threshold (for DShot300)
- mov DShot_Frame_Length_Thr, #80 ; Load DShot frame length criteria
-
- Set_DShot_Tlm_Bitrate 375000 ; = 5/4 * 300000
-
- ; Test whether signal is DShot300
- mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
- call wait100ms ; Wait for new RC pulse
- mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
- jz arming_begin
-
- ; Setup variables for DShot600 (Only on 48MHz for performance reasons)
-IF MCU_TYPE >= 1
- mov DShot_Timer_Preset, #-64 ; Load DShot sync timer preset (for DShot600)
- mov DShot_Pwm_Thr, #8 ; Load DShot pwm threshold (for DShot600)
- mov DShot_Frame_Length_Thr, #40 ; Load DShot frame length criteria
-
- Set_DShot_Tlm_Bitrate 750000 ; = 5/4 * 600000
-
- ; Test whether signal is DShot600
- mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
- call wait100ms ; Wait for new RC pulse
- mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
- jz arming_begin
-ENDIF
-
- ljmp init_no_signal
-
-arming_begin:
- push PSW
- mov PSW, #10h ; Temp8 in register bank 2 holds value
- mov Temp8, CKCON0 ; Save DShot clock settings for telemetry
- pop PSW
-
- setb Flag_Had_Signal ; Mark that a signal has been detected
- mov Startup_Stall_Cnt, #0 ; Reset stall count
-
- clr IE_EA
- call beep_f1_short ; Beep signal that RC pulse is ready
- setb IE_EA
-
-arming_wait:
- clr C
- mov A, Rcp_Stop_Cnt
- subb A, #10
- jc arming_wait ; Wait until rcp has been zero for ~300ms
-
- clr IE_EA
- call beep_f2_short ; Beep signal that ESC is armed
- setb IE_EA
-
-wait_for_start: ; Armed and waiting for power on
- clr A
- mov Comm_Period4x_L, A ; Reset commutation period for telemetry
- mov Comm_Period4x_H, A
- mov DShot_Cmd, A ; Reset DShot command (only considered in this loop)
- mov DShot_Cmd_Cnt, A
- mov Beacon_Delay_Cnt, A ; Clear beacon wait counter
- mov Timer2_X, A ; Clear Timer2 extended byte
-
-wait_for_start_loop:
- clr C
- mov A, Timer2_X
- subb A, #94
- jc wait_for_start_no_beep ; Counter wrapping (about 3 sec)
-
- mov Timer2_X, #0
- inc Beacon_Delay_Cnt ; Increment beacon wait counter
-
- mov Temp1, #Pgm_Beacon_Delay
- mov A, @Temp1
- mov Temp1, #20 ; 1 min
- dec A
- jz beep_delay_set
-
- mov Temp1, #40 ; 2 min
- dec A
- jz beep_delay_set
-
- mov Temp1, #100 ; 5 min
- dec A
- jz beep_delay_set
-
- mov Temp1, #200 ; 10 min
- dec A
- jz beep_delay_set
-
- mov Beacon_Delay_Cnt, #0 ; Reset beacon counter for infinite delay
-
-beep_delay_set:
- clr C
- mov A, Beacon_Delay_Cnt
- subb A, Temp1 ; Check against chosen delay
- jc wait_for_start_no_beep ; Has delay elapsed?
-
- dec Beacon_Delay_Cnt ; Decrement counter for continued beeping
-
- mov Temp1, #4 ; Beep tone 4
- clr IE_EA ; Disable all interrupts
- call switch_power_off ; Switch power off in case braking is set
- call beacon_beep
- setb IE_EA ; Enable all interrupts
-
-wait_for_start_no_beep:
- jb Flag_Telemetry_Pending, wait_for_start_check_rcp
- call dshot_tlm_create_packet ; Create telemetry packet (0 rpm)
- call scheduler_run
-
-wait_for_start_check_rcp:
- jnb Flag_Rcp_Stop, wait_for_start_nonzero ; Higher than stop, Yes - proceed
-
- mov A, Rcp_Timeout_Cntd ; Load RC pulse timeout counter value
- ljz init_no_signal ; If pulses are missing - go back to detect input signal
-
- call dshot_cmd_check ; Check and process DShot command
-
- sjmp wait_for_start_loop ; Go back to beginning of wait loop
-
-wait_for_start_nonzero:
- call wait100ms ; Wait to see if start pulse was glitch
-
- ; If Rcp returned to stop - start over
- jb Flag_Rcp_Stop, wait_for_start_loop
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Motor start entry point
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-motor_start:
- clr IE_EA ; Disable interrupts
- call switch_power_off
- setb IE_EA ; Enable interrupts
-
- clr A
- mov Flags0, A ; Clear run time flags
- mov Flags1, A
- mov Demag_Detected_Metric, A ; Clear demag metric
- mov Demag_Detected_Metric_Max, A ; Clear demag metric max
-
- call wait1ms
-
- mov Ext_Telemetry_H, #0 ; Clear extended telemetry data
-
- ; Set up start operating conditions
- clr IE_EA ; Disable interrupts
- mov Temp2, #Pgm_Startup_Power_Max
- mov Pwm_Limit_Beg, @Temp2 ; Set initial pwm limit
- mov Pwm_Limit, Pwm_Limit_Beg
- mov Pwm_Limit_By_Rpm, Pwm_Limit_Beg
- mov Temp_Pwm_Level_Setpoint, Pwm_Limit_Beg
-
- ; Begin startup sequence
-IF MCU_TYPE >= 1
- Set_MCU_Clk_48MHz
-
- ; Scale DShot criteria for 48MHz
- clr C
- rlca DShot_Timer_Preset ; Scale sync timer preset
-
- clr C
- rlca DShot_Frame_Length_Thr ; Scale frame length criteria
-
- clr C
- rlca DShot_Pwm_Thr ; Scale pulse width criteria
-
- ; Scale DShot telemetry for 48MHz
- xcha DShot_GCR_Pulse_Time_1, DShot_GCR_Pulse_Time_1_Tmp
- xcha DShot_GCR_Pulse_Time_2, DShot_GCR_Pulse_Time_2_Tmp
- xcha DShot_GCR_Pulse_Time_3, DShot_GCR_Pulse_Time_3_Tmp
-
- mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY_48
-ENDIF
- setb IE_EA ; Enable interrupts
-
- mov C, Flag_Pgm_Dir_Rev ; Read spin direction setting
- mov Flag_Motor_Dir_Rev, C
-
- jnb Flag_Pgm_Bidir, motor_start_bidir_done ; Check if bidirectional operation
-
- mov C, Flag_Rcp_Dir_Rev ; Read force direction
- mov Flag_Motor_Dir_Rev, C ; Set spinning direction
-
-;**** **** **** **** ****
-; Motor start beginning
-motor_start_bidir_done:
- setb Flag_Startup_Phase ; Set startup phase flags
- setb Flag_Initial_Run_Phase
- mov Startup_Cnt, #0 ; Reset startup phase run counter
- mov Initial_Run_Rot_Cntd, #12 ; Set initial run rotation countdown
- call comm5_comm6 ; Initialize commutation
- call comm6_comm1
- call initialize_timing ; Initialize timing
- call calc_next_comm_period ; Set virtual commutation point
- call initialize_timing ; Initialize timing
- call calc_next_comm_period
- call initialize_timing ; Initialize timing
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Run entry point
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-
-; Run 1 = B(p-on) + C(n-pwm) - comparator A evaluated
-; Out_cA changes from low to high
-run1:
- call wait_for_comp_out_high ; Wait for high
-; setup_comm_wait ; Setup wait time from zero cross to commutation
-; evaluate_comparator_integrity ; Check whether comparator reading has been normal
- call wait_for_comm ; Wait from zero cross to commutation
- call comm1_comm2 ; Commutate
- call calc_next_comm_period ; Calculate next timing and wait advance timing wait
-; wait_advance_timing ; Wait advance timing and start zero cross wait
-; calc_new_wait_times
-; wait_before_zc_scan ; Wait zero cross wait and start zero cross timeout
-
-; Run 2 = A(p-on) + C(n-pwm) - comparator B evaluated
-; Out_cB changes from high to low
-run2:
- call wait_for_comp_out_low
-; setup_comm_wait
-; evaluate_comparator_integrity
- call set_pwm_limit ; Set pwm power limit for low or high rpm
- call wait_for_comm
- call comm2_comm3
- call calc_next_comm_period
-; wait_advance_timing
-; calc_new_wait_times
-; wait_before_zc_scan
-
-; Run 3 = A(p-on) + B(n-pwm) - comparator C evaluated
-; Out_cC changes from low to high
-run3:
- call wait_for_comp_out_high
-; setup_comm_wait
-; evaluate_comparator_integrity
- call wait_for_comm
- call comm3_comm4
- call calc_next_comm_period
-; wait_advance_timing
-; calc_new_wait_times
-; wait_before_zc_scan
-
-; Run 4 = C(p-on) + B(n-pwm) - comparator A evaluated
-; Out_cA changes from high to low
-run4:
- call wait_for_comp_out_low
-; setup_comm_wait
-; evaluate_comparator_integrity
- call wait_for_comm
- call comm4_comm5
- call calc_next_comm_period
-; wait_advance_timing
-; calc_new_wait_times
-; wait_before_zc_scan
-
-; Run 5 = C(p-on) + A(n-pwm) - comparator B evaluated
-; Out_cB changes from low to high
-run5:
- call wait_for_comp_out_high
-; setup_comm_wait
-; evaluate_comparator_integrity
- call wait_for_comm
- call comm5_comm6
- call calc_next_comm_period
-; wait_advance_timing
-; calc_new_wait_times
-; wait_before_zc_scan
-
-; Run 6 = B(p-on) + A(n-pwm) - comparator C evaluated
-; Out_cC changes from high to low
-run6:
- call wait_for_comp_out_low
-; setup_comm_wait
-; evaluate_comparator_integrity
- call wait_for_comm
- call comm6_comm1
- call calc_next_comm_period
- call scheduler_run
-; wait_advance_timing
-; calc_new_wait_times
-; wait_before_zc_scan
-
- ; Check if it is startup phases
- jnb Flag_Initial_Run_Phase, normal_run_checks
- jnb Flag_Startup_Phase, initial_run_phase
-
- ; Startup phase
- mov Pwm_Limit, Pwm_Limit_Beg ; Set initial max power
- clr C
- mov A, Startup_Cnt ; Load startup counter
- subb A, #24 ; Is counter above requirement?
- jnc startup_phase_done
-
- jnb Flag_Rcp_Stop, run1 ; If pulse is above stop value - Continue to run
- sjmp exit_run_mode
-
-startup_phase_done:
- ; Clear startup phase flag & remove pwm limits
- clr Flag_Startup_Phase
- mov Pwm_Limit, #255 ; Reset temperature level pwm limit
- mov Pwm_Limit_By_Rpm, #255
- mov Temp_Pwm_Level_Setpoint, #255 ; Reset temperature level setpoint
-
-initial_run_phase:
- ; If it is a direction change - branch
- jb Flag_Dir_Change_Brake, normal_run_checks
-
- ; Decrement startup rotation count
- mov A, Initial_Run_Rot_Cntd
- dec A
- ; Check number of initial rotations
- jz initial_run_phase_done ; Branch if counter is zero
-
- mov Initial_Run_Rot_Cntd, A ; Not zero - store counter
-
- jnb Flag_Rcp_Stop, run1 ; Check if pulse is below stop value
- jb Flag_Pgm_Bidir, run1 ; Check if bidirectional operation
-
- sjmp exit_run_mode
-
-initial_run_phase_done:
- clr Flag_Initial_Run_Phase ; Clear initial run phase flag
- setb Flag_Motor_Started ; Set motor started
- jmp run1 ; Continue with normal run
-
-normal_run_checks:
- ; Reset stall count
- mov Startup_Stall_Cnt, #0
- setb Flag_Motor_Running
-
- jnb Flag_Rcp_Stop, run6_check_bidir ; Check if stop
- jb Flag_Pgm_Bidir, run6_check_timeout ; Check if bidirectional operation
-
- mov Temp2, #Pgm_Brake_On_Stop ; Check if using brake on stop
- mov A, @Temp2
- jz run6_check_timeout
-
- ; Exit run mode after 100ms when using brake on stop
- clr C
- mov A, Rcp_Stop_Cnt ; Load stop RC pulse counter value
- subb A, #3 ; Is number of stop RC pulses above limit?
- jnc exit_run_mode ; Yes - exit run mode
-
-run6_check_timeout:
- ; Exit run mode immediately if timeout
- mov A, Rcp_Timeout_Cntd ; Load RC pulse timeout counter value
- jz exit_run_mode ; If it is zero - go back to wait for power on
-
-run6_check_bidir:
- jb Flag_Pgm_Bidir, run6_bidir ; Check if bidirectional operation
-
-run6_check_speed:
- clr C
- mov A, Comm_Period4x_H ; Is Comm_Period4x below minimum speed?
- subb A, #0F0h ; Default minimum speed (~1330 erpm)
- jnc exit_run_mode ; Yes - exit run mode
- jmp run1 ; No - go back to run 1
-
-run6_bidir:
- ; Check if direction change braking is in progress
- jb Flag_Dir_Change_Brake, run6_bidir_braking
-
- ; Check if actual rotation direction matches force direction
- jb Flag_Motor_Dir_Rev, run6_bidir_check_reversal
- jb Flag_Rcp_Dir_Rev, run6_bidir_reversal
- sjmp run6_check_speed
-
-run6_bidir_check_reversal:
- jb Flag_Rcp_Dir_Rev, run6_check_speed
-
-run6_bidir_reversal:
- ; Initiate direction and start braking
- setb Flag_Dir_Change_Brake ; Set brake flag
- mov Pwm_Limit, Pwm_Limit_Beg ; Set max power while braking to initial power limit
- jmp run4 ; Go back to run 4, thereby changing force direction
-
-run6_bidir_braking:
- mov Pwm_Limit, Pwm_Limit_Beg ; Set max power while braking to initial power limit
-
- clr C
- mov A, Comm_Period4x_H ; Is Comm_Period4x below minimum speed?
- subb A, #20h ; Bidirectional braking termination speed (~9970 erpm)
- jc run6_bidir_continue ; No - continue braking
-
- ; Braking done, set new spinning direction
- clr Flag_Dir_Change_Brake ; Clear braking flag
- mov C, Flag_Rcp_Dir_Rev ; Read force direction
- mov Flag_Motor_Dir_Rev, C ; Set spinning direction
- setb Flag_Initial_Run_Phase
- mov Initial_Run_Rot_Cntd, #18
- mov Pwm_Limit, Pwm_Limit_Beg ; Set initial max power
-
-run6_bidir_continue:
- jmp run1 ; Go back to run 1
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Exit run mode and power off
-; on normal stop or comparator timeout
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-exit_run_mode_on_timeout:
- jb Flag_Motor_Running, exit_run_mode
- inc Startup_Stall_Cnt ; Increment stall count if motors did not properly start
-
-exit_run_mode:
- clr IE_EA ; Disable all interrupts
- clr Flag_Ext_Tele ; Clear extended DSHOT telemetry flag
- call switch_power_off
- mov Flags0, #0 ; Clear run time flags (in case they are used in interrupts)
- mov Flags1, #0
-
-IF MCU_TYPE >= 1
- Set_MCU_Clk_24MHz
-
- ; Scale DShot criteria for 24MHz
- setb C
- rrca DShot_Timer_Preset ; Scale sync timer preset
-
- clr C
- rrca DShot_Frame_Length_Thr ; Scale frame length criteria
-
- clr C
- rrca DShot_Pwm_Thr ; Scale pulse width criteria
-
- ; Scale DShot telemetry for 24MHz
- xcha DShot_GCR_Pulse_Time_1, DShot_GCR_Pulse_Time_1_Tmp
- xcha DShot_GCR_Pulse_Time_2, DShot_GCR_Pulse_Time_2_Tmp
- xcha DShot_GCR_Pulse_Time_3, DShot_GCR_Pulse_Time_3_Tmp
-
- mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY
-ENDIF
-
- setb IE_EA ; Enable all interrupts
-
- ; Check if RCP is zero, then it is a normal stop or signal timeout
- jb Flag_Rcp_Stop, exit_run_mode_no_stall
-
- ; Signal stall
- setb Flag_Stall_Notify
-
- clr C ; Otherwise - it's a stall
- mov A, Startup_Stall_Cnt
- subb A, #4 ; Maximum consecutive stalls
- jnc exit_run_mode_stall_done
-
- call wait100ms ; Wait for a bit between stall restarts
- ljmp motor_start ; Go back and try starting motors again
-
-exit_run_mode_stall_done:
- ; Stalled too many times
- clr IE_EA
- call beep_motor_stalled
- setb IE_EA
-
- ljmp arming_begin ; Go back and wait for arming
-
-exit_run_mode_no_stall:
- mov Startup_Stall_Cnt, #0
-
- mov Temp1, #Pgm_Brake_On_Stop ; Check if using brake on stop
- mov A, @Temp1
- jz exit_run_mode_brake_done
-
- A_Com_Fet_On ; Brake on stop
- B_Com_Fet_On
- C_Com_Fet_On
-
-exit_run_mode_brake_done:
- ljmp wait_for_start ; Go back to wait for power on
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Reset
-;
-; Should execution ever reach this point the ESC will be reset,
-; as code flash after offset 1A00 is used for EEPROM storage
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-IF MCU_TYPE == 2
- CSEG AT 2FFDh
-ELSE
- CSEG AT 19FDh
-ENDIF
-reset:
- ljmp pgm_start
-
-
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;
-; Bootloader
-;
-; Include source code for BLHeli bootloader
-;
-;**** **** **** **** **** **** **** **** **** **** **** **** ****
-;CSEG AT 1C00h
-$include (BLHeliBootLoad.inc)
-
-
-END
diff --git a/Common.inc b/Common.inc
deleted file mode 100644
index d55cde60..00000000
--- a/Common.inc
+++ /dev/null
@@ -1,219 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Common definitions for EFM8BB1x/2x based ESCs
-;
-;**** **** **** **** ****
-
-;*********************
-; Device SiLabs EFM8BB1x/2x/51
-;*********************
-IF MCU_TYPE == 0
- $include (Silabs/SI_EFM8BB1_Defs.inc)
-ELSEIF MCU_TYPE == 1
- $include (Silabs/SI_EFM8BB2_Defs.inc)
-ELSEIF MCU_TYPE == 2
- $include (Silabs/SI_EFM8BB51_Defs.inc)
-ENDIF
-
-;**** **** **** **** ****
-; Uses internal calibrated oscillator set to 24/48Mhz
-;**** **** **** **** ****
-
-;**** **** **** **** ****
-; ESC selection statements
-IF MCU_TYPE < 2
- IF ESCNO == A_
- $include (Layouts/A.inc) ; Select pinout A
- ELSEIF ESCNO == B_
- $include (Layouts/B.inc) ; Select pinout B
- ELSEIF ESCNO == C_
- $include (Layouts/C.inc) ; Select pinout C
- ELSEIF ESCNO == D_
- $include (Layouts/D.inc) ; Select pinout D
- ELSEIF ESCNO == E_
- $include (Layouts/E.inc) ; Select pinout E
- ELSEIF ESCNO == F_
- $include (Layouts/F.inc) ; Select pinout F
- ELSEIF ESCNO == G_
- $include (Layouts/G.inc) ; Select pinout G
- ELSEIF ESCNO == H_
- $include (Layouts/H.inc) ; Select pinout H
- ELSEIF ESCNO == I_
- $include (Layouts/I.inc) ; Select pinout I
- ELSEIF ESCNO == J_
- $include (Layouts/J.inc) ; Select pinout J
- ELSEIF ESCNO == K_
- $include (Layouts/K.inc) ; Select pinout K
- ELSEIF ESCNO == L_
- $include (Layouts/L.inc) ; Select pinout L
- ELSEIF ESCNO == M_
- $include (Layouts/M.inc) ; Select pinout M
- ELSEIF ESCNO == N_
- $include (Layouts/N.inc) ; Select pinout N
- ELSEIF ESCNO == O_
- $include (Layouts/O.inc) ; Select pinout O
- ELSEIF ESCNO == P_
- $include (Layouts/P.inc) ; Select pinout P
- ELSEIF ESCNO == Q_
- $include (Layouts/Q.inc) ; Select pinout Q
- ELSEIF ESCNO == R_
- $include (Layouts/R.inc) ; Select pinout R
- ELSEIF ESCNO == S_
- $include (Layouts/S.inc) ; Select pinout S
- ELSEIF ESCNO == T_
- $include (Layouts/T.inc) ; Select pinout T
- ELSEIF ESCNO == U_
- $include (Layouts/U.inc) ; Select pinout U
- ELSEIF ESCNO == V_
- $include (Layouts/V.inc) ; Select pinout V
- ELSEIF ESCNO == W_
- $include (Layouts/W.inc) ; Select pinout W
- ;ELSEIF ESCNO == X_
- ;$include (Layouts/X.inc) ; Select pinout X
- ;ELSEIF ESCNO == Y_
- ;$include (Layouts/Y.inc) ; Select pinout Y
- ELSEIF ESCNO == Z_
- $include (Layouts/Z.inc) ; Select pinout Z
- ENDIF
-ENDIF
-
-IF MCU_TYPE == 2
- IF ESCNO == A_
- $include (Layouts/BB51/A.inc) ; Select pinout A
- ELSEIF ESCNO == B_
- $include (Layouts/BB51/B.inc) ; Select pinout B
- ELSEIF ESCNO == C_
- $include (Layouts/BB51/C.inc) ; Select pinout C
- ENDIF
-ENDIF
-
-SIGNATURE_001 EQU 0E8h ; Device signature
-IF MCU_TYPE == 0
- SIGNATURE_002 EQU 0B1h
-ELSEIF MCU_TYPE == 1
- SIGNATURE_002 EQU 0B2h
-ELSEIF MCU_TYPE == 2
- SIGNATURE_002 EQU 0B5h
-ENDIF
-
-;**** **** **** **** ****
-; Constant definitions
-;**** **** **** **** ****
-ESC_C EQU "A" + ESCNO - 1 ; ESC target letter
-
-; MCU letter (24Mhz=L, 48Mhz=H, BB51=X)
-IF MCU_TYPE == 0
- MCU_C EQU "L"
-ELSEIF MCU_TYPE == 1
- MCU_C EQU "H"
-ELSEIF MCU_TYPE == 2
- MCU_C EQU "X"
-ENDIF
-ENDIF
-
-; Dead time number as chars
-DT_C2 EQU "0" + (DEADTIME / 100)
-DT_C1 EQU "0" + ((DEADTIME / 10) MOD 10)
-DT_C0 EQU "0" + (DEADTIME MOD 10)
-
-; ESC layout tag
-IF MCU_TYPE < 2
- CSEG AT 1A40h
-ELSEIF MCU_TYPE == 2
- CSEG AT 3040h
-ENDIF
-
-IF DEADTIME < 100
-Eep_ESC_Layout: DB "#", ESC_C, "_", MCU_C, "_", DT_C1, DT_C0, "# "
-ELSE
-Eep_ESC_Layout: DB "#", ESC_C, "_", MCU_C, "_", DT_C2, DT_C1, DT_C0, "# "
-ENDIF
-
-IF MCU_TYPE < 2
- CSEG AT 1A50h
-ELSEIF MCU_TYPE == 2
- CSEG AT 3050h
-ENDIF
-
-; Project and MCU tag (16 Bytes)
-IF MCU_TYPE == 0
- Eep_ESC_MCU: DB "#BLHELI$EFM8B10#"
-ELSEIF MCU_TYPE == 1
- Eep_ESC_MCU: DB "#BLHELI$EFM8B21#"
-ELSEIF MCU_TYPE == 2
- Eep_ESC_MCU: DB "#BLHELI$EFM8B51#"
-ENDIF
-
-Interrupt_Table_Definition MACRO
-CSEG AT 0 ;; Code segment start
- jmp reset
-CSEG AT 03h ;; Int0 interrupt
- jmp int0_int
-CSEG AT 0Bh ;; Timer0 overflow interrupt
- jmp t0_int
-CSEG AT 13h ;; Int1 interrupt
- jmp int1_int
-CSEG AT 1Bh ;; Timer1 overflow interrupt
- jmp t1_int
-CSEG AT 2Bh ;; Timer2 overflow interrupt
- jmp t2_int
-CSEG AT 5Bh ;; PCA interrupt
- jmp pca_int
-CSEG AT 73h ;; Timer3 overflow/compare interrupt
- jmp t3_int
-ENDM
-
-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)
-
-IF PWM_CENTERED == 1
- mov PCA0CENT, #07h ;; Center aligned pwm
-ELSE
- mov PCA0CENT, #00h ;; Edge aligned pwm
-ENDIF
-ENDM
-
-Set_MCU_Clk_24MHz MACRO
- mov CLKSEL, #13h ;; Set clock to 24MHz (Oscillator 1 divided by 2)
-
- mov SFRPAGE, #10h
- mov PFE0CN, #00h ;; Set flash timing for 24MHz and disable prefetch engine
- mov SFRPAGE, #00h
-ENDM
-
-Set_MCU_Clk_48MHz MACRO
- mov SFRPAGE, #10h
- IF MCU_TYPE == 1
- mov PFE0CN, #30h ;; Set flash timing for 48MHz and enable prefetch engine
- ELSEIF MCU_TYPE == 2
- mov PFE0CN, #10h ;; Set flash timing for 48MHz
- ENDIF
- mov SFRPAGE, #00h
-
- mov CLKSEL, #03h ;; Set clock to 48MHz (Oscillator 1)
-ENDM
diff --git a/Layouts/A.inc b/Layouts/A.inc
deleted file mode 100644
index 389e56c2..00000000
--- a/Layouts/A.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "A"
-; X X RC X MC MB MA CC X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/B.inc b/Layouts/B.inc
deleted file mode 100644
index 08a00bb2..00000000
--- a/Layouts/B.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "B". Equals "A", but with A and C fets swapped and pwm and com fets swapped
-; X X RC X MC MB MA CC X X Ap Ac Bp Bc Cp Cc
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-A_Pwm EQU 5
-A_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-C_Pwm EQU 1
-C_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/BB51/A.inc b/Layouts/BB51/A.inc
deleted file mode 100644
index 96edb7b1..00000000
--- a/Layouts/BB51/A.inc
+++ /dev/null
@@ -1,93 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2022-2022 Chris Landa
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "A" for BB51.
-; X X RC CC MA MC MB X X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-PCA0CPM_POWER EQU PCA0CPM0
-PCA0CPL_POWER EQU PCA0CPL0
-PCA0CPH_POWER EQU PCA0CPH0
-
-PCA0CPM_DAMP EQU PCA0CPM1
-PCA0CPL_DAMP EQU PCA0CPL1
-PCA0CPH_DAMP EQU PCA0CPH1
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-V_Mux EQU 4
-A_Mux EQU 3
-C_Mux EQU 2
-B_Mux EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (../Base.inc)
diff --git a/Layouts/BB51/B.inc b/Layouts/BB51/B.inc
deleted file mode 100644
index 006362a5..00000000
--- a/Layouts/BB51/B.inc
+++ /dev/null
@@ -1,103 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2022-2022 Chris Landa
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "B" for BB51.
-; X X RC CC MA MC MB X X X Cp Cc Bp Bc Ap Ac
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 1 ; Comparator output inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-V_Mux EQU 4
-A_Mux EQU 3
-C_Mux EQU 2
-B_Mux EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-C_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-A_Pwm EQU 1
-A_Com EQU 0
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 0
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (../Base.inc)
diff --git a/Layouts/BB51/C.inc b/Layouts/BB51/C.inc
deleted file mode 100644
index aff6e185..00000000
--- a/Layouts/BB51/C.inc
+++ /dev/null
@@ -1,103 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2022-2022 Chris Landa
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "C" for BB51.
-; X X RC CC MA MC MB X X X Cp Cc Bp Bc Ap Ac
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 0 ; Pwm inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 1 ; Comparator output inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-V_Mux EQU 4
-A_Mux EQU 3
-C_Mux EQU 2
-B_Mux EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-C_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-A_Pwm EQU 1
-A_Com EQU 0
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm)
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (../Base.inc)
diff --git a/Layouts/Base.inc b/Layouts/Base.inc
deleted file mode 100644
index 8c411ca0..00000000
--- a/Layouts/Base.inc
+++ /dev/null
@@ -1,410 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Base layout
-;
-; The inheriting layout should
-; - Specify PWM_ACTIVE_HIGH, COM_ACTIVE_HIGH and COMPARATOR_PORT
-; - Set CUSTOM_* flags to override default implementation
-;
-;**** **** **** **** ****
-
-
-;**** **** **** **** ****
-; Bootloader definitions
-;**** **** **** **** ****
-; Note: The RTX pin must be on port 0 because we use the IT01CF register for interrupts
-RTX_PORT EQU P0 ; Receive/Transmit port
-RTX_MDOUT EQU P0MDOUT ; Set to 1 for PUSHPULL
-RTX_MDIN EQU P0MDIN ; Set to 1 for DIGITAL
-RTX_SKIP EQU P0SKIP ; Set to 1 for SKIP
-
-RTX_BIT EQU RTX_PORT.RTX_PIN ; RTX pin value
-
-
-;**** **** **** **** ****
-; PWM pin routing and polarity setup
-;**** **** **** **** ****
-$if NOT CUSTOM_PWM_SETUP
-
-Initialize_Crossbar MACRO
- mov XBR2, #40h ;; Crossbar enabled
- mov XBR1, #02h ;; CEX0 and CEX1 routed to pins
-ENDM
-
-Set_Pwm_Polarity MACRO
-IF PCA0CPM_POWER == PCA0CPM0
- mov PCA0POL, #((COM_ACTIVE_HIGH SHL 1) + (1 - PWM_ACTIVE_HIGH))
-ELSE
- mov PCA0POL, #(((1 - PWM_ACTIVE_HIGH) SHL 1) + COM_ACTIVE_HIGH)
-ENDIF
-ENDM
-
-$endif
-
-
-;**** **** **** **** ****
-; PWM channels and updating
-;**** **** **** **** ****
-$if NOT CUSTOM_PWM_UPDATE
-
-Enable_Power_Pwm_Module MACRO
-IF DEADTIME == 0
- mov PCA0CPM_POWER, #4Ah ;; Enable comparator of module, enable match, set pwm mode
-ELSE
- mov PCA0CPM_POWER, #42h ;; Enable comparator of module, set pwm mode
-ENDIF
-ENDM
-
-Enable_Damp_Pwm_Module MACRO
-IF DEADTIME == 0
- mov PCA0CPM_DAMP, #00h ;; Disable
-ELSE
- mov PCA0CPM_DAMP, #42h ;; Enable comparator of module, set pwm mode
-ENDIF
-ENDM
-
-Set_Power_Pwm_Reg_L MACRO value
- mov PCA0CPL_POWER, value
-ENDM
-
-Set_Power_Pwm_Reg_H MACRO value
- mov PCA0CPH_POWER, value
-ENDM
-
-Set_Damp_Pwm_Reg_L MACRO value
- mov PCA0CPL_DAMP, value
-ENDM
-
-Set_Damp_Pwm_Reg_H MACRO value
- mov PCA0CPH_DAMP, value
-ENDM
-
-$endif
-
-
-;**** **** **** **** ****
-; Comparator setup and phase change
-;**** **** **** **** ****
-IF COMPARATOR_PORT == 0
-CMP_CN0 EQU CMP0CN0
-CMP_MD EQU CMP0MD
-CMP_MX EQU CMP0MX
-ELSE
-CMP_CN0 EQU CMP1CN0
-CMP_MD EQU CMP1MD
-CMP_MX EQU CMP1MX
-ENDIF
-
-Initialize_Comparator MACRO
- mov CMP_CN0, #80h ;; Comparator enabled, no hysteresis
- mov CMP_MD, #00h ;; Comparator response time 100ns
-IF COMPARATOR_INVERT == 1 AND MCU_TYPE >= 1
- mov CMP_MD, #40h ;; Output polarity inverted (Only supported on BB2 and BB51)
-ENDIF
-ENDM
-
-Read_Comparator_Output MACRO
- mov A, CMP_CN0 ;; Read comparator output
-IF COMPARATOR_INVERT == 1 AND MCU_TYPE == 0
- cpl A ;; Invert output polarity manually on BB1
-ENDIF
-ENDM
-
-; Set comparator multiplexer to phase A
-Set_Comparator_Phase_A MACRO
- IF MCU_TYPE < 2
- mov CMP_MX, #((A_Mux SHL 4) + V_Mux)
- ELSEIF MCU_TYPE == 2
- mov CMP_MX, #12h
- ENDIF
-ENDM
-
-; Set comparator multiplexer to phase B
-Set_Comparator_Phase_B MACRO
- IF MCU_TYPE < 2
- mov CMP_MX, #((B_Mux SHL 4) + V_Mux)
- ELSEIF MCU_TYPE == 2
- mov CMP_MX, #10h
- ENDIF
-ENDM
-
-; Set comparator multiplexer to phase C
-Set_Comparator_Phase_C MACRO
- IF MCU_TYPE < 2
- mov CMP_MX, #((C_Mux SHL 4) + V_Mux)
- ELSEIF MCU_TYPE == 2
- mov CMP_MX, #11h
- ENDIF
-ENDM
-
-
-; Toggle FETs 'on' and 'off'
-IF PWM_ACTIVE_HIGH == 1 ; PWM FET active high
-pON LIT 'setb'
-pOFF LIT 'clr'
-ELSE ; PWM FET active low
-pON LIT 'clr'
-pOFF LIT 'setb'
-ENDIF
-
-IF COM_ACTIVE_HIGH == 1 ; COM FET active high
-cON LIT 'setb'
-cOFF LIT 'clr'
-ELSE ; COM FET active low
-cON LIT 'clr'
-cOFF LIT 'setb'
-ENDIF
-
-
-;**** **** **** **** ****
-; PWM phase change
-;**** **** **** **** ****
-$if NOT CUSTOM_PWM_PHASE
-
-; All pwm and complementary pwm pins must be on port 1 to use the base code below
-P_A_Pwm EQU P1.A_Pwm
-P_A_Com EQU P1.A_Com
-P_B_Pwm EQU P1.B_Pwm
-P_B_Com EQU P1.B_Com
-P_C_Pwm EQU P1.C_Pwm
-P_C_Com EQU P1.C_Com
-
-Set_Pwm_Phase_A MACRO
-IF DEADTIME == 0
- cON P_A_Com
- mov P1SKIP, #(NOT (1 SHL A_Pwm))
-ELSE
- mov P1SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_B MACRO
-IF DEADTIME == 0
- cON P_B_Com
- mov P1SKIP, #(NOT (1 SHL B_Pwm))
-ELSE
- mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_C MACRO
-IF DEADTIME == 0
- cON P_C_Com
- mov P1SKIP, #(NOT (1 SHL C_Pwm))
-ELSE
- mov P1SKIP, #(NOT ((1 SHL C_Pwm) + (1 SHL C_Com)))
-ENDIF
-ENDM
-
-Set_All_Pwm_Phases_Off MACRO
- mov P1SKIP, #0FFh
-ENDM
-
-$endif
-
-
-;**** **** **** **** ****
-; Toggling FETs on/off
-;**** **** **** **** ****
-$if NOT CUSTOM_FET_TOGGLING
-
-A_Pwm_Fet_On MACRO
- pON P_A_Pwm
-IF DEADTIME == 0
- cON P_A_Com
-ENDIF
-ENDM
-
-A_Pwm_Fet_Off MACRO
-IF DEADTIME != 0
- pOFF P_A_Pwm
-ELSE
- cOFF P_A_Com
-ENDIF
-ENDM
-
-B_Pwm_Fet_On MACRO
- pON P_B_Pwm
-IF DEADTIME == 0
- cON P_B_Com
-ENDIF
-ENDM
-
-B_Pwm_Fet_Off MACRO
-IF DEADTIME != 0
- pOFF P_B_Pwm
-ELSE
- cOFF P_B_Com
-ENDIF
-ENDM
-
-C_Pwm_Fet_On MACRO
- pON P_C_Pwm
-IF DEADTIME == 0
- cON P_C_Com
-ENDIF
-ENDM
-
-C_Pwm_Fet_Off MACRO
-IF DEADTIME != 0
- pOFF P_C_Pwm
-ELSE
- cOFF P_C_Com
-ENDIF
-ENDM
-
-All_Pwm_Fets_Off MACRO
- A_Pwm_Fet_Off
- B_Pwm_Fet_Off
- C_Pwm_Fet_Off
-ENDM
-
-
-A_Com_Fet_On MACRO
-IF DEADTIME == 0
- pOFF P_A_Pwm
-ENDIF
- cON P_A_Com
-ENDM
-
-A_Com_Fet_Off MACRO
- cOFF P_A_Com
-ENDM
-
-B_Com_Fet_On MACRO
-IF DEADTIME == 0
- pOFF P_B_Pwm
-ENDIF
- cON P_B_Com
-ENDM
-
-B_Com_Fet_Off MACRO
- cOFF P_B_Com
-ENDM
-
-C_Com_Fet_On MACRO
-IF DEADTIME == 0
- pOFF P_C_Pwm
-ENDIF
- cON P_C_Com
-ENDM
-
-C_Com_Fet_Off MACRO
- cOFF P_C_Com
-ENDM
-
-All_Com_Fets_Off MACRO
- A_Com_Fet_Off
- B_Com_Fet_Off
- C_Com_Fet_Off
-ENDM
-
-$endif
-
-
-;**** **** **** **** ****
-; ADC and temperature measurement
-;**** **** **** **** ****
-; Temperature measurement ADC value for which main motor power is limited at 80degC (low byte, assuming high byte is 1)
-TEMP_LIMIT_2S EQU 49 ; When using vdd 3.3V reference
-TEMP_LIMIT_1S EQU 92 ; When using 1.65V internal reference
-TEMP_LIMIT_STEP EQU 9 ; Temperature measurement ADC value increment for another 10degC
-
-Initialize_Adc MACRO
-LOCAL initialize_adc_use_internal_1V65_vref initialize_adc_use_vdd_3V3_vref initialize_adc_vref_selected
-IF MCU_TYPE < 2
- mov Temp1, #Pgm_Power_Rating
- cjne @Temp1, #01h, initialize_adc_use_vdd_3V3_vref
-
-initialize_adc_use_internal_1V65_vref:
- mov REF0CN, #1Ch ;; Set internal 1.65V as reference on 1S. Enable temp sensor and bias
- sjmp initialize_adc_vref_selected
-initialize_adc_use_vdd_3V3_vref:
- mov REF0CN, #0Ch ;; Set vdd (3.3V) as reference on 2S+. Enable temp sensor and bias
-
-initialize_adc_vref_selected:
- IF MCU_TYPE == 0
- mov ADC0CF, #59h ;; ADC clock 2MHz, PGA gain 1
- ELSEIF MCU_TYPE == 1
- mov ADC0CF, #0B9h ;; ADC clock 2MHz, PGA gain 1
- ENDIF
-ELSEIF MCU_TYPE == 2
- mov CLKGRP0, #18h ;; Enable SAR clock, at 12MHz
- mov ADC0CF1, #0Ah ;; 800ns tracking time
- mov ADC0CF2, #2Fh ;; 1.65V reference
-ENDIF
-
- mov ADC0MX, #10h ;; Select temp sensor input
-IF MCU_TYPE < 2
- mov ADC0CN0, #80h ;; ADC enabled
- mov ADC0CN1, #01h ;; Common mode buffer enabled
-ELSEIF MCU_TYPE == 2
- mov ADC0CN0, #85h ;; ADC enabled (gain 0.5, temp sensor enabled)
- mov ADC0CN1, #20h ;; 10bit mode
-ENDIF
-ENDM
-
-Start_Adc MACRO
-IF MCU_TYPE < 2
- mov ADC0CN0, #90h ;; Initiate conversion
-ELSEIF MCU_TYPE == 2
- mov ADC0CN0, #95h ;; Initiate conversion (gain 0.5, temp sensor enabled)
-ENDIF
-ENDM
-
-Stop_Adc MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; LEDs
-;**** **** **** **** ****
-$if NOT CUSTOM_LED
-
-Set_LED_0 MACRO
-ENDM
-
-Clear_LED_0 MACRO
-ENDM
-
-Set_LED_1 MACRO
-ENDM
-
-Clear_LED_1 MACRO
-ENDM
-
-Set_LED_2 MACRO
-ENDM
-
-Clear_LED_2 MACRO
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-$endif
diff --git a/Layouts/C.inc b/Layouts/C.inc
deleted file mode 100644
index 490e3e61..00000000
--- a/Layouts/C.inc
+++ /dev/null
@@ -1,156 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "C"
-; Ac Ap MC MB MA CC X RC X X X X Cc Cp Bc Bp
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-A_Com EQU 7
-A_Pwm EQU 6
-C_Mux EQU 5
-B_Mux EQU 4
-A_Mux EQU 3
-V_Mux EQU 2
-; EQU 1
-RTX_PIN EQU 0
-
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU NOT((1 SHL A_Pwm) + (1 SHL A_Com))
-P0_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL A_Com)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-; EQU 5
-; EQU 4
-C_Com EQU 3
-C_Pwm EQU 2
-B_Com EQU 1
-B_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; PWM Phase
-;**** **** **** **** ****
-P_A_Pwm EQU P0.A_Pwm
-P_A_Com EQU P0.A_Com
-P_B_Pwm EQU P1.B_Pwm
-P_B_Com EQU P1.B_Com
-P_C_Pwm EQU P1.C_Pwm
-P_C_Com EQU P1.C_Com
-
-Set_Pwm_Phase_A MACRO
-IF DEADTIME == 0
- cON P_A_Com
- mov P0SKIP, #(NOT (1 SHL A_Pwm))
- mov P1SKIP, #0FFh
-ELSE
- mov P0SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
- mov P1SKIP, #0FFh
-ENDIF
-ENDM
-
-Set_Pwm_Phase_B MACRO
-IF DEADTIME == 0
- cON P_B_Com
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT (1 SHL B_Pwm))
-ELSE
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_C MACRO
-IF DEADTIME == 0
- cON P_C_Com
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT (1 SHL C_Pwm))
-ELSE
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT ((1 SHL C_Pwm) + (1 SHL C_Com)))
-ENDIF
-ENDM
-
-Set_All_Pwm_Phases_Off MACRO
- mov P0SKIP, #0FFh
- mov P1SKIP, #0FFh
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_PWM_PHASE)
-$include (Base.inc)
diff --git a/Layouts/D.inc b/Layouts/D.inc
deleted file mode 100644
index 14c1825a..00000000
--- a/Layouts/D.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "D". Com fets are active low for H/L_N driver and EN_N/PWM driver. A with different comp
-; X X RC X CC MA MC MB X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-C_Mux EQU 1
-B_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/E.inc b/Layouts/E.inc
deleted file mode 100644
index a4d242e7..00000000
--- a/Layouts/E.inc
+++ /dev/null
@@ -1,165 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "E". Equals "A", but with LED control. And with HIP2103/4 driver initialization
-; L1 L0 RC X MC MB MA CC X L2 Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-LED_1 EQU 7
-LED_0 EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU NOT((1 SHL LED_0) + (1 SHL LED_1))
-P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-LED_2 EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) + (1 SHL LED_2)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) + (1 SHL LED_2)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; ESC specific
-;**** **** **** **** ****
-Initialize_Crossbar MACRO
- mov XBR2, #40h ;; Crossbar enabled
- mov XBR1, #02h ;; CEX0 and CEX1 routed to pins
-
- All_Pwm_Fets_Off ;; For unlocking of HIP2103/4 driver circuits
- call wait100ms
- A_Com_Fet_On
- B_Com_Fet_On
- C_Com_Fet_On
- call wait1ms
- All_Com_Fets_Off
-ENDM
-
-Set_Pwm_Polarity MACRO
-IF PCA0CPM_POWER == PCA0CPM0
- mov PCA0POL, #((COM_ACTIVE_HIGH SHL 1) + (1 - PWM_ACTIVE_HIGH))
-ELSE
- mov PCA0POL, #(((1 - PWM_ACTIVE_HIGH) SHL 1) + COM_ACTIVE_HIGH)
-ENDIF
-ENDM
-
-
-;**** **** **** **** ****
-; LED configuration
-;**** **** **** **** ****
-Set_LED_0 MACRO
- setb P0.LED_0
-ENDM
-
-Clear_LED_0 MACRO
- clr P0.LED_0
-ENDM
-
-Set_LED_1 MACRO
- setb P0.LED_1
-ENDM
-
-Clear_LED_1 MACRO
- clr P0.LED_1
-ENDM
-
-Set_LED_2 MACRO
- setb P1.LED_2
-ENDM
-
-Clear_LED_2 MACRO
- clr P1.LED_2
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_PWM_SETUP, CUSTOM_LED)
-$include (Base.inc)
diff --git a/Layouts/F.inc b/Layouts/F.inc
deleted file mode 100644
index 14673cf6..00000000
--- a/Layouts/F.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "F". Equals "A", but with A_Mux and C_Mux swapped
-; X X RC X MA MB MC CC X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-A_Mux EQU 3
-B_Mux EQU 2
-C_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/G.inc b/Layouts/G.inc
deleted file mode 100644
index 3ecf5d31..00000000
--- a/Layouts/G.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "G". A with different comp ordering
-; X X RC X CC MA MC MB X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-C_Mux EQU 1
-B_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/H.inc b/Layouts/H.inc
deleted file mode 100644
index bc0ef894..00000000
--- a/Layouts/H.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "H".
-; RC X X X MA MB CC MC X Ap Bp Cp X Ac Bc Cc
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-RTX_PIN EQU 7
-; EQU 6
-; EQU 5
-; EQU 4
-A_Mux EQU 3
-B_Mux EQU 2
-V_Mux EQU 1
-C_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-A_Pwm EQU 6
-B_Pwm EQU 5
-C_Pwm EQU 4
-; EQU 3
-A_Com EQU 2
-B_Com EQU 1
-C_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/I.inc b/Layouts/I.inc
deleted file mode 100644
index 1f7ce917..00000000
--- a/Layouts/I.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "I"
-; X X RC X MC MB MA CC X X Ac Bc Cc Ap Bp Cp
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-A_Com EQU 5
-B_Com EQU 4
-C_Com EQU 3
-A_Pwm EQU 2
-B_Pwm EQU 1
-C_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/J.inc b/Layouts/J.inc
deleted file mode 100644
index 43b94ba2..00000000
--- a/Layouts/J.inc
+++ /dev/null
@@ -1,140 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "J"
-; L2 L1 L0 RC CC MB MC MA X X Cc Bc Ac Cp Bp Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-LED_2 EQU 7
-LED_1 EQU 6
-LED_0 EQU 5
-RTX_PIN EQU 4
-V_Mux EQU 3
-B_Mux EQU 2
-C_Mux EQU 1
-A_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL LED_2)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-B_Com EQU 4
-A_Com EQU 3
-C_Pwm EQU 2
-B_Pwm EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; LED configuration
-;**** **** **** **** ****
-Set_LED_0 MACRO
- clr P0.LED_0
-ENDM
-
-Clear_LED_0 MACRO
- setb P0.LED_0
-ENDM
-
-Set_LED_1 MACRO
- clr P0.LED_1
-ENDM
-
-Clear_LED_1 MACRO
- setb P0.LED_1
-ENDM
-
-Set_LED_2 MACRO
- clr P0.LED_2
-ENDM
-
-Clear_LED_2 MACRO
- setb P0.LED_2
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_LED)
-$include (Base.inc)
diff --git a/Layouts/K.inc b/Layouts/K.inc
deleted file mode 100644
index 5c635a5e..00000000
--- a/Layouts/K.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "K". Com fets are active low for H/L_N driver and EN_N/PWM driver
-; X X MC X MB CC MA RC X X Ap Bp Cp Cc Bc Ac Com fets inverted
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Mux EQU 5
-; EQU 4
-B_Mux EQU 3
-V_Mux EQU 2
-A_Mux EQU 1
-RTX_PIN EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-A_Pwm EQU 5
-B_Pwm EQU 4
-C_Pwm EQU 3
-C_Com EQU 2
-B_Com EQU 1
-A_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/L.inc b/Layouts/L.inc
deleted file mode 100644
index 53c6f493..00000000
--- a/Layouts/L.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "L". I with different comp ordering
-; X X RC X CC MA MB MC X X Ac Bc Cc Ap Bp Cp
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-B_Mux EQU 1
-C_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-A_com EQU 5
-B_Com EQU 4
-C_Com EQU 3
-A_Pwm EQU 2
-B_Pwm EQU 1
-C_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/M.inc b/Layouts/M.inc
deleted file mode 100644
index 045b232b..00000000
--- a/Layouts/M.inc
+++ /dev/null
@@ -1,136 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "M".
-; MA MC CC MB RC L0 X X X Cc Bc Ac Cp Bp Ap X
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-A_Mux EQU 7
-C_Mux EQU 6
-V_Mux EQU 5
-B_Mux EQU 4
-RTX_PIN EQU 3
-LED_0 EQU 2
-; EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU NOT(1 SHL LED_0)
-P0_PUSHPULL EQU (1 SHL LED_0)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-C_Com EQU 6
-B_Com EQU 5
-A_Com EQU 4
-C_Pwm EQU 3
-B_Pwm EQU 2
-A_Pwm EQU 1
-; EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; LED configuration
-;**** **** **** **** ****
-Set_LED_0 MACRO
- setb P0.LED_0
-ENDM
-
-Clear_LED_0 MACRO
- clr P0.LED_0
-ENDM
-
-Set_LED_1 MACRO
-ENDM
-
-Clear_LED_1 MACRO
-ENDM
-
-Set_LED_2 MACRO
-ENDM
-
-Clear_LED_2 MACRO
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_LED)
-$include (Base.inc)
diff --git a/Layouts/N.inc b/Layouts/N.inc
deleted file mode 100644
index 75ec0363..00000000
--- a/Layouts/N.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "N". B with A and C fets swapped
-; X X RC X MC MB MA CC X X Cp Cc Bp Bc Ap Ac
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-C_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-A_Pwm EQU 1
-A_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/O.inc b/Layouts/O.inc
deleted file mode 100644
index 1decad38..00000000
--- a/Layouts/O.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "O". Com fets are active low for H/L_N driver and EN_N/PWM driver. Low side pwm and 1S flag set
-; X X RC X CC MA MC MB X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 1 ; Comparator output inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-C_Mux EQU 1
-B_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Com EQU 5
-C_Pwm EQU 4
-B_Com EQU 3
-B_Pwm EQU 2
-A_Com EQU 1
-A_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/P.inc b/Layouts/P.inc
deleted file mode 100644
index 2826e858..00000000
--- a/Layouts/P.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "P". M with different comp and no LEDs
-; X X RC MA CC MB MC X X Cc Bc Ac Cp Bp Ap X
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-A_Mux EQU 4
-V_Mux EQU 3
-B_Mux EQU 2
-C_Mux EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-C_Com EQU 6
-B_Com EQU 5
-A_Com EQU 4
-C_Pwm EQU 3
-B_Pwm EQU 2
-A_Pwm EQU 1
-; EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/Q.inc b/Layouts/Q.inc
deleted file mode 100644
index ddef4b94..00000000
--- a/Layouts/Q.inc
+++ /dev/null
@@ -1,188 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "Q"
-; Cp Bp Ap L1 L0 X RC X X MA MB MC CC Cc Bc Ac
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 1 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-C_Pwm EQU 7
-B_Pwm EQU 6
-A_Pwm EQU 5
-LED_1 EQU 4
-LED_0 EQU 3
-; EQU 2
-RTX_PIN EQU 1
-; EQU 0
-
-
-P0_DIGITAL EQU 0FFh
-P0_INIT EQU (1 SHL RTX_PIN)
-P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-A_Mux EQU 6
-B_Mux EQU 5
-C_Mux EQU 4
-V_Mux EQU 3
-C_Com EQU 2
-B_Com EQU 1
-A_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; PWM Phase
-;**** **** **** **** ****
-P_A_Pwm EQU P0.A_Pwm
-P_A_Com EQU P1.A_Com
-P_B_Pwm EQU P0.B_Pwm
-P_B_Com EQU P1.B_Com
-P_C_Pwm EQU P0.C_Pwm
-P_C_Com EQU P1.C_Com
-
-Set_Pwm_Phase_A MACRO
-IF DEADTIME == 0
- cON P_A_Com
- mov P0SKIP, #(NOT (1 SHL A_Pwm))
- mov P1SKIP, #0FFh
-ELSE
- mov P0SKIP, #(NOT (1 SHL A_Pwm))
- mov P1SKIP, #(NOT (1 SHL A_Com))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_B MACRO
-IF DEADTIME == 0
- cON P_B_Com
- mov P0SKIP, #(NOT (1 SHL B_Pwm))
- mov P1SKIP, #0FFh
-ELSE
- mov P0SKIP, #(NOT (1 SHL B_Pwm))
- mov P1SKIP, #(NOT (1 SHL B_Com))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_C MACRO
-IF DEADTIME == 0
- cON P_C_Com
- mov P0SKIP, #(NOT (1 SHL C_Pwm))
- mov P1SKIP, #0FFh
-ELSE
- mov P0SKIP, #(NOT (1 SHL C_Pwm))
- mov P1SKIP, #(NOT (1 SHL C_Com))
-ENDIF
-ENDM
-
-Set_All_Pwm_Phases_Off MACRO
- mov P0SKIP, #0FFh
- mov P1SKIP, #0FFh
-ENDM
-
-
-;**** **** **** **** ****
-; LED configuration
-;**** **** **** **** ****
-Set_LED_0 MACRO
- setb P0.LED_0
-ENDM
-
-Clear_LED_0 MACRO
- clr P0.LED_0
-ENDM
-
-Set_LED_1 MACRO
- setb P0.LED_1
-ENDM
-
-Clear_LED_1 MACRO
- clr P0.LED_1
-ENDM
-
-Set_LED_2 MACRO
-ENDM
-
-Clear_LED_2 MACRO
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_PWM_PHASE, CUSTOM_LED)
-$include (Base.inc)
diff --git a/Layouts/R.inc b/Layouts/R.inc
deleted file mode 100644
index 76747831..00000000
--- a/Layouts/R.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "R". L with different comp
-; X X RC X MC MB MA CC X X Ac Bc Cc Ap Bp Cp
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-B_Mux EQU 2
-A_Mux EQU 1
-V_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-A_Com EQU 5
-B_Com EQU 4
-C_Com EQU 3
-A_Pwm EQU 2
-B_Pwm EQU 1
-C_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/S.inc b/Layouts/S.inc
deleted file mode 100644
index 04ad2f19..00000000
--- a/Layouts/S.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "S".
-; X X RC X CC MA MC MB X X Cc Cp Bc Bp Ac Ap
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-C_Mux EQU 1
-B_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-C_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-A_Pwm EQU 1
-A_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/T.inc b/Layouts/T.inc
deleted file mode 100644
index ab3b0f12..00000000
--- a/Layouts/T.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "T".
-; RC X MA X MB CC MC X X X Cp Bp Ap Ac Bc Cc
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-RTX_PIN EQU 7
-; EQU 6
-A_Mux EQU 5
-; EQU 4
-B_Mux EQU 3
-V_Mux EQU 2
-C_Mux EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-B_Pwm EQU 4
-A_Pwm EQU 3
-A_Com EQU 2
-B_Com EQU 1
-C_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Layouts/U.inc b/Layouts/U.inc
deleted file mode 100644
index 6abaf25c..00000000
--- a/Layouts/U.inc
+++ /dev/null
@@ -1,140 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "U". Like M, but with 3 LEDs
-; MA MC CC MB RC L0 L1 L2 X Cc Bc Ac Cp Bp Ap X
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-A_Mux EQU 7
-C_Mux EQU 6
-V_Mux EQU 5
-B_Mux EQU 4
-RTX_PIN EQU 3
-LED_0 EQU 2
-LED_1 EQU 1
-LED_2 EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL LED_2)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-C_Com EQU 6
-B_Com EQU 5
-A_Com EQU 4
-C_Pwm EQU 3
-B_Pwm EQU 2
-A_Pwm EQU 1
-; EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; LED configuration
-;**** **** **** **** ****
-Set_LED_0 MACRO
- clr P0.LED_0
-ENDM
-
-Clear_LED_0 MACRO
- setb P0.LED_0
-ENDM
-
-Set_LED_1 MACRO
- clr P0.LED_1
-ENDM
-
-Clear_LED_1 MACRO
- setb P0.LED_1
-ENDM
-
-Set_LED_2 MACRO
- clr P0.LED_2
-ENDM
-
-Clear_LED_2 MACRO
- setb P0.LED_2
-ENDM
-
-Set_LED_3 MACRO
-ENDM
-
-Clear_LED_3 MACRO
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_LED)
-$include (Base.inc)
diff --git a/Layouts/V.inc b/Layouts/V.inc
deleted file mode 100644
index c4f51310..00000000
--- a/Layouts/V.inc
+++ /dev/null
@@ -1,156 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "V"
-; Cc X RC X MC CC MB MA X Ap Ac Bp X X Bc Cp
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-C_Com EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-C_Mux EQU 3
-V_Mux EQU 2
-B_Mux EQU 1
-A_Mux EQU 0
-
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU NOT(1 SHL C_Com)
-P0_PUSHPULL EQU (1 SHL C_Com)
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-A_Pwm EQU 6
-A_Com EQU 5
-B_Pwm EQU 4
-; EQU 3
-; EQU 2
-B_Com EQU 1
-C_Pwm EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com)
-P1_INIT EQU 00h
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; PWM Phase
-;**** **** **** **** ****
-P_A_Pwm EQU P1.A_Pwm
-P_A_Com EQU P1.A_Com
-P_B_Pwm EQU P1.B_Pwm
-P_B_Com EQU P1.B_Com
-P_C_Pwm EQU P1.C_Pwm
-P_C_Com EQU P0.C_Com
-
-Set_Pwm_Phase_A MACRO
-IF DEADTIME == 0
- cON P_A_Com
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT (1 SHL A_Pwm))
-ELSE
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_B MACRO
-IF DEADTIME == 0
- cON P_B_Com
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT (1 SHL B_Pwm))
-ELSE
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
-ENDIF
-ENDM
-
-Set_Pwm_Phase_C MACRO
-IF DEADTIME == 0
- cON P_C_Com
- mov P0SKIP, #0FFh
- mov P1SKIP, #(NOT (1 SHL C_Pwm))
-ELSE
- mov P0SKIP, #(NOT (1 SHL C_Com))
- mov P1SKIP, #(NOT (1 SHL C_Pwm))
-ENDIF
-ENDM
-
-Set_All_Pwm_Phases_Off MACRO
- mov P0SKIP, #0FFh
- mov P1SKIP, #0FFh
-ENDM
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_PWM_PHASE)
-$include (Base.inc)
diff --git a/Layouts/W.inc b/Layouts/W.inc
deleted file mode 100644
index 74e8987a..00000000
--- a/Layouts/W.inc
+++ /dev/null
@@ -1,190 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "W". This is for tristate input style FET driver chips
-; RC MC MB X CC MA X X X Ap Bp Cp X X X X
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-RTX_PIN EQU 7
-C_Mux EQU 6
-B_Mux EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-; EQU 1
-; EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-A_Pwm EQU 6
-B_Pwm EQU 5
-C_Pwm EQU 4
-; EQU 3
-; EQU 2
-; EQU 1
-; EQU 0
-
-
-; pwm outputs start as analog in -> floating
-; this ensures all mosfet drivers start with floating outputs
-P1_DIGITAL EQU NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))
-P1_INIT EQU 00h
-P1_PUSHPULL EQU ((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))
-P1_SKIP EQU 0FFh
-
-
-A_Pwm_Fet_On MACRO
- setb P1.A_Pwm ; set pin to high
- orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
-ENDM
-
-A_Pwm_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL A_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-B_Pwm_Fet_On MACRO
- setb P1.B_Pwm ; set pin to high
- orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
-ENDM
-
-B_Pwm_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL B_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-C_Pwm_Fet_On MACRO
- setb P1.C_Pwm ; set pin to high
- orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
-ENDM
-
-C_Pwm_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL C_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-All_Pwm_Fets_Off MACRO
- anl P1MDIN, #(NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-A_Com_Fet_On MACRO
- clr P1.A_Pwm ; set pin to low
- orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
-ENDM
-
-A_Com_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL A_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-B_Com_Fet_On MACRO
- clr P1.B_Pwm ; set pin to low
- orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
-ENDM
-
-B_Com_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL B_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-C_Com_Fet_On MACRO
- clr P1.C_Pwm ; set pin to low
- orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
-ENDM
-
-C_Com_Fet_Off MACRO
- anl P1MDIN, #(NOT(1 SHL C_Pwm)) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-All_Com_Fets_Off MACRO
- anl P1MDIN, #(NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))) ; analog in -> pullup, driver and digital in is disable = floating
-ENDM
-
-Set_Pwm_Phase_A MACRO
- mov P1SKIP, #(NOT(1 SHL A_Pwm));
- orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
-ENDM
-
-Set_Pwm_Phase_B MACRO
- mov P1SKIP, #(NOT(1 SHL B_Pwm));
- orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
-ENDM
-
-Set_Pwm_Phase_C MACRO
- mov P1SKIP, #(NOT(1 SHL C_Pwm));
- orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
-ENDM
-
-Set_All_Pwm_Phases_Off MACRO
- mov P1SKIP, #P1_SKIP;
-ENDM
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$set(CUSTOM_PWM_PHASE, CUSTOM_FET_TOGGLING)
-$include (Base.inc)
diff --git a/Layouts/Z.inc b/Layouts/Z.inc
deleted file mode 100644
index 7054b509..00000000
--- a/Layouts/Z.inc
+++ /dev/null
@@ -1,105 +0,0 @@
-;**** **** **** **** ****
-;
-; Bluejay digital ESC firmware for controlling brushless motors in multirotors
-;
-; Copyright 2020-2022 Mathias Rasmussen
-; Copyright 2011-2017 Steffen Skaug
-;
-; This file is part of Bluejay.
-;
-; Bluejay is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; Bluejay is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with Bluejay. If not, see .
-;
-;**** **** **** **** ****
-;
-; Hardware definition file "Z". N different comp and pwm active low
-; X X RC X CC MA MC MB X X Cp Cc Bp Bc Ap Ac
-;
-;**** **** **** **** ****
-
-PWM_ACTIVE_HIGH EQU 0 ; Pwm inverted
-COM_ACTIVE_HIGH EQU 1 ; Damping inverted
-
-COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
-COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
-
-IF DEADTIME == 0
- PCA0CPM_POWER EQU PCA0CPM0
- PCA0CPL_POWER EQU PCA0CPL0
- PCA0CPH_POWER EQU PCA0CPH0
-
- PCA0CPM_DAMP EQU PCA0CPM1
- PCA0CPL_DAMP EQU PCA0CPL1
- PCA0CPH_DAMP EQU PCA0CPH1
-ELSE
- PCA0CPM_POWER EQU PCA0CPM1
- PCA0CPL_POWER EQU PCA0CPL1
- PCA0CPH_POWER EQU PCA0CPH1
-
- PCA0CPM_DAMP EQU PCA0CPM0
- PCA0CPL_DAMP EQU PCA0CPL0
- PCA0CPH_DAMP EQU PCA0CPH0
-ENDIF
-
-
-;*********************
-; PORT 0 definitions *
-;*********************
-; EQU 7
-; EQU 6
-RTX_PIN EQU 5
-; EQU 4
-V_Mux EQU 3
-A_Mux EQU 2
-C_Mux EQU 1
-B_Mux EQU 0
-
-P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
-P0_INIT EQU 0FFh
-P0_PUSHPULL EQU 0
-P0_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 1 definitions *
-;*********************
-; EQU 7
-; EQU 6
-C_Pwm EQU 5
-C_Com EQU 4
-B_Pwm EQU 3
-B_Com EQU 2
-A_Pwm EQU 1
-A_Com EQU 0
-
-
-P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_INIT EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) ; Active low pwm fets
-P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
-P1_SKIP EQU 0FFh
-
-
-;*********************
-; PORT 2 definitions *
-;*********************
-DebugPin EQU 0
-
-P2_DIGITAL EQU (1 SHL DebugPin)
-P2_PUSHPULL EQU (1 SHL DebugPin)
-P2_SKIP EQU (1 SHL DebugPin)
-
-
-;**** **** **** **** ****
-; Inherit base layout
-;**** **** **** **** ****
-$include (Base.inc)
diff --git a/Makefile b/Makefile
index 19a77b3f..90fd9044 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,8 @@ 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
+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 \
+ OA
MCUS = H
LAYOUTS_X = A B C
MCUS_X = X
@@ -37,8 +38,27 @@ AX51_FLAGS = NOMOD51 REGISTERBANK(0,1,2) NOLIST NOSYMBOLS
LX51_FLAGS =
# Source files
-ASM_SRC = Bluejay.asm
-ASM_INC = $(LAYOUTS:%=Layouts/%.inc) Layouts/Base.inc Common.inc BLHeliBootLoad.inc Silabs/SI_EFM8BB1_Defs.inc Silabs/SI_EFM8BB2_Defs.inc
+ASM_SRC = src/Bluejay.asm
+
+ASM_INC = \
+ $(LAYOUTS:%=src/Layouts/%.inc) \
+ src/Layouts/Base.inc \
+ src/BLHeliBootLoad.inc \
+ src/Silabs/SI_EFM8BB1_Defs.inc \
+ src/Silabs/SI_EFM8BB2_Defs.inc \
+ src/Silabs/SI_EFM8BB51_Defs.inc \
+ src/Silabs/SI_EFM8LB1_Defs.inc \
+ src/Modules/Common.asm \
+ src/Modules/Commutation.asm \
+ src/Modules/DShot.asm \
+ src/Modules/Eeprom.asm \
+ src/Modules/Fx.asm \
+ src/Modules/Isrs.asm \
+ src/Modules/Macros.asm \
+ src/Modules/Power.asm \
+ src/Modules/Scheduler.asm \
+ src/Modules/Settings.asm \
+ src/Modules/Timing.asm
# Check that wine/simplicity studio is available
EXECUTABLES = $(AX51_BIN) $(LX51_BIN) $(OX51_BIN)
@@ -63,6 +83,9 @@ $(OUTPUT_DIR)/$(1)_$(2)_$(3)_$(4)_$(VERSION).OBJ : $(ASM_SRC) $(ASM_INC)
$(eval _ESC := $(1))
$(eval _ESC_INT := $(shell printf "%d" "'${_ESC}"))
$(eval _ESCNO := $(shell echo $$(( $(_ESC_INT) - 65 + 1))))
+
+ $(if $(shell if [ ${_ESC} = "OA" ]; then echo "TRUE"; fi),$(eval _ESCNO := '27'),)
+
$(eval _MCU_TYPE := $(subst L,0,$(subst H,1,$(subst X,2,$(2)))))
$(eval _DEADTIME := $(3))
$(eval _PWM_FREQ := $(subst 24,0,$(subst 48,1,$(subst 96,2,$(4)))))
diff --git a/README.md b/README.md
index 871771e2..213b783c 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ See the project [changelog](CHANGELOG.md) for a list of changes.
- SiLabs EFM8 BB51
### Deprecated Platforms
-The `SiLabs EFM8 BB10` has been deprecated. The last official release is [0.18.1](https://github.com/bird-sanctuary/bluejay/releases/tag/v0.18.1). The BB10 has it's limitations in comparison to the BB21 and BB51. Not many of those seem to be around anymore and the team does not have a single one for testing, thus decided to drop support.
+The `SiLabs EFM8 BB10` - commonly also known as L layout - has been deprecated. The last official release is [0.18.1](https://github.com/bird-sanctuary/bluejay/releases/tag/v0.18.1). The BB10 has it's limitations in comparison to the BB21 and BB51. Not many of those seem to be around anymore and the team does not have a single one for testing, thus decided to drop support.
> You will still be able to manually build for it, but we can not guarantee compatibility and do not want to suffer from it's limitations during further development.
@@ -45,12 +45,36 @@ You can also do it manually by downloading the [release binaries](https://github
## Documentation
See the [wiki](https://github.com/bird-sanctuary/bluejay/wiki) for useful information. A very detailed documentation with flow charts is [available too](https://github.com/bird-sanctuary/bluejay-documentation).
-
## Ancestry
This is a fork of the original [Bluejay](https://github.com/mathiasvr/bluejay) project. The team has decided to detach this fork from the orignal project in order to have all github features to their disposal.
The decision to keep the name was made in order to honour the orignal project and the hope that the original developer will join us here, once he decides to make a comeback.
+## Supporters
+This project is run by a small core team devoting a lot of their spare time and money into pushing this project forward. Development of ESC firmware is time consuming and mistakes are expensive: Motors, ESCs and Flight-Controllers tend to break from time to time, especially if pushing the limits.
+
+We do not take monetary donations, but we have a [donation Wiki page](https://github.com/bird-sanctuary/bluejay/wiki/Donations) where you can see which hardware we are currently looking for - if you want to help out, consider getting in touch with us and buying us some hardware we need.
+
+### Community
+A big shout out goes out to the following members of the community for donating hardware - listed by their real name, Discord handle or github username if known:
+
+* 406FPV - for donating a F722 based flight-controller, motors and a whole 1105 based micro quad
+* belrik - for donating a set of 2207 motors
+* Ced_51 - for dontaing multiple sets of different motors (2207, 2306)
+* geordil - for donating a F722 based flight-controller
+* Miguel Juncal - for donating a 5" quad and a set of Sunnysky motors
+* RabbitAmbulance - for donating a set of 2207 motors
+
+### Manufacturers
+We are in a very lucky position to have manufacturers who keep helping us out continuously and who deserve a shoutout:
+
+* [BetaFPV](https://betafpv.com/) - for providing us with dev boards for BB51 MCUs, AIO Flight-controllers, Motors and Whoops
+* [Happymodel](https://www.happymodel.cn/) - for providing us with Whoops
+* [Skystars](https://skystars-rc.com/) - for providing us with flight-controllers and ESCs
+* [T-Motor](https://tmotorhobby.com/) - for providing us with an AIO flight-controller
+* [TuneRC](https://www.tunerc.com/) - for providing us with AIO flight-controllers
+* [weBLEEDfpv](https://webleedfpv.com/) - for a set of "Gore V2" motors
+
## Contribute
Any help you can provide is greatly appreciated!
diff --git a/src/BLHeliBootLoad.inc b/src/BLHeliBootLoad.inc
new file mode 100644
index 00000000..94afe977
--- /dev/null
+++ b/src/BLHeliBootLoad.inc
@@ -0,0 +1,422 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; BLHeli bootloader for SiLabs MCUs. Based upon AVRootloader (copyright HR)
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+XTAL EQU 25000000
+
+BOOT_DELAY EQU XTAL/4 ; About 250ms (don't set to fast to avoid connection problems)
+BOOT_BAUDRATE EQU 19200 ; Only used if no baudrate detection activated,XTAL is than important
+BOOT_VERSION EQU 6 ; Version 6 (must be not changed)
+BOOT_PAGES EQU 1 ; Number of flash segments for bootloader
+
+UART_LOOP EQU 26 ; Depends upon timing of putc,getc
+BAUDTIME EQU ((XTAL/BOOT_BAUDRATE)/3)-UART_LOOP
+
+SUCCESS EQU 030h
+ERRORVERIFY EQU 0C0h
+ERRORCOMMAND EQU 0C1h
+ERRORCRC EQU 0C2h
+ERRORPROG EQU 0C5h
+
+POLYNOM EQU 0A001h ; CRC Polynom
+
+Xl EQU R0 ; Temporary X
+Xh EQU R1
+Paral EQU R2 ; Params for UART
+Parah EQU R3
+Cmdl EQU R4 ; Commands
+Cmdh EQU R5
+Cntl EQU R6 ; Baudtime
+Cnth EQU R7
+
+DSEG AT 20h
+Bit_Reg: DS 1 ; Bit storage register
+Byte_Reg: DS 1 ; Byte storage register
+Crcl: DS 1 ; CRC 16Bit
+Crch: DS 1
+Baudl: DS 1 ; Baudtime
+Baudh: DS 1
+Bit_Cnt: DS 1 ; Counter in UART loops
+Byte_Cntl: DS 1 ; Generic counter
+Byte_Cnth: DS 1
+BL_Flash_Key_1: DS 1 ; Flash keys
+BL_Flash_Key_2: DS 1
+
+CSEG AT CSEG_BOOT_START ; Bootloader start
+init:
+ clr IE_EA
+
+ ; Select register bank 0 for main program routines
+ clr PSW.3 ; Select register bank 0 for main program routines
+
+ ; Disable the WDT.
+ mov WDTCN, #0DEh ; Disable watchdog
+ mov WDTCN, #0ADh
+
+ ; Initialize stack
+ mov SP, #0c0h ; Stack = 64 upper bytes of RAM
+ ; Initialize clock
+ mov CLKSEL, #00h ; Set clock divider to 1
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE = MCU_BB2
+ ; Initialize VDD monitor
+ orl VDM0CN, #080h ; Enable the VDD monitor
+ENDIF
+ mov Baudl, #38h ; Wait 100us
+ mov Baudh, #03h
+ acall waitf
+
+ ; Initialize flash keys
+ Unlock_Flash
+
+ ; Initialize ports
+ orl RTX_MDIN, #(1 SHL RTX_PIN) ; Set digital
+ anl RTX_MDOUT, #NOT(1 SHL RTX_PIN) ; Disable pushpull
+ setb RTX_PORT.RTX_PIN ; Set data high
+ mov RTX_SKIP, #0FFh
+ mov XBR2, #40h ; ; Enable crossbar
+
+ ; Set number of connect attempts before exiting bootloader
+ mov Cmdh, #250
+
+abd:
+ ; Identifier scanning
+ mov Xl, #(low(BOOT_DELAY / 6)+1)
+ mov Xh, #(high(BOOT_DELAY / 6)+1)
+ mov Cmdl, #(high((BOOT_DELAY / 6) SHR 8)+1)
+ mov Crcl, #0
+ mov Crch, #0
+ mov DPTR, #BOOT_SIGN
+ mov Parah, #(BOOT_MSG - BOOT_SIGN)
+ mov Baudl, #low(BAUDTIME)
+ mov Baudh, #high(BAUDTIME)
+
+wait_for_low:
+ jnb RTX_PORT.RTX_PIN, ($+5)
+ ajmp wait_for_low
+
+; Identifier (BOOT_SIGN) scanning with timeout and checksum
+id1:
+ jb RTX_PORT.RTX_PIN, id3 ; Look for high
+ djnz Xl, id1 ; Subtract 1 from X (BOOT_DELAY)
+ djnz Xh, id1
+ djnz Cmdl, id1
+
+ ajmp exit
+
+id3:
+ jnb RTX_PORT.RTX_PIN, id4 ; Look for low
+ djnz Xl, id3 ; Subtract 1 from X (BOOT_DELAY)
+ djnz Xh, id3
+ djnz Cmdl, id3
+
+ ajmp exit
+
+id4:
+ acall getx ; Read character
+ clr A
+ movc A, @A+DPTR ; Load BOOT_SIGN character
+ inc DPTR
+ clr C
+ subb A, Paral ; Compare with read character
+ jz id5
+ djnz Cmdh, abd ; Retry if not last connect attempt
+ ajmp exit
+
+id5:
+ djnz Parah, id1
+
+ acall getw ; Read CRC
+ jz ($+4) ; Check CRC
+ ajmp abd
+
+ ; Send info about chip/bootloader (BOOT_MSG + BOOT_INFO)
+ mov Parah, #((BOOT_INFO - BOOT_MSG) + 4)
+in1:
+ clr A
+ movc A, @A+DPTR ; Load character
+ mov Paral, A
+ inc DPTR
+ acall putc
+ djnz Parah, in1
+
+; Main commandloop
+; 0=Run/restart
+; 1=Program flash, 2=Erase flash, 3=Read flash
+; 0xFF=Set address, 0xFE=Set buffer, 0xFD=Keep alive
+main:
+ mov Paral, #SUCCESS
+mai1:
+ acall putc
+ mov Crcl, #0 ; Reset CRC
+ mov Crch, #0
+ acall getw ; Get command
+ mov A, Paral
+ mov Cmdl, A
+ mov A, Parah
+ mov Cmdh, A
+ clr C
+ mov A, Cmdh
+ subb A, #0FEh
+ jc mai2 ; Jump if not set address or set buffer
+
+ acall getw ; Address or number of bytes
+ mov Byte_Cntl, Paral ; Store number of bytes for set buffer
+ mov Byte_Cnth, Parah
+ mov A, Cmdh
+ jnb ACC.0, mai2 ; Jump if set buffer
+
+ mov DPL, Paral ; Store flash address (for set address)
+ mov DPH, Parah
+
+mai2:
+ acall getw ; Get CRC
+ mov Paral, #ERRORCRC
+ jnz mai1
+ clr C
+ mov A, Cmdh
+ subb A, #0FEh
+ jz setbuf ; If command is set buffer,receive data
+ jnc main
+
+ cjne Cmdh, #0, mai4 ; Jump if command != 0 (and not set buffer)
+
+ ; Run application/restart bootloader
+ mov A, Cmdl
+ jz rst
+exit:
+ mov Bit_Access, #0 ; Clear variable used by flash lock detect
+ mov Bit_Access_Int, #0FFh ; Set variable to indicate that program execution came from bootloader
+ Lock_Flash
+ ljmp 0000h
+rst:
+ ajmp init
+
+; Set buffer
+setbuf:
+ mov Xl, Byte_Cntl ; Set number of bytes
+ mov Xh, Byte_Cnth
+ inc Xl
+ inc Xh
+set4:
+ djnz Xl, set5
+ djnz Xh, set5
+ ajmp set6
+
+set5:
+ acall getc ; Receive data
+ mov A, Paral
+ movx @Xl, A ; Store data in XRAM
+ ajmp set4
+
+set6:
+ inc Cmdh
+ ajmp mai2
+
+mai4:
+ clr C
+ mov A, Cmdh
+ subb A, #3
+ jnc mai5 ; Jump if command >= 3
+
+ ; Program/erase
+ mov A, Cmdh
+ mov C, ACC.0
+ mov Bit_Reg.0, C
+ mov Paral, #ERRORPROG
+ clr C
+ mov A, DPL
+ subb A, #low(CSEG_BOOT_START)
+ mov A, DPH
+ subb A, #high(CSEG_BOOT_START)
+ jnc mai1 ; Jump if in bootloader segment
+ jb Bit_Reg.0, pro3 ; Jump if program command
+
+ ; Erase flash
+ orl PSCTL, #02h ; Set the PSEE bit
+ orl PSCTL, #01h ; Set the PSWE bit
+ mov FLKEY, BL_Flash_Key_1 ; First key code
+ mov FLKEY, BL_Flash_Key_2 ; Second key code
+ movx @DPTR, A
+ jnb Bit_Reg.0, pro6 ; Jump if erase command
+
+; Program flash
+pro3:
+ mov Xl, Byte_Cntl ; Set number of bytes
+ mov Xh, Byte_Cnth
+ inc Xl
+ inc Xh
+ orl PSCTL, #01h ; Set the PSWE bit
+ anl PSCTL, #0FDh ; Clear the PSEE bit
+pro4:
+ djnz Xl, pro5
+ djnz Xh, pro5
+ ajmp pro6
+
+pro5:
+ clr C
+ mov A, DPH ; Check that address is not in bootloader area
+ subb A, #BOOTLOADER_OFFSET
+ jc ($+5)
+
+ inc DPTR ; Increment flash address
+ ajmp pro4
+
+ movx A, @Xl ; Read from XRAM
+ mov FLKEY, BL_Flash_Key_1 ; First key code
+ mov FLKEY, BL_Flash_Key_2 ; Second key code
+ movx @DPTR, A ; Write to flash
+ inc DPTR ; Increment flash address
+ ajmp pro4
+
+pro6:
+ anl PSCTL, #0FCh ; Clear the PSEE and PSWE bits
+ ajmp main ; Successfully done erase or program
+
+; Read flash
+mai5:
+ mov Paral, #ERRORCOMMAND ; Illegal command
+ cjne Cmdh, #3, mai6 ; Jump if not read flash command
+
+rd1:
+ clr A
+ movc A, @A+DPTR ; Read from flash
+ inc DPTR ; Increment flash address
+ mov Paral, A
+ acall putp
+ djnz Cmdl, rd1 ; Decrement bytes to read
+
+ acall putw ; CRC
+ ajmp main
+
+mai6:
+ ajmp mai1
+
+; Send char with crc
+putw:
+ mov Paral, Crcl
+ mov Parah, Crch
+ acall putc
+ mov A, Parah
+ mov Paral, A
+putp:
+ mov A, Paral
+ xrl Crcl, A
+ mov Bit_Cnt, #8
+put1:
+ clr C
+ mov A, Crch
+ rrc A
+ mov Crch, A
+ mov A, Crcl
+ rrc A
+ mov Crcl, A
+ jnc put2
+
+ xrl Crch, #high(POLYNOM)
+ xrl Crcl, #low(POLYNOM)
+
+put2:
+ djnz Bit_Cnt, put1
+
+; Send char
+putc:
+ acall waitf
+ acall waitf
+ mov Bit_Cnt, #10
+ mov A, Paral
+ cpl A
+put3:
+ jb Bit_Reg.1, ($+5)
+ setb RTX_PORT.RTX_PIN ; Set pin high
+ jnb Bit_Reg.1, ($+5)
+ clr RTX_PORT.RTX_PIN ; Set pin low
+ acall waitf
+ clr C
+ rrc A
+ jc put4
+
+ clr Bit_Reg.1
+
+put4:
+ djnz Bit_Cnt, put3
+ ret
+
+; Receive char/word
+getw:
+ acall getc
+ mov A, Paral
+ mov Parah, A
+getc:
+ jb RTX_PORT.RTX_PIN, ($+5) ; Wait for high
+ ajmp getc
+
+get1:
+ jnb RTX_PORT.RTX_PIN, ($+5) ; Wait for low
+ ajmp get1
+
+getx:
+ mov Bit_Cnt, #8
+ mov Cntl, Baudl
+ mov Cnth, Baudh
+ clr C
+ mov A, Cnth ; Wait half a baud
+ rrc A
+ mov Cnth, A
+ mov A, Cntl
+ rrc A
+ mov Cntl, A
+ acall waith
+
+get2:
+ acall waitf ; Wait one baud
+ clr C
+ mov A, Paral
+ rrc A
+ jnb RTX_PORT.RTX_PIN, ($+5)
+ orl A, #080h
+
+ mov Paral, A
+ jnb ACC.7, ($+6)
+ xrl Crcl, #low(POLYNOM)
+
+ clr C
+ mov A, Crch
+ rrc A
+ mov Crch, A
+ mov A, Crcl
+ rrc A
+ mov Crcl, A
+ jnc get3
+
+ xrl Crch, #high(POLYNOM)
+ xrl Crcl, #low(POLYNOM)
+
+get3:
+ djnz Bit_Cnt, get2
+ mov A, Crcl
+ xrl A, Crch
+ xrl A, Crch
+ mov Crcl, A
+ ret
+
+; UART delays
+waitf:
+ mov Cntl, Baudl
+ mov Cnth, Baudh
+
+waith:
+ inc Cntl
+ inc Cnth
+
+wait1:
+ djnz Cntl, wait1
+ djnz Cnth, wait1
+
+ setb Bit_Reg.1
+ ret
+
+BOOT_SIGN: DB "BLHeli"
+BOOT_MSG: DB "471d" ; Interface-MCU_BootlaoderRevision
+BOOT_INFO: DB SIGNATURE_001,SIGNATURE_002,BOOT_VERSION,BOOT_PAGES
diff --git a/src/Bluejay.asm b/src/Bluejay.asm
new file mode 100644
index 00000000..c223d698
--- /dev/null
+++ b/src/Bluejay.asm
@@ -0,0 +1,1141 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay is a fork of BLHeli_S by Steffen Skaug.
+;
+; The input signal can be DShot with rates: DShot150, DShot300 and DShot600.
+;
+; This file is best viewed with tab width set to 5.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Master clock is internal 24MHz oscillator (or 48MHz, for which the times below are halved)
+; Although 24/48 are used in the code, the exact clock frequencies are 24.5MHz or 49.0 MHz
+; Timer0 (41.67ns counts) always counts up and is used for
+; - RC pulse measurement
+; - DShot telemetry pulse timing
+; Timer1 (41.67ns counts) always counts up and is used for
+; - DShot frame sync detection
+; Timer2 (500ns counts) always counts up and is used for
+; - RC pulse timeout counts and commutation times
+; Timer3 (500ns counts) always counts up and is used for
+; - Commutation timeouts
+; PCA0 (41.67ns counts) always counts up and is used for
+; - Hardware PWM generation
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Motor control:
+; - Brushless motor control with 6 states for each electrical 360 degrees
+; - An advance timing of 0deg has zero cross 30deg after one commutation and 30deg before the next
+; - Timing advance in this implementation is set to 15deg nominally
+; - Motor pwm is always damped light (aka complementary pwm, regenerative braking)
+; Motor sequence starting from zero crossing:
+; - Timer wait: Wt_Comm 15deg ; Time to wait from zero cross to actual commutation
+; - Timer wait: Wt_Advance 15deg ; Time to wait for timing advance. Nominal commutation point is after this
+; - Timer wait: Wt_Zc_Scan 7.5deg ; Time to wait before looking for zero cross
+; - Scan for zero cross 22.5deg ; Nominal, with some motor variations
+;
+; Motor startup:
+; There is a startup phase and an initial run phase, before normal bemf commutation run begins.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Legend:
+; RX Receive/transmit pin
+; Am, Bm, Cm Comparator inputs for BEMF
+; Vn Common Comparator input
+; Ap, Bp, Cp PWM pins
+; Ac, Bc, Cc Complementary PWM pins
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+$include (Modules\Enums.asm)
+
+; List of enumerated supported ESCs
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ A_ EQU 1 ; Vn Am Bm Cm __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _
+ B_ EQU 2 ; Vn Am Bm Cm __ RX __ __ | Cc Cp Bc Bp Ac Ap __ __ | no no high _
+ C_ EQU 3 ; RX __ Vn Am Bm Cm Ap Ac | Bp Bc Cp Cc __ __ __ __ | no no high _
+ D_ EQU 4 ; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes high _
+ E_ EQU 5 ; Vn Am Bm Cm __ RX L0 L1 | Ap Ac Bp Bc Cp Cc L2 __ | no no high 3 Pinout like A, with LEDs
+ F_ EQU 6 ; Vn Cm Bm Am __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _
+ G_ EQU 7 ; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _ Pinout like D, but non-inverted com FETs
+ H_ EQU 8 ; Cm Vn Bm Am __ __ __ RX | Cc Bc Ac __ Cp Bp Ap __ | no no high _
+ I_ EQU 9 ; Vn Am Bm Cm __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _
+ J_ EQU 10 ; Am Cm Bm Vn RX L0 L1 L2 | Ap Bp Cp Ac Bc Cc __ __ | no no high 3
+ K_ EQU 11 ; RX Am Vn Bm __ Cm __ __ | Ac Bc Cc Cp Bp Ap __ __ | no yes high _
+ L_ EQU 12 ; Cm Bm Am Vn __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _
+ M_ EQU 13 ; __ __ L0 RX Bm Vn Cm Am | __ Ap Bp Cp Ac Bc Cc __ | no no high 1
+ N_ EQU 14 ; Vn Am Bm Cm __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no no high _
+ O_ EQU 15 ; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes low _ Pinout Like D, but low side pwm
+ P_ EQU 16 ; __ Cm Bm Vn Am RX __ __ | __ Ap Bp Cp Ac Bc Cc __ | no no high _
+ Q_ EQU 17 ; __ RX __ L0 L1 Ap Bp Cp | Ac Bc Cc Vn Cm Bm Am __ | no no high 2
+ R_ EQU 18 ; Vn Am Bm Cm __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _ Same as I
+ S_ EQU 19 ; Bm Cm Am Vn __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no no high _
+ T_ EQU 20 ; __ Cm Vn Bm __ Am __ RX | Cc Bc Ac Ap Bp Cp __ __ | no no high _
+ U_ EQU 21 ; L2 L1 L0 RX Bm Vn Cm Am | __ Ap Bp Cp Ac Bc Cc __ | no no high 3 Pinout like M, with 3 LEDs
+ V_ EQU 22 ; Am Bm Vn Cm __ RX __ Cc | Cp Bc __ __ Bp Ac Ap __ | no no high _
+ W_ EQU 23 ; __ __ Am Vn __ Bm Cm RX | __ __ __ __ Cp Bp Ap __ | n/a n/a high _ Tristate gate driver
+ X_ EQU 24
+ Y_ EQU 25
+ Z_ EQU 26 ; Bm Cm Am Vn __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | yes no high _ Pinout like S, but inverted pwm FETs
+
+ ; Two letter layouts start here. Preferably the first letter is the base
+ ; layout and the second letter is the variation in alphabetical order.
+ OA_ EQU 27 ; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes low _ Pinout Like O, but open drain instead of push-pull COM FETs
+ENDIF
+
+; BB51 - Required
+IF MCU_TYPE == MCU_BB51
+ A_ EQU 1 ; __ Bm Cm Am Vn RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no low _
+ B_ EQU 2 ; __ Bm Cm Am Vn RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no yes high _
+ C_ EQU 3 ; __ Bm Cm Am Vn RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | yes yes high _
+ENDIF
+
+; Select the port mapping to use (or unselect all for use with external batch compile file)
+;ESCNO EQU A_
+
+; Select the MCU type (or unselect for use with external batch compile file)
+;MCU_TYPE EQU 0 ; BB1
+;MCU_TYPE EQU 1 ; BB2
+;MCU_TYPE EQU 2 ; BB51
+
+; Select the FET dead time (or unselect for use with external batch compile file)
+;DEADTIME EQU 15 ; 20.4ns per step
+
+; Select the pwm frequency (or unselect for use with external batch compile file)
+;PWM_FREQ EQU 0 ; 0=24, 1=48, 2=96 kHz
+
+PWM_CENTERED EQU DEADTIME > 0 ; Use center aligned pwm on ESCs with dead time
+
+IF MCU_TYPE == MCU_BB1
+ IS_MCU_48MHZ EQU 0
+ELSE
+ IS_MCU_48MHZ EQU 1
+ENDIF
+
+IF PWM_FREQ == PWM_24 or PWM_FREQ == PWM_48 or PWM_FREQ == PWM_96
+ ; Number of bits in pwm high byte
+ PWM_BITS_H EQU (2 + IS_MCU_48MHZ - PWM_CENTERED - PWM_FREQ)
+ENDIF
+
+$include (Modules\McuOffsets.asm)
+$include (Modules\Codespace.asm)
+$include (Modules\Common.asm)
+$include (Modules\Macros.asm)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Programming defaults
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DEFAULT_PGM_RPM_POWER_SLOPE EQU 9 ; 0=Off,1..13 (Power limit factor in relation to rpm)
+DEFAULT_PGM_COMM_TIMING EQU 4 ; 1=Low 2=MediumLow 3=Medium 4=MediumHigh 5=High
+DEFAULT_PGM_DEMAG_COMP EQU 2 ; 1=Disabled 2=Low 3=High
+DEFAULT_PGM_DIRECTION EQU 1 ; 1=Normal 2=Reversed 3=Bidir 4=Bidir rev
+DEFAULT_PGM_BEEP_STRENGTH EQU 40 ; 0..255 (BLHeli_S is 1..255)
+DEFAULT_PGM_BEACON_STRENGTH EQU 80 ; 0..255
+DEFAULT_PGM_BEACON_DELAY EQU 4 ; 1=1m 2=2m 3=5m 4=10m 5=Infinite
+DEFAULT_PGM_ENABLE_TEMP_PROT EQU 0 ; 0=Disabled 1=80C 2=90C 3=100C 4=110C 5=120C 6=130C 7=140C
+
+DEFAULT_PGM_POWER_RATING EQU 2 ; 1=1S,2=2S+
+
+DEFAULT_PGM_BRAKE_ON_STOP EQU 0 ; 1=Enabled 0=Disabled
+DEFAULT_PGM_LED_CONTROL EQU 0 ; Byte for LED control. 2 bits per LED,0=Off,1=On
+
+DEFAULT_PGM_STARTUP_POWER_MIN EQU 51 ; 0..255 => (1000..1125 Throttle): value * (1000 / 2047) + 1000
+DEFAULT_PGM_STARTUP_BEEP EQU 1 ; 0=Short beep,1=Melody
+DEFAULT_PGM_DITHERING EQU 0 ; 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_SAFETY_ARM EQU 0 ; EDT safety arm is disabled by default
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Temporary register definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Temp1 EQU R0
+Temp2 EQU R1
+Temp3 EQU R2
+Temp4 EQU R3
+Temp5 EQU R4
+Temp6 EQU R5
+Temp7 EQU R6
+Temp8 EQU R7
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; RAM definitions
+; Bit-addressable data segment
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DSEG AT 20h
+Bit_Access: DS 1 ; MUST BE AT THIS ADDRESS. Variable at bit accessible address (for non interrupt routines)
+Bit_Access_Int: DS 1 ; Variable at bit accessible address (for interrupts)
+
+Flags0: DS 1 ; State flags. Reset upon motor_start
+ Flag_Startup_Phase BIT Flags0.0 ; Set when in startup phase
+ Flag_Initial_Run_Phase BIT Flags0.1 ; Set when in initial run phase (or startup phase),before synchronized run is achieved.
+ Flag_Motor_Dir_Rev BIT Flags0.2 ; Set if the current spinning direction is reversed
+ Flag_Demag_Notify BIT Flags0.3 ; Set when motor demag has been detected but still not notified
+ Flag_Desync_Notify BIT Flags0.4 ; Set when motor desync has been detected but still not notified
+ Flag_Stall_Notify BIT Flags0.5 ; Set when motor stall detected but still not notified
+
+Flags1: DS 1 ; State flags. Reset upon motor_start
+ Flag_Timer3_Pending BIT Flags1.0 ; Timer3 pending flag
+ Flag_Demag_Detected BIT Flags1.1 ; Set when excessive demag time is detected
+ Flag_Comp_Timed_Out BIT Flags1.2 ; Set when comparator reading timed out
+ Flag_Motor_Running BIT Flags1.3
+ Flag_Motor_Started BIT Flags1.4 ; Set when motor is started
+ Flag_Dir_Change_Brake BIT Flags1.5 ; Set when braking before direction change in case of bidirectional operation
+ Flag_High_Rpm BIT Flags1.6 ; Set when motor rpm is high (Comm_Period4x_H less than 2)
+
+Flags2: DS 1 ; State flags. NOT reset upon motor_start
+ ; BIT Flags2.0
+ Flag_Pgm_Dir_Rev BIT Flags2.1 ; Set if the programmed direction is reversed
+ Flag_Pgm_Bidir BIT Flags2.2 ; Set if the programmed control mode is bidirectional operation
+ Flag_16ms_Elapsed BIT Flags2.3 ; Set when timer2 interrupt is triggered
+ Flag_Ext_Tele BIT Flags2.4 ; Set if Extended DHOT telemetry is enabled
+ Flag_Rcp_Stop BIT Flags2.5 ; Set if the RC pulse value is zero or if timeout occurs
+ Flag_Rcp_Dir_Rev BIT Flags2.6 ; RC pulse direction in bidirectional mode
+ Flag_Rcp_DShot_Inverted BIT Flags2.7 ; DShot RC pulse input is inverted (and supports telemetry)
+
+Flags3: DS 1 ; State flags. NOT reset upon motor_start
+ Flag_Telemetry_Pending BIT Flags3.0 ; DShot telemetry data packet is ready to be sent
+ Flag_Dithering BIT Flags3.1 ; PWM dithering enabled
+ Flag_Had_Signal BIT Flags3.2 ; Used to detect reset after having had a valid signal
+ Flag_User_Reverse_Requested BIT Flags3.3 ; It is set when user request to reverse motors in turtle mode
+
+
+Tlm_Data_L: DS 1 ; DShot telemetry data (lo byte)
+Tlm_Data_H: DS 1 ; DShot telemetry data (hi byte)
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Direct addressing data segment
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DSEG AT 30h
+Rcp_Outside_Range_Cnt: DS 1 ; RC pulse outside range counter (incrementing)
+Rcp_Timeout_Cntd: DS 1 ; RC pulse timeout counter (decrementing)
+Rcp_Stop_Cnt: DS 1 ; Counter for RC pulses below stop value
+
+Beacon_Delay_Cnt: DS 1 ; Counter to trigger beacon during wait for start
+Startup_Cnt: DS 1 ; Startup phase commutations counter (incrementing)
+Startup_Zc_Timeout_Cntd: DS 1 ; Startup zero cross timeout counter (decrementing)
+Initial_Run_Rot_Cntd: DS 1 ; Initial run rotations counter (decrementing)
+Startup_Stall_Cnt: DS 1 ; Counts start/run attempts that resulted in stall. Reset upon a proper stop
+Demag_Detected_Metric: DS 1 ; Metric used to gauge demag event frequency
+Demag_Detected_Metric_Max: DS 1 ; Metric used to gauge demag event frequency
+Demag_Pwr_Off_Thresh: DS 1 ; Metric threshold above which power is cut
+Low_Rpm_Pwr_Slope: DS 1 ; Sets the slope of power increase for low rpm
+Timer2_X: DS 1 ; Timer2 extended byte
+Prev_Comm_L: DS 1 ; Previous commutation Timer2 timestamp (lo byte)
+Prev_Comm_H: DS 1 ; Previous commutation Timer2 timestamp (hi byte)
+Prev_Comm_X: DS 1 ; Previous commutation Timer2 timestamp (ext byte)
+Prev_Prev_Comm_L: DS 1 ; Pre-previous commutation Timer2 timestamp (lo byte)
+Prev_Prev_Comm_H: DS 1 ; Pre-previous commutation Timer2 timestamp (hi byte)
+Comm_Period4x_L: DS 1 ; Timer2 ticks between the last 4 commutations (lo byte)
+Comm_Period4x_H: DS 1 ; Timer2 ticks between the last 4 commutations (hi byte)
+Comparator_Read_Cnt: DS 1 ; Number of comparator reads done
+Wt_Adv_Start_L: DS 1 ; Timer3 start point for commutation advance timing (lo byte)
+Wt_Adv_Start_H: DS 1 ; Timer3 start point for commutation advance timing (hi byte)
+Wt_Zc_Scan_Start_L: DS 1 ; Timer3 start point from commutation to zero cross scan (lo byte)
+Wt_Zc_Scan_Start_H: DS 1 ; Timer3 start point from commutation to zero cross scan (hi byte)
+Wt_Zc_Tout_Start_L: DS 1 ; Timer3 start point for zero cross scan timeout (lo byte)
+Wt_Zc_Tout_Start_H: DS 1 ; Timer3 start point for zero cross scan timeout (hi byte)
+Wt_Comm_Start_L: DS 1 ; Timer3 start point from zero cross to commutation (lo byte)
+Wt_Comm_Start_H: DS 1 ; Timer3 start point from zero cross to commutation (hi byte)
+Pwm_Limit: DS 1 ; Maximum allowed pwm (8-bit)
+Pwm_Limit_By_Rpm: DS 1 ; Maximum allowed pwm for low or high rpm (8-bit)
+Pwm_Limit_Beg: DS 1 ; Initial pwm limit (8-bit)
+Pwm_Braking_L: DS 1 ; Max Braking pwm (lo byte)
+Pwm_Braking_H: DS 1 ; Max Braking pwm (hi byte)
+Temp_Prot_Limit: DS 1 ; Temperature protection limit
+Temp_Pwm_Level_Setpoint: DS 1 ; PWM level setpoint
+Beep_Strength: DS 1 ; Strength of beeps
+Flash_Key_1: DS 1 ; Flash key one
+Flash_Key_2: DS 1 ; Flash key two
+DShot_Pwm_Thr: DS 1 ; DShot pulse width threshold value (Timer0 ticks)
+DShot_Timer_Preset: DS 1 ; DShot timer preset for frame sync detection (Timer1 lo byte)
+DShot_Frame_Start_L: DS 1 ; DShot frame start timestamp (Timer2 lo byte)
+DShot_Frame_Start_H: DS 1 ; DShot frame start timestamp (Timer2 hi byte)
+DShot_Frame_Length_Thr: DS 1 ; DShot frame length criteria (Timer2 ticks)
+DShot_Cmd: DS 1 ; DShot command
+DShot_Cmd_Cnt: DS 1 ; DShot command count
+; Pulse durations for GCR encoding DShot telemetry data
+DShot_GCR_Pulse_Time_1: DS 1 ; Encodes binary: 1
+DShot_GCR_Pulse_Time_2: DS 1 ; Encodes binary: 01
+DShot_GCR_Pulse_Time_3: DS 1 ; Encodes binary: 001
+
+DShot_GCR_Pulse_Time_1_Tmp: DS 1
+DShot_GCR_Pulse_Time_2_Tmp: DS 1
+DShot_GCR_Pulse_Time_3_Tmp: DS 1
+DShot_GCR_Start_Delay: DS 1
+Ext_Telemetry_L: DS 1 ; Extended telemetry data to be sent
+Ext_Telemetry_H: DS 1
+Scheduler_Counter: DS 1 ; Scheduler Heartbeat
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Indirect addressing data segments
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+ISEG AT 080h ; The variables below must be in this sequence
+_Pgm_Gov_P_Gain: DS 1 ;
+Pgm_Startup_Power_Min: DS 1 ; Minimum power during startup phase
+Pgm_Startup_Beep: DS 1 ; Startup beep melody on/off
+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_Direction: DS 1 ; Rotation direction
+_Pgm_Input_Pol: DS 1 ; Input PWM polarity
+Initialized_L_Dummy: DS 1 ; Place holder
+Initialized_H_Dummy: DS 1 ; Place holder
+_Pgm_Enable_TX_Program: DS 1 ; Enable/disable value for TX programming
+Pgm_Braking_Strength: DS 1 ; Set maximum braking strength (complementary pwm)
+_Pgm_Gov_Setup_Target: DS 1 ; Main governor setup target
+_Pgm_Startup_Rpm: DS 1 ; Startup RPM
+_Pgm_Startup_Accel: DS 1 ; Startup acceleration
+_Pgm_Volt_Comp: DS 1 ; Voltage comp
+Pgm_Comm_Timing: DS 1 ; Commutation timing
+_Pgm_Damping_Force: DS 1 ; Damping force
+_Pgm_Gov_Range: DS 1 ; Governor range
+_Pgm_Startup_Method: DS 1 ; Startup method
+_Pgm_Min_Throttle: DS 1 ; Minimum throttle
+_Pgm_Max_Throttle: DS 1 ; Maximum throttle
+Pgm_Beep_Strength: DS 1 ; Beep strength
+Pgm_Beacon_Strength: DS 1 ; Beacon strength
+Pgm_Beacon_Delay: DS 1 ; Beacon delay
+_Pgm_Throttle_Rate: DS 1 ; Throttle rate
+Pgm_Demag_Comp: DS 1 ; Demag compensation
+_Pgm_BEC_Voltage_High: DS 1 ; BEC voltage
+_Pgm_Center_Throttle: DS 1 ; Center throttle (in bidirectional mode)
+_Pgm_Main_Spoolup_Time: DS 1 ; Main spoolup time
+Pgm_Enable_Temp_Prot: DS 1 ; Temperature protection enable
+_Pgm_Enable_Power_Prot: DS 1 ; Low RPM power protection enable
+_Pgm_Enable_Pwm_Input: DS 1 ; Enable PWM input signal
+_Pgm_Pwm_Dither: DS 1 ; Output PWM dither
+Pgm_Brake_On_Stop: DS 1 ; Braking when throttle is zero
+Pgm_LED_Control: DS 1 ; LED control
+Pgm_Power_Rating: DS 1 ; Power rating
+Pgm_Safety_Arm: DS 1 ; Various flag settings: bit 0 is require edt enable to arm
+
+ISEG AT 0B0h
+Stack: DS 16 ; Reserved stack space
+
+ISEG AT 0C0h
+Dithering_Patterns: DS 16 ; Bit patterns for pwm dithering
+
+ISEG AT 0D0h
+Temp_Storage: DS 48 ; Temporary storage (internal memory)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EEPROM code segments
+; A segment of the flash is used as "EEPROM", which is not available in SiLabs MCUs
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+CSEG AT CSEG_EEPROM
+EEPROM_FW_MAIN_REVISION EQU 0 ; Main revision of the firmware
+EEPROM_FW_SUB_REVISION EQU 20 ; Sub revision of the firmware
+EEPROM_LAYOUT_REVISION EQU 207 ; Revision of the EEPROM layout
+EEPROM_B2_PARAMETERS_COUNT EQU 28 ; Number of parameters
+
+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
+Eep_Layout_Revision: DB EEPROM_LAYOUT_REVISION ; EEPROM layout revision number
+_Eep_Pgm_Gov_P_Gain: DB 0FFh
+Eep_Pgm_Startup_Power_Min: DB DEFAULT_PGM_STARTUP_POWER_MIN
+Eep_Pgm_Startup_Beep: DB DEFAULT_PGM_STARTUP_BEEP
+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_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)
+Eep_Initialized_H: DB 0AAh ; EEPROM initialized signature (hi byte)
+; EEPROM parameters block 2 (B2)
+_Eep_Enable_TX_Program: DB 0FFh ; EEPROM TX programming enable
+Eep_Pgm_Braking_Strength: DB DEFAULT_PGM_BRAKING_STRENGTH
+_Eep_Pgm_Gov_Setup_Target: DB 0FFh
+_Eep_Pgm_Startup_Rpm: DB 0FFh
+_Eep_Pgm_Startup_Accel: DB 0FFh
+_Eep_Pgm_Volt_Comp: DB 0FFh
+Eep_Pgm_Comm_Timing: DB DEFAULT_PGM_COMM_TIMING ; EEPROM copy of programmed commutation timing
+_Eep_Pgm_Damping_Force: DB 0FFh
+_Eep_Pgm_Gov_Range: DB 0FFh
+_Eep_Pgm_Startup_Method: DB 0FFh
+_Eep_Pgm_Min_Throttle: DB 0FFh ; EEPROM copy of programmed minimum throttle
+_Eep_Pgm_Max_Throttle: DB 0FFh ; EEPROM copy of programmed minimum throttle
+Eep_Pgm_Beep_Strength: DB DEFAULT_PGM_BEEP_STRENGTH ; EEPROM copy of programmed beep strength
+Eep_Pgm_Beacon_Strength: DB DEFAULT_PGM_BEACON_STRENGTH ; EEPROM copy of programmed beacon strength
+Eep_Pgm_Beacon_Delay: DB DEFAULT_PGM_BEACON_DELAY ; EEPROM copy of programmed beacon delay
+_Eep_Pgm_Throttle_Rate: DB 0FFh
+Eep_Pgm_Demag_Comp: DB DEFAULT_PGM_DEMAG_COMP ; EEPROM copy of programmed demag compensation
+_Eep_Pgm_BEC_Voltage_High: DB 0FFh
+_Eep_Pgm_Center_Throttle: DB 0FFh ; EEPROM copy of programmed center throttle
+_Eep_Pgm_Main_Spoolup_Time: DB 0FFh
+Eep_Pgm_Temp_Prot_Enable: DB DEFAULT_PGM_ENABLE_TEMP_PROT ; EEPROM copy of programmed temperature protection enable
+_Eep_Pgm_Enable_Power_Prot: DB 0FFh ; EEPROM copy of programmed low rpm power protection enable
+_Eep_Pgm_Enable_Pwm_Input: DB 0FFh
+_Eep_Pgm_Pwm_Dither: DB 0FFh
+Eep_Pgm_Brake_On_Stop: DB DEFAULT_PGM_BRAKE_ON_STOP ; EEPROM copy of programmed braking when throttle is zero
+Eep_Pgm_LED_Control: DB DEFAULT_PGM_LED_CONTROL ; EEPROM copy of programmed LED control
+Eep_Pgm_Power_Rating: DB DEFAULT_PGM_POWER_RATING ; EEPROM copy of programmed power rating
+Eep_Pgm_Safety_Arm: DB DEFAULT_PGM_SAFETY_ARM ; Various flag settings: bit 0 is require edt enable to arm
+
+Eep_Dummy: DB 0FFh ; EEPROM address for safety reason
+CSEG AT CSEG_NAME
+Eep_Name: DB "Bluejay " ; Name tag (16 Bytes)
+
+CSEG AT CSEG_MELODY
+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
+
+ Interrupt_Table_Definition ; SiLabs interrupts
+CSEG AT CSEG_APP ; Code segment after interrupt vectors
+
+; Submodule includes
+$include (Modules\Isrs.asm)
+$include (Modules\Fx.asm)
+$include (Modules\Power.asm)
+$include (Modules\Scheduler.asm)
+$include (Modules\Timing.asm)
+$include (Modules\Commutation.asm)
+$include (Modules\DShot.asm)
+$include (Modules\Eeprom.asm)
+$include (Modules\Settings.asm)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Main program
+;
+; Main program entry point
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+pgm_start:
+ Lock_Flash
+ mov WDTCN, #0DEh ; Disable watchdog (WDT)
+ mov WDTCN, #0ADh
+ mov SP, #Stack ; Initialize stack (16 bytes of indirect RAM)
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ orl VDM0CN, #080h ; Enable the VDD monitor
+ENDIF
+ mov RSTSRC, #06h ; Set missing clock and VDD monitor as a reset source if not 1S capable
+ mov CLKSEL, #00h ; Set clock divider to 1 (Oscillator 0 at 24MHz)
+ call switch_power_off
+ ; Ports initialization
+ mov P0, #P0_INIT
+ mov P0MDIN, #P0_DIGITAL
+ mov P0MDOUT, #P0_PUSHPULL
+ mov P0, #P0_INIT
+ mov P0SKIP, #P0_SKIP
+ mov P1, #P1_INIT
+ mov P1MDIN, #P1_DIGITAL
+ mov P1MDOUT, #P1_PUSHPULL
+ mov P1, #P1_INIT
+ mov P1SKIP, #P1_SKIP
+ mov P2MDOUT, #P2_PUSHPULL
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ ; Not available on BB1
+ mov SFRPAGE, #20h
+ mov P2MDIN, #P2_DIGITAL
+IF MCU_TYPE == MCU_BB2
+ ; Not available on BB51
+ mov P2SKIP, #P2_SKIP
+ENDIF
+ mov SFRPAGE, #00h
+ENDIF
+ Initialize_Crossbar ; Initialize the crossbar and related functionality
+ call switch_power_off ; Switch power off again,after initializing ports
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Internal RAM
+;
+; EFM8 consists of 256 bytes of internal RAM of which the lower 128 bytes can be
+; directly adressed and the upper portion (starting at 0x80) can only be
+; indirectly accessed.
+;
+; NOTE: Upper portion of RAM and SFR use the same address space. RAM is accessed
+; indirectly. If you are directly accessing the upper space, you are - in
+; fact - addressing the SFR.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Clear internal RAM
+;
+; First the accumlator is cleared, then address is overflowed to 255 and content
+; of addresses 255 - 0 is set to 0.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+ clr A ; Clear accumulator
+ mov Temp1, A ; Clear Temp1
+clear_ram:
+ mov @Temp1, A ; Clear RAM address
+ djnz Temp1, clear_ram ; Decrement address and repeat
+
+ call set_default_parameters ; Set default programmed parameters
+ call read_all_eeprom_parameters ; Read all programmed parameters
+ call decode_settings ; Decode programmed settings
+
+ ; Initializing beeps
+ clr IE_EA ; Disable interrupts explicitly
+ call wait100ms ; Wait a bit to avoid audible resets if not properly powered
+ call play_beep_melody ; Play startup beep melody
+ call led_control ; Set LEDs to programmed values
+
+ call wait100ms ; Wait for flight controller to get ready
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; No signal entry point
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+init_no_signal:
+ clr IE_EA ; Disable interrupts explicitly
+ Lock_Flash
+ call switch_power_off
+
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ ; While not armed, all MCUs run at 24MHz clock frequency. After arming those
+ ; MCUs that support it (BB2 & BB51) are switched to 48MHz clock frequency.
+ Set_MCU_Clk_24MHz
+ENDIF
+
+ ; If input signal is high for about ~150ms, enter bootloader mode
+ mov Temp1, #9
+ mov Temp2, #0
+ mov Temp3, #0
+input_high_check:
+ jnb RTX_BIT, bootloader_done ; If low is detected, skip bootloader check
+ djnz Temp3, input_high_check
+ djnz Temp2, input_high_check
+ djnz Temp1, input_high_check
+
+ call beep_enter_bootloader
+
+ ljmp CSEG_BOOT_START ; Jump to bootloader
+
+bootloader_done:
+ ; If we had a signal before, reset the flag, beep, wait a bit and contiune
+ ; with DSHOT setup. If we did not have a signal yet, continue with DSHOT
+ ; setup straight away.
+ jnb Flag_Had_Signal, setup_dshot
+ call beep_signal_lost
+
+ ; Wait for flight controller to get ready
+ call wait250ms
+ call wait250ms
+ call wait250ms
+ clr Flag_Had_Signal
+
+setup_dshot:
+ ; Setup timers for DShot
+ mov TCON, #51h ; Timer0/1 run and Int0 edge triggered
+ mov CKCON0, #01h ; Timer0/1 clock is system clock divided by 4 (for DShot150)
+ mov TMOD, #0AAh ; Timer0/1 set to 8-bits auto reload and gated by Int0/1
+ mov TH0, #0 ; Auto reload value zero
+ mov TH1, #0
+
+ mov TMR2CN0, #04h ; Timer2 enabled (system clock divided by 12)
+ mov TMR3CN0, #04h ; Timer3 enabled (system clock divided by 12)
+
+ Initialize_PCA ; Initialize PCA
+ Set_Pwm_Polarity ; Set pwm polarity
+ Enable_Power_Pwm_Module ; Enable power pwm module
+ Enable_Damp_Pwm_Module ; Enable damping pwm module
+ Initialize_Comparator ; Initialize comparator
+ Initialize_Adc ; Initialize ADC operation
+ call wait1ms
+
+ call detect_rcp_level ; Detect RCP level (normal or inverted DShot)
+
+ ; Route RCP according to detected DShot signal (normal or inverted)
+ mov IT01CF, #(80h + (RTX_PIN SHL 4) + RTX_PIN) ; Route RCP input to Int0/1,with Int1 inverted
+ jnb Flag_Rcp_DShot_Inverted, setup_dshot_clear_flags
+ mov IT01CF, #(08h + (RTX_PIN SHL 4) + RTX_PIN) ; Route RCP input to Int0/1,with Int0 inverted
+
+setup_dshot_clear_flags:
+ clr Flag_Demag_Notify ; Clear motor events
+ clr Flag_Desync_Notify
+ clr Flag_Stall_Notify
+ clr Flag_Telemetry_Pending ; Clear DShot telemetry flag
+ clr Flag_Ext_Tele ; Clear extended telemetry enabled flag
+
+ ; Setup interrupts
+ mov IE, #2Dh ; Enable Timer1/2 interrupts and Int0/1 interrupts
+ mov EIE1, #80h ; Enable Timer3 interrupts
+ mov IP, #03h ; High priority to Timer0 and Int0 interrupts
+
+ setb IE_EA ; Enable all interrupts
+
+; Setup variables for DShot150 (Only on 24MHz because frame length threshold cannot be scaled up)
+IF MCU_TYPE == MCU_BB1
+ mov DShot_Timer_Preset, #-64 ; Load DShot sync timer preset (for DShot150)
+ mov DShot_Pwm_Thr, #8 ; Load DShot qualification pwm threshold (for DShot150)
+ mov DShot_Frame_Length_Thr, #160 ; Load DShot frame length criteria
+
+ Set_DShot_Tlm_Bitrate 187500 ; = 5/4 * 150000
+
+ ; Test whether signal is DShot150
+ mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
+ call wait100ms ; Wait for new RC pulse
+ mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
+ jz arming_begin
+ENDIF
+
+ mov CKCON0, #0Ch ; Timer0/1 clock is system clock (for DShot300/600)
+
+ ; Setup variables for DShot300
+ mov DShot_Timer_Preset, #-128 ; Load DShot sync timer preset (for DShot300)
+ mov DShot_Pwm_Thr, #16 ; Load DShot pwm threshold (for DShot300)
+ mov DShot_Frame_Length_Thr, #80 ; Load DShot frame length criteria
+
+ Set_DShot_Tlm_Bitrate 375000 ; = 5/4 * 300000
+
+ ; Test whether signal is DShot300, if so begin arming
+ mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
+ call wait100ms ; Wait for new RC pulse
+ mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
+ jz arming_begin
+
+; Setup variables for DShot600 (Only on 48MHz for performance reasons)
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ mov DShot_Timer_Preset, #-64 ; Load DShot sync timer preset (for DShot600)
+ mov DShot_Pwm_Thr, #8 ; Load DShot pwm threshold (for DShot600)
+ mov DShot_Frame_Length_Thr, #40 ; Load DShot frame length criteria
+
+ Set_DShot_Tlm_Bitrate 750000 ; = 5/4 * 600000
+
+ ; Test whether signal is DShot600, if so begin arming
+ mov Rcp_Outside_Range_Cnt, #10 ; Set out of range counter
+ call wait100ms ; Wait for new RC pulse
+ mov A, Rcp_Outside_Range_Cnt ; Check if pulses were accepted
+ jz arming_begin
+ENDIF
+
+ ; No valid signal detected, try again
+ ljmp init_no_signal
+
+arming_begin:
+ push PSW
+ mov PSW, #10h ; Temp8 in register bank 2 holds value
+ mov Temp8, CKCON0 ; Save DShot clock settings for telemetry
+ pop PSW
+
+ setb Flag_Had_Signal ; Mark that a signal has been detected
+ mov Startup_Stall_Cnt, #0 ; Reset stall count
+
+ clr IE_EA
+ call beep_f1_short ; Confirm RC pulse detection by beeping
+ setb IE_EA
+
+; Make sure RC pulse has been zero for ~300ms
+arming_wait:
+ clr C
+ mov A, Rcp_Stop_Cnt
+ subb A, #10
+ jc arming_wait
+
+ clr IE_EA
+ call beep_f2_short ; Confirm arm state by beeping
+ setb IE_EA
+
+; Armed and waiting for power on (RC pulse > 0)
+wait_for_start:
+ clr A
+ mov Comm_Period4x_L, A ; Reset commutation period for telemetry
+ mov Comm_Period4x_H, A
+ mov DShot_Cmd, A ; Reset DShot command (only considered in this loop)
+ mov DShot_Cmd_Cnt, A
+ mov Beacon_Delay_Cnt, A ; Clear beacon wait counter
+ mov Timer2_X, A ; Clear Timer2 extended byte
+
+wait_for_start_loop:
+ clr C
+ mov A, Timer2_X
+ subb A, #94
+ jc wait_for_start_no_beep ; Counter wrapping (about 3 sec)
+
+ mov Timer2_X, #0
+ inc Beacon_Delay_Cnt ; Increment beacon wait counter
+
+ mov Temp1, #Pgm_Beacon_Delay
+ mov A, @Temp1
+ mov Temp1, #20 ; 1 min
+ dec A
+ jz beep_delay_set
+
+ mov Temp1, #40 ; 2 min
+ dec A
+ jz beep_delay_set
+
+ mov Temp1, #100 ; 5 min
+ dec A
+ jz beep_delay_set
+
+ mov Temp1, #200 ; 10 min
+ dec A
+ jz beep_delay_set
+
+ mov Beacon_Delay_Cnt, #0 ; Reset beacon counter for infinite delay
+
+beep_delay_set:
+ clr C
+ mov A, Beacon_Delay_Cnt
+ subb A, Temp1 ; Check against chosen delay
+ jc wait_for_start_no_beep ; Has delay elapsed?
+
+ dec Beacon_Delay_Cnt ; Decrement counter for continued beeping
+
+ mov Temp1, #4 ; Beep tone 4
+ clr IE_EA ; Disable all interrupts
+ call switch_power_off ; Switch power off in case braking is set
+ call beacon_beep
+ setb IE_EA ; Enable all interrupts
+
+wait_for_start_no_beep:
+ jb Flag_Telemetry_Pending, wait_for_start_check_rcp
+ call dshot_tlm_create_packet ; Create telemetry packet (0 rpm)
+ call scheduler_run
+
+wait_for_start_check_rcp:
+ ; If RC pulse is higher than stop (>0) then proceed to start the motor
+ jnb Flag_Rcp_Stop, wait_for_start_nonzero
+
+ mov A, Rcp_Timeout_Cntd ; Load RC pulse timeout counter value
+ ljz init_no_signal ; If pulses are missing - go back to detect input signal
+
+ call dshot_cmd_check ; Check and process DShot command
+
+ sjmp wait_for_start_loop ; Go back to beginning of wait loop
+
+wait_for_start_nonzero:
+ call wait100ms ; Wait to see if start pulse was glitch
+
+ ; If RC pulse returned to stop (0) - start over
+ jb Flag_Rcp_Stop, wait_for_start_loop
+
+ ; If no safety arm jump to motor start
+ mov Temp1, #Pgm_Safety_Arm
+ cjne @Temp1, #001h, motor_start
+
+ ; If EDT flag is set start motor
+ jb Flag_Ext_Tele, motor_start
+
+ ; Safety is enabled. Check Flag_Ext_Tele is set
+ ; If not set beep and wait again
+ call beep_safety_no_arm
+ jmp wait_for_start_loop
+
+
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Motor start entry point
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+motor_start:
+ clr IE_EA ; Disable interrupts
+ call switch_power_off
+ setb IE_EA ; Enable interrupts
+
+ clr A
+ mov Flags0, A ; Clear run time flags
+ mov Flags1, A
+ mov Demag_Detected_Metric, A ; Clear demag metric
+ mov Demag_Detected_Metric_Max, A ; Clear demag metric max
+
+ call wait1ms
+
+ mov Ext_Telemetry_H, #0 ; Clear extended telemetry data
+
+ ; Set up start operating conditions
+ clr IE_EA ; Disable interrupts
+ mov Temp2, #Pgm_Startup_Power_Max
+ mov Pwm_Limit_Beg, @Temp2 ; Set initial pwm limit
+ mov Pwm_Limit_By_Rpm, Pwm_Limit_Beg
+
+ ; Set temperature PWM limit and setpoint to the maximum value
+ mov Pwm_Limit, #255
+ mov Temp_Pwm_Level_Setpoint, #255
+
+; Begin startup sequence
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ Set_MCU_Clk_48MHz ; Enable 48MHz clock frequency
+
+ ; Scale DShot criteria for 48MHz
+ clr C
+ rlca DShot_Timer_Preset ; Scale sync timer preset
+
+ clr C
+ rlca DShot_Frame_Length_Thr ; Scale frame length criteria
+
+ clr C
+ rlca DShot_Pwm_Thr ; Scale pulse width criteria
+
+ ; Scale DShot telemetry for 48MHz
+ xcha DShot_GCR_Pulse_Time_1, DShot_GCR_Pulse_Time_1_Tmp
+ xcha DShot_GCR_Pulse_Time_2, DShot_GCR_Pulse_Time_2_Tmp
+ xcha DShot_GCR_Pulse_Time_3, DShot_GCR_Pulse_Time_3_Tmp
+
+ mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY_48
+ENDIF
+ setb IE_EA ; Enable interrupts
+
+ mov C, Flag_Pgm_Dir_Rev ; Read spin direction setting
+ mov Flag_Motor_Dir_Rev, C
+
+ jnb Flag_Pgm_Bidir, motor_start_bidir_done ; Check if bidirectional operation
+
+ mov C, Flag_Rcp_Dir_Rev ; Read force direction
+ mov Flag_Motor_Dir_Rev, C ; Set spinning direction
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Motor start beginning
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+motor_start_bidir_done:
+ setb Flag_Startup_Phase ; Set startup phase flags
+ setb Flag_Initial_Run_Phase
+ mov Startup_Cnt, #0 ; Reset startup phase run counter
+ mov Initial_Run_Rot_Cntd, #12 ; Set initial run rotation countdown
+ call comm5_comm6 ; Initialize commutation
+ call comm6_comm1
+ call initialize_timing ; Initialize timing
+ call calc_next_comm_period ; Set virtual commutation point
+ call initialize_timing ; Initialize timing
+ call calc_next_comm_period
+ call initialize_timing ; Initialize timing
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Run entry point
+;
+; Run 1 = B(p-on) + C(n-pwm) - comparator A evaluated
+; Out_cA changes from low to high
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+run1:
+ call wait_for_comp_out_high ; Wait for high
+ ; setup_comm_wait ; Setup wait time from zero cross to commutation
+ ; evaluate_comparator_integrity ; Check whether comparator reading has been normal
+ call wait_for_comm ; Wait from zero cross to commutation
+ call comm1_comm2 ; Commutate
+ call calc_next_comm_period ; Calculate next timing and wait advance timing wait
+ ; wait_advance_timing ; Wait advance timing and start zero cross wait
+ ; calc_new_wait_times
+ ; wait_before_zc_scan ; Wait zero cross wait and start zero cross timeout
+
+; Run 2 = A(p-on) + C(n-pwm) - comparator B evaluated
+; Out_cB changes from high to low
+run2:
+ call wait_for_comp_out_low
+ ; setup_comm_wait
+ ; evaluate_comparator_integrity
+ call set_pwm_limit ; Set pwm power limit for low or high rpm
+ call wait_for_comm
+ call comm2_comm3
+ call calc_next_comm_period
+ ; wait_advance_timing
+ ; calc_new_wait_times
+ ; wait_before_zc_scan
+
+; Run 3 = A(p-on) + B(n-pwm) - comparator C evaluated
+; Out_cC changes from low to high
+run3:
+ call wait_for_comp_out_high
+ ; setup_comm_wait
+ ; evaluate_comparator_integrity
+ call wait_for_comm
+ call comm3_comm4
+ call calc_next_comm_period
+ ; wait_advance_timing
+ ; calc_new_wait_times
+ ; wait_before_zc_scan
+
+; Run 4 = C(p-on) + B(n-pwm) - comparator A evaluated
+; Out_cA changes from high to low
+run4:
+ call wait_for_comp_out_low
+ ; setup_comm_wait
+ ; evaluate_comparator_integrity
+ call wait_for_comm
+ call comm4_comm5
+ call calc_next_comm_period
+ ; wait_advance_timing
+ ; calc_new_wait_times
+ ; wait_before_zc_scan
+
+; Run 5 = C(p-on) + A(n-pwm) - comparator B evaluated
+; Out_cB changes from low to high
+run5:
+ call wait_for_comp_out_high
+ ; setup_comm_wait
+ ; evaluate_comparator_integrity
+ call wait_for_comm
+ call comm5_comm6
+ call calc_next_comm_period
+ ; wait_advance_timing
+ ; calc_new_wait_times
+ ; wait_before_zc_scan
+
+; Run 6 = B(p-on) + A(n-pwm) - comparator C evaluated
+; Out_cC changes from high to low
+run6:
+ call wait_for_comp_out_low
+ ; setup_comm_wait
+ ; evaluate_comparator_integrity
+ call wait_for_comm
+ call comm6_comm1
+ call calc_next_comm_period
+ call scheduler_run
+ ; wait_advance_timing
+ ; calc_new_wait_times
+ ; wait_before_zc_scan
+
+ ; Check if it is startup phases
+ jnb Flag_Initial_Run_Phase, normal_run_checks
+ jnb Flag_Startup_Phase, initial_run_phase
+
+ ; Startup phase
+ mov Pwm_Limit_By_Rpm, Pwm_Limit_Beg; Set initial max power
+ clr C
+ mov A, Startup_Cnt ; Load startup counter
+ subb A, #24 ; Is counter above requirement?
+ jnc startup_phase_done
+
+ jnb Flag_Rcp_Stop, run1 ; If pulse is above stop value - Continue to run
+ sjmp exit_run_mode
+
+startup_phase_done:
+ ; Clear startup phase flag & remove pwm limits
+ clr Flag_Startup_Phase
+ mov Pwm_Limit_By_Rpm, #255
+
+initial_run_phase:
+ ; If it is a direction change - branch
+ jb Flag_Dir_Change_Brake, normal_run_checks
+
+ ; Decrement startup rotation count
+ mov A, Initial_Run_Rot_Cntd
+ dec A
+ ; Check number of initial rotations
+ jz initial_run_phase_done ; Branch if counter is zero
+
+ mov Initial_Run_Rot_Cntd, A ; Not zero - store counter
+
+ jnb Flag_Rcp_Stop, run1 ; Check if pulse is below stop value
+ jb Flag_Pgm_Bidir, run1 ; Check if bidirectional operation
+
+ sjmp exit_run_mode
+
+initial_run_phase_done:
+ clr Flag_Initial_Run_Phase ; Clear initial run phase flag
+ setb Flag_Motor_Started ; Set motor started
+ jmp run1 ; Continue with normal run
+
+normal_run_checks:
+ ; Reset stall count
+ mov Startup_Stall_Cnt, #0
+ setb Flag_Motor_Running
+
+ jnb Flag_Rcp_Stop, run6_check_bidir ; Check if stop
+ jb Flag_Pgm_Bidir, run6_check_timeout ; Check if bidirectional operation
+
+ mov Temp2, #Pgm_Brake_On_Stop ; Check if using brake on stop
+ mov A, @Temp2
+ jz run6_check_timeout
+
+ ; Exit run mode after 100ms when using brake on stop
+ clr C
+ mov A, Rcp_Stop_Cnt ; Load stop RC pulse counter value
+ subb A, #3 ; Is number of stop RC pulses above limit?
+ jnc exit_run_mode ; Yes - exit run mode
+
+run6_check_timeout:
+ ; Exit run mode immediately if timeout
+ mov A, Rcp_Timeout_Cntd ; Load RC pulse timeout counter value
+ jz exit_run_mode ; If it is zero - go back to wait for power on
+
+run6_check_bidir:
+ jb Flag_Pgm_Bidir, run6_bidir ; Check if bidirectional operation
+
+run6_check_speed:
+ clr C
+ mov A, Comm_Period4x_H ; Is Comm_Period4x below minimum speed?
+ subb A, #0F0h ; Default minimum speed (~1330 erpm)
+ jnc exit_run_mode ; Yes - exit run mode
+ jmp run1 ; No - go back to run 1
+
+run6_bidir:
+ ; Check if direction change braking is in progress
+ jb Flag_Dir_Change_Brake, run6_bidir_braking
+
+ ; Check if actual rotation direction matches force direction
+ jb Flag_Motor_Dir_Rev, run6_bidir_check_reversal
+ jb Flag_Rcp_Dir_Rev, run6_bidir_reversal
+ sjmp run6_check_speed
+
+run6_bidir_check_reversal:
+ jb Flag_Rcp_Dir_Rev, run6_check_speed
+
+run6_bidir_reversal:
+ ; Initiate direction and start braking
+ setb Flag_Dir_Change_Brake ; Set brake flag
+ mov Pwm_Limit_By_Rpm, Pwm_Limit_Beg; Set max power while braking to initial power limit
+ jmp run4 ; Go back to run 4,thereby changing force direction
+
+run6_bidir_braking:
+ mov Pwm_Limit_By_Rpm, Pwm_Limit_Beg; Set max power while braking to initial power limit
+
+ clr C
+ mov A, Comm_Period4x_H ; Is Comm_Period4x below minimum speed?
+ subb A, #40h ; Bidirectional braking termination speed (~5000 erpm)
+ jc run6_bidir_continue ; No - continue braking
+
+ ; Braking done, set new spinning direction
+ clr Flag_Dir_Change_Brake ; Clear braking flag
+ mov C, Flag_Rcp_Dir_Rev ; Read force direction
+ mov Flag_Motor_Dir_Rev, C ; Set spinning direction
+ setb Flag_Initial_Run_Phase
+ mov Initial_Run_Rot_Cntd, #18
+
+run6_bidir_continue:
+ jmp run1 ; Go back to run 1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Exit run mode and power off
+;
+; Happens on normal stop (RC pulse == 0) or comparator timeout
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+exit_run_mode_on_timeout:
+ jb Flag_Motor_Running, exit_run_mode
+ inc Startup_Stall_Cnt ; Increment stall count if motors did not properly start
+
+exit_run_mode:
+ clr IE_EA ; Disable all interrupts
+ clr Flag_Ext_Tele ; Clear extended DSHOT telemetry flag
+ call switch_power_off
+ mov Flags0, #0 ; Clear run time flags (in case they are used in interrupts)
+ mov Flags1, #0
+
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ Set_MCU_Clk_24MHz
+
+ ; Scale DShot criteria for 24MHz
+ setb C
+ rrca DShot_Timer_Preset ; Scale sync timer preset
+
+ clr C
+ rrca DShot_Frame_Length_Thr ; Scale frame length criteria
+
+ clr C
+ rrca DShot_Pwm_Thr ; Scale pulse width criteria
+
+ ; Scale DShot telemetry for 24MHz
+ xcha DShot_GCR_Pulse_Time_1, DShot_GCR_Pulse_Time_1_Tmp
+ xcha DShot_GCR_Pulse_Time_2, DShot_GCR_Pulse_Time_2_Tmp
+ xcha DShot_GCR_Pulse_Time_3, DShot_GCR_Pulse_Time_3_Tmp
+
+ mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY
+ENDIF
+
+ setb IE_EA ; Enable all interrupts
+
+ ; Check if RCP is zero, then it is a normal stop or signal timeout
+ jb Flag_Rcp_Stop, exit_run_mode_no_stall
+
+ ; Signal stall
+ setb Flag_Stall_Notify
+
+ clr C ; Otherwise - it's a stall
+ mov A, Startup_Stall_Cnt
+ subb A, #4 ; Maximum consecutive stalls
+ jnc exit_run_mode_stall_done
+
+ call wait100ms ; Wait for a bit between stall restarts
+ ljmp motor_start ; Go back and try starting motors again
+
+exit_run_mode_stall_done:
+ ; Clear extended DSHOT telemetry flag if turtle mode is not active
+ ; This flag is also used for EDT safety arm flag
+ ; We don't want to deactivate extended telemetry during turtle mode
+ ; Extended telemetry flag is important because it is involved in
+ ; EDT safety feature. We don't want to disable EDT arming during
+ ; turtle mode.
+ jb Flag_User_Reverse_Requested, exit_run_mode_stall_done_beep
+ clr Flag_Ext_Tele
+
+exit_run_mode_stall_done_beep:
+ ; Stalled too many times
+ clr IE_EA
+ call beep_motor_stalled
+ setb IE_EA
+
+ ljmp arming_begin ; Go back and wait for arming
+
+exit_run_mode_no_stall:
+ ; Clear extended DSHOT telemetry flag if turtle mode is not active
+ ; This flag is also used for EDT safety arm flag
+ ; We don't want to deactivate extended telemetry during turtle mode
+ ; Extended telemetry flag is important because it is involved in
+ ; EDT safety feature. We don't want to disable EDT arming during
+ ; turtle mode.
+ jb Flag_User_Reverse_Requested, exit_run_mode_no_stall_beep
+ clr Flag_Ext_Tele
+
+exit_run_mode_no_stall_beep:
+ ; Clear stall counter
+ mov Startup_Stall_Cnt, #0
+
+ mov Temp1, #Pgm_Brake_On_Stop ; Check if using brake on stop
+ mov A, @Temp1
+ jz exit_run_mode_brake_done
+
+ A_Com_Fet_On ; Brake on stop
+ B_Com_Fet_On
+ C_Com_Fet_On
+
+exit_run_mode_brake_done:
+ ljmp wait_for_start ; Go back to wait for power on
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Reset
+;
+; Should execution ever reach this point the ESC will be reset,
+; as code flash after offset 1A00 is used for EEPROM storage
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+CSEG AT CSEG_RESET
+reset:
+ ljmp pgm_start
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bootloader
+;
+; Include source code for BLHeli bootloader
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;CSEG AT 1C00h
+$include (BLHeliBootLoad.inc)
+
+END
diff --git a/src/Layouts/A.inc b/src/Layouts/A.inc
new file mode 100644
index 00000000..3781bfb7
--- /dev/null
+++ b/src/Layouts/A.inc
@@ -0,0 +1,94 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "A".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/B.inc b/src/Layouts/B.inc
new file mode 100644
index 00000000..bef2f359
--- /dev/null
+++ b/src/Layouts/B.inc
@@ -0,0 +1,106 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "B".
+;
+; Equals "A", but with A and C fets swapped and pwm and com fets swapped.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX __ __ | Cc Cp Bc Bp Ac Ap __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+A_Pwm EQU 5
+A_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+C_Pwm EQU 1
+C_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/BB51/A.inc b/src/Layouts/BB51/A.inc
new file mode 100644
index 00000000..7ebd2094
--- /dev/null
+++ b/src/Layouts/BB51/A.inc
@@ -0,0 +1,93 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2022-2022 Chris Landa
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "A" for BB51.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ Bm Cm Am Vn RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no low _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+V_Mux EQU 4
+A_Mux EQU 3
+C_Mux EQU 2
+B_Mux EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (../Base.inc)
diff --git a/src/Layouts/BB51/B.inc b/src/Layouts/BB51/B.inc
new file mode 100644
index 00000000..505aa903
--- /dev/null
+++ b/src/Layouts/BB51/B.inc
@@ -0,0 +1,103 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2022-2022 Chris Landa
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "B" for BB51.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ Bm Cm Am Vn RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no yes high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 1 ; Comparator output inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+V_Mux EQU 4
+A_Mux EQU 3
+C_Mux EQU 2
+B_Mux EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+C_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+A_Pwm EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 0
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (../Base.inc)
diff --git a/src/Layouts/BB51/C.inc b/src/Layouts/BB51/C.inc
new file mode 100644
index 00000000..7439ff66
--- /dev/null
+++ b/src/Layouts/BB51/C.inc
@@ -0,0 +1,103 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2022-2022 Chris Landa
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "C" for BB51.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ Bm Cm Am Vn RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | yes yes high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 0 ; Pwm inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 1 ; Comparator output inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+V_Mux EQU 4
+A_Mux EQU 3
+C_Mux EQU 2
+B_Mux EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+C_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+A_Pwm EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm)
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (../Base.inc)
diff --git a/src/Layouts/Base.inc b/src/Layouts/Base.inc
new file mode 100644
index 00000000..de9e5ccc
--- /dev/null
+++ b/src/Layouts/Base.inc
@@ -0,0 +1,405 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Base layout
+;
+; The inheriting layout should
+; - Specify PWM_ACTIVE_HIGH, COM_ACTIVE_HIGH and COMPARATOR_PORT
+; - Set CUSTOM_* flags to override default implementation
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Bootloader definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Note: The RTX pin must be on port 0 because we use the IT01CF register for interrupts
+RTX_PORT EQU P0 ; Receive/Transmit port
+RTX_MDOUT EQU P0MDOUT ; Set to 1 for PUSHPULL
+RTX_MDIN EQU P0MDIN ; Set to 1 for DIGITAL
+RTX_SKIP EQU P0SKIP ; Set to 1 for SKIP
+
+RTX_BIT EQU RTX_PORT.RTX_PIN ; RTX pin value
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM pin routing and polarity setup
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$if NOT CUSTOM_PWM_SETUP
+
+Initialize_Crossbar MACRO
+ mov XBR2, #40h ; Crossbar enabled
+ mov XBR1, #02h ; CEX0 and CEX1 routed to pins
+ENDM
+
+Set_Pwm_Polarity MACRO
+IF PCA0CPM_POWER == PCA0CPM0
+ mov PCA0POL, #((COM_ACTIVE_HIGH SHL 1) + (1 - PWM_ACTIVE_HIGH))
+ELSE
+ mov PCA0POL, #(((1 - PWM_ACTIVE_HIGH) SHL 1) + COM_ACTIVE_HIGH)
+ENDIF
+ENDM
+
+$endif
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM channels and updating
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$if NOT CUSTOM_PWM_UPDATE
+
+Enable_Power_Pwm_Module MACRO
+IF DEADTIME == 0
+ mov PCA0CPM_POWER, #4Ah ; Enable comparator of module,enable match,set pwm mode
+ELSE
+ mov PCA0CPM_POWER, #42h ; Enable comparator of module,set pwm mode
+ENDIF
+ENDM
+
+Enable_Damp_Pwm_Module MACRO
+IF DEADTIME == 0
+ mov PCA0CPM_DAMP, #00h ; Disable
+ELSE
+ mov PCA0CPM_DAMP, #42h ; Enable comparator of module,set pwm mode
+ENDIF
+ENDM
+
+Set_Power_Pwm_Reg_L MACRO value
+ mov PCA0CPL_POWER, value
+ENDM
+
+Set_Power_Pwm_Reg_H MACRO value
+ mov PCA0CPH_POWER, value
+ENDM
+
+Set_Damp_Pwm_Reg_L MACRO value
+ mov PCA0CPL_DAMP, value
+ENDM
+
+Set_Damp_Pwm_Reg_H MACRO value
+ mov PCA0CPH_DAMP, value
+ENDM
+
+$endif
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Comparator setup and phase change
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF COMPARATOR_PORT == 0
+ CMP_CN0 EQU CMP0CN0
+ CMP_MD EQU CMP0MD
+ CMP_MX EQU CMP0MX
+ELSE
+ CMP_CN0 EQU CMP1CN0
+ CMP_MD EQU CMP1MD
+ CMP_MX EQU CMP1MX
+ENDIF
+
+Initialize_Comparator MACRO
+ mov CMP_CN0, #80h ; Comparator enabled,no hysteresis
+ mov CMP_MD, #00h ; Comparator response time 100ns
+IF COMPARATOR_INVERT == 1 AND MCU_TYPE >= 1
+ mov CMP_MD, #40h ; Output polarity inverted (Only supported on BB2 and BB51)
+ENDIF
+ENDM
+
+Read_Comparator_Output MACRO
+ mov A, CMP_CN0 ; Read comparator output
+IF COMPARATOR_INVERT == 1 AND MCU_TYPE == 0
+ cpl A ; Invert output polarity manually on BB1
+ENDIF
+ENDM
+
+; Set comparator multiplexer to phase A
+Set_Comparator_Phase_A MACRO
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov CMP_MX, #((A_Mux SHL 4) + V_Mux)
+ELSEIF MCU_TYPE == MCU_BB51
+ mov CMP_MX, #12h
+ENDIF
+ENDM
+
+; Set comparator multiplexer to phase B
+Set_Comparator_Phase_B MACRO
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov CMP_MX, #((B_Mux SHL 4) + V_Mux)
+ELSEIF MCU_TYPE == MCU_BB51
+ mov CMP_MX, #10h
+ENDIF
+ENDM
+
+; Set comparator multiplexer to phase C
+Set_Comparator_Phase_C MACRO
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov CMP_MX, #((C_Mux SHL 4) + V_Mux)
+ELSEIF MCU_TYPE == MCU_BB51
+ mov CMP_MX, #11h
+ENDIF
+ENDM
+
+; Toggle FETs 'on' and 'off'
+IF PWM_ACTIVE_HIGH == 1 ; PWM FET active high
+ pON LIT 'setb'
+ pOFF LIT 'clr'
+ELSE ; PWM FET active low
+ pON LIT 'clr'
+ pOFF LIT 'setb'
+ENDIF
+
+IF COM_ACTIVE_HIGH == 1 ; COM FET active high
+ cON LIT 'setb'
+ cOFF LIT 'clr'
+ELSE ; COM FET active low
+ cON LIT 'clr'
+ cOFF LIT 'setb'
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM phase change
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$if NOT CUSTOM_PWM_PHASE
+
+; All pwm and complementary pwm pins must be on port 1 to use the base code below
+P_A_Pwm EQU P1.A_Pwm
+P_A_Com EQU P1.A_Com
+P_B_Pwm EQU P1.B_Pwm
+P_B_Com EQU P1.B_Com
+P_C_Pwm EQU P1.C_Pwm
+P_C_Com EQU P1.C_Com
+
+Set_Pwm_Phase_A MACRO
+IF DEADTIME == 0
+ cON P_A_Com
+ mov P1SKIP, #(NOT (1 SHL A_Pwm))
+ELSE
+ mov P1SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_B MACRO
+IF DEADTIME == 0
+ cON P_B_Com
+ mov P1SKIP, #(NOT (1 SHL B_Pwm))
+ELSE
+ mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_C MACRO
+IF DEADTIME == 0
+ cON P_C_Com
+ mov P1SKIP, #(NOT (1 SHL C_Pwm))
+ELSE
+ mov P1SKIP, #(NOT ((1 SHL C_Pwm) + (1 SHL C_Com)))
+ENDIF
+ENDM
+
+Set_All_Pwm_Phases_Off MACRO
+ mov P1SKIP, #0FFh
+ENDM
+
+$endif
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Toggling FETs on/off
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$if NOT CUSTOM_FET_TOGGLING
+
+A_Pwm_Fet_On MACRO
+ pON P_A_Pwm
+IF DEADTIME == 0
+ cON P_A_Com
+ENDIF
+ENDM
+
+A_Pwm_Fet_Off MACRO
+IF DEADTIME != 0
+ pOFF P_A_Pwm
+ELSE
+ cOFF P_A_Com
+ENDIF
+ENDM
+
+B_Pwm_Fet_On MACRO
+ pON P_B_Pwm
+IF DEADTIME == 0
+ cON P_B_Com
+ENDIF
+ENDM
+
+B_Pwm_Fet_Off MACRO
+IF DEADTIME != 0
+ pOFF P_B_Pwm
+ELSE
+ cOFF P_B_Com
+ENDIF
+ENDM
+
+C_Pwm_Fet_On MACRO
+ pON P_C_Pwm
+IF DEADTIME == 0
+ cON P_C_Com
+ENDIF
+ENDM
+
+C_Pwm_Fet_Off MACRO
+IF DEADTIME != 0
+ pOFF P_C_Pwm
+ELSE
+ cOFF P_C_Com
+ENDIF
+ENDM
+
+All_Pwm_Fets_Off MACRO
+ A_Pwm_Fet_Off
+ B_Pwm_Fet_Off
+ C_Pwm_Fet_Off
+ENDM
+
+A_Com_Fet_On MACRO
+IF DEADTIME == 0
+ pOFF P_A_Pwm
+ENDIF
+ cON P_A_Com
+ENDM
+
+A_Com_Fet_Off MACRO
+ cOFF P_A_Com
+ENDM
+
+B_Com_Fet_On MACRO
+IF DEADTIME == 0
+ pOFF P_B_Pwm
+ENDIF
+ cON P_B_Com
+ENDM
+
+B_Com_Fet_Off MACRO
+ cOFF P_B_Com
+ENDM
+
+C_Com_Fet_On MACRO
+IF DEADTIME == 0
+ pOFF P_C_Pwm
+ENDIF
+ cON P_C_Com
+ENDM
+
+C_Com_Fet_Off MACRO
+ cOFF P_C_Com
+ENDM
+
+All_Com_Fets_Off MACRO
+ A_Com_Fet_Off
+ B_Com_Fet_Off
+ C_Com_Fet_Off
+ENDM
+
+$endif
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; ADC and temperature measurement
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Temperature measurement ADC value for which main motor power is limited at 80degC (low byte, assuming high byte is 1)
+TEMP_LIMIT_2S EQU 49 ; When using vdd 3.3V reference
+TEMP_LIMIT_1S EQU 92 ; When using 1.65V internal reference
+TEMP_LIMIT_STEP EQU 9 ; Temperature measurement ADC value increment for another 10degC
+
+Initialize_Adc MACRO
+ LOCAL initialize_adc_use_internal_1V65_vref initialize_adc_use_vdd_3V3_vref initialize_adc_vref_selected
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov Temp1, #Pgm_Power_Rating
+ cjne @Temp1, #01h, initialize_adc_use_vdd_3V3_vref
+
+initialize_adc_use_internal_1V65_vref:
+ mov REF0CN, #1Ch ; Set internal 1.65V as reference on 1S. Enable temp sensor and bias
+ sjmp initialize_adc_vref_selected
+initialize_adc_use_vdd_3V3_vref:
+ mov REF0CN, #0Ch ; Set vdd (3.3V) as reference on 2S+. Enable temp sensor and bias
+
+initialize_adc_vref_selected:
+IF MCU_TYPE == MCU_BB1
+ mov ADC0CF, #59h ; ADC clock 2MHz,PGA gain 1
+ELSEIF MCU_TYPE == MCU_BB2
+ mov ADC0CF, #0B9h ; ADC clock 2MHz,PGA gain 1
+ENDIF
+ELSEIF MCU_TYPE == MCU_BB51
+ mov CLKGRP0, #18h ; Enable SAR clock,at 12MHz
+ mov ADC0CF1, #0Ah ; 800ns tracking time
+ mov ADC0CF2, #2Fh ; 1.65V reference
+ENDIF
+
+ mov ADC0MX, #10h ; Select temp sensor input
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov ADC0CN0, #80h ; ADC enabled
+ mov ADC0CN1, #01h ; Common mode buffer enabled
+ELSEIF MCU_TYPE == MCU_BB51
+ mov ADC0CN0, #85h ; ADC enabled (gain 0.5,temp sensor enabled)
+ mov ADC0CN1, #20h ; 10bit mode
+ENDIF
+ENDM
+
+Start_Adc MACRO
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov ADC0CN0, #90h ; Initiate conversion
+ELSEIF MCU_TYPE == MCU_BB51
+ mov ADC0CN0, #95h ; Initiate conversion (gain 0.5,temp sensor enabled)
+ENDIF
+ENDM
+
+Stop_Adc MACRO
+ENDM
+
+Restart_Adc MACRO
+ Stop_Adc
+ Start_Adc
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LEDs
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$if NOT CUSTOM_LED
+
+Set_LED_0 MACRO
+ENDM
+
+Clear_LED_0 MACRO
+ENDM
+
+Set_LED_1 MACRO
+ENDM
+
+Clear_LED_1 MACRO
+ENDM
+
+Set_LED_2 MACRO
+ENDM
+
+Clear_LED_2 MACRO
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+$endif
diff --git a/src/Layouts/C.inc b/src/Layouts/C.inc
new file mode 100644
index 00000000..4e22bd9a
--- /dev/null
+++ b/src/Layouts/C.inc
@@ -0,0 +1,143 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "C".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; RX __ Vn Am Bm Cm Ap Ac | Bp Bc Cp Cc __ __ __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+A_Com EQU 7
+A_Pwm EQU 6
+C_Mux EQU 5
+B_Mux EQU 4
+A_Mux EQU 3
+V_Mux EQU 2
+; EQU 1
+RTX_PIN EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU NOT((1 SHL A_Pwm) + (1 SHL A_Com))
+P0_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL A_Com)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+; EQU 5
+; EQU 4
+C_Com EQU 3
+C_Pwm EQU 2
+B_Com EQU 1
+B_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM Phase
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+P_A_Pwm EQU P0.A_Pwm
+P_A_Com EQU P0.A_Com
+P_B_Pwm EQU P1.B_Pwm
+P_B_Com EQU P1.B_Com
+P_C_Pwm EQU P1.C_Pwm
+P_C_Com EQU P1.C_Com
+
+Set_Pwm_Phase_A MACRO
+IF DEADTIME == 0
+ cON P_A_Com
+ mov P0SKIP, #(NOT (1 SHL A_Pwm))
+ mov P1SKIP, #0FFh
+ELSE
+ mov P0SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
+ mov P1SKIP, #0FFh
+ENDIF
+ENDM
+
+Set_Pwm_Phase_B MACRO
+IF DEADTIME == 0
+ cON P_B_Com
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT (1 SHL B_Pwm))
+ELSE
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_C MACRO
+IF DEADTIME == 0
+ cON P_C_Com
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT (1 SHL C_Pwm))
+ELSE
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT ((1 SHL C_Pwm) + (1 SHL C_Com)))
+ENDIF
+ENDM
+
+Set_All_Pwm_Phases_Off MACRO
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #0FFh
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_PWM_PHASE)
+$include (Base.inc)
diff --git a/src/Layouts/D.inc b/src/Layouts/D.inc
new file mode 100644
index 00000000..d856265b
--- /dev/null
+++ b/src/Layouts/D.inc
@@ -0,0 +1,97 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "D".
+;
+; Com fets are active low for H/L_N driver and EN_N/PWM driver.
+; "A" with different comp.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/E.inc b/src/Layouts/E.inc
new file mode 100644
index 00000000..655cac50
--- /dev/null
+++ b/src/Layouts/E.inc
@@ -0,0 +1,155 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "E".
+;
+; Equals "A", but with LED control.
+; And with HIP2103/4 driver initialization.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX L0 L1 | Ap Ac Bp Bc Cp Cc L2 __ | no no high 3
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+LED_1 EQU 7
+LED_0 EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU NOT((1 SHL LED_0) + (1 SHL LED_1))
+P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+LED_2 EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) + (1 SHL LED_2)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) + (1 SHL LED_2)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; ESC specific
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Initialize_Crossbar MACRO
+ mov XBR2, #40h ; Crossbar enabled
+ mov XBR1, #02h ; CEX0 and CEX1 routed to pins
+
+ All_Pwm_Fets_Off ; For unlocking of HIP2103/4 driver circuits
+ call wait100ms
+ A_Com_Fet_On
+ B_Com_Fet_On
+ C_Com_Fet_On
+ call wait1ms
+ All_Com_Fets_Off
+ENDM
+
+Set_Pwm_Polarity MACRO
+IF PCA0CPM_POWER == PCA0CPM0
+ mov PCA0POL, #((COM_ACTIVE_HIGH SHL 1) + (1 - PWM_ACTIVE_HIGH))
+ELSE
+ mov PCA0POL, #(((1 - PWM_ACTIVE_HIGH) SHL 1) + COM_ACTIVE_HIGH)
+ENDIF
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LED configuration
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Set_LED_0 MACRO
+ setb P0.LED_0
+ENDM
+
+Clear_LED_0 MACRO
+ clr P0.LED_0
+ENDM
+
+Set_LED_1 MACRO
+ setb P0.LED_1
+ENDM
+
+Clear_LED_1 MACRO
+ clr P0.LED_1
+ENDM
+
+Set_LED_2 MACRO
+ setb P1.LED_2
+ENDM
+
+Clear_LED_2 MACRO
+ clr P1.LED_2
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_PWM_SETUP,CUSTOM_LED)
+$include (Base.inc)
diff --git a/src/Layouts/F.inc b/src/Layouts/F.inc
new file mode 100644
index 00000000..f4d94305
--- /dev/null
+++ b/src/Layouts/F.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "F".
+;
+; Equals "A", but with A_Mux and C_Mux swapped.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Cm Bm Am __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+A_Mux EQU 3
+B_Mux EQU 2
+C_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/G.inc b/src/Layouts/G.inc
new file mode 100644
index 00000000..e1384be5
--- /dev/null
+++ b/src/Layouts/G.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "G".
+;
+; "A" with different comp ordering.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/H.inc b/src/Layouts/H.inc
new file mode 100644
index 00000000..1f8190bf
--- /dev/null
+++ b/src/Layouts/H.inc
@@ -0,0 +1,104 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "H".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Cm Vn Bm Am __ __ __ RX | Cc Bc Ac __ Cp Bp Ap __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+RTX_PIN EQU 7
+; EQU 6
+; EQU 5
+; EQU 4
+A_Mux EQU 3
+B_Mux EQU 2
+V_Mux EQU 1
+C_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+A_Pwm EQU 6
+B_Pwm EQU 5
+C_Pwm EQU 4
+; EQU 3
+A_Com EQU 2
+B_Com EQU 1
+C_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/I.inc b/src/Layouts/I.inc
new file mode 100644
index 00000000..d177d514
--- /dev/null
+++ b/src/Layouts/I.inc
@@ -0,0 +1,94 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "I".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+A_Com EQU 5
+B_Com EQU 4
+C_Com EQU 3
+A_Pwm EQU 2
+B_Pwm EQU 1
+C_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/J.inc b/src/Layouts/J.inc
new file mode 100644
index 00000000..1c4931bb
--- /dev/null
+++ b/src/Layouts/J.inc
@@ -0,0 +1,128 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "J".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Am Cm Bm Vn RX L0 L1 L2 | Ap Bp Cp Ac Bc Cc __ __ | no no high 3
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+LED_2 EQU 7
+LED_1 EQU 6
+LED_0 EQU 5
+RTX_PIN EQU 4
+V_Mux EQU 3
+B_Mux EQU 2
+C_Mux EQU 1
+A_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL LED_2)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+B_Com EQU 4
+A_Com EQU 3
+C_Pwm EQU 2
+B_Pwm EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LED configuration
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Set_LED_0 MACRO
+ clr P0.LED_0
+ENDM
+
+Clear_LED_0 MACRO
+ setb P0.LED_0
+ENDM
+
+Set_LED_1 MACRO
+ clr P0.LED_1
+ENDM
+
+Clear_LED_1 MACRO
+ setb P0.LED_1
+ENDM
+
+Set_LED_2 MACRO
+ clr P0.LED_2
+ENDM
+
+Clear_LED_2 MACRO
+ setb P0.LED_2
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_LED)
+$include (Base.inc)
diff --git a/src/Layouts/K.inc b/src/Layouts/K.inc
new file mode 100644
index 00000000..d7825a6f
--- /dev/null
+++ b/src/Layouts/K.inc
@@ -0,0 +1,106 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "K".
+;
+; Com fets are active low for H/L_N driver and EN_N/PWM driver.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; RX Am Vn Bm __ Cm __ __ | Ac Bc Cc Cp Bp Ap __ __ | no yes high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Mux EQU 5
+; EQU 4
+B_Mux EQU 3
+V_Mux EQU 2
+A_Mux EQU 1
+RTX_PIN EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+A_Pwm EQU 5
+B_Pwm EQU 4
+C_Pwm EQU 3
+C_Com EQU 2
+B_Com EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/L.inc b/src/Layouts/L.inc
new file mode 100644
index 00000000..114df131
--- /dev/null
+++ b/src/Layouts/L.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "L".
+;
+; "I" with different comp ordering.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Cm Bm Am Vn __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+B_Mux EQU 1
+C_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+A_com EQU 5
+B_Com EQU 4
+C_Com EQU 3
+A_Pwm EQU 2
+B_Pwm EQU 1
+C_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/M.inc b/src/Layouts/M.inc
new file mode 100644
index 00000000..f69a74fc
--- /dev/null
+++ b/src/Layouts/M.inc
@@ -0,0 +1,124 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "M".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ __ L0 RX Bm Vn Cm Am | __ Ap Bp Cp Ac Bc Cc __ | no no high 1
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+A_Mux EQU 7
+C_Mux EQU 6
+V_Mux EQU 5
+B_Mux EQU 4
+RTX_PIN EQU 3
+LED_0 EQU 2
+; EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU NOT(1 SHL LED_0)
+P0_PUSHPULL EQU (1 SHL LED_0)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+C_Com EQU 6
+B_Com EQU 5
+A_Com EQU 4
+C_Pwm EQU 3
+B_Pwm EQU 2
+A_Pwm EQU 1
+; EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LED configuration
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Set_LED_0 MACRO
+ setb P0.LED_0
+ENDM
+
+Clear_LED_0 MACRO
+ clr P0.LED_0
+ENDM
+
+Set_LED_1 MACRO
+ENDM
+
+Clear_LED_1 MACRO
+ENDM
+
+Set_LED_2 MACRO
+ENDM
+
+Clear_LED_2 MACRO
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_LED)
+$include (Base.inc)
diff --git a/src/Layouts/N.inc b/src/Layouts/N.inc
new file mode 100644
index 00000000..5ecf4927
--- /dev/null
+++ b/src/Layouts/N.inc
@@ -0,0 +1,106 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "N".
+;
+; "B" with A and C fets swapped.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+C_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+A_Pwm EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/O.inc b/src/Layouts/O.inc
new file mode 100644
index 00000000..a3616507
--- /dev/null
+++ b/src/Layouts/O.inc
@@ -0,0 +1,97 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "O".
+;
+; Com fets are active low for H/L_N driver and EN_N/PWM driver.
+; Low side pwm and 1S flag set.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes low _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 1 ; Comparator output inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/OA.inc b/src/Layouts/OA.inc
new file mode 100644
index 00000000..8028037a
--- /dev/null
+++ b/src/Layouts/OA.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "OA".
+;
+; Equals "O", but open drain instead of push-pull COM FETs.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ap Ac Bp Bc Cp Cc __ __ | no yes low _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 0 ; Damping non-inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 1 ; Comparator output inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Com EQU 5
+C_Pwm EQU 4
+B_Com EQU 3
+B_Pwm EQU 2
+A_Com EQU 1
+A_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com) ; Active low com fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/P.inc b/src/Layouts/P.inc
new file mode 100644
index 00000000..c57bdb21
--- /dev/null
+++ b/src/Layouts/P.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "P".
+;
+; "M" with different comp and no LEDs.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ Cm Bm Vn Am RX __ __ | __ Ap Bp Cp Ac Bc Cc __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+A_Mux EQU 4
+V_Mux EQU 3
+B_Mux EQU 2
+C_Mux EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+C_Com EQU 6
+B_Com EQU 5
+A_Com EQU 4
+C_Pwm EQU 3
+B_Pwm EQU 2
+A_Pwm EQU 1
+; EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/Q.inc b/src/Layouts/Q.inc
new file mode 100644
index 00000000..8c237245
--- /dev/null
+++ b/src/Layouts/Q.inc
@@ -0,0 +1,174 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "Q".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ RX __ L0 L1 Ap Bp Cp | Ac Bc Cc Vn Cm Bm Am __ | no no high 2
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 1 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+C_Pwm EQU 7
+B_Pwm EQU 6
+A_Pwm EQU 5
+LED_1 EQU 4
+LED_0 EQU 3
+; EQU 2
+RTX_PIN EQU 1
+; EQU 0
+
+P0_DIGITAL EQU 0FFh
+P0_INIT EQU (1 SHL RTX_PIN)
+P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+A_Mux EQU 6
+B_Mux EQU 5
+C_Mux EQU 4
+V_Mux EQU 3
+C_Com EQU 2
+B_Com EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM Phase
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+P_A_Pwm EQU P0.A_Pwm
+P_A_Com EQU P1.A_Com
+P_B_Pwm EQU P0.B_Pwm
+P_B_Com EQU P1.B_Com
+P_C_Pwm EQU P0.C_Pwm
+P_C_Com EQU P1.C_Com
+
+Set_Pwm_Phase_A MACRO
+IF DEADTIME == 0
+ cON P_A_Com
+ mov P0SKIP, #(NOT (1 SHL A_Pwm))
+ mov P1SKIP, #0FFh
+ELSE
+ mov P0SKIP, #(NOT (1 SHL A_Pwm))
+ mov P1SKIP, #(NOT (1 SHL A_Com))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_B MACRO
+IF DEADTIME == 0
+ cON P_B_Com
+ mov P0SKIP, #(NOT (1 SHL B_Pwm))
+ mov P1SKIP, #0FFh
+ELSE
+ mov P0SKIP, #(NOT (1 SHL B_Pwm))
+ mov P1SKIP, #(NOT (1 SHL B_Com))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_C MACRO
+IF DEADTIME == 0
+ cON P_C_Com
+ mov P0SKIP, #(NOT (1 SHL C_Pwm))
+ mov P1SKIP, #0FFh
+ELSE
+ mov P0SKIP, #(NOT (1 SHL C_Pwm))
+ mov P1SKIP, #(NOT (1 SHL C_Com))
+ENDIF
+ENDM
+
+Set_All_Pwm_Phases_Off MACRO
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #0FFh
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LED configuration
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Set_LED_0 MACRO
+ setb P0.LED_0
+ENDM
+
+Clear_LED_0 MACRO
+ clr P0.LED_0
+ENDM
+
+Set_LED_1 MACRO
+ setb P0.LED_1
+ENDM
+
+Clear_LED_1 MACRO
+ clr P0.LED_1
+ENDM
+
+Set_LED_2 MACRO
+ENDM
+
+Clear_LED_2 MACRO
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_PWM_PHASE,CUSTOM_LED)
+$include (Base.inc)
diff --git a/src/Layouts/R.inc b/src/Layouts/R.inc
new file mode 100644
index 00000000..5920e971
--- /dev/null
+++ b/src/Layouts/R.inc
@@ -0,0 +1,96 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "R".
+;
+; "L" with different comp.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Vn Am Bm Cm __ RX __ __ | Cp Bp Ap Cc Bc Ac __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+B_Mux EQU 2
+A_Mux EQU 1
+V_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+A_Com EQU 5
+B_Com EQU 4
+C_Com EQU 3
+A_Pwm EQU 2
+B_Pwm EQU 1
+C_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/S.inc b/src/Layouts/S.inc
new file mode 100644
index 00000000..2557ed6d
--- /dev/null
+++ b/src/Layouts/S.inc
@@ -0,0 +1,104 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "S".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+C_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+A_Pwm EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/T.inc b/src/Layouts/T.inc
new file mode 100644
index 00000000..e5d82310
--- /dev/null
+++ b/src/Layouts/T.inc
@@ -0,0 +1,104 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "T".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ Cm Vn Bm __ Am __ RX | Cc Bc Ac Ap Bp Cp __ __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+RTX_PIN EQU 7
+; EQU 6
+A_Mux EQU 5
+; EQU 4
+B_Mux EQU 3
+V_Mux EQU 2
+C_Mux EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+B_Pwm EQU 4
+A_Pwm EQU 3
+A_Com EQU 2
+B_Com EQU 1
+C_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Layouts/U.inc b/src/Layouts/U.inc
new file mode 100644
index 00000000..ad406bc3
--- /dev/null
+++ b/src/Layouts/U.inc
@@ -0,0 +1,130 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "U".
+;
+; Like "M", but with 3 LEDs.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; L2 L1 L0 RX Bm Vn Cm Am | __ Ap Bp Cp Ac Bc Cc __ | no no high 3
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+PCA0CPM_POWER EQU PCA0CPM0
+PCA0CPL_POWER EQU PCA0CPL0
+PCA0CPH_POWER EQU PCA0CPH0
+
+PCA0CPM_DAMP EQU PCA0CPM1
+PCA0CPL_DAMP EQU PCA0CPL1
+PCA0CPH_DAMP EQU PCA0CPH1
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+A_Mux EQU 7
+C_Mux EQU 6
+V_Mux EQU 5
+B_Mux EQU 4
+RTX_PIN EQU 3
+LED_0 EQU 2
+LED_1 EQU 1
+LED_2 EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU (1 SHL LED_0) + (1 SHL LED_1) + (1 SHL LED_2)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+C_Com EQU 6
+B_Com EQU 5
+A_Com EQU 4
+C_Pwm EQU 3
+B_Pwm EQU 2
+A_Pwm EQU 1
+; EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; LED configuration
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Set_LED_0 MACRO
+ clr P0.LED_0
+ENDM
+
+Clear_LED_0 MACRO
+ setb P0.LED_0
+ENDM
+
+Set_LED_1 MACRO
+ clr P0.LED_1
+ENDM
+
+Clear_LED_1 MACRO
+ setb P0.LED_1
+ENDM
+
+Set_LED_2 MACRO
+ clr P0.LED_2
+ENDM
+
+Clear_LED_2 MACRO
+ setb P0.LED_2
+ENDM
+
+Set_LED_3 MACRO
+ENDM
+
+Clear_LED_3 MACRO
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_LED)
+$include (Base.inc)
diff --git a/src/Layouts/V.inc b/src/Layouts/V.inc
new file mode 100644
index 00000000..88607f9f
--- /dev/null
+++ b/src/Layouts/V.inc
@@ -0,0 +1,153 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "V".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Am Bm Vn Cm __ RX __ Cc | Cp Bc __ __ Bp Ac Ap __ | no no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+C_Com EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+C_Mux EQU 3
+V_Mux EQU 2
+B_Mux EQU 1
+A_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU NOT(1 SHL C_Com)
+P0_PUSHPULL EQU (1 SHL C_Com)
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+A_Pwm EQU 6
+A_Com EQU 5
+B_Pwm EQU 4
+; EQU 3
+; EQU 2
+B_Com EQU 1
+C_Pwm EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com)
+P1_INIT EQU 00h
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM Phase
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+P_A_Pwm EQU P1.A_Pwm
+P_A_Com EQU P1.A_Com
+P_B_Pwm EQU P1.B_Pwm
+P_B_Com EQU P1.B_Com
+P_C_Pwm EQU P1.C_Pwm
+P_C_Com EQU P0.C_Com
+
+Set_Pwm_Phase_A MACRO
+IF DEADTIME == 0
+ cON P_A_Com
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT (1 SHL A_Pwm))
+ELSE
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT ((1 SHL A_Pwm) + (1 SHL A_Com)))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_B MACRO
+IF DEADTIME == 0
+ cON P_B_Com
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT (1 SHL B_Pwm))
+ELSE
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT ((1 SHL B_Pwm) + (1 SHL B_Com)))
+ENDIF
+ENDM
+
+Set_Pwm_Phase_C MACRO
+IF DEADTIME == 0
+ cON P_C_Com
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #(NOT (1 SHL C_Pwm))
+ELSE
+ mov P0SKIP, #(NOT (1 SHL C_Com))
+ mov P1SKIP, #(NOT (1 SHL C_Pwm))
+ENDIF
+ENDM
+
+Set_All_Pwm_Phases_Off MACRO
+ mov P0SKIP, #0FFh
+ mov P1SKIP, #0FFh
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_PWM_PHASE)
+$include (Base.inc)
diff --git a/src/Layouts/W.inc b/src/Layouts/W.inc
new file mode 100644
index 00000000..d7a00f2a
--- /dev/null
+++ b/src/Layouts/W.inc
@@ -0,0 +1,188 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "W".
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; __ __ Am Vn __ Bm Cm RX | __ __ __ __ Cp Bp Ap __ | n/a n/a high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 1 ; Pwm non-inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+RTX_PIN EQU 7
+C_Mux EQU 6
+B_Mux EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+; EQU 1
+; EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+A_Pwm EQU 6
+B_Pwm EQU 5
+C_Pwm EQU 4
+; EQU 3
+; EQU 2
+; EQU 1
+; EQU 0
+
+; pwm outputs start as analog in -> floating
+; this ensures all mosfet drivers start with floating outputs
+P1_DIGITAL EQU NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))
+P1_INIT EQU 00h
+P1_PUSHPULL EQU ((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))
+P1_SKIP EQU 0FFh
+
+A_Pwm_Fet_On MACRO
+ setb P1.A_Pwm ; set pin to high
+ orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
+ENDM
+
+A_Pwm_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL A_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+B_Pwm_Fet_On MACRO
+ setb P1.B_Pwm ; set pin to high
+ orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
+ENDM
+
+B_Pwm_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL B_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+C_Pwm_Fet_On MACRO
+ setb P1.C_Pwm ; set pin to high
+ orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
+ENDM
+
+C_Pwm_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL C_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+All_Pwm_Fets_Off MACRO
+ anl P1MDIN, #(NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+A_Com_Fet_On MACRO
+ clr P1.A_Pwm ; set pin to low
+ orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
+ENDM
+
+A_Com_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL A_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+B_Com_Fet_On MACRO
+ clr P1.B_Pwm ; set pin to low
+ orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
+ENDM
+
+B_Com_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL B_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+C_Com_Fet_On MACRO
+ clr P1.C_Pwm ; set pin to low
+ orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
+ENDM
+
+C_Com_Fet_Off MACRO
+ anl P1MDIN, #(NOT(1 SHL C_Pwm)) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+All_Com_Fets_Off MACRO
+ anl P1MDIN, #(NOT((1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm))) ; analog in -> pullup,driver and digital in is disable = floating
+ENDM
+
+Set_Pwm_Phase_A MACRO
+ mov P1SKIP, #(NOT(1 SHL A_Pwm)) ;
+ orl P1MDIN, #(1 SHL A_Pwm) ; enable pin driver
+ENDM
+
+Set_Pwm_Phase_B MACRO
+ mov P1SKIP, #(NOT(1 SHL B_Pwm)) ;
+ orl P1MDIN, #(1 SHL B_Pwm) ; enable pin driver
+ENDM
+
+Set_Pwm_Phase_C MACRO
+ mov P1SKIP, #(NOT(1 SHL C_Pwm)) ;
+ orl P1MDIN, #(1 SHL C_Pwm) ; enable pin driver
+ENDM
+
+Set_All_Pwm_Phases_Off MACRO
+ mov P1SKIP, #P1_SKIP
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$set (CUSTOM_PWM_PHASE,CUSTOM_FET_TOGGLING)
+$include (Base.inc)
diff --git a/src/Layouts/Z.inc b/src/Layouts/Z.inc
new file mode 100644
index 00000000..723a0b3c
--- /dev/null
+++ b/src/Layouts/Z.inc
@@ -0,0 +1,106 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Hardware definition file "Z".
+;
+; "N" different comp and pwm active low.
+;
+; PORT 0 | PORT 1 | PWM COM PWM LED
+; P0 P1 P2 P3 P4 P5 P6 P7 | P0 P1 P2 P3 P4 P5 P6 P7 | inv inv side n
+; ----------------------- | ----------------------- | -------------------------
+; Bm Cm Am Vn __ RX __ __ | Ac Ap Bc Bp Cc Cp __ __ | yes no high _
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+PWM_ACTIVE_HIGH EQU 0 ; Pwm inverted
+COM_ACTIVE_HIGH EQU 1 ; Damping inverted
+
+COMPARATOR_PORT EQU 0 ; All comparator (mux) pins must be on the same port
+COMPARATOR_INVERT EQU 0 ; Comparator output non-inverted
+
+IF DEADTIME == 0
+ PCA0CPM_POWER EQU PCA0CPM0
+ PCA0CPL_POWER EQU PCA0CPL0
+ PCA0CPH_POWER EQU PCA0CPH0
+
+ PCA0CPM_DAMP EQU PCA0CPM1
+ PCA0CPL_DAMP EQU PCA0CPL1
+ PCA0CPH_DAMP EQU PCA0CPH1
+ELSE
+ PCA0CPM_POWER EQU PCA0CPM1
+ PCA0CPL_POWER EQU PCA0CPL1
+ PCA0CPH_POWER EQU PCA0CPH1
+
+ PCA0CPM_DAMP EQU PCA0CPM0
+ PCA0CPL_DAMP EQU PCA0CPL0
+ PCA0CPH_DAMP EQU PCA0CPH0
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 0 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+RTX_PIN EQU 5
+; EQU 4
+V_Mux EQU 3
+A_Mux EQU 2
+C_Mux EQU 1
+B_Mux EQU 0
+
+P0_DIGITAL EQU NOT((1 SHL A_Mux) + (1 SHL B_Mux) + (1 SHL C_Mux) + (1 SHL V_Mux))
+P0_INIT EQU 0FFh
+P0_PUSHPULL EQU 0
+P0_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 1 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; EQU 7
+; EQU 6
+C_Pwm EQU 5
+C_Com EQU 4
+B_Pwm EQU 3
+B_Com EQU 2
+A_Pwm EQU 1
+A_Com EQU 0
+
+P1_DIGITAL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_INIT EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) ; Active low pwm fets
+P1_PUSHPULL EQU (1 SHL A_Pwm) + (1 SHL B_Pwm) + (1 SHL C_Pwm) + (1 SHL A_Com) + (1 SHL B_Com) + (1 SHL C_Com)
+P1_SKIP EQU 0FFh
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PORT 2 definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+DebugPin EQU 0
+
+P2_DIGITAL EQU (1 SHL DebugPin)
+P2_PUSHPULL EQU (1 SHL DebugPin)
+P2_SKIP EQU (1 SHL DebugPin)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Inherit base layout
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+$include (Base.inc)
diff --git a/src/Modules/Codespace.asm b/src/Modules/Codespace.asm
new file mode 100644
index 00000000..c06becc8
--- /dev/null
+++ b/src/Modules/Codespace.asm
@@ -0,0 +1,49 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2023 Chris Landa
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Codespace segment definitions for different MCU types
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+ ; General
+ CSEG_APP EQU 80h
+
+IF MCU_TYPE == MCU_BB51
+ ; BB51
+ CSEG_RESET EQU 2FFDh
+ CSEG_EEPROM EQU 3000h
+ CSEG_LAYOUT_TAG EQU 3040h
+ CSEG_MCU_TAG EQU 3050h
+ CSEG_NAME EQU 3060h
+ CSEG_MELODY EQU 3070h
+ CSEG_BOOT_START EQU 0F000h
+ELSE
+ ; BB1 & BB21
+ CSEG_RESET EQU 19FDh
+ CSEG_EEPROM EQU 1A00h
+ CSEG_LAYOUT_TAG EQU 1A40h
+ CSEG_MCU_TAG EQU 1A50h
+ CSEG_NAME EQU 1A60h
+ CSEG_MELODY EQU 1A70h
+ CSEG_BOOT_START EQU 1C00h
+ENDIF
diff --git a/src/Modules/Common.asm b/src/Modules/Common.asm
new file mode 100644
index 00000000..29c02ce5
--- /dev/null
+++ b/src/Modules/Common.asm
@@ -0,0 +1,266 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Common definitions for EFM8BB1x/2x/5x based ESCs
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Device SiLabs EFM8BB1x/2x/51
+;
+; Include defines provided by SiLabs depending on target platform.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF MCU_TYPE == MCU_BB1
+ $include (Silabs/SI_EFM8BB1_Defs.inc)
+ELSEIF MCU_TYPE == MCU_BB2
+ $include (Silabs/SI_EFM8BB2_Defs.inc)
+ELSEIF MCU_TYPE == MCU_BB51
+ $include (Silabs/SI_EFM8BB51_Defs.inc)
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Uses internal calibrated oscillator set to 24/48Mhz
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; ESC target letter(s)
+;
+; The initial set of layouts are labeled A-Z and their character can be
+; calculated based on that.
+;
+; The extended set of layouts consisting of two letters will assign the letters
+; manually for maximum flexibility.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF ESCNO < 27
+ ESC_C_COUNT EQU 1
+ ESC_C EQU "A" + ESCNO - 1
+ELSE
+ ESC_C_COUNT EQU 2
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; ESC selection statements
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE = MCU_BB2
+IF ESCNO == A_
+ $include (Layouts/A.inc) ; Select pinout A
+ELSEIF ESCNO == B_
+ $include (Layouts/B.inc) ; Select pinout B
+ELSEIF ESCNO == C_
+ $include (Layouts/C.inc) ; Select pinout C
+ELSEIF ESCNO == D_
+ $include (Layouts/D.inc) ; Select pinout D
+ELSEIF ESCNO == E_
+ $include (Layouts/E.inc) ; Select pinout E
+ELSEIF ESCNO == F_
+ $include (Layouts/F.inc) ; Select pinout F
+ELSEIF ESCNO == G_
+ $include (Layouts/G.inc) ; Select pinout G
+ELSEIF ESCNO == H_
+ $include (Layouts/H.inc) ; Select pinout H
+ELSEIF ESCNO == I_
+ $include (Layouts/I.inc) ; Select pinout I
+ELSEIF ESCNO == J_
+ $include (Layouts/J.inc) ; Select pinout J
+ELSEIF ESCNO == K_
+ $include (Layouts/K.inc) ; Select pinout K
+ELSEIF ESCNO == L_
+ $include (Layouts/L.inc) ; Select pinout L
+ELSEIF ESCNO == M_
+ $include (Layouts/M.inc) ; Select pinout M
+ELSEIF ESCNO == N_
+ $include (Layouts/N.inc) ; Select pinout N
+ELSEIF ESCNO == O_
+ $include (Layouts/O.inc) ; Select pinout O
+ELSEIF ESCNO == P_
+ $include (Layouts/P.inc) ; Select pinout P
+ELSEIF ESCNO == Q_
+ $include (Layouts/Q.inc) ; Select pinout Q
+ELSEIF ESCNO == R_
+ $include (Layouts/R.inc) ; Select pinout R
+ELSEIF ESCNO == S_
+ $include (Layouts/S.inc) ; Select pinout S
+ELSEIF ESCNO == T_
+ $include (Layouts/T.inc) ; Select pinout T
+ELSEIF ESCNO == U_
+ $include (Layouts/U.inc) ; Select pinout U
+ELSEIF ESCNO == V_
+ $include (Layouts/V.inc) ; Select pinout V
+ELSEIF ESCNO == W_
+ $include (Layouts/W.inc) ; Select pinout W
+;ELSEIF ESCNO == X_
+ ;$include (Layouts/X.inc) ; Select pinout X
+;ELSEIF ESCNO == Y_
+ ;$include (Layouts/Y.inc) ; Select pinout Y
+ELSEIF ESCNO == Z_
+ $include (Layouts/Z.inc) ; Select pinout Z
+ELSEIF ESCNO == OA_
+ $include (Layouts/OA.inc) ; Select pinout OA
+ ESC_C0 EQU "O"
+ ESC_C1 EQU "A"
+ENDIF
+ENDIF
+
+IF MCU_TYPE == MCU_BB51
+IF ESCNO == A_
+ $include (Layouts/BB51/A.inc) ; Select pinout A
+ELSEIF ESCNO == B_
+ $include (Layouts/BB51/B.inc) ; Select pinout B
+ELSEIF ESCNO == C_
+ $include (Layouts/BB51/C.inc) ; Select pinout C
+ENDIF
+ENDIF
+
+; Build device signature based on target platform: 0xE8, [0xB1 | 0xB2 | 0xB5]
+SIGNATURE_001 EQU 0E8h
+IF MCU_TYPE == MCU_BB1
+ SIGNATURE_002 EQU 0B1h
+ELSEIF MCU_TYPE == MCU_BB2
+ SIGNATURE_002 EQU 0B2h
+ELSEIF MCU_TYPE == MCU_BB51
+ SIGNATURE_002 EQU 0B5h
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Constant definitions
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; MCU letter
+;
+; BB1: L
+; BB21: H
+; BB51: X
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF MCU_TYPE == MCU_BB1
+ MCU_C EQU "L"
+ELSEIF MCU_TYPE == MCU_BB2
+ MCU_C EQU "H"
+ELSEIF MCU_TYPE == MCU_BB51
+ MCU_C EQU "X"
+ENDIF
+
+; Dead time number as chars
+DT_C2 EQU "0" + (DEADTIME / 100)
+DT_C1 EQU "0" + ((DEADTIME / 10) MOD 10)
+DT_C0 EQU "0" + (DEADTIME MOD 10)
+
+; Full ESC layout tag including layout letter, mcu letter and deadtime
+CSEG AT CSEG_LAYOUT_TAG
+IF ESC_C_COUNT == 1
+; Eg.: G_H_30, O_L_5,...
+IF DEADTIME < 100
+ Eep_ESC_Layout: DB "#", ESC_C, "_", MCU_C, "_", DT_C1, DT_C0, "# "
+ELSE
+ Eep_ESC_Layout: DB "#", ESC_C, "_", MCU_C, "_", DT_C2, DT_C1, DT_C0, "# "
+ENDIF
+ELSEIF ESC_C_COUNT == 2
+; Eg.: AA_H_30, AO_L_5,...
+IF DEADTIME < 100
+ Eep_ESC_Layout: DB "#", ESC_C0, ESC_C1, "_", MCU_C, "_", DT_C1, DT_C0, "# "
+ELSE
+ Eep_ESC_Layout: DB "#", ESC_C0, ESC_C1, "_", MCU_C, "_", DT_C2, DT_C1, DT_C0, "# "
+ENDIF
+ENDIF
+
+; Project and MCU tag (16 Bytes)
+CSEG AT CSEG_MCU_TAG
+IF MCU_TYPE == MCU_BB1
+ Eep_ESC_MCU: DB "#BLHELI$EFM8B10#"
+ELSEIF MCU_TYPE == MCU_BB2
+ Eep_ESC_MCU: DB "#BLHELI$EFM8B21#"
+ELSEIF MCU_TYPE == MCU_BB51
+ Eep_ESC_MCU: DB "#BLHELI$EFM8B51#"
+ENDIF
+
+Interrupt_Table_Definition MACRO
+CSEG AT 0 ; Code segment start
+ jmp reset
+CSEG AT 03h ; Int0 interrupt
+ jmp int0_int
+CSEG AT 0Bh ; Timer0 overflow interrupt
+ jmp t0_int
+CSEG AT 13h ; Int1 interrupt
+ jmp int1_int
+CSEG AT 1Bh ; Timer1 overflow interrupt
+ jmp t1_int
+CSEG AT 2Bh ; Timer2 overflow interrupt
+ jmp t2_int
+CSEG AT 5Bh ; PCA interrupt
+ jmp pca_int
+CSEG AT 73h ; Timer3 overflow/compare interrupt
+ jmp t3_int
+ENDM
+
+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)
+
+IF PWM_CENTERED == 1
+ mov PCA0CENT, #07h ; Center aligned pwm
+ELSE
+ mov PCA0CENT, #00h ; Edge aligned pwm
+ENDIF
+ENDM
+
+Set_MCU_Clk_24MHz MACRO
+ mov CLKSEL, #13h ; Set clock to 24MHz (Oscillator 1 divided by 2)
+
+ mov SFRPAGE, #10h
+ mov PFE0CN, #00h ; Set flash timing for 24MHz and disable prefetch engine
+ mov SFRPAGE, #00h
+ENDM
+
+Set_MCU_Clk_48MHz MACRO
+ mov SFRPAGE, #10h
+IF MCU_TYPE == MCU_BB2
+ mov PFE0CN, #30h ; Set flash timing for 48MHz and enable prefetch engine
+ELSEIF MCU_TYPE == MCU_BB51
+ mov PFE0CN, #10h ; Set flash timing for 48MHz
+ENDIF
+ mov SFRPAGE, #00h
+
+ mov CLKSEL, #03h ; Set clock to 48MHz (Oscillator 1)
+ENDM
+
+Unlock_Flash MACRO
+ mov Flash_Key_1, #0A5h
+ mov Flash_Key_2, #0F1h
+ENDM
+
+Lock_Flash MACRO
+ mov Flash_Key_1, #0
+ mov Flash_Key_2, #0
+ENDM
+
diff --git a/src/Modules/Commutation.asm b/src/Modules/Commutation.asm
new file mode 100644
index 00000000..90f867e7
--- /dev/null
+++ b/src/Modules/Commutation.asm
@@ -0,0 +1,185 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Commutation
+;
+; Performs 6-step commutation switching.
+;
+; In 6-step commutation switching a full rotation is segregated in 6 sectors.
+; Every sectors is 60 degrees (6 * 60 = 360), thus 6 steps are needed to
+; complete one full rotation.
+;
+; Non reversed switching (PWM, non inverted shown here). The diagram shows two
+; full commutation runs:
+;
+; 123456123456
+; A __/‾‾\__/‾‾\
+;
+; B /‾‾\__/‾‾\__
+;
+; C ‾\__/‾‾\__/‾
+;
+; The followind table shows the states of the FETs for all phases including
+; complementary states:
+;
+; Step AA' BB' CC'
+; 1 C->A 01 00 10
+; 2 B->A 01 10 00
+; 3 B->C 00 10 01
+; 4 A->C 10 00 01
+; 5 A->B 10 01 00
+; 6 C->B 00 01 10
+;
+; NOTE: Every step has a "reverse" step which is used in bi-directional mode
+; where the motor is allowed to spin in both directions. Depending on the
+; current RC pulse the motor is commutated either in "normal" direction
+; or in "reverse".
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+; Comm phase 1 to comm phase 2
+comm1_comm2: ; C->A
+ jb Flag_Motor_Dir_Rev, comm1_comm2_rev
+
+ clr IE_EA
+ B_Com_Fet_Off
+ A_Com_Fet_On
+ Set_Pwm_Phase_C ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_B
+ ret
+
+comm1_comm2_rev: ; A->C
+ clr IE_EA
+ B_Com_Fet_Off
+ C_Com_Fet_On
+ Set_Pwm_Phase_A ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_B
+ ret
+
+; Comm phase 2 to comm phase 3
+comm2_comm3: ; B->A
+ jb Flag_Motor_Dir_Rev, comm2_comm3_rev
+
+ clr IE_EA
+ C_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_B
+ A_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_C
+ ret
+
+comm2_comm3_rev: ; B->C
+ clr IE_EA
+ A_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_B
+ C_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_A
+ ret
+
+; Comm phase 3 to comm phase 4
+comm3_comm4: ; B->C
+ jb Flag_Motor_Dir_Rev, comm3_comm4_rev
+
+ clr IE_EA
+ A_Com_Fet_Off
+ C_Com_Fet_On
+ Set_Pwm_Phase_B ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_A
+ ret
+
+comm3_comm4_rev: ; B->A
+ clr IE_EA
+ C_Com_Fet_Off
+ A_Com_Fet_On
+ Set_Pwm_Phase_B ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_C
+ ret
+
+; Comm phase 4 to comm phase 5
+comm4_comm5: ; A->C
+ jb Flag_Motor_Dir_Rev, comm4_comm5_rev
+
+ clr IE_EA
+ B_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_A
+ C_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_B
+ ret
+
+comm4_comm5_rev: ; C->A
+ clr IE_EA
+ B_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_C
+ A_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_B
+ ret
+
+; Comm phase 5 to comm phase 6
+comm5_comm6: ; A->B
+ jb Flag_Motor_Dir_Rev, comm5_comm6_rev
+
+ clr IE_EA
+ C_Com_Fet_Off
+ B_Com_Fet_On
+ Set_Pwm_Phase_A ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_C
+ ret
+
+comm5_comm6_rev: ; C->B
+ clr IE_EA
+ A_Com_Fet_Off
+ B_Com_Fet_On
+ Set_Pwm_Phase_C ; Reapply power after a demag cut
+ setb IE_EA
+ Set_Comparator_Phase_A
+ ret
+
+; Comm phase 6 to comm phase 1
+comm6_comm1: ; C->B
+ jb Flag_Motor_Dir_Rev, comm6_comm1_rev
+
+ clr IE_EA
+ A_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_C
+ B_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_A
+ ret
+
+comm6_comm1_rev: ; A->B
+ clr IE_EA
+ C_Pwm_Fet_Off ; Turn off pwm FET (Necessary for EN/PWM driver)
+ Set_Pwm_Phase_A
+ B_Com_Fet_On ; Reapply power after a demag cut (Necessary for EN/PWM driver)
+ setb IE_EA
+ Set_Comparator_Phase_C
+ ret
diff --git a/src/Modules/DShot.asm b/src/Modules/DShot.asm
new file mode 100644
index 00000000..0001b0d6
--- /dev/null
+++ b/src/Modules/DShot.asm
@@ -0,0 +1,585 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; DShot
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Detect DShot RC pulse level
+;
+; Determine if RC pulse signal level is normal or inverted DShot. If inverted
+; DShot - we are using
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+detect_rcp_level:
+ mov A, #50 ; Must detect the same level 50 times (25 us)
+ mov C, RTX_BIT
+
+detect_rcp_level_read:
+ jc detect_rcp_level_read_check_high_to_low
+ jb RTX_BIT, detect_rcp_level ; Level changed from low to high - start over
+
+detect_rcp_level_read_check_high_to_low:
+ jnc detect_rcp_level_check_loop
+ jnb RTX_BIT, detect_rcp_level ; Level changed from high to low - start over
+
+detect_rcp_level_check_loop:
+ djnz ACC, detect_rcp_level_read
+
+ mov Flag_Rcp_DShot_Inverted, C
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Check DShot command
+;
+; Determine received DShot command and perform action if DShot command is not
+; zero:
+;
+; 1-5: Beacon beep
+;
+; All following commands need to be received 6 times in a row before action is
+; taken:
+;
+; 7: Set motor direction to normal
+; 8: Set motor direction to reverse
+; 9: Disable 3D mode
+; 10: Enable 3D mode
+; 12: Save settings
+; 13: Enable EDT (Extended DShot Telemetry)
+; 14: Disable EDT (Extended DShot Telemetry)
+; 20: Set motor direction to user programmed direction
+; 21: Set motor direction to reversed user programmed direction
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+dshot_cmd_check:
+ mov A, DShot_Cmd
+ jnz dshot_cmd_beeps_check
+ ret
+
+dshot_cmd_beeps_check:
+ mov Temp1, A
+ clr C
+ subb A, #6 ; Beacon beeps for command 1-5
+ jnc dshot_cmd_check_count
+
+ clr IE_EA ; Disable all interrupts
+ call switch_power_off ; Switch power off in case braking is set
+ call beacon_beep
+ call wait200ms ; Wait a bit for next beep
+ setb IE_EA ; Enable all interrupts
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_check_count:
+ ; Remaining commands must be received 6 times in a row
+ clr C
+ mov A, DShot_Cmd_Cnt
+ subb A, #6
+ jc dshot_cmd_exit_no_clear
+
+dshot_cmd_direction_normal:
+ ; Set motor spinning direction to normal
+ cjne Temp1, #CMD_DIRECTION_NORMAL, dshot_cmd_direction_reverse
+
+ clr Flag_Pgm_Dir_Rev
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_direction_reverse:
+ ; Set motor spinning direction to reversed
+ cjne Temp1, #CMD_DIRECTION_REVERSE, dshot_cmd_direction_bidir_off
+
+ setb Flag_Pgm_Dir_Rev
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_direction_bidir_off:
+ ; Set motor control mode to normal (not bidirectional)
+ cjne Temp1, #CMD_BIDIR_OFF, dshot_cmd_direction_bidir_on
+
+ ; 9: Set motor control mode to normal (not bidirectional)
+ clr Flag_Pgm_Bidir
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_direction_bidir_on:
+ ; Set motor control mode to bidirectional
+ cjne Temp1, #CMD_BIDIR_ON, dshot_cmd_extended_telemetry_enable
+
+ setb Flag_Pgm_Bidir
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_extended_telemetry_enable:
+ ; Enable extended telemetry
+ cjne Temp1, #CMD_EXTENDED_TELEMETRY_ENABLE, dshot_cmd_extended_telemetry_disable
+
+ mov Ext_Telemetry_L, #00h
+ mov Ext_Telemetry_H, #0Eh ; Send state/event 0 frame to signal telemetry enable
+
+ setb Flag_Ext_Tele
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_extended_telemetry_disable:
+ ; Disable extended telemetry
+ cjne Temp1, #CMD_EXTENDED_TELEMETRY_DISABLE, dshot_cmd_direction_user_normal
+
+ mov Ext_Telemetry_L, #0FFh
+ mov Ext_Telemetry_H, #0Eh ; Send state/event 0xff frame to signal telemetry disable
+
+ clr Flag_Ext_Tele
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_direction_user_normal:
+ ; Set motor spinning direction to user programmed direction
+ cjne Temp1, #CMD_DIRECTION_USER_NORMAL, dshot_cmd_direction_user_reverse
+
+ mov Temp2, #Pgm_Direction ; Read programmed direction
+ mov A, @Temp2
+ dec A
+ mov C, ACC.0 ; Set direction
+ mov Flag_Pgm_Dir_Rev, C
+
+ ; User reverse operation is off (used in turtle mode)
+ clr Flag_User_Reverse_Requested
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_direction_user_reverse: ; Temporary reverse
+ ; Set motor spinning direction to reverse of user programmed direction
+ cjne Temp1, #CMD_DIRECTION_USER_REVERSE, dshot_cmd_save_settings
+
+ mov Temp2, #Pgm_Direction ; Read programmed direction
+ mov A, @Temp2
+ dec A
+ mov C, ACC.0
+ cpl C ; Set reverse direction
+ mov Flag_Pgm_Dir_Rev, C
+
+ ; User reverse operation is on (used in turtle mode)
+ setb Flag_User_Reverse_Requested
+
+ sjmp dshot_cmd_exit
+
+dshot_cmd_save_settings:
+ cjne Temp1, #CMD_SAVE_SETTINGS, dshot_cmd_exit
+
+ clr A ; Set programmed direction from flags
+ mov C, Flag_Pgm_Dir_Rev
+ mov ACC.0, C
+ mov C, Flag_Pgm_Bidir
+ mov ACC.1, C
+ inc A
+ mov Temp2, #Pgm_Direction ; Store programmed direction
+ mov @Temp2, A
+
+ Unlock_Flash
+
+ call erase_and_store_all_in_eeprom
+
+ Lock_Flash
+
+ setb IE_EA
+
+dshot_cmd_exit:
+ mov DShot_Cmd, #0 ; Clear DShot command
+ mov DShot_Cmd_Cnt, #0 ; Clear Dshot command counter
+
+dshot_cmd_exit_no_clear:
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; DShot telemetry create packet
+;
+; Create DShot telemetry packet and prepare it for being sent
+; The routine is divided into 6 sections that can return early
+; in order to reduce commutation interference
+;
+; Requirements:
+; - Must NOT be called while Flag_Telemetry_Pending is set
+; - Must NOT write to Temp7, Temp8
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+dshot_tlm_create_packet:
+ push PSW
+ mov PSW, #10h ; Select register bank 2
+
+ Early_Return_Packet_Stage 0
+
+ ; If coded telemetry ready jump to telemetry ready
+ mov A, Ext_Telemetry_H
+ jnz dshot_tlm_ready
+
+ clr IE_EA
+ mov A, Comm_Period4x_L ; Read commutation period
+ mov Tlm_Data_H, Comm_Period4x_H
+ setb IE_EA
+
+ ; Calculate e-period (6 commutations) in microseconds
+ ; Comm_Period * 6 * 0.5 = Comm_Period4x * 3/4 (1/2 + 1/4)
+ mov C, Tlm_Data_H.0
+ rrc A
+ mov Temp2, A
+ mov C, Tlm_Data_H.1
+ rrc A
+ add A, Temp2
+ mov Temp3, A ; Comm_Period3x_L
+
+ mov A, Tlm_Data_H
+ rr A
+ clr ACC.7
+ mov Temp2, A
+ rr A
+ clr ACC.7
+ addc A, Temp2
+ mov Temp4, A ; Comm_Period3x_H
+
+ ; Timer2 ticks are ~489ns (not 500ns) - use approximation for better
+ ; accuracy:
+ ;
+ ; E-period = Comm_Period3x - 4 * Comm_Period4x_H
+
+ ; NOTE: For better performance assume Comm_Period4x_H < 64
+ ; (6-bit, above ~5k erpm). At lower speed result will be less precise.
+ mov A, Tlm_Data_H ; Comm_Period4x_H
+ rl A ; Multiply by 4
+ rl A
+ anl A, #0FCh
+ mov Temp5, A
+
+ clr C
+ mov A, Temp3 ; Comm_Period3x_L
+ subb A, Temp5
+ mov Tlm_Data_L, A
+ mov A, Temp4 ; Comm_Period3x_H
+ subb A, #0
+ mov Tlm_Data_H, A
+
+dshot_tlm_ready:
+ Early_Return_Packet_Stage 1
+
+ ; If extended telemetry ready jump to extended telemetry coded
+ mov A, Ext_Telemetry_H
+ jnz dshot_tlm_ext_coded
+
+ ; 12-bit encode telemetry data
+ mov A, Tlm_Data_H
+ jnz dshot_12bit_encode
+ mov A, Tlm_Data_L ; Already 12-bit
+ jnz dshot_tlm_12bit_encoded
+
+ ; If period is zero then reset to FFFFh (FFFh for 12-bit)
+ mov Tlm_Data_H, #0Fh
+ mov Tlm_Data_L, #0FFh
+ sjmp dshot_tlm_12bit_encoded
+
+dshot_tlm_ext_coded:
+ ; Move extended telemetry data to telemetry data to send
+ mov Tlm_Data_L, Ext_Telemetry_L
+ mov Tlm_Data_H, Ext_Telemetry_H
+ ; Clear extended telemetry data
+ mov Ext_Telemetry_H, #0
+
+dshot_tlm_12bit_encoded:
+ Early_Return_Packet_Stage 2
+ mov A, Tlm_Data_L
+
+ ; Compute inverted xor checksum (4-bit)
+ swap A
+ xrl A, Tlm_Data_L
+ xrl A, Tlm_Data_H
+ cpl A
+
+ ; GCR encode the telemetry data (16-bit)
+ mov Temp1, #Temp_Storage ; Store pulse timings in Temp_Storage
+ mov @Temp1, DShot_GCR_Pulse_Time_1 ; Final transition time
+
+ call dshot_gcr_encode ; GCR encode lowest 4-bit of A (store through Temp1)
+
+ Early_Return_Packet_Stage 3
+
+ mov A, Tlm_Data_L
+ call dshot_gcr_encode
+
+ Early_Return_Packet_Stage 4
+
+ mov A, Tlm_Data_L
+ swap A
+ call dshot_gcr_encode
+
+ Early_Return_Packet_Stage 5
+
+ mov A, Tlm_Data_H
+ call dshot_gcr_encode
+
+ inc Temp1
+ mov Temp7, #0 ; Reset current packet stage
+
+ pop PSW
+ setb Flag_Telemetry_Pending ; Mark that packet is ready to be sent
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; DShot 12-bit encode
+;
+; Encodes 16-bit e-period as a 12-bit value of the form:
+; where M SHL E ~ e-period [us]
+;
+; NOTE: Not callable to improve performance
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+dshot_12bit_encode:
+ ; Encode 16-bit e-period as a 12-bit value
+ jb ACC.7, dshot_12bit_7 ; ACC = Tlm_Data_H
+ jb ACC.6, dshot_12bit_6
+ jb ACC.5, dshot_12bit_5
+ jb ACC.4, dshot_12bit_4
+ jb ACC.3, dshot_12bit_3
+ jb ACC.2, dshot_12bit_2
+ jb ACC.1, dshot_12bit_1
+ mov A, Tlm_Data_L ; Already 12-bit (E=0)
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_7:
+ ;mov A, Tlm_Data_H
+ mov C, Tlm_Data_L.7
+ rlc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #0fh
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_6:
+ ;mov A, Tlm_Data_H
+ mov C, Tlm_Data_L.7
+ rlc A
+ mov C, Tlm_Data_L.6
+ rlc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #0dh
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_5:
+ ;mov A, Tlm_Data_H
+ mov C, Tlm_Data_L.7
+ rlc A
+ mov C, Tlm_Data_L.6
+ rlc A
+ mov C, Tlm_Data_L.5
+ rlc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #0bh
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_4:
+ mov A, Tlm_Data_L
+ anl A, #0f0h
+ clr Tlm_Data_H.4
+ orl A, Tlm_Data_H
+ swap A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #09h
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_3:
+ mov A, Tlm_Data_L
+ mov C, Tlm_Data_H.0
+ rrc A
+ mov C, Tlm_Data_H.1
+ rrc A
+ mov C, Tlm_Data_H.2
+ rrc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #07h
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_2:
+ mov A, Tlm_Data_L
+ mov C, Tlm_Data_H.0
+ rrc A
+ mov C, Tlm_Data_H.1
+ rrc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #05h
+ jmp dshot_tlm_12bit_encoded
+
+dshot_12bit_1:
+ mov A, Tlm_Data_L
+ mov C, Tlm_Data_H.0
+ rrc A
+ mov Tlm_Data_L, A
+ mov Tlm_Data_H, #03h
+ jmp dshot_tlm_12bit_encoded
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; DShot GCR encode
+;
+; GCR encode e-period data for DShot telemetry
+;
+; Input
+; - Temp1: Data pointer for storing pulse timings
+; - A: 4-bit value to GCR encode
+; - B: Time that must be added to transition
+;
+; Output
+; - B: Time remaining to be added to next transition
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+dshot_gcr_encode:
+ anl A, #0Fh
+ rl A ; Multiply by 2 to match jump offsets
+ mov DPTR, #dshot_gcr_encode_jump_table
+ jmp @A+DPTR
+
+dshot_gcr_encode_jump_table:
+ ajmp dshot_gcr_encode_0_11001
+ ajmp dshot_gcr_encode_1_11011
+ ajmp dshot_gcr_encode_2_10010
+ ajmp dshot_gcr_encode_3_10011
+ ajmp dshot_gcr_encode_4_11101
+ ajmp dshot_gcr_encode_5_10101
+ ajmp dshot_gcr_encode_6_10110
+ ajmp dshot_gcr_encode_7_10111
+ ajmp dshot_gcr_encode_8_11010
+ ajmp dshot_gcr_encode_9_01001
+ ajmp dshot_gcr_encode_A_01010
+ ajmp dshot_gcr_encode_B_01011
+ ajmp dshot_gcr_encode_C_11110
+ ajmp dshot_gcr_encode_D_01101
+ ajmp dshot_gcr_encode_E_01110
+ ajmp dshot_gcr_encode_F_01111
+
+; GCR encoding is ordered by least significant bit first,
+; and represented as pulse durations.
+dshot_gcr_encode_0_11001:
+ imov Temp1, DShot_GCR_Pulse_Time_3
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_1_11011:
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_2_10010:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_3
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_3_10011:
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_3
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_4_11101:
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_5_10101:
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_6_10110:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_7_10111:
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_8_11010:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_9_01001:
+ imov Temp1, DShot_GCR_Pulse_Time_3
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
+
+dshot_gcr_encode_A_01010:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
+
+dshot_gcr_encode_B_01011:
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
+
+dshot_gcr_encode_C_11110:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ ret
+
+dshot_gcr_encode_D_01101:
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
+
+dshot_gcr_encode_E_01110:
+ GCR_Add_Time Temp1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
+
+dshot_gcr_encode_F_01111:
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_1
+ imov Temp1, DShot_GCR_Pulse_Time_2
+ ret
diff --git a/src/Modules/Eeprom.asm b/src/Modules/Eeprom.asm
new file mode 100644
index 00000000..d99925f3
--- /dev/null
+++ b/src/Modules/Eeprom.asm
@@ -0,0 +1,293 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; ESC programming (EEPROM emulation)
+;
+; The BB EFM8 technically does not have a dedicated EEPROM but in Bluejay a
+; part of the flash space is dedicated to emulate an EEPROM. This is the space
+; that holds all the settings and is what the configurator reads/writes ( via
+; the bootloader).
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+ESC_LAYOUT_SIZE EQU 48
+MELODY_SIZE EQU 140
+
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Read all "EEPROM" parameters
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+read_all_eeprom_parameters:
+ ; Check initialized signature
+ mov DPTR, #Eep_Initialized_L
+ mov Temp1, #Bit_Access
+ call read_eeprom_byte
+ mov A, Bit_Access
+ cjne A, #055h, read_eeprom_store_defaults
+ inc DPTR ; Now Eep_Initialized_H
+ call read_eeprom_byte
+ mov A, Bit_Access
+ cjne A, #0AAh, read_eeprom_store_defaults
+ sjmp read_eeprom_read
+
+read_eeprom_store_defaults:
+ Unlock_Flash
+ call set_default_parameters
+ call erase_and_store_all_in_eeprom
+ Lock_Flash
+ sjmp read_eeprom_exit
+
+read_eeprom_read:
+ ; Read "EEPROM"
+ mov DPTR, #_Eep_Pgm_Gov_P_Gain
+ mov Temp1, #_Pgm_Gov_P_Gain
+ mov Temp4, #10 ; 10 parameters
+
+read_eeprom_block1:
+ call read_eeprom_byte
+ inc DPTR
+ inc Temp1
+ djnz Temp4, read_eeprom_block1
+
+ ; Read "EEPROM" after Eep_Initialized_x flags
+ ; Temp4 = EEPROM_B2_PARAMETERS_COUNT parameters: [_Eep_Enable_TX_Program - Eep_Pgm_Power_Rating]
+ mov DPTR, #_Eep_Enable_TX_Program
+ mov Temp1, #_Pgm_Enable_TX_Program
+ mov Temp4, #EEPROM_B2_PARAMETERS_COUNT
+
+read_eeprom_block2:
+ call read_eeprom_byte
+ inc DPTR
+ inc Temp1
+ djnz Temp4, read_eeprom_block2
+
+ ; Set pointer to uncritical area
+ mov DPTR, #Eep_Dummy
+
+read_eeprom_exit:
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Erase flash and store all parameter values in "EEPROM"
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+erase_and_store_all_in_eeprom:
+ clr IE_EA ; Disable interrupts
+ call read_esc_layout
+ call read_melody
+ call erase_flash
+
+ ; Store firmware main revision
+ mov DPTR, #Eep_FW_Main_Revision
+ mov A, #EEPROM_FW_MAIN_REVISION
+ call write_eeprom_byte_from_acc
+
+ ; Store firmware sub revision
+ inc DPTR
+ mov A, #EEPROM_FW_SUB_REVISION
+ call write_eeprom_byte_from_acc
+
+ ; Store layout revision
+ inc DPTR
+ mov A, #EEPROM_LAYOUT_REVISION
+ call write_eeprom_byte_from_acc
+
+ ; Write eeprom before Eep_Initialized_x flags
+ ; Temp4 = 10 parameters [_Eep_Pgm_Gov_P_Gain - Eep_Initialized_x]
+ mov DPTR, #_Eep_Pgm_Gov_P_Gain
+ mov Temp1, #_Pgm_Gov_P_Gain
+ mov Temp4, #10
+
+write_eeprom_block1:
+ call write_eeprom_byte
+ inc DPTR
+ inc Temp1
+ djnz Temp4, write_eeprom_block1
+
+ ; Write eeprom after Eep_Initialized_x flags
+ ; Temp4 = EEPROM_B2_PARAMETERS_COUNT parameters: [_Eep_Enable_TX_Program - Eep_Pgm_Power_Rating]
+ mov DPTR, #_Eep_Enable_TX_Program
+ mov Temp1, #_Pgm_Enable_TX_Program
+ mov Temp4, #EEPROM_B2_PARAMETERS_COUNT
+
+write_eeprom_block2:
+ call write_eeprom_byte
+ inc DPTR
+ inc Temp1
+ djnz Temp4, write_eeprom_block2
+
+ ; Now write tags, melogy and signature
+ call write_esc_layout
+ call write_melody
+ call write_eeprom_signature
+
+ ; Set pointer to uncritical area
+ mov DPTR, #Eep_Dummy
+
+ ; Allow the flash controller to settle data down
+ call wait200ms
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Read eeprom byte
+;
+; ASSERT:
+; - Target address in DPTR
+; - Destination address in Temp1
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+read_eeprom_byte:
+ clr A
+ movc A, @A+DPTR ; Read from flash
+ mov @Temp1, A
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Write eeprom byte
+;
+; ASSERT:
+; - Data in address given by Temp1
+; - Destination address in DPTR
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+write_eeprom_byte:
+ mov A, @Temp1
+
+; Shorthand if data is already in accumulator
+write_eeprom_byte_from_acc:
+ orl PSCTL, #01h ; Set the PSWE bit
+ anl PSCTL, #0FDh ; Clear the PSEE bit
+ mov Temp8, A
+ clr C
+ mov A, DPH ; Check that address is not in bootloader area
+ subb A, #BOOTLOADER_OFFSET
+ jc write_eeprom_byte_write
+ ret
+
+write_eeprom_byte_write:
+ mov A, Temp8
+
+ ; Attempt to unlock flash
+ mov FLKEY, Flash_Key_1 ; First key code
+ mov FLKEY, Flash_Key_2 ; Second key code
+
+ movx @DPTR, A ; Write to flash
+ anl PSCTL, #0FEh ; Clear the PSWE bit
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Erase flash (erases the flash segment used for "eeprom" variables)
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+erase_flash:
+ orl PSCTL, #02h ; Set the PSEE bit
+ orl PSCTL, #01h ; Set the PSWE bit
+
+ ; Attempt to unlock flash
+ mov FLKEY, Flash_Key_1 ; First key code
+ mov FLKEY, Flash_Key_2 ; Second key code
+
+ mov DPTR, #Eep_Initialized_L
+ movx @DPTR, A
+ anl PSCTL, #0FCh ; Clear the PSEE and PSWE bits
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Write eeprom signature
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+write_eeprom_signature:
+ mov DPTR, #Eep_Initialized_L
+ mov A, #055h
+ call write_eeprom_byte_from_acc
+
+ mov DPTR, #Eep_Initialized_H
+ mov A, #0AAh
+ call write_eeprom_byte_from_acc
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Read esc layout bytes from flash and store in temporary storage
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+read_esc_layout:
+ mov Temp3, #ESC_LAYOUT_SIZE ; Number of esc layout bytes
+ mov Temp2, #Temp_Storage ; Set RAM address
+ mov Temp1, #Bit_Access
+ mov DPTR, #Eep_ESC_Layout ; Set flash address
+read_esc_layout_byte:
+ call read_eeprom_byte
+ mov A, Bit_Access
+ mov @Temp2, A ; Write to RAM
+ inc Temp2
+ inc DPTR
+ djnz Temp3, read_esc_layout_byte
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Write all esc layout bytes from temporary storage and
+; store them in flash
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+write_esc_layout:
+ mov Temp3, #ESC_LAYOUT_SIZE ; Number of esc layout bytes
+ mov Temp2, #Temp_Storage ; Set RAM address
+ mov DPTR, #Eep_ESC_Layout ; Set flash address
+write_esc_layout_byte:
+ mov A, @Temp2 ; Read from RAM
+ call write_eeprom_byte_from_acc
+ inc Temp2
+ inc DPTR
+ djnz Temp3, write_esc_layout_byte
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Melody
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+; Read 140 bytes from "EEPROM" and store in external memory (XRAM)
+read_melody:
+ mov Temp3, #MELODY_SIZE ; Number of bytes
+ mov Temp2, #0 ; Set XRAM address
+ mov Temp1, #Bit_Access
+ mov DPTR, #Eep_Pgm_Beep_Melody ; Set flash address
+read_melody_byte:
+ call read_eeprom_byte
+ mov A, Bit_Access
+ movx @Temp2, A ; Write to XRAM
+ inc Temp2
+ inc DPTR
+ djnz Temp3, read_melody_byte
+ ret
+
+; Read 140 bytes from external memory (XRAM) and store them in "EEPROM"
+write_melody:
+ mov Temp3, #MELODY_SIZE ; Number of bytes
+ mov Temp2, #0 ; Set XRAM address
+ mov DPTR, #Eep_Pgm_Beep_Melody ; Set flash address
+write_melody_byte:
+ movx A, @Temp2 ; Read from XRAM
+ call write_eeprom_byte_from_acc
+ inc Temp2
+ inc DPTR
+ djnz Temp3, write_melody_byte
+ ret
diff --git a/src/Modules/Enums.asm b/src/Modules/Enums.asm
new file mode 100644
index 00000000..732c091c
--- /dev/null
+++ b/src/Modules/Enums.asm
@@ -0,0 +1,69 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2023 Chris Landa
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Enums
+;
+; Enumerations to make code more readable
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; MCU Types
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+ MCU_BB51 EQU 2
+ MCU_BB2 EQU 1
+ MCU_BB1 EQU 0
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; PWM frequency and resolution
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+ ; Frequency
+ PWM_96 EQU 2
+ PWM_48 EQU 1
+ PWM_24 EQU 0
+
+ ; Resolution
+ PWM_11_BIT EQU 3
+ PWM_10_BIT EQU 2
+ PWM_9_BIT EQU 1
+ PWM_8_BIT EQU 0
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; DSHOT Commands
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+ CMD_DIRECTION_USER_REVERSE EQU 21
+ CMD_DIRECTION_USER_NORMAL EQU 20
+ CMD_EXTENDED_TELEMETRY_DISABLE EQU 14
+ CMD_EXTENDED_TELEMETRY_ENABLE EQU 13
+ CMD_SAVE_SETTINGS EQU 12
+ CMD_BIDIR_ON EQU 10
+ CMD_BIDIR_OFF EQU 9
+ CMD_DIRECTION_REVERSE EQU 8
+ CMD_DIRECTION_NORMAL EQU 7
+ CMD_ESC_INFO EQU 6
+ CMD_BEEP_5 EQU 5
+ CMD_BEEP_4 EQU 4
+ CMD_BEEP_3 EQU 3
+ CMD_BEEP_2 EQU 2
+ CMD_BEEP_1 EQU 1
diff --git a/src/Modules/Fx.asm b/src/Modules/Fx.asm
new file mode 100644
index 00000000..4cba8831
--- /dev/null
+++ b/src/Modules/Fx.asm
@@ -0,0 +1,347 @@
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Misc utility functions
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Wait a number of milliseconds (Multiple entry points)
+;
+; Requirements:
+; - System clock should be set to 24MHz
+; - Interrupts should be disabled for precision
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+wait1ms:
+ mov Temp3, #0 ; Milliseconds (hi byte)
+ mov Temp2, #1 ; Milliseconds (lo byte)
+ sjmp wait_ms
+
+wait5ms:
+ mov Temp3, #0
+ mov Temp2, #5
+ sjmp wait_ms
+
+wait10ms:
+ mov Temp3, #0
+ mov Temp2, #10
+ sjmp wait_ms
+
+wait100ms:
+ mov Temp3, #0
+ mov Temp2, #100
+ sjmp wait_ms
+
+wait200ms:
+ mov Temp3, #0
+ mov Temp2, #200
+ sjmp wait_ms
+
+wait250ms:
+ mov Temp3, #0
+ mov Temp2, #250
+ sjmp wait_ms
+
+wait_ms:
+ inc Temp2 ; Increment for use with djnz
+ inc Temp3
+ sjmp wait_ms_start
+
+wait_ms_o: ; Outer loop
+ mov Temp1, #24
+
+wait_ms_m: ; Middle loop
+ mov A, #255
+ djnz ACC, $ ; Inner loop (41.6us - 1020 cycles)
+ djnz Temp1, wait_ms_m
+
+wait_ms_start:
+ djnz Temp2, wait_ms_o
+ djnz Temp3, wait_ms_o
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Beeper routines (Multiple entry points)
+;
+; Requirements:
+; - Interrupts must be disabled and FETs turned off
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+beep_f1:
+ mov Temp3, #66 ; Off wait loop length (Tone)
+ mov Temp4, #(3500 / 66) ; Number of beep pulses (Duration)
+ sjmp beep
+
+beep_f2:
+ mov Temp3, #45
+ mov Temp4, #(3500 / 45)
+ sjmp beep
+
+beep_f3:
+ mov Temp3, #38
+ mov Temp4, #(3500 / 38)
+ sjmp beep
+
+beep_f4:
+ mov Temp3, #25
+ mov Temp4, #(3500 / 25)
+ sjmp beep
+
+beep_f5:
+ mov Temp3, #20
+ mov Temp4, #(3500 / 20)
+ sjmp beep
+
+beep_f1_short:
+ mov Temp3, #66
+ mov Temp4, #(2000 / 66)
+ sjmp beep
+
+beep_f2_short:
+ mov Temp3, #45
+ mov Temp4, #(2000 / 45)
+ sjmp beep
+
+beep:
+ mov A, Beep_Strength
+ jnz beep_start ; Start if beep strength is not 0
+ ret
+
+beep_start:
+ mov Temp2, #2
+
+beep_on_off:
+ clr A
+ B_Com_Fet_Off ; B com FET off
+ djnz ACC, $ ; Allow some time after com FET is turned off
+ B_Pwm_Fet_On ; B pwm FET on (in order to charge the driver of the B com FET)
+ djnz ACC, $ ; Let the pwm FET be turned on a while
+ B_Pwm_Fet_Off ; B pwm FET off again
+ djnz ACC, $ ; Allow some time after pwm FET is turned off
+ B_Com_Fet_On ; B com FET on
+ djnz ACC, $ ; Allow some time after com FET is turned on
+
+ mov A, Temp2 ; Turn on pwm FET
+ jb ACC.0, beep_a_pwm_on
+ A_Pwm_Fet_On
+beep_a_pwm_on:
+ jnb ACC.0, beep_c_pwm_on
+ C_Pwm_Fet_On
+beep_c_pwm_on:
+
+ mov A, Beep_Strength ; On time according to beep strength
+ djnz ACC, $
+
+ mov A, Temp2 ; Turn off pwm FET
+ jb ACC.0, beep_a_pwm_off
+ A_Pwm_Fet_Off
+beep_a_pwm_off:
+ jnb ACC.0, beep_c_pwm_off
+ C_Pwm_Fet_Off
+beep_c_pwm_off:
+
+ mov A, #150 ; Off for 25 us
+ djnz ACC, $
+
+ djnz Temp2, beep_on_off ; Toggle next pwm FET
+
+ mov A, Temp3
+beep_off: ; Fets off loop
+ mov Temp1, #200
+ djnz Temp1, $
+ djnz ACC, beep_off ; Off time according to beep frequency
+
+ djnz Temp4, beep_start ; Number of beep pulses (duration)
+
+ B_Com_Fet_Off
+ ret
+
+; Beep sequences
+beep_signal_lost:
+ call beep_f1
+ call beep_f2
+ call beep_f3
+ ret
+
+beep_enter_bootloader:
+ call beep_f2_short
+ call beep_f1
+ ret
+
+beep_motor_stalled:
+ call beep_f3
+ call beep_f2
+ call beep_f1
+ ret
+
+beep_safety_no_arm:
+ call beep_f2_short
+ call beep_f1_short
+ ret
+
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Beacon beep
+;
+; Beep with beacon strength.
+;
+; Requirements:
+; - Interrupts must be disabled
+; - FETs must be turned off
+; - Beep tone 1-5 in Temp1
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+beacon_beep:
+ mov Temp2, #Pgm_Beacon_Strength ; Set beacon beep strength
+ mov Beep_Strength, @Temp2
+
+ cjne Temp1, #CMD_BEEP_1, beacon_beep2
+ call beep_f1
+ sjmp beacon_beep_exit
+
+beacon_beep2:
+ cjne Temp1, #CMD_BEEP_2, beacon_beep3
+ call beep_f2
+ sjmp beacon_beep_exit
+
+beacon_beep3:
+ cjne Temp1, #CMD_BEEP_3, beacon_beep4
+ call beep_f3
+ sjmp beacon_beep_exit
+
+beacon_beep4:
+ cjne Temp1, #CMD_BEEP_4, beacon_beep5
+ call beep_f4
+ sjmp beacon_beep_exit
+
+beacon_beep5:
+ call beep_f5
+
+beacon_beep_exit:
+ mov Temp2, #Pgm_Beep_Strength ; Set normal beep strength
+ mov Beep_Strength, @Temp2
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Play beep melody
+;
+; Plays a beep melody from eeprom storage
+;
+; A melody has 64 pairs of (item1, item2) - a total of 128 items.
+; the first 4 values of the 128 items are metadata
+; item2 - is the duration of each pulse of the musical note.
+; The lower the value, the higher the pitch.
+; item1 - if item2 is zero, it is the number of milliseconds of wait time, else
+; it is the number of pulses of item2.
+;
+; Requirements:
+; - Interrupts must be disabled
+; - FETs must be turned off
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+play_beep_melody:
+ mov DPTR, #(Eep_Pgm_Beep_Melody)
+ clr A
+ movc A, @A+DPTR
+ cpl A
+ jz play_beep_melody_exit ; If first byte is 255,skip startup melody (settings may be invalid)
+
+ mov Temp5, #62
+ mov DPTR, #(Eep_Pgm_Beep_Melody + 04h)
+
+play_beep_melody_loop:
+ ; Read current location at Eep_Pgm_Beep_Melody to Temp4 and increment DPTR. If the value is 0, no point trying to play this note
+ clr A
+ movc A, @A+DPTR
+ inc DPTR
+ mov Temp4, A
+ jz play_beep_melody_exit
+
+ ; Read current location at Eep_Pgm_Beep_Melody to Temp3. If the value zero, that means this is a silent note
+ clr A
+ movc A, @A+DPTR
+ mov Temp3, A
+ jz play_beep_melody_item_wait_ms
+ call beep
+ sjmp play_beep_melody_loop_next_item
+
+play_beep_melody_item_wait_ms:
+ mov A, Temp4
+ mov Temp2, A
+ mov Temp3, #0
+ call wait_ms
+
+play_beep_melody_loop_next_item:
+ inc DPTR
+ djnz Temp5, play_beep_melody_loop
+
+play_beep_melody_exit:
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; LED control
+;
+; Controls LEDs
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+led_control:
+ mov Temp1, #Pgm_LED_Control
+ mov A, @Temp1
+ mov Temp2, A
+ anl A, #03h
+ Set_LED_0
+ jnz led_0_done
+ Clear_LED_0
+
+led_0_done:
+ mov A, Temp2
+ anl A, #0Ch
+ Set_LED_1
+ jnz led_1_done
+ Clear_LED_1
+
+led_1_done:
+ mov A, Temp2
+ anl A, #030h
+ Set_LED_2
+ jnz led_2_done
+ Clear_LED_2
+
+led_2_done:
+ mov A, Temp2
+ anl A, #0C0h
+ Set_LED_3
+ jnz led_3_done
+ Clear_LED_3
+
+led_3_done:
+ ret
diff --git a/src/Modules/Isrs.asm b/src/Modules/Isrs.asm
new file mode 100644
index 00000000..e1ad05a2
--- /dev/null
+++ b/src/Modules/Isrs.asm
@@ -0,0 +1,669 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Interrupt handlers
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Timer0 interrupt routine (High priority)
+;
+; Generate DShot telemetry signal
+;
+; ASSERT:
+; - Must NOT be called while Flag_Telemetry_Pending is cleared
+; - Must NOT write to Temp7, Temp8
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+t0_int:
+ push PSW
+ mov PSW, #10h ; Select register bank 2 for this interrupt
+
+ dec Temp1
+ cjne Temp1, #(Temp_Storage - 1), t0_int_dshot_tlm_transition
+
+ inc Temp1 ; Set pointer to uncritical position
+
+ ; If last pulse is high, telemetry is finished,
+ ; otherwise wait for it to return to high
+ jb RTX_BIT, t0_int_dshot_tlm_finish
+
+t0_int_dshot_tlm_transition:
+ cpl RTX_BIT ; Invert signal level
+
+ mov TL0, @Temp1 ; Schedule next update
+
+ pop PSW
+ reti
+
+t0_int_dshot_tlm_finish:
+ ; Configure RTX_PIN for digital input
+ anl RTX_MDOUT, #(NOT (1 SHL RTX_PIN)) ; Set RTX_PIN output mode to open-drain
+ setb RTX_BIT ; Float high
+
+ clr IE_ET0 ; Disable Timer0 interrupts
+
+ mov CKCON0, Temp8 ; Restore regular DShot Timer0/1 clock settings
+ mov TMOD, #0AAh ; Timer0/1 gated by Int0/1
+
+ clr TCON_IE0 ; Clear Int0 pending flag
+ clr TCON_IE1 ; Clear Int1 pending flag
+
+ mov TL0, #0 ; Reset Timer0 count
+ setb IE_EX0 ; Enable Int0 interrupts
+ setb IE_EX1 ; Enable Int1 interrupts
+
+ clr Flag_Telemetry_Pending ; Mark that new telemetry packet may be created
+
+ pop PSW
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Timer1 interrupt routine
+;
+; Tasks:
+; - Decode DShot frame
+; - Process new throttle value and update PWM registers
+; - Schedule DShot telemetry
+;
+; NOTE: The ISR should be left as soon as possible. Instead of using loops,
+; often times more codespace is used since it saves valuable time.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+t1_int:
+ clr IE_EX0 ; Disable Int0 interrupts
+ clr TCON_TR1 ; Stop Timer1
+ mov TL1, DShot_Timer_Preset ; Reset sync timer
+
+ push PSW
+ mov PSW, #8h ; Select register bank 1 for this interrupt
+ push ACC
+ push B
+
+ ; NOTE: Interrupts are not explicitly disabled. Assume higher priority
+ ; interrupts (Int0, Timer0) to be disabled at this point.
+ clr TMR2CN0_TR2 ; Timer2 disabled
+ mov Temp2, TMR2L ; Read timer value
+ mov Temp3, TMR2H
+ setb TMR2CN0_TR2 ; Timer2 enabled
+
+ ; Check frame time length
+ clr C
+ mov A, Temp2
+ subb A, DShot_Frame_Start_L
+ mov Temp2, A
+ mov A, Temp3
+ subb A, DShot_Frame_Start_H
+ jnz t1_int_frame_fail ; Frame too long
+
+ clr C
+ mov A, Temp2
+ subb A, DShot_Frame_Length_Thr
+ jc t1_int_frame_fail ; Frame too short
+ subb A, DShot_Frame_Length_Thr
+ jnc t1_int_frame_fail ; Frame too long
+
+ ; Check that correct number (16) of pulses is received
+ cjne Temp1, #16, t1_int_frame_fail ; Read current pointer
+
+ ; Decode transmitted data
+ mov Temp1, #0 ; Set pointer
+ mov Temp2, DShot_Pwm_Thr ; DShot pulse width criteria
+ mov Temp6, #0 ; Reset timestamp
+
+ ; Decode DShot data MSB nibble (4bit).
+ ; Use more code space to save time (by not using loop)
+ Decode_DShot_2Bit Temp5, t1_int_frame_fail
+ Decode_DShot_2Bit Temp5, t1_int_frame_fail
+ sjmp t1_int_decode_lsb ; Continue with decoding LSB
+
+t1_int_frame_fail:
+ sjmp t1_int_outside_range
+
+t1_int_decode_lsb:
+ ; Decode DShot data LSB (8bit)
+ Decode_DShot_2Bit Temp4, t1_int_outside_range
+ Decode_DShot_2Bit Temp4, t1_int_outside_range
+ Decode_DShot_2Bit Temp4, t1_int_outside_range
+ Decode_DShot_2Bit Temp4, t1_int_outside_range
+ sjmp t1_int_decode_checksum
+
+t1_int_outside_range:
+ inc Rcp_Outside_Range_Cnt
+ mov A, Rcp_Outside_Range_Cnt
+ jnz t1_int_outside_range_check_limit
+ dec Rcp_Outside_Range_Cnt
+
+t1_int_outside_range_check_limit:
+ clr C
+ mov A, Rcp_Outside_Range_Cnt
+ subb A, #50 ; Allow a given number of outside pulses
+ jc t1_int_exit_timeout ; If outside limits - ignore first pulses
+
+ ; RC pulse signal has not timed out, but pulses are not recognized as DShot
+ setb Flag_Rcp_Stop ; Set pulse length to zero
+ mov DShot_Cmd, #0 ; Reset DShot command
+ mov DShot_Cmd_Cnt, #0 ; Reset Dshot command counter
+
+ ajmp t1_int_exit_no_tlm ; Exit without resetting timeout
+
+t1_int_exit_timeout:
+ mov Rcp_Timeout_Cntd, #10 ; Set timeout count
+ ajmp t1_int_exit_no_tlm
+
+t1_int_decode_checksum:
+ ; Decode DShot data checksum
+ Decode_DShot_2Bit Temp3, t1_int_outside_range
+ Decode_DShot_2Bit Temp3, t1_int_outside_range
+
+ ; XOR check (in inverted data, which is ok), only low nibble is considered
+ mov A, Temp4
+ swap A
+ xrl A, Temp4
+ xrl A, Temp5
+ xrl A, Temp3
+ jnb Flag_Rcp_DShot_Inverted, t1_int_decode_checksum_xor_check
+ cpl A ; Invert checksum if using inverted DShot
+
+t1_int_decode_checksum_xor_check:
+ anl A, #0Fh
+ jnz t1_int_outside_range ; XOR check
+
+ ; Invert DShot data and subtract 96 (still 12 bits)
+ clr C
+ mov A, Temp4
+ cpl A
+ mov Temp3, A ; Store in case it is a DShot command
+ subb A, #96
+ mov Temp4, A
+ mov A, Temp5
+ cpl A
+ anl A, #0Fh
+ subb A, #0
+ mov Temp5, A
+ jnc t1_int_normal_range
+
+ mov A, Temp3 ; Check for 0 or DShot command
+ mov Temp5, #0
+ mov Temp4, #0
+ jz t1_int_dshot_set_cmd ; Clear DShot command when RC pulse is zero
+
+ clr C ; We are in the special DShot range
+ rrc A ; Shift tlm bit into carry
+ jnc t1_int_dshot_clear_cmd ; Check for tlm bit set (if not telemetry,invalid command)
+
+ cjne A, DShot_Cmd, t1_int_dshot_set_cmd
+
+ inc DShot_Cmd_Cnt
+ sjmp t1_int_normal_range
+
+t1_int_dshot_clear_cmd:
+ clr A
+
+t1_int_dshot_set_cmd:
+ mov DShot_Cmd, A
+ mov DShot_Cmd_Cnt, #0
+
+t1_int_normal_range:
+ ; Check for bidirectional operation (0=stop, 96-2095->fwd, 2096-4095->rev)
+ jnb Flag_Pgm_Bidir, t1_int_not_bidir ; If not bidirectional operation - branch
+
+ ; Subtract 2000 (still 12 bits)
+ clr C
+ mov A, Temp4
+ subb A, #0D0h
+ mov B, A
+ mov A, Temp5
+ subb A, #07h
+ jc t1_int_bidir_set ; Is result is positive?
+ mov Temp4, B ; Yes - Use the subtracted value
+ mov Temp5, A
+
+t1_int_bidir_set:
+ jnb Flag_Pgm_Dir_Rev, t1_int_bidir_set_dir ; Check programmed direction
+ cpl C ; Reverse direction
+
+t1_int_bidir_set_dir:
+ mov Flag_Rcp_Dir_Rev, C ; Set rcp direction
+
+ ; Multiply throttle value by 2
+ clr C
+ rlca Temp4
+ rlca Temp5
+
+t1_int_not_bidir:
+ ; From here Temp5/Temp4 should be at most 3999 (4095-96)
+ mov A, Temp4 ; Divide by 16 (12 to 8-bit)
+ anl A, #0F0h
+ orl A, Temp5 ; NOTE: Assumes Temp5 to be 4-bit
+ swap A
+ mov B, #5 ; Divide by 5 (80 in total)
+ div AB
+ mov Temp3, A
+
+ ; Align to 11 bits
+ ;clr C ; NOTE: Cleared by div
+
+ rrca Temp5
+ mov A, Temp4
+ rrc A
+
+ ; From here Temp5/Temp4 should be at most 1999 (4095-96) / 2
+ ; Scale from 2000 to 2048
+ add A, Temp3
+ mov Temp4, A
+ mov A, Temp5
+ addc A, #0
+ mov Temp5, A
+ jnb ACC.3, t1_int_not_bidir_do_not_boost ; Limit to 11-bit maximum
+ mov Temp4, #0FFh
+ mov Temp5, #07h
+
+t1_int_not_bidir_do_not_boost:
+ ; Do not boost when changing direction in bidirectional mode
+ jb Flag_Motor_Started, t1_int_startup_boosted
+
+ ; Boost pwm during direct start
+ jnb Flag_Initial_Run_Phase, t1_int_startup_boosted
+
+ mov A, Temp5
+ jnz t1_int_stall_boost ; Already more power than minimum at startup
+
+ mov Temp2, #Pgm_Startup_Power_Min ; Read minimum startup power setting
+ mov B, @Temp2
+
+ clr C ; Set power to at least be minimum startup power
+ mov A, Temp4
+ subb A, B
+ jnc t1_int_stall_boost
+ mov Temp4, B
+
+t1_int_stall_boost:
+ mov A, Startup_Stall_Cnt ; Check stall count
+ jz t1_int_startup_boosted
+ mov B, #40 ; NOTE: Stall count should be less than 6
+ mul AB
+
+ add A, Temp4 ; Increase power when motor fails to start (stalling)
+ mov Temp4, A
+ mov A, Temp5
+ addc A, #0
+ mov Temp5, A
+ jnb ACC.3, t1_int_startup_boosted ; Limit to 11-bit maximum
+ mov Temp4, #0FFh
+ mov Temp5, #07h
+
+t1_int_startup_boosted:
+ ; Set 8-bit value
+ mov A, Temp4
+ anl A, #0F8h
+ orl A, Temp5 ; Assumes Temp5 to be 3-bit (11-bit RC pulse)
+ swap A
+ rl A
+ mov Temp2, A
+
+ jnz t1_int_rcp_not_zero
+
+ mov A, Temp4 ; Only set Rcp_Stop if all all 11 bits are zero
+ jnz t1_int_rcp_not_zero
+
+ setb Flag_Rcp_Stop
+ sjmp t1_int_zero_rcp_checked
+
+t1_int_rcp_not_zero:
+ mov Rcp_Stop_Cnt, #0 ; Reset RC pulse stop counter
+ clr Flag_Rcp_Stop ; Pulse ready
+
+t1_int_zero_rcp_checked:
+ ; Decrement outside range counter
+ mov A, Rcp_Outside_Range_Cnt
+ jz t1_int_zero_rcp_checked_set_limit
+ dec Rcp_Outside_Range_Cnt
+
+t1_int_zero_rcp_checked_set_limit:
+ ; Set pwm limit
+ clr C
+ mov A, Pwm_Limit ; Limit to the smallest
+ mov Temp6, A ; Store limit in Temp6
+ subb A, Pwm_Limit_By_Rpm
+ jc t1_int_zero_rcp_checked_check_limit
+ mov Temp6, Pwm_Limit_By_Rpm
+
+t1_int_zero_rcp_checked_check_limit:
+ ; Check against limit
+ clr C
+ mov A, Temp6
+ subb A, Temp2 ; 8-bit rc pulse
+ jnc t1_int_scale_pwm_resolution
+
+IF PWM_BITS_H == PWM_8_BIT ; 8-bit pwm
+ mov A, Temp6
+ mov Temp2, A
+ELSE
+ mov A, Temp6 ; Multiply limit by 8 for 11-bit pwm
+ mov B, #8
+ mul AB
+ mov Temp4, A
+ mov Temp5, B
+ENDIF
+
+t1_int_scale_pwm_resolution:
+; Scale pwm resolution and invert (duty cycle is defined inversely)
+IF PWM_BITS_H == PWM_11_BIT
+ mov A, Temp5
+ cpl A
+ anl A, #7
+ mov Temp3, A
+ mov A, Temp4
+ cpl A
+ mov Temp2, A
+ELSEIF PWM_BITS_H == PWM_10_BIT
+ clr C
+ mov A, Temp5
+ rrc A
+ cpl A
+ anl A, #3
+ mov Temp3, A
+ mov A, Temp4
+ rrc A
+ cpl A
+ mov Temp2, A
+ELSEIF PWM_BITS_H == PWM_9_BIT
+ mov B, Temp5
+ mov A, Temp4
+ mov C, B.0
+ rrc A
+ mov C, B.1
+ rrc A
+ cpl A
+ mov Temp2, A
+ mov A, Temp5
+ rr A
+ rr A
+ cpl A
+ anl A, #1
+ mov Temp3, A
+ELSEIF PWM_BITS_H == PWM_8_BIT
+ mov A, Temp2 ; Temp2 already 8-bit
+ cpl A
+ mov Temp2, A
+ mov Temp3, #0
+ENDIF
+
+; 11-bit effective dithering of 8/9/10-bit pwm
+IF PWM_BITS_H == PWM_8_BIT or PWM_BITS_H == PWM_9_BIT or PWM_BITS_H == PWM_10_BIT
+ 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
+
+ add A, #Dithering_Patterns
+ mov Temp1, A ; Reuse DShot pwm pointer since it is not currently in use.
+ mov A, @Temp1 ; Retrieve pattern
+ rl A ; Rotate pattern
+ mov @Temp1, A ; Store pattern
+
+ jnb ACC.0, t1_int_set_pwm ; Increment if bit is set
+
+ mov A, Temp2
+ add A, #1
+ mov Temp2, A
+ jnz t1_int_set_pwm
+IF PWM_BITS_H != PWM_8_BIT
+ mov A, Temp3
+ addc A, #0
+ mov Temp3, A
+ jnb ACC.PWM_BITS_H, t1_int_set_pwm
+ dec Temp3 ; Reset on overflow
+ENDIF
+ dec Temp2
+ENDIF
+
+t1_int_set_pwm:
+; Set PWM registers
+IF DEADTIME != 0
+ ; Subtract dead time from normal pwm and store as damping PWM
+ ; Damping PWM duty cycle will be higher because numbers are inverted
+ clr C
+ mov A, Temp2 ; Skew damping FET timing
+IF MCU_TYPE == MCU_BB1
+ subb A, #((DEADTIME + 1) SHR 1)
+ELSE
+ subb A, #(DEADTIME)
+ENDIF
+ mov Temp4, A
+ mov A, Temp3
+ subb A, #0
+ mov Temp5, A
+ jnc t1_int_max_braking_set
+
+ clr A ; Set to minimum value
+ mov Temp4, A
+ mov Temp5, A
+ sjmp t1_int_pwm_braking_set ; Max braking is already zero - branch
+
+t1_int_max_braking_set:
+ clr C
+ mov A, Temp4
+ subb A, Pwm_Braking_L
+ mov A, Temp5
+ subb A, Pwm_Braking_H ; Is braking pwm more than maximum allowed braking?
+ jc t1_int_pwm_braking_set ; Yes - branch
+ mov Temp4, Pwm_Braking_L ; No - set desired braking instead
+ mov Temp5, Pwm_Braking_H
+
+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 != 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 != PWM_8_BIT
+ Set_Damp_Pwm_Reg_L Temp4
+ Set_Damp_Pwm_Reg_H Temp5
+ELSE
+ Set_Damp_Pwm_Reg_H Temp4
+ENDIF
+ENDIF
+
+ mov Rcp_Timeout_Cntd, #10 ; Set timeout count
+
+ ; Prepare DShot telemetry
+ jnb Flag_Rcp_DShot_Inverted, t1_int_exit_no_tlm ; Only send telemetry for inverted DShot
+ jnb Flag_Telemetry_Pending, t1_int_exit_no_tlm ; Check if telemetry packet is ready
+
+ ; Prepare Timer0 for sending telemetry data
+ mov CKCON0, #01h ; Timer0 is system clock divided by 4
+ mov TMOD, #0A2h ; Timer0 runs free not gated by Int0
+
+ ; Configure RTX_PIN for digital output
+ setb RTX_BIT ; Default to high level
+ orl RTX_MDOUT, #(1 SHL RTX_PIN) ; Set output mode to push-pull
+
+ mov Temp1, #0 ; Set pointer to start
+
+ ; NOTE: Delay must be large enough to ensure port is ready for output
+ mov TL0, DShot_GCR_Start_Delay ; Telemetry will begin after this delay
+ clr TCON_TF0 ; Clear Timer0 overflow flag
+ setb IE_ET0 ; Enable Timer0 interrupts
+
+ sjmp t1_int_exit_no_int
+
+t1_int_exit_no_tlm:
+ mov Temp1, #0 ; Set pointer to start
+ mov TL0, #0 ; Reset Timer0
+ setb IE_EX0 ; Enable Int0 interrupts
+ setb IE_EX1 ; Enable Int1 interrupts
+
+t1_int_exit_no_int:
+ pop B ; Restore preserved registers
+ pop ACC
+ pop PSW
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Timer2 interrupt routine
+;
+; Happens every 32ms before arming and every 16 ms after arming (on 48MHz MCUs)
+;
+; Tasks:
+; - Update RC pulse timeout
+; - Update stop counters
+;
+; ASSERT:
+; - No PSW instructions
+; - Mp usage of Temp registers
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+t2_int:
+ push ACC ; Preserve registers
+ clr TMR2CN0_TF2H ; Clear interrupt flag
+ inc Timer2_X ; Increment extended byte
+ setb Flag_16ms_Elapsed ; Set 16ms elapsed flag
+
+ ; Check RC pulse timeout counter
+ mov A, Rcp_Timeout_Cntd ; RC pulse timeout count zero?
+ jnz t2_int_rcp_timeout_decrement
+ setb Flag_Rcp_Stop ; If zero -> Set rcp stop in case of timeout
+ sjmp t2_int_flag_rcp_stop_check
+
+t2_int_rcp_timeout_decrement:
+ dec Rcp_Timeout_Cntd ; No - decrement
+
+t2_int_flag_rcp_stop_check:
+ ; If rc pulse is not zero
+ jnb Flag_Rcp_Stop, t2_int_exit ; If rc pulse is not zero don't increment rcp stop counter
+
+ ; Increment Rcp_Stop_Cnt clipping it to 255
+ mov A, Rcp_Stop_Cnt
+ inc A
+ jz t2_int_exit
+ inc Rcp_Stop_Cnt
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Return from timer2
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+t2_int_exit:
+ pop ACC ; Restore preserved registers
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Timer3 interrupt routine
+;
+; Tasks:
+; - Commutation timing
+;
+; ASSERT:
+; - No PSW instructions
+; - No usage of Temp/Acc/B registers
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+t3_int:
+ clr IE_EA ; Disable all interrupts
+ anl EIE1, #7Fh ; Disable Timer3 interrupts
+ anl TMR3CN0, #07Fh ; Clear Timer3 interrupt flag
+ mov TMR3RLL, #0FAh ; Short delay to avoid re-loading regular delay
+ mov TMR3RLH, #0FFh
+ clr Flag_Timer3_Pending ; Flag that timer has wrapped
+ setb IE_EA ; Enable all interrupts
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Int0 interrupt routine (High priority)
+;
+; Tasks:
+; - Read and store DShot PWM signal for decoding
+;
+; ASSERT:
+; - No PSW instructions
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+int0_int:
+ push ACC
+ mov A, TL0 ; Read PWM for DShot immediately
+ mov TL1, DShot_Timer_Preset ; Reset sync timer
+
+ ; Temp1 in register bank 1 points to PWM timings
+ push PSW
+ mov PSW, #8h
+ movx @Temp1, A ; Store PWM in external memory
+ inc Temp1
+ pop PSW
+
+ pop ACC
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Int1 interrupt routine
+;
+; Tasks:
+; - RC pulse timing
+;
+; ASSERT:
+; - No PSW instructions
+; - No Temp/Acc registers
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+int1_int:
+ clr IE_EX1 ; Disable Int1 interrupts
+ setb TCON_TR1 ; Start Timer1
+
+ ; NOTE: Interrupts are not explicitly disabled, assuming higher priority
+ ; interrupts:
+ ; - Timer0 to be disabled at this point
+ ; - Int0 to not trigger for valid DShot signal
+ clr TMR2CN0_TR2 ; Timer2 disabled
+ mov DShot_Frame_Start_L, TMR2L ; Read timer value
+ mov DShot_Frame_Start_H, TMR2H
+ setb TMR2CN0_TR2 ; Timer2 enabled
+ reti
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; PCA interrupt routine
+;
+; Update pwm registers according to PCA clock signal
+;
+; Requirements: No PSW instructions or Temp registers
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+pca_int:
+ reti
diff --git a/src/Modules/Macros.asm b/src/Modules/Macros.asm
new file mode 100644
index 00000000..e4a9b5be
--- /dev/null
+++ b/src/Modules/Macros.asm
@@ -0,0 +1,350 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Macros
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+DSHOT_TLM_CLOCK EQU 24500000 ; 24.5MHz
+DSHOT_TLM_START_DELAY EQU -(5 * 25 / 4) ; Start telemetry after 5 us (~30 us after receiving DShot cmd)
+IF MCU_TYPE == MCU_BB1
+ DSHOT_TLM_PREDELAY EQU 9 ; 9 Timer0 ticks inherent delay
+ELSE
+ DSHOT_TLM_PREDELAY EQU 7 ; 7 Timer0 ticks inherent delay
+ENDIF
+
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ DSHOT_TLM_CLOCK_48 EQU 49000000 ; 49MHz
+ DSHOT_TLM_START_DELAY_48 EQU -(16 * 49 / 4) ; Start telemetry after 16 us (~30 us after receiving DShot cmd)
+ DSHOT_TLM_PREDELAY_48 EQU 11 ; 11 Timer0 ticks inherent delay
+ENDIF
+
+Set_DShot_Tlm_Bitrate MACRO rate
+ mov DShot_GCR_Pulse_Time_1, #(DSHOT_TLM_PREDELAY - (1 * DSHOT_TLM_CLOCK / 4 / rate))
+ mov DShot_GCR_Pulse_Time_2, #(DSHOT_TLM_PREDELAY - (2 * DSHOT_TLM_CLOCK / 4 / rate))
+ mov DShot_GCR_Pulse_Time_3, #(DSHOT_TLM_PREDELAY - (3 * DSHOT_TLM_CLOCK / 4 / rate))
+
+ mov DShot_GCR_Start_Delay, #DSHOT_TLM_START_DELAY
+
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ mov DShot_GCR_Pulse_Time_1_Tmp, #(DSHOT_TLM_PREDELAY_48 - (1 * DSHOT_TLM_CLOCK_48 / 4 / rate))
+ mov DShot_GCR_Pulse_Time_2_Tmp, #(DSHOT_TLM_PREDELAY_48 - (2 * DSHOT_TLM_CLOCK_48 / 4 / rate))
+ mov DShot_GCR_Pulse_Time_3_Tmp, #(DSHOT_TLM_PREDELAY_48 - (3 * DSHOT_TLM_CLOCK_48 / 4 / rate))
+ENDIF
+ENDM
+
+; DShot GCR encoding, adjust time by adding to previous item
+GCR_Add_Time MACRO reg
+ LOCAL gcr_add_time_set
+ mov B, @reg
+ mov A, DShot_GCR_Pulse_Time_2
+ cjne A, B, gcr_add_time_set
+ mov A, DShot_GCR_Pulse_Time_3
+gcr_add_time_set:
+ mov @reg, A
+ENDM
+
+; Prepare telemetry packet while waiting for Timer3 to wrap
+Wait_For_Timer3 MACRO
+ LOCAL wait_for_t3 done_waiting
+ jb Flag_Telemetry_Pending, wait_for_t3
+
+ jnb Flag_Timer3_Pending, done_waiting
+ call dshot_tlm_create_packet
+
+wait_for_t3:
+ jnb Flag_Timer3_Pending, done_waiting
+ sjmp wait_for_t3
+
+done_waiting:
+ENDM
+
+; Used for subdividing the DShot telemetry routine into chunks,
+; that will return if Timer3 has wrapped
+Early_Return_Packet_Stage MACRO num
+ Early_Return_Packet_Stage_ num, %(num + 1)
+ENDM
+
+Early_Return_Packet_Stage_ MACRO num next
+IF num > 0
+ inc Temp7 ; Increment current packet stage
+ jb Flag_Timer3_Pending, dshot_packet_stage_&num ; Return early if Timer3 has wrapped
+ pop PSW
+ ret
+dshot_packet_stage_&num:
+ENDIF
+IF num < 5
+ cjne Temp7, #(num), dshot_packet_stage_&next ; If this is not current stage,skip to next
+ENDIF
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Decode 2 bit of a DShot frame
+;
+; ASSERT:
+; - Temp1 is a pointer to the first pulse timestamp to be decoded
+; - Temp2 holds DShot pulse width mimimum criteria
+; - Temp6 holds the previous timestamp
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Decode 4 bit example with DShot 300:
+;
+; Temp1 | Value
+; -------------
+; 0 | 16
+; 1 | 49
+; 2 | 83
+; 3 | 102
+;
+; 1st call: (Temp1 = 0, Temp2 = 16, Temp6 = 0, dest = 0b00000000)
+; ---------------------------------------------------------------
+; Bit 1 (Temp1 = 0, dest = 0b00000000):
+; - New value: A = 16
+; - last timestamp (0) is subtracted: A = 16
+; - min pulse width criteria (16) is subtracted: A = 0
+; - carry not set - value valid
+; - A - Temp2 = 0 - 16 -> carry set
+; - rotate dest left through carry -> dest = 0b00000001
+;
+; Bit 2 (Temp1 = 1, dest = 0b00000001):
+; - New value: A = 49
+; - last timestamp (16) is subtracted: A = 33
+; - min pulse width criteria (16) is subtracted: A = 17
+; - carry not set - value valid
+; - A - Temp2 = 17 - 16 -> carry NOT set
+; - rotate dest left through carry -> dest = 0b00000010
+;
+; 2nd call: (Temp1 = 2, Temp2 = 16, Temp6 = 49, dest = 0b00000010)
+; ----------------------------------------------------------------
+; Bit 1 (Temp1 = 2, dest = 0b00000010):
+; - New value: A = 83
+; - last timestamp (49) is subtracted: A = 34
+; - min pulse width criteria (16) is subtracted: A = 18
+; - carry not set - value valid
+; - A - Temp2 = 18 - 16 -> carry NOT set
+; - rotate dest left through carry -> dest = 0b00000100
+;
+; Bit 2 (Temp3 = 2, dest = 0b00000100):
+; - New value: A = 102
+; - last timestamp (83) is subtracted: A = 19
+; - min pulse width criteria (16) is subtracted: A = 3
+; - carry not set - value valid
+; - A - Temp2 = 3 - 16 -> carry set
+; - rotate dest left through carry -> dest = 0b00001001
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Decode_DShot_2Bit MACRO dest, decode_fail
+ ; Bit 1
+ movx A, @Temp1
+ mov Temp7, A
+ clr C
+ subb A, Temp6 ; Subtract previous timestamp
+ clr C
+ subb A, Temp2
+ jc decode_fail ; Check that bit is longer than minimum
+
+ subb A, Temp2 ; Check if bit is zero or one
+ rlca dest ; Shift bit into data byte
+
+ ; Bit 2
+ inc Temp1 ; Next bit
+
+ movx A, @Temp1
+ mov Temp6, A ; Update timestamp
+ clr C
+ subb A, Temp7 ; Subtract previous timestamp
+ clr C
+ subb A, Temp2
+ jc decode_fail ; Check that bit is longer than minimum
+
+ subb A, Temp2 ; Check if bit is zero or one
+ rlca dest ; Shift bit into data byte
+
+ ; Increase Bit for the (potential) next run of this macro
+ inc Temp1 ; Next bit
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Compound instructions for convenience
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+xcha MACRO var1,var2 ; Exchange via accumulator
+ mov A, var1
+ xch A, var2
+ mov var1, A
+ENDM
+
+rrca MACRO var ; Rotate right through carry via accumulator
+ mov A, var
+ rrc A
+ mov var, A
+ENDM
+
+rlca MACRO var ; Rotate left through carry via accumulator
+ mov A, var
+ rlc A
+ mov var, A
+ENDM
+
+rla MACRO var ; Rotate left via accumulator
+ mov A, var
+ rl A
+ mov var, A
+ENDM
+
+ljc MACRO label ; Long jump if carry set
+ LOCAL skip
+ jnc skip
+ jmp label
+skip:
+ENDM
+
+ljz MACRO label ; Long jump if accumulator is zero
+ LOCAL skip
+ jnz skip
+ jmp label
+skip:
+ENDM
+
+imov MACRO reg,val ; Increment pointer register and move
+ inc reg
+ mov @reg, val ; Write value to memory address pointed to by register
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Division
+;
+; ih, il: input (hi byte, lo byte)
+; oh, ol: output (hi byte, lo byte)
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+; 16 bit Division by 16 (swap nibbles, mask and or)
+Divide_By_16 MACRO ih, il, oh, ol
+ mov A, ih
+ swap A
+ mov ol, A
+ anl A, #00Fh
+ mov oh, A
+ mov A, ol
+ anl A, #0F0h
+ mov ol, A
+ mov A, il
+ swap A
+ anl A, #00Fh
+ orl A, ol
+ mov ol, A
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; 12 bit Division by 16 (reduces 2 byte to a single)
+;
+; ASSERT:
+; - ih < 16
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Divide_12Bit_By_16 MACRO ih, il, ol
+ mov A, ih
+ swap A
+ mov ol, A
+ mov A, il
+ swap A
+ anl A, #00Fh
+ orl A, ol
+ mov ol, A
+ENDM
+
+; 16 bit Division by 8 (swap nibbles, shift, mask and or)
+Divide_By_8 MACRO ih, il, oh, ol
+ mov A, ih
+ swap A
+ rl A
+ mov ol, A
+ anl A, #01Fh
+ mov oh, A
+ mov A, ol
+ anl A, #0E0h
+ mov ol, A
+ mov A, il
+ swap A
+ rl A
+ anl A, #01Fh
+ orl A, ol
+ mov ol, A
+ENDM
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; 11 bit Division by 8 (swap nibbles, shift, mask and or)
+;
+; ASSERT:
+; - ih < 8
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+Divide_11Bit_By_8 MACRO ih, il, ol
+ mov A, ih
+ swap A
+ rl A
+ mov ol, A
+ mov A, il
+ swap A
+ rl A
+ anl A, #01Fh
+ orl A, ol
+ mov ol, A
+ENDM
+
+; 16 bit Division by 4 (divide through 2, two times) (14 cycles)
+; ih, oh and il, ol can be the same if inplace operation is fine
+Divide_By_4 MACRO ih, il, oh, ol
+ ; Hi: Division by 2 through right shift
+ clr C
+ mov A, ih
+ rrc A
+ mov oh, A
+
+ ; Lo: Division by 2 through carry (previous Hi right shift might have set it)
+ mov A, il
+ rrc A
+ mov ol, A
+
+ ; Hi: Division by 2 trough right shift
+ clr C
+ mov A, oh
+ rrc A
+ mov oh, A
+
+ ; Lo: Division by 2 through carry (previous Hi right shift might have set it)
+ mov A, ol
+ rrc A
+ mov ol, A
+ENDM
+
+Divide_16Bit_By_2 MACRO hi, lo
+ clr C
+ rrca hi
+ rrca lo
+ENDM
diff --git a/src/Modules/McuOffsets.asm b/src/Modules/McuOffsets.asm
new file mode 100644
index 00000000..29d83588
--- /dev/null
+++ b/src/Modules/McuOffsets.asm
@@ -0,0 +1,34 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2023 Chris Landa
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; MCU Offsets
+;
+; Offsets for memory space based on MCU
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+IF MCU_TYPE == MCU_BB51
+ BOOTLOADER_OFFSET EQU 0F0h
+ELSE
+ BOOTLOADER_OFFSET EQU 1Ch
+ENDIF
diff --git a/src/Modules/Power.asm b/src/Modules/Power.asm
new file mode 100644
index 00000000..91d9a628
--- /dev/null
+++ b/src/Modules/Power.asm
@@ -0,0 +1,123 @@
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Power control
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Switch power off
+;
+; Switches all FETs off
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+switch_power_off:
+ All_Pwm_Fets_Off ; Turn off all pwm FETs
+ All_Com_Fets_Off ; Turn off all commutation FETs
+ Set_All_Pwm_Phases_Off
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Set PWM limit low RPM
+;
+; Sets power limit for low RPM
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+set_pwm_limit:
+ jb Flag_High_Rpm, set_pwm_limit_high_rpm ; If high rpm,limit pwm by rpm instead
+
+ ;set_pwm_limit_low_rpm:
+ ; Set pwm limit
+ mov Temp1, #0FFh ; Default full power
+ jb Flag_Startup_Phase, set_pwm_limit_low_rpm_exit ; Exit if startup phase set
+
+ mov A, Low_Rpm_Pwr_Slope ; Check if low RPM power protection is enabled
+ jz set_pwm_limit_low_rpm_exit ; Exit if disabled (zero)
+
+ mov A, Comm_Period4x_H
+ jz set_pwm_limit_low_rpm_exit ; Avoid divide by zero
+
+ mov A, #255 ; Divide 255 by Comm_Period4x_H
+ jnb Flag_Initial_Run_Phase, set_pwm_limit_calculate ; More protection for initial run phase
+ mov A, #127
+
+set_pwm_limit_calculate:
+ mov B, Comm_Period4x_H
+ div AB
+ mov B, Low_Rpm_Pwr_Slope ; Multiply by slope
+ mul AB
+ mov Temp1, A ; Set new limit
+ xch A, B
+ jz set_pwm_limit_check_limit_to_min ; Limit to max
+
+ mov Temp1, #0FFh
+
+set_pwm_limit_check_limit_to_min:
+ clr C
+ mov A, Temp1 ; Limit to min
+ subb A, Pwm_Limit_Beg
+ jnc set_pwm_limit_low_rpm_exit
+
+ mov Temp1, Pwm_Limit_Beg
+
+set_pwm_limit_low_rpm_exit:
+ mov Pwm_Limit_By_Rpm, Temp1
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Set PWM limit high RPM
+;
+; Sets power limit for high RPM
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+set_pwm_limit_high_rpm:
+ clr C
+ mov A, Comm_Period4x_L
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ subb A, #0A0h ; Limit Comm_Period4x to 160,which is ~510k erpm
+ELSE
+ subb A, #0E4h ; Limit Comm_Period4x to 228,which is ~358k erpm
+ENDIF
+ mov A, Comm_Period4x_H
+ subb A, #00h
+
+ mov A, Pwm_Limit_By_Rpm
+ jnc set_pwm_limit_high_rpm_inc_limit
+
+ dec A
+ sjmp set_pwm_limit_high_rpm_store
+
+set_pwm_limit_high_rpm_inc_limit:
+ inc A
+
+set_pwm_limit_high_rpm_store:
+ jz set_pwm_limit_high_rpm_end
+ mov Pwm_Limit_By_Rpm, A
+
+set_pwm_limit_high_rpm_end:
+ ret
diff --git a/src/Modules/Scheduler.asm b/src/Modules/Scheduler.asm
new file mode 100644
index 00000000..4f17fac7
--- /dev/null
+++ b/src/Modules/Scheduler.asm
@@ -0,0 +1,370 @@
+;**** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Scheduler
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Divider of scheduler counter as a power of 2 number.
+;
+; This macro exists for convenience to easily change scheduler step time.
+; In the table below you can find valid values for this parameter.
+;
+; Value Step Cycle (8 steps) Zero crossing scan interference
+; ---------------------------------------------------------------------
+; 0 16ms 128ms Medium - High
+; 1 32ms 256ms Medium
+; 2 64ms 512ms Low
+; 3 128ms 1024ms Low
+; 4 256ms 2048ms Low
+; 5 512ms 4096ms Low
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+SCHEDULER_COUNTER_DIVIDER_POW2 EQU 3
+
+; Bitmask to get the remainder of dividing a number by 8
+MASK_REMAINDER_DIV8 EQU ((001h SHL SCHEDULER_COUNTER_DIVIDER_POW2) - 001h)
+
+; Mask to get the scheduler step
+MASK_STEP EQU (007h SHL SCHEDULER_COUNTER_DIVIDER_POW2)
+
+; Scheduler steps for steps 1, 3, 5
+STEP1_STATUS_FRAME EQU (001h SHL SCHEDULER_COUNTER_DIVIDER_POW2)
+STEP3_DEBUG1_FRAME EQU (003h SHL SCHEDULER_COUNTER_DIVIDER_POW2)
+STEP5_DEBUG2_FRAME EQU (005h SHL SCHEDULER_COUNTER_DIVIDER_POW2)
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Scheduler
+;
+; Each step is 128ms, a complete cycle is 1024ms (8 steps)
+;
+; ReqSch00: - Steps even [0, 2, 4, 6]
+; ReqSch01: - Update temperature setpoint on every even step
+; ReqSch02: - [TELEMETRY] Send demag metric frame
+; ReqSch03: - Steps odd [1, 3, 5, 7]
+; ReqSch04: - Update temperature PWM limit on every odd step
+; ReqSch06: - Case step 1
+; ReqSch07: - [TELEMETRY] Send status frame
+; ReqSch08: - Case step 3
+; ReqSch09: - [TELEMETRY] Send debug1 frame
+; ReqSch10: - Case step 5
+; ReqSch11: - [TELEMETRY] Send debug2 frame
+; ReqSch12: - Case step 7
+; ReqSch13: - [TELEMETRY] Send temperature frame
+; ReqSch14: - Start new ADC conversion after every odd step
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+scheduler_run:
+ ; Exit if not 16ms elapsed, otherwise start schedule
+ jbc Flag_16ms_Elapsed, scheduler_check_time
+ ret
+
+scheduler_check_time:
+ ; Increment Scheduler Counter
+ inc Scheduler_Counter
+
+ ; Scheduler cycle defined by SCHEDULER_COUNTER_DIVIDER_POW2
+ ; Get the remainder of dividing Scheduler_Counter
+ mov A, Scheduler_Counter
+ anl A, #MASK_REMAINDER_DIV8
+ jz scheduler_start
+
+ ; 128ms not fully elapsed so do nothing
+ ret
+
+scheduler_start:
+ ; Choose between odd or even steps
+ mov A, Scheduler_Counter
+ jb ACC.SCHEDULER_COUNTER_DIVIDER_POW2, scheduler_steps_odd
+
+scheduler_steps_even:
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; UPDATE TEMPERATURE SETPOINT
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+ ; Check temp protection: skip when protection is disabled
+ mov A, Temp_Prot_Limit
+ jz scheduler_steps_even_demag_metric_frame
+
+ ; Set setpoint maximum value
+ mov Temp_Pwm_Level_Setpoint, #255
+
+ ; Check TEMP_LIMIT in Base.inc and make calculations to understand temperature readings
+ ; Is temperature reading below 256?
+ ;
+ ; On BB1 & BB21:
+ ; - Using external voltage regulator and vdd 3.3V as ADC reference -> ADC 10bit value corresponding to about 25ºC
+ ; - Using external voltage regulator and internal 1.65V as ADC reference -> ADC 10bit value corresponding to about 0ºC
+ ;
+ ; On BB51:
+ ; - Using external voltage regulator and internal 1.65V as ADC reference -> ADC 10bit value corresponding to about 0ºC
+ mov A, ADC0H ; Load temp hi
+ jz scheduler_steps_even_demag_metric_frame ; Temperature below 25ºC (on 2S+ (BB1,BB2)) and below 0ºC (on 1S (BB1,BB21),BB51) do not update setpoint
+
+ mov A, ADC0L ; Load temp lo
+
+ clr C
+ subb A, Temp_Prot_Limit ; Is temperature below first limit?
+ jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
+
+ mov Temp_Pwm_Level_Setpoint, #200 ; No - update pwm limit (about 80%)
+
+ subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below second limit
+ jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
+
+ mov Temp_Pwm_Level_Setpoint, #150 ; No - update pwm limit (about 60%)
+
+ subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below third limit
+ jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
+
+ mov Temp_Pwm_Level_Setpoint, #100 ; No - update pwm limit (about 40% allowing landing)
+
+ subb A, #(TEMP_LIMIT_STEP / 2) ; Is temperature below final limit
+ jc scheduler_steps_even_demag_metric_frame ; Yes - Jump to next scheduler
+
+ mov Temp_Pwm_Level_Setpoint, #50 ; No - update pwm limit (about 20% forced landing)
+ ; Zero pwm cannot be set because of set_pwm_limit algo restrictions
+ ; Otherwise hard stuttering is produced
+
+
+scheduler_steps_even_demag_metric_frame:
+ ; Check if extended telemetry is enabled, otherwise we are done here.
+ jb Flag_Ext_Tele, scheduler_steps_even_demag_metric_frame_prepare
+
+ ; No more work to do
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; [TELEMETRY] SEND DEMAG METRIC FRAME
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_even_demag_metric_frame_prepare:
+ mov Ext_Telemetry_L, Demag_Detected_Metric ; Set telemetry low value to demag metric data
+ mov Ext_Telemetry_H, #0Ch ; Set telemetry high value to demag metric frame ID
+
+ ; No more work to do
+ ret
+
+scheduler_steps_odd:
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; UPDATE TEMPERATURE PWM LIMIT EVERY 256ms (ON ODD STEP)
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+ ; Check if temp protection is enabled, otherwise continue with odd step
+ mov A, Temp_Prot_Limit
+ jz scheduler_steps_odd_choose_step
+
+ ; PWM limit is updated one unit at a time to avoid abrupt PWM changes
+ ; resulting in current spikes, that may damage motor/ESC.
+ ; Compare pwm limit to setpoint
+ clr C
+ mov A, Pwm_Limit
+ subb A, Temp_Pwm_Level_Setpoint
+ jz scheduler_steps_odd_choose_step ; pwm limit == setpoint -> next
+ jc scheduler_steps_odd_temp_pwm_limit_inc ; pwm limit < setpoint -> increase pwm limit
+
+scheduler_steps_odd_temp_pwm_limit_dec:
+ ; Decrease pwm limit
+ dec Pwm_Limit
+
+ ; Continue with odd scheduler step selection
+ sjmp scheduler_steps_odd_choose_step
+
+scheduler_steps_odd_temp_pwm_limit_inc:
+ ; Increase pwm limit
+ inc Pwm_Limit
+
+; Run speciffic odd scheduler step
+scheduler_steps_odd_choose_step:
+ ; Check if extended telemetry is enabled, otherwise skip frame generation
+ jnb Flag_Ext_Tele, scheduler_steps_odd_restart_ADC
+
+ ; Get scheduler step
+ mov A, Scheduler_Counter
+ anl A, #MASK_STEP
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; [TELEMETRY] SEND STATUS FRAME
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_status_frame:
+ cjne A, #STEP1_STATUS_FRAME, scheduler_steps_odd_debug1_frame
+
+ ; if (Demag_Detected_Metric_Max >= 120)
+ ; stat.demagMetricMax = (Demag_Detected_Metric_Max - 120) / 9
+ ; else
+ ; stat.demagMetricMax = 0
+ clr C
+ mov A, Demag_Detected_Metric_Max
+ subb A, #120 ; 120: substract the minimum
+ jnc scheduler_steps_odd_status_frame_max_load
+ clr A
+ sjmp scheduler_steps_odd_status_frame_max_loaded
+
+scheduler_steps_odd_status_frame_max_load:
+ mov B, #9
+ div AB ; Ranges: [0 - 135] / 9 == [0 - 15]
+
+scheduler_steps_odd_status_frame_max_loaded:
+ ; Load flags
+ mov C, Flag_Demag_Notify
+ mov ACC.7, C
+ mov C, Flag_Desync_Notify
+ mov ACC.6, C
+ mov C, Flag_Stall_Notify
+ mov ACC.5, C
+
+ ; Data loaded clear flags
+ clr Flag_Demag_Notify
+ clr Flag_Desync_Notify
+ clr Flag_Stall_Notify
+
+ ; Load status frame
+ mov Ext_Telemetry_L, A ; Set telemetry low value to status data
+ mov Ext_Telemetry_H, #0Eh ; Set telemetry high value to status frame ID
+
+ ; Now restart ADC conversion
+ Restart_Adc
+
+ ; Nothing else to do
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; [TELEMETRY] SEND DEBUG1 FRAME
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_debug1_frame:
+ cjne A, #STEP3_DEBUG1_FRAME, scheduler_steps_odd_debug2_frame
+
+ ; Stub for debug 1
+ mov Ext_Telemetry_L, #088h ; Set telemetry low value
+ mov Ext_Telemetry_H, #08h ; Set telemetry high value to debug1 frame ID
+
+ ; Now restart ADC conversion
+ Restart_Adc
+
+ ; Nothing else to do
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; [TELEMETRY] SEND DEBUG2 FRAME
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_debug2_frame:
+ cjne A, #STEP5_DEBUG2_FRAME, scheduler_steps_odd_temperature_frame
+
+ ; Stub for debug 2
+ mov Ext_Telemetry_L, #0AAh ; Set telemetry low value
+ mov Ext_Telemetry_H, #0Ah ; Set telemetry high value to debug2 frame ID
+
+ ; Now restart ADC conversion
+ Restart_Adc
+
+ ; Nothing else to do
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; [TELEMETRY] SEND TEMPERATURE FRAME
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_temperature_frame:
+ ; If step is not 1, 3 or 5 it has to be 7, so cjmp is not necessary
+ ; cjne A, #STEP7_TEMPERATURE_FRAME, scheduler_steps_odd_restart_ADC
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Power rating only applies to BB21 because voltage references behave diferently
+; depending on an external voltage regulator is used or not.
+; For BB51 (MCU_TYPE == 2) 1s power rating code path is mandatory
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ mov Temp1, #Pgm_Power_Rating
+ cjne @Temp1, #01h, scheduler_steps_odd_temperature_frame_power_rating_2s
+ENDIF
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; ON BB51 and BB1, BB2 at 1S, all using internal 1.65V ADC reference
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_temperature_frame_power_rating_1s:
+ mov A, ADC0H
+ jnz scheduler_steps_odd_temperature_frame_pr1s_temperature_above_0
+
+scheduler_steps_odd_temperature_frame_pr1s_temperature_below_0:
+ ; If Hi Byte is not 0x01 we are definetly below 0, thus
+ ; clamp to 0.
+ clr A
+ sjmp scheduler_steps_odd_temperature_frame_temp_load
+
+scheduler_steps_odd_temperature_frame_pr1s_temperature_above_0:
+ ; Prepare extended telemetry temperature value for next telemetry transmission
+ ; On BB51 they hi byte is always 1 if the temperature is above 0ºC.
+ ; In fact the value is 0x0114 at 0ºC, thus we ignore the hi byte and normalize
+ ; the low byte to
+ mov A, ADC0L
+ subb A, #14h
+ sjmp scheduler_steps_odd_temperature_frame_temp_load
+
+scheduler_steps_odd_temperature_frame_power_rating_2s:
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; ON BB1, BB2 at more than 1S, using vdd V3.3 ADC reference
+;
+; Prepare extended telemetry temperature value for next telemetry transmission
+; Check value above or below 20ºC - this is an approximation ADCOH having a value
+; of 0x01 equals to around 22.5ºC.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+ mov A, ADC0H
+ jnz scheduler_steps_odd_temperature_frame_pr2s_temperature_above_20
+
+scheduler_steps_odd_temperature_frame_pr2s_temperature_below_20:
+ ; Value below 20ºC -> to code between 0-20
+ mov A, ADC0L
+ clr C
+ subb A, #(255 - 20)
+ jnc scheduler_steps_odd_temperature_frame_temp_load
+
+ ; Value below 0ºC -> clamp to 0
+ clr A
+ sjmp scheduler_steps_odd_temperature_frame_temp_load
+
+scheduler_steps_odd_temperature_frame_pr2s_temperature_above_20:
+ ; Value above 20ºC -> to code between 20-255
+ mov A, ADC0L ; This is an approximation: 9 ADC steps @10 Bit are 10 degrees
+ add A, #20
+
+scheduler_steps_odd_temperature_frame_temp_load:
+ mov Ext_Telemetry_L, A ; Set telemetry low value with temperature data
+ mov Ext_Telemetry_H, #02h ; Set telemetry high value on first repeated dshot coding partition
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; START NEW ADC CONVERSION
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+scheduler_steps_odd_restart_ADC:
+ ; Restart ADC conversion
+ Restart_Adc
+
+ ; Nothing else to do
+ ret
diff --git a/src/Modules/Settings.asm b/src/Modules/Settings.asm
new file mode 100644
index 00000000..69e8e701
--- /dev/null
+++ b/src/Modules/Settings.asm
@@ -0,0 +1,240 @@
+;**** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Settings
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+; Sets default programming parameters
+set_default_parameters:
+ mov Temp1, #_Pgm_Gov_P_Gain
+ mov @Temp1, #0FFh ; _Pgm_Gov_P_Gain
+ imov Temp1, #DEFAULT_PGM_STARTUP_POWER_MIN ; Pgm_Startup_Power_Min
+ imov Temp1, #DEFAULT_PGM_STARTUP_BEEP ; Pgm_Startup_Beep
+ imov Temp1, #DEFAULT_PGM_DITHERING ; Pgm_Dithering
+ 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_DIRECTION ; Pgm_Direction
+ imov Temp1, #0FFh ; _Pgm_Input_Pol
+
+ inc Temp1 ; Skip Initialized_L_Dummy
+ inc Temp1 ; Skip Initialized_H_Dummy
+
+ imov Temp1, #0FFh ; _Pgm_Enable_TX_Program
+ imov Temp1, #DEFAULT_PGM_BRAKING_STRENGTH ; Pgm_Braking_Strength
+ imov Temp1, #0FFh ; _Pgm_Gov_Setup_Target
+ imov Temp1, #0FFh ; _Pgm_Startup_Rpm
+ imov Temp1, #0FFh ; _Pgm_Startup_Accel
+ imov Temp1, #0FFh ; _Pgm_Volt_Comp
+ imov Temp1, #DEFAULT_PGM_COMM_TIMING ; Pgm_Comm_Timing
+ imov Temp1, #0FFh ; _Pgm_Damping_Force
+ imov Temp1, #0FFh ; _Pgm_Gov_Range
+ imov Temp1, #0FFh ; _Pgm_Startup_Method
+ imov Temp1, #0FFh ; _Pgm_Min_Throttle
+ imov Temp1, #0FFh ; _Pgm_Max_Throttle
+ imov Temp1, #DEFAULT_PGM_BEEP_STRENGTH ; Pgm_Beep_Strength
+ imov Temp1, #DEFAULT_PGM_BEACON_STRENGTH ; Pgm_Beacon_Strength
+ imov Temp1, #DEFAULT_PGM_BEACON_DELAY ; Pgm_Beacon_Delay
+ imov Temp1, #0FFh ; _Pgm_Throttle_Rate
+ imov Temp1, #DEFAULT_PGM_DEMAG_COMP ; Pgm_Demag_Comp
+ imov Temp1, #0FFh ; _Pgm_BEC_Voltage_High
+ imov Temp1, #0FFh ; _Pgm_Center_Throttle
+ imov Temp1, #0FFh ; _Pgm_Main_Spoolup_Time
+ imov Temp1, #DEFAULT_PGM_ENABLE_TEMP_PROT ; Pgm_Enable_Temp_Prot
+ imov Temp1, #0FFh ; _Pgm_Enable_Power_Prot
+ imov Temp1, #0FFh ; _Pgm_Enable_Pwm_Input
+ imov Temp1, #0FFh ; _Pgm_Pwm_Dither
+ imov Temp1, #DEFAULT_PGM_BRAKE_ON_STOP ; Pgm_Brake_On_Stop
+ imov Temp1, #DEFAULT_PGM_LED_CONTROL ; Pgm_LED_Control
+ imov Temp1, #DEFAULT_PGM_POWER_RATING ; Pgm_Power_Rating
+ imov Temp1, #DEFAULT_PGM_SAFETY_ARM ; Pgm_Safety_Arm
+
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Decode settings
+;
+; Decodes programmed settings and set RAM variables accordingly
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+decode_settings:
+ mov Temp1, #Pgm_Direction ; Load programmed direction
+ mov A, @Temp1
+ dec A
+ mov C, ACC.1 ; Set bidirectional mode
+ mov Flag_Pgm_Bidir, C
+ mov C, ACC.0 ; Set direction (Normal / Reversed)
+ mov Flag_Pgm_Dir_Rev, C
+
+ ; Check startup power
+ mov Temp1, #Pgm_Startup_Power_Max
+ mov A, #80 ; Limit to at most 80
+ subb A, @Temp1
+ jnc decode_settings_check_low_rpm
+ mov @Temp1, #80
+
+decode_settings_check_low_rpm:
+ ; Check low rpm power slope
+ mov Temp1, #Pgm_Rpm_Power_Slope
+ mov A, #13 ; Limit to at most 13
+ subb A, @Temp1
+ jnc decode_settings_set_low_rpm
+ mov @Temp1, #13
+
+decode_settings_set_low_rpm:
+ mov Low_Rpm_Pwr_Slope, @Temp1
+
+ ; Decode demag compensation
+ mov Temp1, #Pgm_Demag_Comp
+ mov A, @Temp1
+ mov Demag_Pwr_Off_Thresh, #255 ; Set default
+
+ cjne A, #2, decode_demag_high
+
+ mov Demag_Pwr_Off_Thresh, #160 ; Settings for demag comp low
+
+decode_demag_high:
+ cjne A, #3, decode_demag_done
+
+ mov Demag_Pwr_Off_Thresh, #130 ; Settings for demag comp high
+
+decode_demag_done:
+ ; Decode temperature protection limit
+ mov Temp_Prot_Limit, #0
+ mov Temp1, #Pgm_Enable_Temp_Prot
+ mov A, @Temp1
+ mov Temp2, A ; Temp2 = *Pgm_Enable_Temp_Prot;
+ jz decode_temp_done
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Power rating only applies to BB21 because voltage references behave diferently
+; depending on if an external voltage regulator is used or not.
+;
+; NOTE: For BB51, the 1s power rating code path is mandatory
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+IF MCU_TYPE == MCU_BB1 or MCU_TYPE == MCU_BB2
+ ; Read power rating and decode temperature limit
+ mov Temp1, #Pgm_Power_Rating
+ cjne @Temp1, #01h, decode_temp_use_adc_use_vdd_3V3_vref
+ENDIF
+
+; Set A to temperature limit depending on power rating
+decode_temp_use_adc_use_internal_1V65_vref:
+ mov A, #(TEMP_LIMIT_1S - TEMP_LIMIT_STEP)
+ sjmp decode_temp_step
+decode_temp_use_adc_use_vdd_3V3_vref:
+ mov A, #(TEMP_LIMIT_2S - TEMP_LIMIT_STEP)
+
+; Increase A while Temp2-- != 0;
+decode_temp_step:
+ add A, #TEMP_LIMIT_STEP
+ djnz Temp2, decode_temp_step
+
+; Set Temp_Prot_Limit to the temperature limit calculated in A
+decode_temp_done:
+ mov Temp_Prot_Limit, A
+
+ 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
+ mov A, @Temp1
+IF PWM_BITS_H == PWM_11_BIT ; Scale braking strength to pwm resolution
+ ; Note: Added for completeness
+ ; 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 == PWM_10_BIT
+ rl A
+ rl A
+ mov Temp2, A
+ anl A, #03h
+ mov Pwm_Braking_H, A
+ mov A, Temp2
+ anl A, #0FCh
+ mov Pwm_Braking_L, A
+ELSEIF PWM_BITS_H == PWM_9_BIT
+ rl A
+ mov Temp2, A
+ anl A, #01h
+ mov Pwm_Braking_H, A
+ mov A, Temp2
+ anl A, #0FEh
+ mov Pwm_Braking_L, A
+ELSEIF PWM_BITS_H == PWM_8_BIT
+ 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
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Dithering
+;
+; Depending on resolution, different dithering patterns are available.
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+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
+
+IF PWM_BITS_H == PWM_10_BIT ; 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 == PWM_9_BIT
+ 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 == PWM_8_BIT
+ mov Temp1, #Dithering_Patterns ; 3-bit dithering (8-bit to 11-bit)
+ mov @Temp1, #00h ; 00000000
+ imov Temp1, #01h ; 00000001
+ imov Temp1, #11h ; 00010001
+ imov Temp1, #25h ; 00100101
+ imov Temp1, #55h ; 01010101
+ imov Temp1, #5Bh ; 01011011
+ imov Temp1, #77h ; 01110111
+ imov Temp1, #7fh ; 01111111
+ENDIF
+ ret
diff --git a/src/Modules/Timing.asm b/src/Modules/Timing.asm
new file mode 100644
index 00000000..d12dea68
--- /dev/null
+++ b/src/Modules/Timing.asm
@@ -0,0 +1,859 @@
+;**** **** **** **** ****
+;
+; Bluejay digital ESC firmware for controlling brushless motors in multirotors
+;
+; Copyleft 2022-2023 Daniel Mosquera
+; Copyright 2020-2022 Mathias Rasmussen
+; Copyright 2011-2017 Steffen Skaug
+;
+; This file is part of Bluejay.
+;
+; Bluejay is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; Bluejay is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Bluejay. If not, see .
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Timing
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Initialize timing
+;
+; Part of initialization before motor start
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+initialize_timing:
+ ; Initialize commutation period to 7.5ms (~1330 erpm)
+ mov Comm_Period4x_L, #00h
+ mov Comm_Period4x_H, #0F0h
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Calculate next commutation period
+;
+; Measure the duration of current commutation period,
+; and update Comm_Period4x by averaging a fraction of it.
+;
+; Called immediately after each commutation
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+calc_next_comm_period:
+ ; Read commutation time
+ clr IE_EA ; Disable all interrupts
+ clr TMR2CN0_TR2 ; Disable Timer2
+ mov Temp1, TMR2L ; Load Timer2 value
+ mov Temp2, TMR2H
+ mov Temp3, Timer2_X
+ jnb TMR2CN0_TF2H,calc_next_comm_period_enable_timer2 ; Check if interrupt is pending
+ inc Temp3 ; If it is pending,then timer has already wrapped
+
+calc_next_comm_period_enable_timer2:
+ setb TMR2CN0_TR2 ; Timer2 enabled
+ setb IE_EA
+
+; Divide time by 2 on 48MHz
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ clr C
+ rrca Temp3
+ rrca Temp2
+ rrca Temp1
+ENDIF
+
+ jb Flag_Startup_Phase, calc_next_comm_startup
+
+ ; Calculate this commutation time
+ clr C
+ mov A, Temp1
+ subb A, Prev_Comm_L ; Calculate the new commutation time
+ mov Prev_Comm_L, Temp1 ; Save timestamp as previous commutation
+ mov Temp1, A ; Store commutation period in Temp1 (lo byte)
+ mov A, Temp2
+ subb A, Prev_Comm_H
+ mov Prev_Comm_H, Temp2 ; Save timestamp as previous commutation
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ anl A, #7Fh
+ENDIF
+ mov Temp2, A ; Store commutation period in Temp2 (hi byte)
+
+ jnb Flag_High_Rpm, calc_next_comm_normal ; Branch normal RPM
+ ajmp calc_next_comm_period_fast ; Branch high RPM
+
+calc_next_comm_startup:
+ ; Calculate this commutation time
+ mov Temp4, Prev_Comm_L
+ mov Temp5, Prev_Comm_H
+ mov Temp6, Prev_Comm_X
+ mov Prev_Comm_L, Temp1 ; Store timestamp as previous commutation
+ mov Prev_Comm_H, Temp2
+ mov Prev_Comm_X, Temp3 ; Store extended timestamp as previous commutation
+
+ clr C
+ mov A, Temp1
+ subb A, Temp4 ; Calculate the new commutation time
+ mov A, Temp2
+ subb A, Temp5
+ mov A, Temp3
+ subb A, Temp6 ; Calculate the new extended commutation time
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ anl A, #7Fh
+ENDIF
+ jz calc_next_comm_startup_no_X
+
+ ; Extended byte is not zero, so commutation time is above 0xFFFF
+ mov Comm_Period4x_L, #0FFh
+ mov Comm_Period4x_H, #0FFh
+ ajmp calc_next_comm_done
+
+calc_next_comm_startup_no_X:
+ ; Extended byte = 0, so commutation time fits within two bytes
+ mov Temp7, Prev_Prev_Comm_L
+ mov Temp8, Prev_Prev_Comm_H
+ mov Prev_Prev_Comm_L, Temp4
+ mov Prev_Prev_Comm_H, Temp5
+
+ ; Calculate the new commutation time based upon the two last commutations (to reduce sensitivity to offset)
+ clr C
+ mov A, Temp1
+ subb A, Temp7
+ mov Temp1, A
+ mov A, Temp2
+ subb A, Temp8
+ mov Temp2, A
+
+ mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
+ mov Temp4, Comm_Period4x_H
+
+ sjmp calc_next_comm_div_4_1
+
+calc_next_comm_normal:
+ ; Prepare averaging by dividing Comm_Period4x and current commutation period (Temp2/1) according to speed.
+ mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
+ mov Temp4, Comm_Period4x_H
+
+ clr C
+ mov A, Temp4
+
+ subb A, #4 ; Is Comm_Period4x_H below 4? (above ~80k erpm)
+ jc calc_next_comm_div_16_4 ; Yes - Use averaging for high speeds
+
+ subb A, #4 ; Is Comm_Period4x_H below 8? (above ~40k erpm)
+ jc calc_next_comm_div_8_2 ; Yes - Use averaging for low speeds
+
+ ; No - Use averaging for even lower speeds
+
+ ; Do not average very fast during initial run
+ jb Flag_Initial_Run_Phase, calc_next_comm_div_8_2_slow
+
+; Update Comm_Period4x from 1 new commutation period
+calc_next_comm_div_4_1:
+ ; Divide Temp4/3 by 4 and store in Temp6/5
+ Divide_By_4 Temp4, Temp3, Temp6, Temp5
+
+ sjmp calc_next_comm_average_and_update
+
+; Update Comm_Period4x from 1/2 new commutation period
+calc_next_comm_div_8_2:
+ ; Divide Temp4/3 by 8 and store in Temp5
+ Divide_11Bit_By_8 Temp4, Temp3, Temp5
+ mov Temp6, #0
+
+ Divide_16Bit_By_2 Temp2, Temp1
+
+ sjmp calc_next_comm_average_and_update
+
+; Update Comm_Period4x from 1/2 new commutation period
+calc_next_comm_div_8_2_slow:
+ ; Divide Temp4/3 by 8 and store in Temp6/5
+ Divide_By_8 Temp4, Temp3, Temp6, Temp5
+
+ Divide_16Bit_By_2 Temp2, Temp1
+
+ sjmp calc_next_comm_average_and_update
+
+; Update Comm_Period4x from 1/4 new commutation period
+calc_next_comm_div_16_4:
+ ; Divide Temp4/3 by 16 and store in Temp5
+ Divide_12Bit_By_16 Temp4, Temp3, Temp5
+ mov Temp6, #0
+
+ ; Divide Temp2/1 by 4 and store in Temp2/1
+ Divide_By_4 Temp2, Temp1, Temp2, Temp1
+
+calc_next_comm_average_and_update:
+ ; Comm_Period4x = Comm_Period4x - (Comm_Period4x / (16, 8 or 4)) + (Comm_Period / (4, 2 or 1))
+
+ ; Temp6/5: Comm_Period4x divided by (16, 8 or 4)
+ clr C ; Subtract a fraction
+ mov A, Temp3 ; Comm_Period4x_L
+ subb A, Temp5
+ mov Temp3, A
+ mov A, Temp4 ; Comm_Period4x_H
+ subb A, Temp6
+ mov Temp4, A
+
+ ; Temp2/1: This commutation period divided by (4, 2 or 1)
+ mov A, Temp3 ; Add the divided new time
+ add A, Temp1
+ mov Comm_Period4x_L, A
+ mov A, Temp4
+ addc A, Temp2
+ mov Comm_Period4x_H, A
+
+ jnc calc_next_comm_done ; Is period larger than 0xffff?
+ mov Comm_Period4x_L, #0FFh ; Yes - Set commutation period registers to very slow timing (0xffff)
+ mov Comm_Period4x_H, #0FFh
+
+calc_next_comm_done:
+ clr C
+ mov A, Comm_Period4x_H
+ subb A, #2 ; Is Comm_Period4x_H below 2? (above ~160k erpm)
+ jnc calc_next_comm_15deg
+ setb Flag_High_Rpm ; Yes - Set high rpm flag
+
+calc_next_comm_15deg:
+ ; Commutation period: 360 deg / 6 runs = 60 deg
+ ; 60 deg / 4 = 15 deg
+
+ ; Load current commutation timing and compute 15 deg timing
+ ; Divide Comm_Period4x by 16 (Comm_Period1x divided by 4) and store in Temp4/3
+ Divide_By_16 Comm_Period4x_H, Comm_Period4x_L, Temp4, Temp3
+
+ ; Subtract timing reduction
+ clr C
+ mov A, Temp3
+ subb A, #2 ; Set timing reduction
+ mov Temp3, A
+ mov A, Temp4
+ subb A, #0
+ mov Temp4, A
+
+ jc calc_next_comm_15deg_set_min ; Check that result is still positive
+ jnz calc_next_comm_period_exit ; Check that result is still above minimum
+ mov A, Temp3
+ jnz calc_next_comm_period_exit
+
+calc_next_comm_15deg_set_min:
+ mov Temp3, #1 ; Set minimum waiting time (Timers cannot wait for a delay of 0)
+ mov Temp4, #0
+
+ sjmp calc_next_comm_period_exit
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Calculate next commutation period (fast)
+; Fast calculation (Comm_Period4x_H less than 2)
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+calc_next_comm_period_fast:
+ ; Calculate new commutation time
+ mov Temp3, Comm_Period4x_L ; Comm_Period4x holds the time of 4 commutations
+ mov Temp4, Comm_Period4x_H
+
+ ; Divide by 16 and store in Temp5
+ Divide_12Bit_By_16 Temp4, Temp3, Temp5
+
+ clr C
+ mov A, Temp3 ; Subtract a fraction
+ subb A, Temp5
+ mov Temp3, A
+ mov A, Temp4
+ subb A, #0
+ mov Temp4, A
+
+ ; NOTE: Temp2 is assumed to be zero (approx. Comm_Period4x_H / 4)
+ mov A, Temp1 ; Divide by 4
+ rr A
+ rr A
+ anl A, #03Fh
+
+ add A, Temp3 ; Add the divided new time
+ mov Temp3, A
+ mov A, Temp4
+ addc A, #0
+ mov Temp4, A
+
+ mov Comm_Period4x_L, Temp3 ; Store Comm_Period4x
+ mov Comm_Period4x_H, Temp4
+
+ clr C
+ subb A, #2 ; Is Comm_Period4x_H 2 or more? (below ~160k erpm)
+ jc calc_next_comm_period_fast_div_comm_perio4x_by_16
+ clr Flag_High_Rpm ; Yes - Clear high rpm bit
+
+calc_next_comm_period_fast_div_comm_perio4x_by_16:
+ mov A, Temp4 ; Divide Comm_Period4x by 16 and store in Temp4/3
+ swap A
+ mov Temp7, A
+ mov Temp4, #0 ; Clear waiting time high byte
+ mov A, Temp3
+ swap A
+ anl A, #0Fh
+ orl A, Temp7
+ clr C
+ subb A, #2 ; Timing reduction
+ mov Temp3, A
+ jc calc_next_comm_fast_set_min ; Check that result is still positive
+ jnz calc_next_comm_period_exit ; Check that result is still above minimum
+
+calc_next_comm_fast_set_min:
+ mov Temp3, #1 ; Set minimum waiting time (Timers cannot wait for a delay of 0)
+
+calc_next_comm_period_exit:
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Wait advance timing
+;
+; Waits for the advance timing to elapse
+;
+; NOTE: Be VERY careful if using temp registers. They are passed over this routine
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+wait_advance_timing:
+ ; If it has not already, we wait here for the Wt_Adv_Start_ delay to elapse.
+ Wait_For_Timer3
+
+ ; At this point Timer3 has (already) wrapped and been reloaded with the Wt_Zc_Scan_Start_ delay.
+ ; In case this delay has also elapsed, Timer3 has been reloaded with a short delay any number of times.
+ ; - The interrupt flag is set and the pending flag will clear immediately after enabling the interrupt.
+ mov TMR3RLL, Wt_ZC_Tout_Start_L ; Setup next wait time
+ mov TMR3RLH, Wt_ZC_Tout_Start_H
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Calculate new wait times
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+calc_new_wait_times:
+ mov Temp1, #Pgm_Comm_Timing ; Load commutation timing setting
+ mov A, @Temp1
+ mov Temp8, A ; Store in Temp8
+
+ clr C
+ clr A
+ subb A, Temp3 ; Negate
+ mov Temp1, A
+ clr A
+ subb A, Temp4
+ mov Temp2, A
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ clr C
+ rlca Temp1 ; Multiply by 2
+ rlca Temp2
+ENDIF
+
+ ; Temp2/1 = 15deg Timer2 period
+ jb Flag_High_Rpm, calc_new_wait_times_fast ; Branch if high rpm
+
+ ; Load programmed commutation timing
+ jnb Flag_Startup_Phase, adjust_comm_timing
+
+ mov Temp8, #3 ; Set dedicated timing during startup
+ sjmp load_comm_timing_done
+
+adjust_comm_timing:
+ ; Adjust commutation timing according to demag metric
+ clr C
+ mov A, Demag_Detected_Metric ; Check demag metric
+ subb A, #130
+ jc load_comm_timing_done
+
+ inc Temp8 ; Increase timing (if metric 130 or above)
+
+ subb A, #30
+ jc adjust_comm_timing_limit_to_max
+
+ inc Temp8 ; Increase timing again (if metric 160 or above)
+
+adjust_comm_timing_limit_to_max:
+ clr C
+ mov A, Temp8 ; Limit timing to max
+ subb A, #6
+ jc load_comm_timing_done
+
+ mov Temp8, #5 ; Set timing to max (if timing 6 or above)
+
+load_comm_timing_done:
+ mov A, Temp1 ; Copy values
+ mov Temp3, A
+ mov A, Temp2
+ mov Temp4, A
+
+ setb C ; Negative numbers - set carry
+ mov A, Temp2 ; Store 7.5deg in Temp5/6 (15deg / 2)
+ rrc A
+ mov Temp6, A
+ mov A, Temp1
+ rrc A
+ mov Temp5, A
+
+ mov Wt_Zc_Scan_Start_L, Temp5 ; Set 7.5deg time for zero cross scan delay
+ mov Wt_Zc_Scan_Start_H, Temp6
+ mov Wt_Zc_Tout_Start_L, Temp1 ; Set 15deg time for zero cross scan timeout
+ mov Wt_Zc_Tout_Start_H, Temp2
+
+ clr C
+ mov A, Temp8 ; (Temp8 has Pgm_Comm_Timing)
+ subb A, #3 ; Is timing normal?
+ jz store_times_decrease ; Yes - branch
+
+ mov A, Temp8
+ jb ACC.0, adjust_timing_two_steps ; If an odd number - branch
+
+ ; Commutation timing setting is 2 or 4
+ mov A, Temp1 ; Store 22.5deg in Temp1/2 (15deg + 7.5deg)
+ add A, Temp5
+ mov Temp1, A
+ mov A, Temp2
+ addc A, Temp6
+ mov Temp2, A
+
+ mov A, Temp5 ; Store 7.5deg in Temp3/4
+ mov Temp3, A
+ mov A, Temp6
+ mov Temp4, A
+
+ sjmp store_times_up_or_down
+
+adjust_timing_two_steps:
+ ; Commutation timing setting is 1 or 5
+ mov A, Temp1 ; Store 30deg in Temp1/2 (15deg + 15deg)
+ setb C ; Add 1 to final result (Temp1/2 * 2 + 1)
+ addc A, Temp1
+ mov Temp1, A
+ mov A, Temp2
+ addc A, Temp2
+ mov Temp2, A
+
+ mov Temp3, #-1 ; Store minimum time (0deg) in Temp3/4
+ mov Temp4, #-1
+
+store_times_up_or_down:
+ clr C
+ mov A, Temp8
+ subb A, #3 ; Is timing higher than normal?
+ jc store_times_decrease ; No - branch
+
+store_times_increase:
+ mov Wt_Comm_Start_L, Temp3 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
+ mov Wt_Comm_Start_H, Temp4
+ mov Wt_Adv_Start_L, Temp1 ; New commutation advance time (~15deg nominal)
+ mov Wt_Adv_Start_H, Temp2
+ sjmp calc_new_wait_times_exit
+
+store_times_decrease:
+ mov Wt_Comm_Start_L, Temp1 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
+ mov Wt_Comm_Start_H, Temp2
+ mov Wt_Adv_Start_L, Temp3 ; New commutation advance time (~15deg nominal)
+ mov Wt_Adv_Start_H, Temp4
+
+ ; Set very short delays for all but advance time during startup, in order to widen zero cross capture range
+ jnb Flag_Startup_Phase, calc_new_wait_times_exit
+ mov Wt_Comm_Start_L, #-16
+ mov Wt_Comm_Start_H, #-1
+ mov Wt_Zc_Scan_Start_L, #-16
+ mov Wt_Zc_Scan_Start_H, #-1
+ mov Wt_Zc_Tout_Start_L, #-16
+ mov Wt_Zc_Tout_Start_H, #-1
+
+ sjmp calc_new_wait_times_exit
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+; Calculate new wait times fast routine
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+calc_new_wait_times_fast:
+ mov A, Temp1 ; Copy values
+ mov Temp3, A
+ setb C ; Negative numbers - set carry
+ rrc A ; Divide by 2
+ mov Temp5, A
+
+ mov Wt_Zc_Scan_Start_L, Temp5 ; Use this value for zero cross scan delay (7.5deg)
+ mov Wt_Zc_Tout_Start_L, Temp1 ; Set 15deg time for zero cross scan timeout
+
+ clr C
+ mov A, Temp8 ; (Temp8 has Pgm_Comm_Timing)
+ subb A, #3 ; Is timing normal?
+ jz store_times_decrease_fast ; Yes - branch
+
+ mov A, Temp8
+ jb ACC.0, adjust_timing_two_steps_fast ; If an odd number - branch
+
+ mov A, Temp1 ; Add 7.5deg and store in Temp1
+ add A, Temp5
+ mov Temp1, A
+ mov A, Temp5 ; Store 7.5deg in Temp3
+ mov Temp3, A
+ sjmp store_times_up_or_down_fast
+
+adjust_timing_two_steps_fast:
+ mov A, Temp1 ; Add 15deg and store in Temp1
+ add A, Temp1
+ add A, #1
+ mov Temp1, A
+ mov Temp3, #-1 ; Store minimum time in Temp3
+
+store_times_up_or_down_fast:
+ clr C
+ mov A, Temp8
+ subb A, #3 ; Is timing higher than normal?
+ jc store_times_decrease_fast ; No - branch
+
+store_times_increase_fast:
+ mov Wt_Comm_Start_L, Temp3 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
+ mov Wt_Adv_Start_L, Temp1 ; New commutation advance time (~15deg nominal)
+ sjmp calc_new_wait_times_exit
+
+store_times_decrease_fast:
+ mov Wt_Comm_Start_L, Temp1 ; Now commutation time (~60deg) divided by 4 (~15deg nominal)
+ mov Wt_Adv_Start_L, Temp3 ; New commutation advance time (~15deg nominal)
+
+calc_new_wait_times_exit:
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Wait before zero cross scan
+;
+; Waits for the zero cross scan wait time to elapse
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+wait_before_zc_scan:
+ ; If it has not already, we wait here for the Wt_Zc_Scan_Start_ delay to elapse.
+ Wait_For_Timer3
+
+ ; At this point Timer3 has (already) wrapped and been reloaded with the Wt_ZC_Tout_Start_ delay.
+ ; In case this delay has also elapsed, Timer3 has been reloaded with a short delay any number of times.
+ ; - The interrupt flag is set and the pending flag will clear immediately after enabling the interrupt.
+ mov Startup_Zc_Timeout_Cntd, #2
+
+setup_zc_scan_timeout:
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+
+ jnb Flag_Initial_Run_Phase, wait_before_zc_scan_exit
+
+ mov Temp1, Comm_Period4x_L ; Set long timeout when starting
+ mov Temp2, Comm_Period4x_H
+ Divide_16Bit_By_2 Temp2, Temp1
+IF MCU_TYPE == MCU_BB1
+ Divide_16Bit_By_2 Temp2, Temp1
+ENDIF
+ jnb Flag_Startup_Phase, setup_zc_scan_timeout_startup_done
+
+ mov A, Temp2
+ add A, #40h ; Increase timeout somewhat to avoid false wind up
+ mov Temp2, A
+
+setup_zc_scan_timeout_startup_done:
+ clr IE_EA
+ anl EIE1, #7Fh ; Disable Timer3 interrupts
+ mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
+ clr C
+ clr A
+ subb A, Temp1 ; Set timeout
+ mov TMR3L, A
+ clr A
+ subb A, Temp2
+ mov TMR3H, A
+ mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+ setb IE_EA
+
+wait_before_zc_scan_exit:
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Wait for comparator to go low/high
+;
+; Scans for comparator going low/high
+; Exit if zero cross timeout has elapsed
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+wait_for_comp_out_low:
+ mov B, #00h ; Desired comparator output
+ jnb Flag_Dir_Change_Brake, comp_init
+ mov B, #40h
+ sjmp comp_init
+
+wait_for_comp_out_high:
+ mov B, #40h ; Desired comparator output
+ jnb Flag_Dir_Change_Brake, comp_init
+ mov B, #00h
+
+comp_init:
+ setb Flag_Demag_Detected ; Set demag detected flag as default
+ mov Comparator_Read_Cnt, #0 ; Reset number of comparator reads
+
+comp_start:
+ ; Set number of comparator readings required
+ mov Temp3, #(1 SHL IS_MCU_48MHZ) ; Number of OK readings required
+ mov Temp4, #(1 SHL IS_MCU_48MHZ) ; Max number of readings required
+ jb Flag_High_Rpm, comp_check_timeout ; Branch if high rpm
+
+ jnb Flag_Initial_Run_Phase, comp_start_check_startup_phase
+ clr Flag_Demag_Detected ; Clear demag detected flag if start phases
+
+comp_start_check_startup_phase:
+ jnb Flag_Startup_Phase, comp_not_startup
+ mov Temp3, #(27 SHL IS_MCU_48MHZ) ; Set many samples during startup,approximately one pwm period
+ mov Temp4, #(27 SHL IS_MCU_48MHZ)
+ sjmp comp_check_timeout
+
+comp_not_startup:
+ ; Too low value (~<15) causes rough running at pwm harmonics.
+ ; Too high a value (~>35) causes the RCT4215 630 to run rough on full throttle
+ mov Temp4, #(20 SHL IS_MCU_48MHZ)
+ mov A, Comm_Period4x_H ; Set number of readings higher for lower speeds
+IF MCU_TYPE == MCU_BB1
+ clr C
+ rrc A
+ENDIF
+ jnz comp_not_startup_check_ok_readings
+ inc A ; Minimum 1
+
+comp_not_startup_check_ok_readings:
+ mov Temp3, A
+ clr C
+ subb A, #(20 SHL IS_MCU_48MHZ)
+ jc comp_check_timeout
+ mov Temp3, #(20 SHL IS_MCU_48MHZ) ; Maximum 20
+
+comp_check_timeout:
+ jb Flag_Timer3_Pending, comp_check_timeout_not_timed_out ; Has zero cross scan timeout elapsed?
+
+ mov A, Comparator_Read_Cnt ; Check that comparator has been read
+ jz comp_check_timeout_not_timed_out ; If not yet read - ignore zero cross timeout
+
+ jnb Flag_Startup_Phase, comp_check_timeout_timeout_extended
+
+ ; Extend timeout during startup
+ djnz Startup_Zc_Timeout_Cntd, comp_check_timeout_extend_timeout
+
+comp_check_timeout_timeout_extended:
+ setb Flag_Comp_Timed_Out
+ sjmp comp_exit
+
+comp_check_timeout_extend_timeout:
+ call setup_zc_scan_timeout
+
+comp_check_timeout_not_timed_out:
+ inc Comparator_Read_Cnt ; Increment comparator read count
+ Read_Comparator_Output
+ anl A, #40h
+ cjne A, B, comp_read_wrong
+
+ ; Comp read ok
+ mov A, Startup_Cnt ; Force a timeout for the first commutation
+ jz comp_start
+
+ jb Flag_Demag_Detected, comp_start ; Do not accept correct comparator output if it is demag
+
+ djnz Temp3, comp_check_timeout ; Decrement readings counter - repeat comparator reading if not zero
+
+ clr Flag_Comp_Timed_Out
+ sjmp comp_exit
+
+comp_read_wrong:
+ jb Flag_Startup_Phase, comp_read_wrong_startup
+ jb Flag_Demag_Detected, comp_read_wrong_extend_timeout
+
+ inc Temp3 ; Increment number of OK readings required
+ clr C
+ mov A, Temp3
+ subb A, Temp4
+ jc comp_check_timeout ; If below initial requirement - take another reading
+ sjmp comp_start ; Otherwise - go back and restart
+
+comp_read_wrong_startup:
+ inc Temp3 ; Increment number of OK readings required
+ clr C
+ mov A, Temp3
+ subb A, Temp4 ; If above initial requirement - do not increment further
+ jc comp_read_wrong_startup_jump ; TODO: Skip this jump to optimize
+ dec Temp3
+
+comp_read_wrong_startup_jump:
+ sjmp comp_check_timeout ; Continue to look for good ones
+
+comp_read_wrong_extend_timeout:
+ clr Flag_Demag_Detected ; Clear demag detected flag
+ anl EIE1, #7Fh ; Disable Timer3 interrupts
+ mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
+ jnb Flag_High_Rpm, comp_read_wrong_low_rpm ; Branch if not high rpm
+
+ mov TMR3L, #0 ; Set timeout to ~1ms
+ mov TMR3H, #-(8 SHL IS_MCU_48MHZ)
+
+comp_read_wrong_timeout_set:
+ mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+ ljmp comp_start ; If comparator output is not correct - go back and restart
+
+comp_read_wrong_low_rpm:
+ mov A, Comm_Period4x_H ; Set timeout to ~4x comm period 4x value
+ mov Temp7, #0FFh ; Default to long timeout
+
+IF MCU_TYPE == MCU_BB2 or MCU_TYPE == MCU_BB51
+ clr C
+ rlc A
+ jc comp_read_wrong_load_timeout
+ENDIF
+
+ clr C
+ rlc A
+ jc comp_read_wrong_load_timeout
+
+ clr C
+ rlc A
+ jc comp_read_wrong_load_timeout
+
+ mov Temp7, A
+
+comp_read_wrong_load_timeout:
+ clr C
+ clr A
+ subb A, Temp7
+ mov TMR3L, #0
+ mov TMR3H, A
+ sjmp comp_read_wrong_timeout_set
+
+comp_exit:
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Setup commutation timing
+;
+; Clear the zero cross timeout and sets up wait from zero cross to commutation
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+setup_comm_wait:
+ clr IE_EA
+ anl EIE1, #7Fh ; Disable Timer3 interrupts
+
+ ; It is necessary to update the timer reload registers before the timer registers,
+ ; to avoid a reload of the previous values in case of a short Wt_Comm_Start delay.
+
+ ; Advance wait time will be loaded by Timer3 immediately after the commutation wait elapses
+ mov TMR3RLL, Wt_Adv_Start_L ; Setup next wait time
+ mov TMR3RLH, Wt_Adv_Start_H
+ mov TMR3CN0, #00h ; Timer3 disabled and interrupt flag cleared
+ mov TMR3L, Wt_Comm_Start_L
+ mov TMR3H, Wt_Comm_Start_H
+ mov TMR3CN0, #04h ; Timer3 enabled and interrupt flag cleared
+
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+ setb IE_EA ; Enable interrupts again
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Evaluate comparator integrity
+;
+; Checks comparator signal behavior versus expected behavior
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+evaluate_comparator_integrity:
+ jb Flag_Startup_Phase, eval_comp_startup ; Do not exit run mode during startup phases
+
+ jnb Flag_Comp_Timed_Out, eval_comp_exit ; Has timeout elapsed?
+ jb Flag_Initial_Run_Phase, eval_comp_exit ; Do not exit run mode if initial run phase
+ jb Flag_Dir_Change_Brake, eval_comp_exit ; Do not exit run mode if braking
+ jb Flag_Demag_Detected, eval_comp_exit ; Do not exit run mode if it is a demag situation
+
+ dec SP ; Routine exit without "ret" command
+ dec SP
+ ljmp exit_run_mode_on_timeout ; Exit run mode if timeout has elapsed
+
+eval_comp_startup:
+ inc Startup_Cnt ; Increment startup counter
+
+eval_comp_exit:
+ ret
+
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+;
+; Wait for commutation
+;
+; Waits from zero cross to commutation
+;
+;**** **** **** **** **** **** **** **** **** **** **** **** ****
+wait_for_comm:
+ ; Update demag metric
+ mov A, Demag_Detected_Metric ; Sliding average of 8,256 when demag and 0 when not. Limited to minimum 120
+ mov B, #7
+ mul AB ; Multiply by 7
+
+ jnb Flag_Demag_Detected, wait_for_comm_demag_event_added
+ ; Add new value for current demag status
+ inc B
+ ; Signal demag
+ setb Flag_Demag_Notify
+
+wait_for_comm_demag_event_added:
+ mov C, B.0 ; Divide by 8
+ rrc A
+ mov C, B.1
+ rrc A
+ mov C, B.2
+ rrc A
+ mov Demag_Detected_Metric, A
+ clr C
+ subb A, #120 ; Limit to minimum 120
+ jnc wait_for_comm_update_demag_metric_max
+ mov Demag_Detected_Metric, #120
+
+wait_for_comm_update_demag_metric_max:
+ ; Update demag metric max
+ clr C
+ mov A, Demag_Detected_Metric
+ subb A, Demag_Detected_Metric_Max
+ jc wait_for_comm_demag_metric_max_updated
+ mov Demag_Detected_Metric_Max, Demag_Detected_Metric
+
+wait_for_comm_demag_metric_max_updated:
+ ; Check demag metric
+ clr C
+ mov A, Demag_Detected_Metric
+ subb A, Demag_Pwr_Off_Thresh
+ jc wait_for_comm_wait
+
+ ; Signal desync
+ setb Flag_Desync_Notify
+
+ ; Cut power if many consecutive demags are detected.
+ ; This will help retain sync during hard accelerations.
+ All_Pwm_Fets_Off
+ Set_All_Pwm_Phases_Off
+
+wait_for_comm_wait:
+ ; If it has not already, we wait for the Wt_Comm_Start_ delay to elapse.
+ Wait_For_Timer3
+
+ ; At this point Timer3 has (already) wrapped and been reloaded with
+ ; the Wt_Adv_Start_ delay.
+ ;
+ ; In case this delay has also elapsed, Timer3 has been reloaded with a short
+ ; delay any number of times.
+ ; - The interrupt flag is set and the pending flag will clear immediately
+ ; after enabling the interrupt.
+ mov TMR3RLL, Wt_Zc_Scan_Start_L ; Setup next wait time
+ mov TMR3RLH, Wt_Zc_Scan_Start_H
+ setb Flag_Timer3_Pending
+ orl EIE1, #80h ; Enable Timer3 interrupts
+ ret
diff --git a/Silabs/SI_EFM8BB1_Defs.inc b/src/Silabs/SI_EFM8BB1_Defs.inc
similarity index 100%
rename from Silabs/SI_EFM8BB1_Defs.inc
rename to src/Silabs/SI_EFM8BB1_Defs.inc
diff --git a/Silabs/SI_EFM8BB2_Defs.inc b/src/Silabs/SI_EFM8BB2_Defs.inc
similarity index 100%
rename from Silabs/SI_EFM8BB2_Defs.inc
rename to src/Silabs/SI_EFM8BB2_Defs.inc
diff --git a/Silabs/SI_EFM8BB51_Defs.inc b/src/Silabs/SI_EFM8BB51_Defs.inc
similarity index 100%
rename from Silabs/SI_EFM8BB51_Defs.inc
rename to src/Silabs/SI_EFM8BB51_Defs.inc
diff --git a/Silabs/SI_EFM8LB1_Defs.inc b/src/Silabs/SI_EFM8LB1_Defs.inc
similarity index 100%
rename from Silabs/SI_EFM8LB1_Defs.inc
rename to src/Silabs/SI_EFM8LB1_Defs.inc
diff --git a/tools/build.sh b/tools/build.sh
index 802e1ad9..667e1553 100755
--- a/tools/build.sh
+++ b/tools/build.sh
@@ -2,11 +2,11 @@
source_path=$(dirname $(pwd))
usage() {
- echo "Usage: $0 [-l ] [-m ] [-d ] [-p <24|48|96>]" 1>&2
+ echo "Usage: $0 [-l ] [-m ] [-d ] [-p <24|48|96>] [-s ]" 1>&2
exit 1
}
-while getopts ":l:m:d:p:" o; do
+while getopts ":l:m:d:p:s:" o; do
case "${o}" in
l)
layout=${OPTARG}
@@ -22,6 +22,9 @@ while getopts ":l:m:d:p:" o; do
pwm=${OPTARG}
((pwm == 24 || pwm == 48 || pwm == 96)) || usage
;;
+ s)
+ version=${OPTARG}
+ ;;
*)
usage
;;
@@ -43,6 +46,10 @@ else
params="LAYOUT=${layout} MCU=${mcu} DEADTIME=${deadtime} PWM=${pwm}"
fi
+if [ -n "${version}" ]; then
+ params="${params} VERSION=${version}"
+fi
+
echo "Building ${target}"
docker run -t -d --name bluejay-$target --mount type=bind,source="$source_path",target=/root/source bluejay-build:latest
diff --git a/tools/formatter/formatter.py b/tools/formatter/formatter.py
new file mode 100644
index 00000000..ab3908d9
--- /dev/null
+++ b/tools/formatter/formatter.py
@@ -0,0 +1,372 @@
+'''
+Attempts to auto format assembler code by the following rules:
+* Replace all tabs with whitespaces
+* Replace multiple ; with single ;
+* Replace multiple empty lines with single empty line
+* Find longest fields
+'''
+import argparse
+import filecmp
+import os
+import re
+import sys
+
+parser = argparse.ArgumentParser(description="Format and lint 8051 assembler files.")
+parser.add_argument("path", metavar="PATH", type=str,
+ help="directory to search for files")
+parser.add_argument("--extensions", dest="extensions", nargs="+",
+ default=["asm", "inc"],
+ help="list of file extension to parse")
+parser.add_argument("--exclude", dest="exclude", nargs="+",
+ default=["build", "tools", "Silabs"],
+ help="list of directories to exclude")
+parser.add_argument("--suffix", dest="suffix",
+ default="", help="suffix for formatted file, default overwrites current file")
+parser.add_argument("--spaces", dest="spaces",
+ default=4, help="spaces per level of indent")
+parser.add_argument("--comment-offset", dest="commentOffset",
+ default=40, help="offset for comments from beginning of the line")
+parser.add_argument("--lint", dest="lint", action="store_true",
+ default=False, help="lint files")
+parser.add_argument("--indent-labels", dest="indentLabels", action="store_true",
+ default=False, help="Indent code after labels")
+parser.add_argument("--indent-macros", dest="indentMacros", action="store_true",
+ default=False, help="Indent code within macros")
+parser.add_argument("--min-indentation", dest="minIndentation",
+ default=1, help="Minimum indentation for all instructions")
+parser.add_argument("--format-comments", dest="formatComments", action="store_true",
+ default=False, help="Attempt to format comments")
+
+
+args = parser.parse_args()
+
+path = args.path
+processExtensions = args.extensions
+excludeDirs = args.exclude
+suffix = args.suffix
+spaces = args.spaces
+offsetInlineComments = args.commentOffset
+lint = args.lint
+indentLabels = args.indentLabels
+indentMacros = args.indentMacros
+minIndentation = args.minIndentation
+formatComments = args.formatComments
+
+if lint:
+ suffix = ".asmb"
+
+noIndent = ["AT", "IF", "ELSE", "ELSEIF", "MACRO", "ENDM", "$if", "$endif", "$set", "EQU", "DB", "DS", "END", "$include", "$set"]
+indentInIf = ["$include", "$set", "EQU", "AT"]
+labelNoBreak = [";", "DS", "DB"]
+increaseDepth = ["IF"]
+decreaseDepth = ["ENDIF"]
+temporaryDecreaseDepth = ["ELSE", "ELSEIF"]
+nestedSameDepth = ["IF", "ENDIF"]
+resetLabel = ["MACRO", "ENDM", "$include", ";****"]
+maxLength = [0, 0]
+
+if indentMacros:
+ increaseDepth.append("MACRO")
+ decreaseDepth.append("ENDM")
+
+def cleanup(line):
+ line = re.sub('[\r\n]', '', line)
+
+ match = re.match(r"\s*\;.*", line)
+ if not match:
+ # Strip spaces from beginning and end
+ line = line.strip()
+
+ # Replace tabs in all lines
+ line = re.sub('\t+', ' ', line)
+
+ # Replace muliple spaces with one unless in quotes or in inline comments
+ fields = line.split(';')
+ fields[0] = re.sub(r'("[^"]*")| +', lambda m: m.group(1) if m.group(1) else ' ', fields[0])
+ line = ";".join(fields)
+
+ # Replace multiple semicolons with one
+ line = re.sub(';+', ';', line)
+
+ # Replace comma with comma space
+ line = re.sub(', +', ',', line)
+
+ # Add space after pre-processor directive
+ line = re.sub(r'\$set\(', '$set (', line)
+
+ fields = line.split(" ")
+ field0 = fields[0]
+ field1 = fields[1] if (len(fields) > 1) else None
+
+ # Find long strings to indent calculation
+ if (not field1 or not field1.startswith(tuple(noIndent))) and not field0.endswith(":"):
+ length = len(field0)
+ if length > maxLength[0] and not field0.startswith(tuple(noIndent)):
+ maxLength[0] = length
+
+ # Only cound if filed 1 is available and does not contain a comma
+ if field1 and "," not in field1:
+ # Only count field 1 if there is one following
+ if len(fields) > 2 and fields[2] != ";":
+ # Only count if field 0 should have indent
+ if not field0.startswith(tuple(noIndent)):
+ length = len(field1)
+ if length > maxLength[1]:
+ maxLength[1] = length
+
+ else:
+ line = re.sub('\t', ' ' * spaces, line)
+
+ return line
+
+# Collect all files to be processed
+processPaths = []
+for root, dirs, files in os.walk(path):
+ dirs[:] = [d for d in dirs if d not in excludeDirs]
+ for file in files:
+ extension = file.split(".")[-1]
+ if extension in processExtensions:
+ path = os.path.join(root, file)
+ processPaths.append(path)
+
+for path in processPaths:
+ '''
+ In the first run we find out what our longest fields are and do some base
+ sanitation.
+ '''
+ depth = 0
+ sawLabel = False
+ inBanner = False
+
+ cleanLines = []
+ formattedLinesRough = []
+ formattedLines = []
+
+ lastEmpty = False
+ maxLength = [0, 0]
+ ifDepth = 0
+
+ file = open(path, 'r')
+ lines = file.readlines()
+ for line in lines:
+ line = cleanup(line)
+
+ # split label and non comment line into two lines
+ match = re.match(r"([\w\s]+\:)(.+)", line)
+ if(match):
+ field0 = match.group(1).strip()
+ field1 = match.group(2).strip()
+
+ if (
+ not field1.startswith(";") and
+ not field1.startswith("DS") and
+ not field1.startswith("DB")
+ ):
+ cleanLines.append(field0)
+ cleanLines.append(field1)
+
+ else:
+ cleanLines.append(line)
+
+ continue
+
+ # Prevent two empty lines after each other
+ if line != "" or not lastEmpty:
+ cleanLines.append(line)
+
+ lastEmpty = False
+ if line == "":
+ lastEmpty = True
+
+ file.close()
+
+ # Reformat all available lines
+ targetPath = "%s%s" % (path, suffix)
+ file = open(targetPath, 'w')
+ for line in cleanLines:
+ lineIsLabel = False
+ lineIsComment = False
+
+ # Empty line
+ if line == "":
+ inBanner = False
+
+ if line != "":
+ fields = line.split(" ")
+
+ match = re.match(r"\s*\;.*", line)
+ if match:
+ lineIsComment = True
+
+ if inBanner:
+ if not line.startswith(";"):
+ inBanner = False
+
+ if line.startswith(";****"):
+ inBanner = True
+
+
+ field0 = fields[0]
+ field1 = fields[1] if (len(fields) > 1) else None
+
+ if field0.endswith(":"):
+ if not field1 or field1.startswith(";"):
+ lineIsLabel = True
+ sawLabel = True
+
+ # Do not touch comments
+ if not lineIsComment and len(fields) > 1:
+ if field0 not in noIndent and field1 not in noIndent:
+ # Append spaces to field 0
+ # append0 = maxLength[0] - len(field0) - (depth * spaces)
+ append0 = 4 - len(field0)
+ fields[0] = "%s%s" % (field0, " " * append0)
+
+ # Append spaced to field 1
+ if len(fields) > 1 and field1 != ";" and "," not in field1:
+ #append1 = maxLength[1] - len(field1)
+ append1 = 0
+
+ # Compensate for lines where field 0 is longer due to indendation
+ if append0 < 0:
+ append1 += append0
+
+ fields[1] = "%s%s" % (field1, " " * append1)
+
+ if len(fields) > 1 and field1 != ";" and "," in field1:
+ fields[1] = re.sub(',', ', ', field1)
+
+ line = " ".join(fields)
+ line = line.rstrip()
+
+ if field0 in decreaseDepth or field1 in decreaseDepth:
+ # Nested IFs are not further indented
+ if field0 == "ENDIF":
+ ifDepth -= 1
+ if ifDepth == 0:
+ depth -= 1
+ else:
+ depth -= 1
+
+ if sawLabel and (field0 in resetLabel or field1 in resetLabel):
+ sawLabel = False
+ depth -= 1
+
+ if sawLabel and indentLabels:
+ if depth == 0:
+ depth += 1
+
+ if depth < 0:
+ depth = 0
+
+ # Calculate space prefix
+ spacePrefix = depth * spaces
+
+ if field0 in temporaryDecreaseDepth:
+ spacePrefix -= spaces
+
+ if lineIsLabel and spacePrefix > 0:
+ spacePrefix = 0
+
+ if inBanner:
+ spacePrefix = 0
+
+ # Do not further indent nested ifs
+ if ifDepth > 0:
+ if field0 in nestedSameDepth:
+ spacePrefix -= spaces
+
+ if spacePrefix == 0:
+ if (
+ field0 not in noIndent and
+ field1 not in noIndent and
+ field0 not in decreaseDepth and
+ not lineIsLabel and
+ not lineIsComment
+ ):
+ spacePrefix = spaces * minIndentation
+
+ if spacePrefix == 0 and ifDepth > 0:
+ if field0 in indentInIf or field1 in indentInIf:
+ spacePrefix = spaces * minIndentation
+
+ if not lineIsComment or formatComments:
+ line = "%s%s" % (" " * spacePrefix, line)
+
+ # Align all inline comments
+ fields = line.split(";")
+ if not line.startswith(";") and fields[0].strip() != "":
+ if len(fields) > 1:
+ append = offsetInlineComments - len(fields[0])
+ fields[0] = "%s%s" % (fields[0], " " * append)
+ line = ";".join(fields)
+
+ if field0 in increaseDepth or field1 in increaseDepth:
+ # Nested IFs should not further be indented
+ if field0 == "IF":
+ ifDepth += 1
+ if ifDepth == 1:
+ depth += 1
+ else:
+ depth += 1
+
+ formattedLinesRough.append(line)
+
+ if formatComments:
+ inBanner = False
+ lineCount = len(formattedLinesRough)
+ index = 0
+ while index < lineCount:
+ line = formattedLinesRough[index]
+
+ if line.startswith(";"):
+ if line.startswith(";**** "):
+ # While in Banner, just push comment lines
+ inBanner = True
+
+ if inBanner:
+ formattedLines.append(line)
+ index += 1
+
+ else:
+ # find first line that is not a comment (or empty) and apply
+ # indentation to all previous lines
+ offset = 1
+ while (
+ formattedLinesRough[index + offset].startswith(";") or
+ formattedLinesRough[index + offset] == ""
+ ):
+ offset += 1
+
+ spacePrefix = formattedLinesRough[index + offset]
+ spaceCount = len(spacePrefix) - len(spacePrefix.lstrip())
+
+ targetIndex = index + offset
+ while index < targetIndex:
+ line = formattedLinesRough[index]
+ if line != "":
+ line = "%s%s" % (" " * spaceCount, line)
+
+ formattedLines.append(line)
+ index += 1
+
+ else:
+ inBanner = False
+ formattedLines.append(line)
+ index += 1
+ else:
+ formattedLines = formattedLinesRough
+
+ if formattedLines[-1] != "":
+ formattedLines.append("")
+
+ file.write("\n".join(formattedLines))
+ file.close()
+
+ if lint:
+ match = filecmp.cmp(path, targetPath)
+ os.unlink(targetPath)
+
+ if not match:
+ print("Failed linting %s" % path)
+ sys.exit(1)