You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
7.9 KiB
385 lines
7.9 KiB
; BLHeli bootloader for SiLabs MCUs. Based upon AVRootloader (copyright HR)
|
|
|
|
XTAL EQU 25000000
|
|
|
|
BOOT_START EQU 1C00h ; Bootloader segment address
|
|
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
|
|
; Initialize VDD monitor
|
|
orl VDM0CN, #080h ; Enable the VDD monitor
|
|
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
|
|
subb A, #1Ch
|
|
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
|
|
|