; *************************************************************************** ; 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. * ; *************************************************************************** .equ FLASH_PAGESIZE = (PAGESIZE*2) ; *************************************************************************** ; data .dseg flashPageNum: .byte 2 flashPageBuffer: .byte FLASH_PAGESIZE ; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; @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 ; ; Interrupts must be disabled! ; ; @clobbers r0, r1, r20, r24, r25, X, Z flash1pWritePage: lds zl, flashPageNum lds zh, flashPageNum+1 ; erase page ldi r20, (1<