avr/module/flash: unified flash code for 1p/4p devices.

AtTiny 841 erases 4 pages at once, others only erase one.
Fixed a bug: only send ONE flash response to FLASH_START!!!
This commit is contained in:
Martin Preuss
2025-05-04 03:32:53 +02:00
parent b632a10fff
commit e25b0ad69d
6 changed files with 385 additions and 619 deletions

View File

@@ -12,7 +12,7 @@
.equ FLASH_ERROR_NONE = 0 .equ FLASH_ERROR_NONE = 0
.equ FLASH_ERROR_MSGERROR = 1 .equ FLASH_ERROR_MSGERROR = 1
.equ FLASH_RECVBUFFER_MAXLEN = 128 .equ FLASH_RECVBUFFER_MAXLEN = 32
.equ FLASH_CMD_FLASH_RSP = 74 .equ FLASH_CMD_FLASH_RSP = 74

View File

@@ -16,7 +16,7 @@
.dseg .dseg
flashPageNum: .byte 2 flashPageStart: .byte 2
flashPageBuffer: .byte FLASH_PAGESIZE flashPageBuffer: .byte FLASH_PAGESIZE
@@ -28,253 +28,6 @@
; ---------------------------------------------------------------------------
; @routine Flash_Init
;
; @clobbers R16
Flash_Init:
ldi r16, 0xff
sts flashPageNum, r16
sts flashPageNum+1, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_Fini
;
; @clobbers (R0, R1, R16, R18, R19, R20, R21, R24, R25, X)
Flash_Fini:
push r15
in r15, SREG
cli
rcall flash1pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_WriteData
;
; @param Z destination address in FLASH memory (byte address as for LPM!)
; @param Y source address
; @param r17 number of bytes to write
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
Flash_WriteData:
push r15
in r15, SREG
cli
Flash_WriteData_loop:
tst r17
breq Flash_WriteData_done
rcall flashWriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
rjmp Flash_WriteData_loop
Flash_WriteData_done:
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteData
;
; Interrupts must be disabled!
;
; @return Z next position
; @return R17 remainder of bytes to flash
; @param Z position to flash data to
; @param Y source pointer
; @param R17 number of bytes to flash
; @clobbers R16, R18, R24, R25, X (R0, R1, R19, R20)
flashWriteData:
rcall flashCheckCurrentValid ; (r18, r19)
brcc flashWriteData_beginPage
rcall flashWriteCheckPage ; (r18, r19)
brcs flashWriteData_calcPosAndLength ; still inside current page, jump
rcall flash1pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
flashWriteData_beginPage:
rcall flash1pBeginPage ; (r16, r24, r25, X)
flashWriteData_calcPosAndLength:
rcall flashCalcPosAndLength ; (r24, r25)
; X=abs pos in buffer, r18=bytes to read, r17=bytes initially requested
; prepare data for return
sub r17, r18 ; r17 holds remainder
add zl, r18 ; Z points to next data
adc zh, r18 ; only add carry flag
sub zh, r18
flashWriteData_copyLoop:
ld r16, Y+
st X+, r16
dec r18
brne flashWriteData_copyLoop
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCalcPosAndLength
;
; @return X absolute write position inside buffer
; @return R18 bytes to write
; @param Z destination pos
; @param R17 number of bytes to write
; @clobbers r24, r25
flashCalcPosAndLength:
; calc offset into buffer
mov r24, zl
andi r24, (FLASH_PAGESIZE-1) ; r24=rel pos inside buffer
ldi r25, FLASH_PAGESIZE
sub r25, r24 ; r25=bytes left inside page
mov r18, r17
cp r25, r17 ; bytes to read > bytes left in page?
brcc flashCalcPosAndLength_l1 ; no: jump
mov r18, r25 ; yes: cut r18 to number of bytes left in page
flashCalcPosAndLength_l1:
ldi xl, LOW(flashPageBuffer) ; set X to pos within page buffer
ldi xh, HIGH(flashPageBuffer)
add xl, r24
adc xh, r24
sub xh, r24
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteCheckPage
;
; check whether the given address is inside the current page in buffer
;
; @return CFLAG set if same page, cleared otherwise
; @param Z address to write to
; @clobbers r18, r19
flashWriteCheckPage:
; check low byte of page
mov r18, zl
andi r18, LOW(~(FLASH_PAGESIZE-1))
lds r19, flashPageNum
cp r18, r19
brne flashWriteCheckPage_ClcRet
; check high byte of page
mov r18, zh
andi r18, HIGH(~(FLASH_PAGESIZE-1))
lds r19, flashPageNum+1
cp r18, r19
brne flashWriteCheckPage_ClcRet
sec
ret
flashWriteCheckPage_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCheckCurrentValid
;
; check whether the page buffer contains a valid page (e.g. flashPageNum is not 0xffff)
;
; @return CFLAG set if current page is valid, cleared otherwise
; @clobbers r18, r19
flashCheckCurrentValid:
lds r18, flashPageNum
lds r19, flashPageNum+1
and r18, r19
inc r18
breq flashCheckCurrentValid_ClcRet
sec
ret
flashCheckCurrentValid_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash1pBeginPage
;
; Interrupts must be disabled!
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers (r16, r24, r25, X)
flash1pBeginPage:
push zl
push zh
andi zl, LOW(~(FLASH_PAGESIZE-1))
andi zh, HIGH(~(FLASH_PAGESIZE-1))
sts flashPageNum, zl
sts flashPageNum+1, zh
rcall flash1pReadPageIntoSram ; r16, r24, r25, X, Z
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash1pEndPage
;
; Interrupts must be disabled!
;
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
flash1pEndPage:
rcall flashCheckCurrentValid ; (r18, r19)
brcs flash1pEndPage_write
ret
flash1pEndPage_write:
push zl
push zh
rcall flash1pWritePage ; (r0, r1, r20, r24, r25, X, Z)
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash1pReadPageIntoSram
;
; Interrupts must be disabled!
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers r16, r24, X, Z
flash1pReadPageIntoSram:
ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer)
ldi r24, LOW(FLASH_PAGESIZE)
flash1pReadPageIntoSram_loop:
lpm r16, Z+
st X+, r16
adiw ZH:ZL, 1
dec r24
brne flash1pReadPageIntoSram_loop
ret
; @end
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; flash1pWritePage ; flash1pWritePage
; ;
@@ -283,58 +36,30 @@ flash1pReadPageIntoSram_loop:
; @clobbers r0, r1, r20, r24, r25, X, Z ; @clobbers r0, r1, r20, r24, r25, X, Z
flash1pWritePage: flash1pWritePage:
lds zl, flashPageNum lds zl, flashPageStart
lds zh, flashPageNum+1 lds zh, flashPageStart+1
; erase page
ldi r20, (1<<PGERS) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall flash1pDoSpm ; (R16)
; copy from SDRAM into MCUs temporary page buffer ; copy from SDRAM into MCUs temporary page buffer
ldi xl, LOW(flashPageBuffer) ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer) ldi xh, HIGH(flashPageBuffer)
ldi r24, LOW(PAGESIZE) ldi r24, LOW(PAGESIZE)
push zl
push zh
flash1pWritePages_loop: flash1pWritePages_loop:
ld r0, X+ ; read source data from buffer (low) ld r0, X+ ; read source data from buffer (low)
ld r1, X+ ; read source data from buffer (high) ld r1, X+ ; read source data from buffer (high)
ldi r20, (1<<SPMEN) ; enable next SPM, write R1:R0 into temp page buffer ldi r20, (1<<SPMEN) ; enable next SPM, write R1:R0 into temp page buffer
rcall flash1pDoSpm ; (R16) rcall flashDoSpm ; (R16)
adiw zh:zl, 2 adiw zh:zl, 2
dec r24 dec r24
brne flash1pWritePages_loop brne flash1pWritePages_loop
pop zh
pop zl subi zl, LOW(PAGESIZE*2) ; point back to begin of page
sbci zh, HIGH(PAGESIZE*2)
; transfer data from temporary page buffer into FLASH memory ; transfer data from temporary page buffer into FLASH memory
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored) ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored)
rcall flash1pDoSpm ; (R16) rcall flashDoSpm ; (R16)
ret ret
; @end ; @end
.equ flashWritePage = flash1pWritePage
; ---------------------------------------------------------------------------
; flash1pDoSpm
;
; wait until possible previous SPM finished and then issue another SPM.
;
; IN:
; - R20: value for register SPMCR
; - R0: low value for SPM
; - R1: high value for SPM
; - Z : address for SPM (byte address!)
; OUT:
; - nothing
; REGS: R16
flash1pDoSpm:
flash1pDoSpm_wait: ; wait for possibly previous SPM to complete
in r16, SPMCSR
sbrc r16, SPMEN
rjmp flash1pDoSpm_wait
; SPM timed sequence
out SPMCSR, r20
spm
ret

