feat: complete assembly mesh relay control path
- synchronize STM8 application and external flash layout updates\n- add assembly bootloader and assembly application test projects\n- add UART1 interrupt receive ring buffer\n- parse JDY-28M Mesh outer frames and source addresses\n- add CRC-16/MODBUS validation\n- implement relay control command 0x01 and response 0x81\n- support unicast and broadcast relay control frames\n- update host protocol, OTA documents, and serial tools
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
PROJECT := stm8_bootloader_asm
|
||||
BUILD_DIR := build
|
||||
SRC_DIR := src
|
||||
|
||||
AS := sdasstm8
|
||||
LD := sdldstm8
|
||||
PACKIHX := packihx
|
||||
|
||||
ASMFLAGS := -plosgff
|
||||
LINKFLAGS := -mjwxu -b HOME=0x8000 -b CODE=0x8068
|
||||
|
||||
OBJECTS := $(BUILD_DIR)/bootloader_vectors.rel
|
||||
IHX := $(BUILD_DIR)/$(PROJECT).ihx
|
||||
HEX := $(BUILD_DIR)/$(PROJECT).hex
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(HEX)
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
$(BUILD_DIR)/bootloader_vectors.rel: $(SRC_DIR)/bootloader_vectors.asm | $(BUILD_DIR)
|
||||
$(AS) $(ASMFLAGS) -o $@ $<
|
||||
|
||||
$(IHX): $(OBJECTS)
|
||||
$(LD) $(LINKFLAGS) -i $@ $^
|
||||
|
||||
$(HEX): $(IHX)
|
||||
$(PACKIHX) $< > $@
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
@@ -0,0 +1,39 @@
|
||||
# STM8 汇编 Bootloader(并行验证工程)
|
||||
|
||||
本目录是独立的汇编 Bootloader 实验工程,不修改现有 `STM8_Bootloader` C 版本。
|
||||
|
||||
当前阶段已经实现固定中断向量、应用程序跳转、SPI1初始化、W25Q80BV JEDEC ID
|
||||
读取、OTA元数据处理、OTA固件搬运、升级成功结果写回、应用损坏自动恢复,以及
|
||||
上电长按后的出厂镜像恢复流程:先分段计算CRC16/MODBUS,校验通过后擦除内部
|
||||
应用区,再逐字节写入并回读比较,成功后跳转到应用程序。固件读取采用小步处理,
|
||||
不把整包镜像装入RAM。
|
||||
|
||||
OTA元数据使用:镜像地址0x003000、元数据地址0x005000;校验成功搬运后将
|
||||
0x005010写为成功结果码,并清除0x00500F升级请求。若OTA校验、擦除、写入或
|
||||
回读失败,Bootloader直接跳转主程序。若应用首字节不是0x82,则自动检查并尝试
|
||||
恢复出厂镜像;本汇编Bootloader不启用看门狗,也不依赖看门狗复位。
|
||||
|
||||
该流程已经完成编译和链接验证,但仍需要连接实际W25Q80BV验证JEDEC读取、外部
|
||||
Flash数据读取、内部Flash擦写时序以及恢复失败时的现场行为。
|
||||
|
||||
如果外部Flash检测失败,当前策略仍是允许内部主程序继续运行;这是为了避免外部
|
||||
Flash故障导致设备完全无法工作。实际量产策略还需要在搬运功能完成后再补充应用
|
||||
有效性判断和故障兜底。
|
||||
|
||||
## 地址规划
|
||||
|
||||
- Bootloader:`0x8000~0x84FF`
|
||||
- Application:`0x8500~0x9FFF`
|
||||
- `0x8500` 为应用中断向量表起始地址,复位入口地址从 `0x8501` 动态读取
|
||||
- TIM4 使用通用转发:`0x8064 -> 0x8564`
|
||||
- TIM4 IRQ23:固定向量 `0x8064`,转发目标 `0x8564`
|
||||
- UART1 RX IRQ18:固定向量 `0x8050`,转发目标 `0x8550`
|
||||
|
||||
## 构建
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
输出文件为 `build/stm8_bootloader_asm.hex`。当前工程与 C Bootloader 并行存在,
|
||||
未验证前不要烧录到量产设备。
|
||||
@@ -0,0 +1,618 @@
|
||||
;-------------------------------------------------------------------------------
|
||||
; STM8S003F3 汇编 Bootloader 实验入口
|
||||
;
|
||||
; 本文件当前实现固定中断向量、PA3上电长按检测和应用跳转;
|
||||
; 外部 Flash 搬运功能将在后续阶段加入。
|
||||
; STM8 中断向量每项为:0x82 + 3 字节目标地址。
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
.module bootloader_vectors
|
||||
.optsdcc -mstm8
|
||||
|
||||
.area HOME (ABS)
|
||||
|
||||
; 固定向量表从 Bootloader 的 0x8000 开始。
|
||||
; 未使用的中断统一指向默认处理函数。
|
||||
int _Asm_Reset
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
|
||||
; IRQ18:UART1接收,跳转到主程序 0x8550。
|
||||
int _Asm_UART1Vector
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
int _Asm_DefaultInterrupt
|
||||
; IRQ23:TIM4更新,转发到应用程序固定向量槽 0x8564。
|
||||
int _Asm_TIM4Vector
|
||||
|
||||
.area CODE
|
||||
|
||||
; 复位后读取应用程序复位向量并动态跳转。
|
||||
; 0x8500 是应用程序复位向量项,格式为:0x82 + 3字节入口地址;
|
||||
; 因此从0x8501开始读取三字节入口地址,避免写死主程序启动地址。
|
||||
_Asm_Reset:
|
||||
sim
|
||||
call _Asm_SPI_Init
|
||||
call _Asm_SPI_CheckJedec
|
||||
; 外部Flash故障时不阻止已有主程序运行。
|
||||
tnz a
|
||||
jrne _Asm_JumpApplication
|
||||
; PA3配置为带上拉输入,按键按下时读取为低电平。
|
||||
mov 0x5002, #0x00
|
||||
mov 0x5003, #0x08
|
||||
mov 0x5004, #0x00
|
||||
; TIM4配置为约1ms更新事件,仅轮询状态标志,不开TIM4中断。
|
||||
mov 0x5340, #0x00
|
||||
mov 0x5343, #0x00
|
||||
mov 0x5347, #0x07
|
||||
mov 0x5348, #0x7C
|
||||
mov 0x5346, #0x00
|
||||
mov 0x5345, #0x01
|
||||
mov 0x5344, #0x00
|
||||
mov 0x5340, #0x01
|
||||
; 未按键时进入正常启动检查;按住后累计5秒。
|
||||
ld a, 0x5001
|
||||
and a, #0x08
|
||||
jrne _Asm_NormalBoot
|
||||
ldw x, #5000
|
||||
_Asm_KeyWaitLoop:
|
||||
ld a, 0x5001
|
||||
and a, #0x08
|
||||
jrne _Asm_NormalBoot
|
||||
_Asm_WaitOneMs:
|
||||
btjf 0x5344, #0, _Asm_WaitOneMs
|
||||
mov 0x5344, #0x00
|
||||
decw x
|
||||
jrne _Asm_KeyWaitLoop
|
||||
; 长按已超过5秒,优先执行出厂固件恢复。
|
||||
call _Asm_CheckFactoryMetadata
|
||||
jrne _Asm_NormalBoot
|
||||
jpf _Asm_FactoryRecovery
|
||||
|
||||
_Asm_NormalBoot:
|
||||
; 普通启动先处理已经提交的OTA请求。
|
||||
call _Asm_CheckOtaMetadata
|
||||
jrne _Asm_NormalAfterOtaCheck
|
||||
jpf _Asm_OtaRecovery
|
||||
_Asm_NormalAfterOtaCheck:
|
||||
; 应用区无有效复位向量时,自动尝试出厂恢复。
|
||||
ld a, 0x8500
|
||||
cp a, #0x82
|
||||
jreq _Asm_JumpApplication
|
||||
call _Asm_CheckFactoryMetadata
|
||||
jreq _Asm_FactoryMetadataReady
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_FactoryMetadataReady:
|
||||
jpf _Asm_FactoryRecovery
|
||||
; 没有有效镜像时也直接交给应用入口;最终行为由主程序自身决定。
|
||||
jpf _Asm_JumpApplication
|
||||
|
||||
_Asm_JumpApplication:
|
||||
jpf [0x8501]
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; SPI1初始化:PC5=SCK、PC6=MOSI、PC7=MISO,PD4=W25Q80BV CS#。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_SPI_Init:
|
||||
mov 0x500C, #0x60
|
||||
mov 0x500D, #0x60
|
||||
mov 0x500E, #0x00
|
||||
mov 0x500F, #0x10
|
||||
mov 0x5011, #0x10
|
||||
mov 0x5012, #0x10
|
||||
mov 0x5013, #0x00
|
||||
bset 0x500F, #4
|
||||
; 主机、软件片选、空闲低电平、数据高位先行,SPI时钟约500kHz。
|
||||
mov 0x5200, #0x4C
|
||||
mov 0x5201, #0x03
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; SPI发送一个字节并返回同时收到的字节,A寄存器作为输入和返回值。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_SPI_Transfer:
|
||||
ld 0x5204, a
|
||||
_Asm_SPI_WaitTx:
|
||||
btjf 0x5203, #1, _Asm_SPI_WaitTx
|
||||
_Asm_SPI_WaitRx:
|
||||
btjf 0x5203, #0, _Asm_SPI_WaitRx
|
||||
ld a, 0x5204
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 读取W25Q80BV JEDEC ID,成功返回A=0,失败返回A=1。
|
||||
; 期望值:EF 40 14。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_SPI_CheckJedec:
|
||||
bres 0x500F, #4
|
||||
ld a, #0x9F
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
cp a, #0xEF
|
||||
jrne _Asm_SPI_JedecFail
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
cp a, #0x40
|
||||
jrne _Asm_SPI_JedecFail
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
cp a, #0x14
|
||||
jrne _Asm_SPI_JedecFail
|
||||
bset 0x500F, #4
|
||||
|
||||
ld a, #0x00
|
||||
ret
|
||||
|
||||
_Asm_SPI_JedecFail:
|
||||
bset 0x500F, #4
|
||||
ld a, #1
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 从W25Q80BV读取一个字节。
|
||||
; 输入:X=低16位地址;当前工程所有固定分区均位于0x010000以下,地址高字节为0。
|
||||
; 返回:A=读取到的数据。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_SPI_ReadByteX:
|
||||
bres 0x500F, #4
|
||||
ld a, #0x03
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, xh
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, xl
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0xFF
|
||||
call _Asm_SPI_Transfer
|
||||
push a
|
||||
bset 0x500F, #4
|
||||
pop a
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 检查出厂固件元数据。
|
||||
; 元数据地址:0x002000;布局与C Bootloader保持一致:
|
||||
; +0x00~+0x03:魔数FAC1,按低字节在前保存,即31 43 41 46;
|
||||
; +0x04~+0x07:固件长度,高字节在前;
|
||||
; +0x0E:镜像有效标志,必须为0xA5。
|
||||
; 返回:A=0表示元数据有效,A=1表示无效。
|
||||
; 同时把长度低16位暂存到RAM 0x0000/0x0001,供后续搬运阶段使用。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_CheckFactoryMetadata:
|
||||
; 出厂镜像从外部Flash 0x000000开始读取。
|
||||
ld a, #0x00
|
||||
ld 0x0004, a
|
||||
ld 0x0005, a
|
||||
ldw x, #0x2000
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x31
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x43
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x41
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x46
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
|
||||
; 读取4字节固件长度,只接受不超过应用区的长度。
|
||||
ldw x, #0x2004
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0000, a
|
||||
ld 0x000E, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0001, a
|
||||
ld 0x000F, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
; 当前应用区小于64KB,高16位必须为0。
|
||||
tnz a
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
tnz a
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
; 长度不能为0,也不能超过0x1800字节的应用空间。
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
jreq _Asm_FactoryMetadataInvalid
|
||||
ld a, 0x0000
|
||||
cp a, #0x1B
|
||||
jrugt _Asm_FactoryMetadataInvalid
|
||||
; 读取元数据中的CRC16,高字节在前,保存到RAM 0x0002/0x0003。
|
||||
ldw x, #0x200A
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0002, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0003, a
|
||||
; 读取有效标志。
|
||||
ldw x, #0x200E
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0xA5
|
||||
jrne _Asm_FactoryMetadataInvalid
|
||||
ld a, #0x00
|
||||
ret
|
||||
|
||||
_Asm_FactoryMetadataInvalid:
|
||||
ld a, #0x01
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 检查OTA元数据:魔数为OTA1,Flash中按低字节在前保存为31 41 54 4F。
|
||||
; 元数据位于0x005000,固件位于0x003000;升级请求位于+0x0F。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_CheckOtaMetadata:
|
||||
ldw x, #0x5000
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x31
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x41
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x54
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0x4F
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
ldw x, #0x5004
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0000, a
|
||||
ld 0x000E, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0001, a
|
||||
ld 0x000F, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
tnz a
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
tnz a
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
jreq _Asm_OtaMetadataInvalid
|
||||
ld a, 0x0000
|
||||
cp a, #0x1B
|
||||
jrugt _Asm_OtaMetadataInvalid
|
||||
ldw x, #0x500A
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0002, a
|
||||
incw x
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x0003, a
|
||||
ldw x, #0x5010
|
||||
call _Asm_SPI_ReadByteX
|
||||
; +0x10为升级结果,不影响请求判断;+0x0F必须为0xA5。
|
||||
ldw x, #0x500F
|
||||
call _Asm_SPI_ReadByteX
|
||||
cp a, #0xA5
|
||||
jrne _Asm_OtaMetadataInvalid
|
||||
ld a, #0x30
|
||||
ld 0x0004, a
|
||||
ld a, #0x00
|
||||
ld 0x0005, a
|
||||
ld a, #0x00
|
||||
ret
|
||||
_Asm_OtaMetadataInvalid:
|
||||
ld a, #0x01
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 出厂镜像恢复主流程。
|
||||
; 先逐字节计算外部镜像CRC16,校验成功后才擦除内部应用区;这样即使
|
||||
; 出厂Flash内容损坏,也不会先破坏当前仍可运行的主程序。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_FactoryRecovery:
|
||||
call _Asm_ValidateFactoryImage
|
||||
jreq _Asm_FactoryAfterValidate
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_FactoryAfterValidate:
|
||||
call _Asm_EraseApplication
|
||||
jreq _Asm_FactoryAfterErase
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_FactoryAfterErase:
|
||||
call _Asm_CopyFactoryImage
|
||||
jreq _Asm_FactoryAfterCopy
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_FactoryAfterCopy:
|
||||
call _Asm_VerifyApplication
|
||||
jreq _Asm_FactoryAfterVerify
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_FactoryAfterVerify:
|
||||
jpf [0x8501]
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; OTA镜像搬运成功后,将结果码写入0x005010并清除升级请求0x00500F。
|
||||
; 这里只写单字节,避免修改已经包含镜像描述信息的其它元数据字段。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_WriteOtaResult:
|
||||
; WREN
|
||||
bres 0x500F, #4
|
||||
ld a, #0x06
|
||||
call _Asm_SPI_Transfer
|
||||
bset 0x500F, #4
|
||||
; PAGE PROGRAM,地址0x005010,结果码由RAM 0x000C提供。
|
||||
bres 0x500F, #4
|
||||
ld a, #0x02
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x50
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x10
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, 0x000C
|
||||
call _Asm_SPI_Transfer
|
||||
bset 0x500F, #4
|
||||
; 等待W25Q80BV内部编程完成。
|
||||
_Asm_OtaResultWait:
|
||||
bres 0x500F, #4
|
||||
ld a, #0x05
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0xFF
|
||||
call _Asm_SPI_Transfer
|
||||
push a
|
||||
bset 0x500F, #4
|
||||
pop a
|
||||
and a, #0x01
|
||||
jrne _Asm_OtaResultWait
|
||||
; 清除升级请求标志。
|
||||
bres 0x500F, #4
|
||||
ld a, #0x06
|
||||
call _Asm_SPI_Transfer
|
||||
bset 0x500F, #4
|
||||
bres 0x500F, #4
|
||||
ld a, #0x02
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x50
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x0F
|
||||
call _Asm_SPI_Transfer
|
||||
ld a, #0x00
|
||||
call _Asm_SPI_Transfer
|
||||
bset 0x500F, #4
|
||||
ld a, #0x00
|
||||
ret
|
||||
|
||||
; OTA恢复入口:复用同一套CRC、擦除、写入和回读逻辑。
|
||||
_Asm_OtaRecovery:
|
||||
call _Asm_ValidateFactoryImage
|
||||
jreq _Asm_OtaAfterValidate
|
||||
ld a, #0x02
|
||||
ld 0x000C, a
|
||||
call _Asm_WriteOtaResult
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_OtaAfterValidate:
|
||||
call _Asm_EraseApplication
|
||||
jreq _Asm_OtaAfterErase
|
||||
ld a, #0x03
|
||||
ld 0x000C, a
|
||||
call _Asm_WriteOtaResult
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_OtaAfterErase:
|
||||
call _Asm_CopyFactoryImage
|
||||
jreq _Asm_OtaAfterCopy
|
||||
ld a, #0x03
|
||||
ld 0x000C, a
|
||||
call _Asm_WriteOtaResult
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_OtaAfterCopy:
|
||||
call _Asm_VerifyApplication
|
||||
jreq _Asm_OtaAfterVerify
|
||||
ld a, #0x04
|
||||
ld 0x000C, a
|
||||
call _Asm_WriteOtaResult
|
||||
jpf _Asm_JumpApplication
|
||||
_Asm_OtaAfterVerify:
|
||||
ld a, #0x01
|
||||
ld 0x000C, a
|
||||
call _Asm_WriteOtaResult
|
||||
jpf [0x8501]
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; CRC16/MODBUS 单字节更新。输入A为数据,累计值保存在0x000A(低字节)、
|
||||
; 0x000B(高字节)。函数不申请栈缓冲区,适合1KB RAM设备。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_CrcByte:
|
||||
ld 0x000C, a
|
||||
ld a, 0x000A
|
||||
xor a, 0x000C
|
||||
ld 0x000A, a
|
||||
ld a, #8
|
||||
ld 0x000D, a
|
||||
_Asm_CrcBitLoop:
|
||||
btjf 0x000A, #0, _Asm_CrcShiftOnly
|
||||
srl 0x000B
|
||||
rrc 0x000A
|
||||
ld a, 0x000A
|
||||
xor a, #0xA1
|
||||
ld 0x000A, a
|
||||
ld a, 0x000B
|
||||
xor a, #0xA0
|
||||
ld 0x000B, a
|
||||
jra _Asm_CrcNextBit
|
||||
_Asm_CrcShiftOnly:
|
||||
srl 0x000B
|
||||
rrc 0x000A
|
||||
_Asm_CrcNextBit:
|
||||
dec 0x000D
|
||||
jrne _Asm_CrcBitLoop
|
||||
ret
|
||||
|
||||
; 递减0x0000/0x0001保存的16位剩余长度,返回A=0表示减后为0。
|
||||
_Asm_DecRemaining:
|
||||
ld a, 0x0001
|
||||
tnz a
|
||||
jrne _Asm_DecRemainingLow
|
||||
dec 0x0000
|
||||
_Asm_DecRemainingLow:
|
||||
dec 0x0001
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 分段读取并校验出厂镜像CRC16。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_ValidateFactoryImage:
|
||||
ld a, #0xFF
|
||||
ld 0x000A, a
|
||||
ld 0x000B, a
|
||||
ldw x, 0x0004
|
||||
ldw y, 0x0000
|
||||
_Asm_ValidateLoop:
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
jreq _Asm_ValidateCompare
|
||||
call _Asm_SPI_ReadByteX
|
||||
call _Asm_CrcByte
|
||||
incw x
|
||||
call _Asm_DecRemaining
|
||||
jra _Asm_ValidateLoop
|
||||
_Asm_ValidateCompare:
|
||||
ld a, 0x000B
|
||||
cp a, 0x0002
|
||||
jrne _Asm_ValidateFail
|
||||
ld a, 0x000A
|
||||
cp a, 0x0003
|
||||
jrne _Asm_ValidateFail
|
||||
ld a, #0x00
|
||||
ret
|
||||
_Asm_ValidateFail:
|
||||
ld a, #0x01
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 擦除内部应用区0x8500~0x9FFF,每次擦除一个64字节块。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_EraseApplication:
|
||||
ld a, #0x56
|
||||
ld 0x5062, a
|
||||
ld a, #0xAE
|
||||
ld 0x5062, a
|
||||
ldw x, #0x8500
|
||||
_Asm_EraseBlock:
|
||||
ld a, #0x20
|
||||
ld 0x505B, a
|
||||
ld a, #0xDF
|
||||
ld 0x505C, a
|
||||
ld a, #0x00
|
||||
ld (x), a
|
||||
_Asm_EraseWait:
|
||||
btjf 0x505F, #2, _Asm_EraseWait
|
||||
addw x, #64
|
||||
cpw x, #0xA000
|
||||
jrne _Asm_EraseBlock
|
||||
ld a, #0x00
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 从出厂区逐字节写入内部应用区。写入后由单独校验流程回读确认。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_CopyFactoryImage:
|
||||
ld a, 0x000E
|
||||
ld 0x0000, a
|
||||
ld a, 0x000F
|
||||
ld 0x0001, a
|
||||
ldw x, 0x0004
|
||||
ldw y, #0x8500
|
||||
_Asm_CopyLoop:
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
jreq _Asm_CopyOK
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x000C, a
|
||||
ld a, #0x01
|
||||
ld 0x505B, a
|
||||
ld a, #0xFE
|
||||
ld 0x505C, a
|
||||
ld a, 0x000C
|
||||
ld (y), a
|
||||
_Asm_CopyWait:
|
||||
btjf 0x505F, #2, _Asm_CopyWait
|
||||
incw x
|
||||
incw y
|
||||
call _Asm_DecRemaining
|
||||
jra _Asm_CopyLoop
|
||||
_Asm_CopyOK:
|
||||
ld a, #0x00
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; 回读校验内部应用区。每个字节都与外部出厂镜像重新比较,避免只依赖
|
||||
; Flash控制器的EOP标志;校验失败时不允许跳转到应用程序。
|
||||
;-------------------------------------------------------------------------------
|
||||
_Asm_VerifyApplication:
|
||||
ld a, 0x000E
|
||||
ld 0x0000, a
|
||||
ld a, 0x000F
|
||||
ld 0x0001, a
|
||||
ldw x, 0x0004
|
||||
ldw y, #0x8500
|
||||
_Asm_VerifyLoop:
|
||||
ld a, 0x0000
|
||||
or a, 0x0001
|
||||
jreq _Asm_VerifyOK
|
||||
call _Asm_SPI_ReadByteX
|
||||
ld 0x000C, a
|
||||
ld a, (y)
|
||||
cp a, 0x000C
|
||||
jrne _Asm_VerifyFail
|
||||
incw x
|
||||
incw y
|
||||
call _Asm_DecRemaining
|
||||
jra _Asm_VerifyLoop
|
||||
_Asm_VerifyOK:
|
||||
ld a, #0x00
|
||||
ret
|
||||
_Asm_VerifyFail:
|
||||
ld a, #0x01
|
||||
ret
|
||||
|
||||
; 未使用中断:清除全局中断状态并停机,避免错误向量执行随机代码。
|
||||
_Asm_DefaultInterrupt:
|
||||
sim
|
||||
_Asm_DefaultLoop:
|
||||
jra _Asm_DefaultLoop
|
||||
|
||||
; 汇编中断跳板不使用C函数序言或尾声,直接跳到主程序向量槽。
|
||||
_Asm_UART1Vector:
|
||||
jpf 0x8550
|
||||
|
||||
_Asm_TIM4Vector:
|
||||
jpf 0x8564
|
||||
Reference in New Issue
Block a user