; *************************************************************************** ; copyright : (C) 2023 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_ERROR_NONE = 0 .equ FLASH_ERROR_BAD_MSGNUM = 1 .equ FLASH_ERROR_BAD_ADDR = 2 .equ FLASH_CMD_FLASH_RSP = 74 .equ FLASH_MSG_OFFS_DESTADDR = 0 .equ FLASH_MSG_OFFS_MSGLEN = 1 .equ FLASH_MSG_OFFS_MSGDATA = 2 .equ FLASH_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA .equ FLASH_MSG_OFFS_SRCADDR = 3 .equ FLASH_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here .equ FLASH_PACKET_DATA_OFFS_ADDR = FLASH_MSG_OFFS_PAYLOAD+0 ; 2 bytes .equ FLASH_PACKET_DATA_OFFS_DATA = FLASH_MSG_OFFS_PAYLOAD+2 ; n bytes ; *************************************************************************** ; data .dseg flashDataBegin: flashUid: .byte 4 flashSendBuffer: .byte 64 flashRecvBuffer: .byte 64 flashDataEnd: ; *************************************************************************** ; code .cseg FLASH_PROTO_BEGIN: bootLoader: cli ; disable interrupts throughout the whole process ; setup stack .ifdef SPH ; if SPH is defined ldi r16, High(RAMEND) out SPH, r16 ; init MSB stack pointer .endif ldi r16, Low(RAMEND) out SPL, r16 ; init LSB stack pointer ; setup pins and interrupts cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable internal pullup for ATTN cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN port as input sbi DDRA, PORTA3 ; out cbi PORTA, PORTA3 ; on sbi DDRA, PORTA2 ; out (debug) sbi PORTA, PORTA2 ; off (debug) rcall flashReadUid sts flashUid, r18 sts flashUid+1, r19 sts flashUid+2, r20 sts flashUid+3, r21 ; wait for 3 secs before sending message ldi r16, 30 rcall flashWaitForMulti100ms ; send flash ready message ldi xl, LOW(flashSendBuffer) ldi xh, HIGH(flashSendBuffer) rcall flashWriteFlashReady rcall flashSendPacketUntilSuccess sbi PORTA, PORTA3 ; LED off ; wait up to 10s for incoming FLASH_START message ldi r16, CPRO_CMD_FLASH_START ldi r17, 100 ; 100*100ms=10s rcall flashWaitForSpecificMessageWithLed brcc bootLoader_startFirmware ; either FLASH_START or FLASH_END received cpi r16, CPRO_CMD_FLASH_START ; not FLASH_START, no flashing requested brne bootLoader_startFirmware ; receive and flash new firmware ; try to start firmware bootLoader_startFirmware: sbi PORTA, PORTA3 ; LED off ldi r16, 20 rcall flashWaitForMulti100ms ldi zl, LOW(firmwareStart*2) ldi zh, HIGH(firmwareStart*2) lpm r20, Z+ lpm r21, Z+ mov r16, r20 or r16, r21 breq bootLoader ; restart boot loader ; jmp via stack push r20 push r21 ret ; --------------------------------------------------------------------------- ; wait for a specific message to arrive within given time, flashing LED ; ; IN: ; - R16: message type to receive ; - R17: wait time in 100ms (1=100ms, 2=200ms etc.) ; OUT: ; - CFLAG: set if msg received (either expected msg or FLASH_END), cleared otherwise ; - R16: message type received (if CFLAG set) ; REGS: R2, R16, R17 (R1, R24, R25, X) flashWaitForSpecificMessageWithLed: mov r2, r16 sbi PORTA, PORTA3 ; LED off flashWaitForSpecificMessageWithLed_loop: sbi PINA, PORTA3 ; toggle LED mov r16, r2 push r17 ldi r17, 100 ; wait up to 100ms rcall flashWaitForSpecificMessage ; (R1, R16, R17, R24, R25, X) pop r17 brcs flashWaitForSpecificMessageWithLed_received dec r17 brne flashWaitForSpecificMessageWithLed_loop sbi PORTA, PORTA3 ; off clc ret flashWaitForSpecificMessageWithLed_received: sbi PORTA, PORTA3 ; off sec ret ; --------------------------------------------------------------------------- ; wait for a specific message to arrive within given time. ; ; IN: ; - R16: msg command to wait for ; - R17: time to wait for packet (in milliseconds) ; OUT: ; - CFLAG: set if msg received, cleared on timeout ; - R16 : message type received ; REGS: R1, R16, R17, X (R24, R25) flashWaitForSpecificMessage: mov r1, r16 ; expected message type ; wait for ATTN to go low flashWaitForSpecificMessage_loop0: flashWaitForSpecificMessage_loop1: ldi r16, 0 ; wait for low rcall flashWaitForAttnState1ms ; (R22, R24) brcs flashWaitForSpecificMessage_isLow dec r17 brne flashWaitForSpecificMessage_loop1 rjmp flashWaitForSpecificMessage_timeout ; receive message flashWaitForSpecificMessage_isLow: ; is low, receive message, check for msg type push r17 ldi r16, COM2_MAINTENANCE_ADDR ldi xl, LOW(flashRecvBuffer) ldi xh, HIGH(flashRecvBuffer) rcall com2ReceivePacketRaw pop r17 brcc flashWaitForSpecificMessage_waitAttnHigh ldi xl, LOW(flashRecvBuffer) ldi xh, HIGH(flashRecvBuffer) adiw xh:xl, COM2_MSG_OFFS_CMD ld r16, X sbiw xh:xl, COM2_MSG_OFFS_CMD cp r16, r1 breq flashWaitForSpecificMessage_received cpi r16, CPRO_CMD_FLASH_END breq flashWaitForSpecificMessage_received flashWaitForSpecificMessage_waitAttnHigh: dec r17 breq flashWaitForSpecificMessage_timeout ; wait for ATTN to go high flashWaitForSpecificMessage_loop2: ldi r16, 0xff ; wait for high rcall flashWaitForAttnState1ms ; (R22, R24) brcs flashWaitForSpecificMessage_isHigh dec r17 brne flashWaitForSpecificMessage_loop2 rjmp flashWaitForSpecificMessage_timeout flashWaitForSpecificMessage_isHigh: rjmp flashWaitForSpecificMessage_loop0 flashWaitForSpecificMessage_received: ; R16 contains message type sec ret flashWaitForSpecificMessage_timeout: clc ret ; --------------------------------------------------------------------------- ; Wait for up to 1ms for ATTN line to reach the given state ; ; IN: ; - R16: expected state (0xff for high, 0 for low) ; OUT: ; - CFLAG: set if state reached, cleared otherwise ; REGS: R24 (R22) flashWaitForAttnState1ms: ldi r24, 100 flashWaitForAttnState1ms_loop: push r17 in r17, COM_PIN_ATTN eor r17, r16 andi r17, (1<