View File

@@ -16,7 +16,7 @@
.dseg .dseg
flashPageNum: .byte 2 flashPageStart: .byte 2
flashPageBuffer: .byte FLASH_PAGESIZE flashPageBuffer: .byte FLASH_PAGESIZE
@@ -29,330 +29,47 @@
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; @routine Flash_Init ; flash4pWritePage
;
; @clobbers R16
Flash_Init:
ldi r16, 0xff
sts flashPageNum, r16
sts flashPageNum+1, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_Fini
;
; @clobbers (R0, R1, R16, R18, R19, R20, R21, R24, R25, X)
Flash_Fini:
push r15
in r15, SREG
cli
rcall flash4pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_WriteData
;
; @param Z destination address in FLASH memory (byte address as for LPM!)
; @param Y source address
; @param r17 number of bytes to write
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
Flash_WriteData:
push r15
in r15, SREG
cli
Flash_WriteData_loop:
tst r17
breq Flash_WriteData_done
rcall flashWriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
rjmp Flash_WriteData_loop
Flash_WriteData_done:
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteData
;
; Interrupts must be disabled!
;
; @return Z next position
; @return R17 remainder of bytes to flash
; @param Z position to flash data to
; @param Y source pointer
; @param R17 number of bytes to flash
; @clobbers R16, R18, R24, R25, X (R0, R1, R19, R20)
flashWriteData:
rcall flashWriteCheckPage ; (r18, r19)
brcs flashWriteData_calcPosAndLength
rcall flash4pEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
rcall flash4pBeginPage ; (r16, r24, r25, X, Z)
flashWriteData_calcPosAndLength:
rcall flashCalcPosAndLength ; (r24, r25)
; X=abs pos in buffer, r18=bytes to read, r17=bytes initially requested
; prepare data for return
sub r17, r18 ; r17 holds remainder
add zl, r18 ; Z points to next data
adc zh, r18 ; only add carry flag
sub zh, r18
flashWriteData_copyLoop:
ld r16, Y+
st X+, r16
dec r18
brne flashWriteData_copyLoop
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCalcPosAndLength
;
; @return X absolute write position inside buffer
; @return R18 bytes to write
; @param Z destination pos
; @param R17 number of bytes to write
; @clobbers r24, r25
flashCalcPosAndLength:
; calc offset into buffer
mov r24, zl
andi r24, (FLASH_PAGESIZE-1) ; r24=rel pos inside buffer
ldi r25, FLASH_PAGESIZE
sub r25, r24 ; r25=bytes left inside page
mov r18, r17
cp r25, r17
brcc flashCalcPosAndLength_l1
mov r18, r25
flashCalcPosAndLength_l1:
ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer)
add xl, r24
adc xh, r24
sub xh, r24
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteCheckPage
;
; check whether the given address is inside the current page in buffer
;
; @return CFLAG set if same page, cleared otherwise
; @clobbers r18, r19
flashWriteCheckPage:
; check low byte of page
mov r18, zl
andi r18, LOW(~(FLASH_PAGESIZE-1))
lds r19, flashPageNum
cp r18, r19
brne flashWriteCheckPage_ClcRet
; check high byte of page
mov r18, zh
andi r18, HIGH(~(FLASH_PAGESIZE-1))
lds r19, flashPageNum+1
cp r18, r19
brne flashWriteCheckPage_ClcRet
sec
ret
flashWriteCheckPage_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCheckCurrentValid
;
; check whether the page buffer contains a valid page (e.g. flashPageNum is not 0xffff)
;
; @return CFLAG set if current page is valid, cleared otherwise
; @clobbers r18, r19
flashCheckCurrentValid:
lds r18, flashPageNum
lds r19, flashPageNum+1
and r18, r19
inc r18
breq flashCheckCurrentValid_ClcRet
sec
ret
flashCheckCurrentValid_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash4pBeginPage
;
; Interrupts must be disabled!
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers (r16, r24, r25, X)
flash4pBeginPage:
push zl
push zh
andi zl, LOW(~(FLASH_PAGESIZE-1))
andi zh, HIGH(~(FLASH_PAGESIZE-1))
sts flashPageNum, zl
sts flashPageNum+1, zh
rcall flash4pReadPagesIntoSram ; r16, r24, r25, X, Z
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash4pEndPage
;
; Interrupts must be disabled!
;
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
flash4pEndPage:
rcall flashCheckCurrentValid ; (r18, r19)
brcs flash4pEndPage_write
ret
flash4pEndPage_write:
push zl
push zh
rcall flash4pErasePages ; (R16, R20, Z)
rcall flash4pWritePages ; (r0, r1, r20, r24, r25, X, Z)
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash4pReadPagesIntoSram
;
; Interrupts must be disabled!
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers r16, r24, X, Z
flash4pReadPagesIntoSram:
ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer)
ldi r24, LOW(FLASH_PAGESIZE)
flash4pReadPagesIntoSram_loop:
lpm r16, Z+
st X+, r16
adiw ZH:ZL, 1
dec r24
brne flash4pReadPagesIntoSram_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine flash4pErasePages
;
; Interrupts must be disabled!
;
; @clobbers R16, R20, Z
flash4pErasePages:
lds zl, flashPageNum
lds zh, flashPageNum+1
ldi r20, (1<<PGERS) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall flash4pDoSpm ; (R16)
ret
; @end
; ---------------------------------------------------------------------------
; flash4pWritePages
; ;
; Interrupts must be disabled! ; Interrupts must be disabled!
; ;
; @clobbers r0, r1, r20, r24, r25, X, Z ; @clobbers r0, r1, r20, r24, r25, X, Z
flash4pWritePages: flash4pWritePage:
; copy from SDRAM into MCUs temporary page buffer ; copy from SDRAM into MCUs temporary page buffer
lds zl, flashPageNum lds zl, flashPageStart
lds zh, flashPageNum+1 lds zh, flashPageStart+1
ldi xl, LOW(flashPageBuffer) ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer) ldi xh, HIGH(flashPageBuffer)
ldi r25, 4 ; handle 4 pages at a time ldi r25, 4 ; handle 4 pages at a time
flash4pWritePages_loop1: flash4pWritePage_loop1:
ldi r24, LOW(PAGESIZE) ldi r24, LOW(PAGESIZE)
flash4pWritePages_loop2: flash4pWritePage_loop2:
ld r0, X+ ; read source data from buffer (low) ld r0, X+ ; read source data from buffer (low)
ld r1, X+ ; read source data from buffer (high) ld r1, X+ ; read source data from buffer (high)
ldi r20, (1<<SPMEN) ; enable next SPM, write R1:R0 into temp page buffer ldi r20, (1<<SPMEN) ; enable next SPM, write R1:R0 into temp page buffer
rcall flash4pDoSpm ; (R16) rcall flashDoSpm ; (R16)
adiw zh:zl, 2 adiw zh:zl, 2
dec r24 dec r24
brne flash4pWritePages_loop2 brne flash4pWritePage_loop2
sbiw zh:zl, (PAGESIZE*2) ; point back to begin of page push zl
; transfer data from temporary page buffer into FLASH memory push zh
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored) subi zl, LOW(PAGESIZE*2) ; point back to begin of page
rcall flash4pDoSpm ; (R16) sbci zh, HIGH(PAGESIZE*2)
adiw zh:zl, (PAGESIZE*2) ; point forward to next page ; transfer data from temporary page buffer into FLASH memory
ldi r20, (1<<PGWRT) + (1<<SPMEN) ; enable next SPM, write page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
pop zh
pop zl
dec r25 dec r25
brne flash4pWritePages_loop1 brne flash4pWritePage_loop1
ret ret
; @end ; @end
.equ flashWritePage = flash4pWritePage
; ---------------------------------------------------------------------------
; flas4phDoSpm
;
; wait until possible previous SPM finished and then issue another SPM.
;
; IN:
; - R20: value for register SPMCR
; - R0: low value for SPM
; - R1: high value for SPM
; - Z : address for SPM (byte address!)
; OUT:
; - nothing
; REGS: R16
flash4pDoSpm:
flash4pDoSpm_wait: ; wait for possibly previous SPM to complete
in r16, SPMCSR
sbrc r16, SPMEN
rjmp flash4pDoSpm_wait
; SPM timed sequence
out SPMCSR, r20
spm
ret

View File

@@ -47,11 +47,11 @@ checkFlash:
rcall flashProcessWriteFlashReady ; (R16, R17, R18, R19, R20, Y, Z) rcall flashProcessWriteFlashReady ; (R16, R17, R18, R19, R20, Y, Z)
rcall ioRawSendMsg ; (r16, r17, X) rcall ioRawSendMsg ; (r16, r17, X)
ldi r16, CPRO_CMD_FLASH_START ldi r16, NETMSG_CMD_FLASH_START
rcall ioWaitForGivenMsg ; (r16, r17, r18, r19, r20, r22, X) rcall ioWaitForGivenMsg ; (r16, r17, r18, r19, r20, r22, X)
brcc checkFlash_end brcc checkFlash_end
cpi r16, CPRO_CMD_FLASH_START cpi r16, NETMSG_CMD_FLASH_START
clc clc
brne checkFlash_end ; no FLASH_START msg received brne checkFlash_end ; no FLASH_START msg received
@@ -60,10 +60,6 @@ checkFlash:
ldi xh, HIGH(flashRecvBuffer) ldi xh, HIGH(flashRecvBuffer)
rcall flashProcessHandleFlashStart rcall flashProcessHandleFlashStart
brcc checkFlash_end brcc checkFlash_end
; prepare and send response
clr r16
rcall flashProcessSendFlashResponse ; (R15, R16, R17, R18, R19, R20, R21, R22, X)
sec sec
checkFlash_end: checkFlash_end:
ret ret
@@ -77,21 +73,21 @@ checkFlash_end:
; handling receiving FLASH_DATA and FLASH_END messages, flash new firmware ; handling receiving FLASH_DATA and FLASH_END messages, flash new firmware
; ;
; @return CFLAG set if okay, cleared otherwise ; @return CFLAG set if okay, cleared otherwise
; @clobbers r16, r20 ; @clobbers r16, r20 (R0, R1, R15, R16, R17, R18, R19, R22, R24, Z)
flashProcess: flashProcess:
rcall Flash_Init rcall Flash_Init
flashProcess_loop1: flashProcess_loop1:
; wait up to 10s for incoming FLASH_DATA message ; wait up to 10s for incoming FLASH_DATA message
ldi r16, CPRO_CMD_FLASH_DATA ldi r16, NETMSG_CMD_FLASH_DATA
rcall ioWaitForGivenMsg ; (r16, r17, r18, r19, r20, r22, X) rcall ioWaitForGivenMsg ; (r16, r17, r18, r19, r20, r22, X)
brcc flashProcess_end ; no FLASH_DATA or FLASH_END msg brcc flashProcess_end ; no FLASH_DATA or FLASH_END msg
; either FLASH_DATA or FLASH_END received ; either FLASH_DATA or FLASH_END received
ldi xl, LOW(flashRecvBuffer) ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer) ldi xh, HIGH(flashRecvBuffer)
cpi r16, CPRO_CMD_FLASH_DATA ; not FLASH_DATA, flashing ended/aborted cpi r16, NETMSG_CMD_FLASH_DATA ; not FLASH_DATA, flashing ended/aborted
brne flashProcess_endReceived ; FLASH_END received, done brne flashProcess_endReceived ; FLASH_END received, done
rcall flashProcessHandleFlashData ; (R0, R1, R15, R16, R17, R18, R19, R20, Z) rcall flashProcessHandleFlashData ; (R0, R1, R15, R16, R17, R18, R19, R20, R22, R24, Z)
rjmp flashProcess_loop1 rjmp flashProcess_loop1
flashProcess_endReceived: flashProcess_endReceived:
rcall flashProcessHandleFlashEnd rcall flashProcessHandleFlashEnd
@@ -161,27 +157,39 @@ flashProcessCheckFlashStart_notMe:
; ;
; @return CFLAG set if okay, cleared otherwise ; @return CFLAG set if okay, cleared otherwise
; @param X buffer containing the message ; @param X buffer containing the message
; @clobbers R0, R1, R18, Z (R15, R16, R17, R19, R20) ; @clobbers R0, R1, R18, Z (R15, R16, R17, R19, R20, R22, R24)
flashProcessHandleFlashData: flashProcessHandleFlashData:
mov yl, xl mov yl, xl
mov yh, xh mov yh, xh
adiw yh:yl, FLASH_MSG_OFFS_MSGLEN ldd r17, Y+FLASH_MSG_OFFS_MSGLEN ; msg length
ld r17, Y ; length (subtract 6) subi r17, 6 ; remaining length (sub cmd(1), src(1), addr(4))
cpi r17, 6 ; cmd(1), src(1), addr(4) brcs flashProcessHandleFlashData_badData ; too few payload bytes
brcs flashProcessHandleFlashData_badData breq flashProcessHandleFlashData_badData ; no payload bytes
subi r17, 6 ; remaining length ldd zl, Y+FLASH_PACKET_DATA_OFFS_ADDR ; only read lower two address bytes
adiw yh:yl, FLASH_PACKET_DATA_OFFS_ADDR-FLASH_MSG_OFFS_MSGLEN ldd zh, Y+(FLASH_PACKET_DATA_OFFS_ADDR+1)
ld zl, Y+ ; address (low) adiw yh:yl, FLASH_PACKET_DATA_OFFS_ADDR+4
ld zh, Y+ ; address (high)
adiw yh:yl, 2 ; ignore high bytes, points to first data byte now
rcall Flash_WriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X) rcall Flash_WriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
clr r16 clr r16
rjmp flashProcessHandleFlashData_sendResponse rjmp flashProcessHandleFlashData_sendResponse
flashProcessHandleFlashData_badData: flashProcessHandleFlashData_badData:
ldi r16, FLASH_ERROR_MSGERROR ldi r16, FLASH_ERROR_MSGERROR
flashProcessHandleFlashData_sendResponse: flashProcessHandleFlashData_sendResponse:
#if 0
push r16
; send flash message back (debugging)
ldi r24, 50
rcall flashWaitForMillisecs ; (R22, R24)
ldi xl, LOW(flashRecvBuffer)
ldi xh, HIGH(flashRecvBuffer)
rcall ioRawSendPacket ; (r16, r17, X)
pop r16
#endif
ldi r24, 50
rcall flashWaitForMillisecs ; (R22, R24)
rcall flashProcessSendFlashResponse ; (R16, R17, R18, R19, R20, X) rcall flashProcessSendFlashResponse ; (R16, R17, R18, R19, R20, X)
sbi LED_PIN, LED_PINNUM ; toggle
sec sec
ret ret
; @end ; @end
@@ -216,7 +224,7 @@ flashProcessHandleFlashEnd:
; @clobbers X (R16, R17, R18, R19, R20) ; @clobbers X (R16, R17, R18, R19, R20)
flashProcessSendFlashResponse: flashProcessSendFlashResponse:
; send flash ready message ; send flash response message
ldi xl, LOW(flashSendBuffer) ldi xl, LOW(flashSendBuffer)
ldi xh, HIGH(flashSendBuffer) ldi xh, HIGH(flashSendBuffer)
rcall flashProcessWriteFlashRsp ; (R16, R17, R18, R19, R20, X) rcall flashProcessWriteFlashRsp ; (R16, R17, R18, R19, R20, X)
@@ -238,7 +246,7 @@ flashProcessWriteFlashRsp:
st X+, r18 ; dest address (unused) st X+, r18 ; dest address (unused)
ldi r18, 3 ; msg code+src address+one payload byte ldi r18, 3 ; msg code+src address+one payload byte
st X+, r18 ; msg len st X+, r18 ; msg len
ldi r17, CPRO_CMD_FLASH_RSP ldi r17, NETMSG_CMD_FLASH_RSP
st X+, r17 ; msg code st X+, r17 ; msg code
clr r17 clr r17
st X+, r17 ; src address (not used) st X+, r17 ; src address (not used)
@@ -262,7 +270,7 @@ flashProcessWriteFlashReady:
st X+, r16 ; dest address (unused) st X+, r16 ; dest address (unused)
ldi r16, 20 ; msg code+src address+18 payload bytes ldi r16, 20 ; msg code+src address+18 payload bytes
st X+, r16 ; msg len st X+, r16 ; msg len
ldi r16, CPRO_CMD_FLASH_READY ldi r16, NETMSG_CMD_FLASH_READY
st X+, r16 ; msg code st X+, r16 ; msg code
ldi r16, COM2_MAINTENANCE_ADDR ldi r16, COM2_MAINTENANCE_ADDR
st X+, r16 ; src address st X+, r16 ; src address

View File

@@ -0,0 +1,304 @@
; ***************************************************************************
; copyright : (C) 2025 by Martin Preuss
; email : martin@libchipcard.de
;
; ***************************************************************************
; * This file is part of the project "AqHome". *
; * Please see toplevel file COPYING of that project for license details. *
; ***************************************************************************
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; @routine Flash_Init
;
; @clobbers R16
Flash_Init:
ldi r16, 0xff
sts flashPageStart, r16
sts flashPageStart+1, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_Fini
;
; @clobbers (R0, R1, R16, R18, R19, R20, R21, R24, R25, X)
Flash_Fini:
push r15
in r15, SREG
cli
rcall flashEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine Flash_WriteData
;
; @param Z destination address in FLASH memory (byte address as for LPM!)
; @param Y source address
; @param r17 number of bytes to write
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
Flash_WriteData:
push r15
in r15, SREG
cli
Flash_WriteData_loop:
rcall flashWriteData ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
tst r17
brne Flash_WriteData_loop
out SREG, r15
pop r15
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteData
;
; Interrupts must be disabled!
;
; @return Z next dest position
; @return Y next source position
; @return R17 remainder of bytes to flash
; @param Z position to flash data to
; @param Y source pointer
; @param R17 number of bytes to flash
; @clobbers R16, R18, R24, R25, X (R0, R1, R19, R20)
flashWriteData:
rcall flashCheckCurrentValid ; (r18, r19)
brcc flashWriteData_beginPage ; jump if this is the first call (no page in work)
rcall flashWriteCheckPage ; (r18, r19)
brcs flashWriteData_calcPosAndLength ; still inside current page, jump
rcall flashEndPage ; (R0, R1, R16, R18, R19, R20, R24, R25, X)
flashWriteData_beginPage:
rcall flashBeginPage ; (r16, r24, r25, X)
flashWriteData_calcPosAndLength:
rcall flashCalcPosAndLength ; r18=bytes_to_write, x=pos_in_buffer (r24, r25)
; X=abs pos in buffer, r18=bytes to read, r17=bytes initially requested
; prepare data for return
sub r17, r18 ; r17 holds remainder
add zl, r18 ; Z points to next data
adc zh, r18 ; only add carry flag
sub zh, r18
; actually write data into buffer
flashWriteData_copyLoop:
ld r16, Y+
st X+, r16
dec r18
brne flashWriteData_copyLoop
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCalcPosAndLength
;
; @param Z destination pos
; @param R17 number of bytes to write
; @return X absolute write position inside buffer
; @return R18 bytes to write
; @clobbers r24, r25
flashCalcPosAndLength:
; calc offset into buffer
mov r24, zl
andi r24, (FLASH_PAGESIZE-1) ; r24=rel pos inside buffer
ldi r25, FLASH_PAGESIZE
sub r25, r24 ; r25=bytes left inside page
mov r18, r17
cp r25, r17 ; bytes to read > bytes left in page?
brcc flashCalcPosAndLength_l1 ; no: jump
mov r18, r25 ; yes: cut r18 to number of bytes left in page
flashCalcPosAndLength_l1:
ldi xl, LOW(flashPageBuffer) ; set X to pos within page buffer
ldi xh, HIGH(flashPageBuffer)
add xl, r24
adc xh, r24
sub xh, r24
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashWriteCheckPage
;
; check whether the given address is inside the current page in buffer
;
; @return CFLAG set if same page, cleared otherwise
; @param Z address to write to
; @clobbers r18, r19
flashWriteCheckPage:
; check low byte of page
mov r18, zl
lds r19, flashPageStart
eor r18, r19
cbr r18, LOW(FLASH_PAGESIZE-1)
brne flashWriteCheckPage_ClcRet
; check high byte of page
mov r18, zh
lds r19, flashPageStart+1
eor r18, r19
cbr r18, HIGH(FLASH_PAGESIZE-1)
brne flashWriteCheckPage_ClcRet
sec
ret
flashWriteCheckPage_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashCheckCurrentValid
;
; check whether the page buffer contains a valid page (e.g. flashPageStart is not 0xffff)
;
; @return CFLAG set if current page is valid, cleared otherwise
; @clobbers r18, r19
flashCheckCurrentValid:
lds r18, flashPageStart
lds r19, flashPageStart+1
and r18, r19
inc r18
breq flashCheckCurrentValid_ClcRet
sec
ret
flashCheckCurrentValid_ClcRet:
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashBeginPage
;
; Interrupts must be disabled!
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers (r16, r24, r25, X)
flashBeginPage:
push zl
push zh
cbr zl, LOW(FLASH_PAGESIZE-1)
cbr zh, HIGH(FLASH_PAGESIZE-1)
sts flashPageStart, zl
sts flashPageStart+1, zh
rcall flashReadPageIntoSram ; (r16, r24, r25, X, Z)
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashEndPage
;
; Interrupts must be disabled!
;
; @clobbers (R0, R1, R16, R18, R19, R20, R24, R25, X)
flashEndPage:
rcall flashCheckCurrentValid ; (r18, r19)
brcs flashEndPage_write
ret
flashEndPage_write:
push zl
push zh
rcall flashErasePage ; (R16, R20, Z)
rcall flashWritePage ; (r0, r1, r20, r24, r25, X, Z)
pop zh
pop zl
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashReadPageIntoSram
;
; @param Z Address to read from (byte address as for LPM!)
; @clobbers r16, r24, X, Z
flashReadPageIntoSram:
ldi xl, LOW(flashPageBuffer)
ldi xh, HIGH(flashPageBuffer)
ldi r24, LOW(FLASH_PAGESIZE)
flashReadPageIntoSram_loop:
lpm r16, Z+
st X+, r16
; adiw ZH:ZL, 1
dec r24
brne flashReadPageIntoSram_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashErasePage
;
; Interrupts must be disabled!
;
; @clobbers R16, R20, Z
flashErasePage:
lds zl, flashPageStart
lds zh, flashPageStart+1
ldi r20, (1<<PGERS) + (1<<SPMEN) ; enable next SPM, erase page (R1/R0 ignored)
rcall flashDoSpm ; (R16)
ret
; @end
; ---------------------------------------------------------------------------
; @routine flashDoSpm
;
; wait until possible previous SPM finished and then issue another SPM.
;
; @param R20 value for register SPMCR
; @param R0 low value for SPM
; @param R1 high value for SPM
; @param Z address for SPM (byte address!)
; @clobbers R16
flashDoSpm:
flashDoSpm_wait: ; wait for possibly previous SPM to complete
in r16, SPMCSR
sbrc r16, SPMEN
rjmp flashDoSpm_wait
; SPM timed sequence
out SPMCSR, r20
spm
ret
; @end

View File

@@ -68,13 +68,25 @@ flashWaitForMulti100ms_loop:
flashWaitFor100ms: flashWaitFor100ms:
ldi r24, 100 ldi r24, 100
flashWaitFor100ms_loop: rjmp flashWaitForMillisecs
; ---------------------------------------------------------------------------
; @routine flashWaitForMillisecs
; wait for multiples of 100 milliseconds.
;
; @param R24 time to wait in milliseconds
; @clobbers R24 (R22)
flashWaitForMillisecs:
push r24 push r24
rcall flashWaitFor1ms ; (R22, R24) rcall flashWaitFor1ms ; (R22, R24)
pop r24 pop r24
dec r24 dec r24
brne flashWaitFor100ms_loop brne flashWaitForMillisecs
ret ret
; @end