diff src/external_flash.asm @ 634:4050675965ea

3.10 stable release
author heinrichsweikamp
date Tue, 28 Apr 2020 17:34:31 +0200
parents 690c48db7b5b
children 75e90cd0c2c3
line wrap: on
line diff
--- a/src/external_flash.asm	Thu Mar 05 15:06:14 2020 +0100
+++ b/src/external_flash.asm	Tue Apr 28 17:34:31 2020 +0200
@@ -1,6 +1,6 @@
 ;=============================================================================
 ;
-;   File external_flash.asm                   combined next generation V3.08.8
+;   File external_flash.asm                 * combined next generation V3.09.4e
 ;
 ;   External flash
 ;
@@ -13,92 +13,121 @@
 	#include "wait.inc"
 	#include "eeprom_rs232.inc"
 
+;=============================================================================
 ext_flash	CODE
-
 ;=============================================================================
 
-; increase flash address by one with wrap-around at 0x400000 to 0x000000
-incf_ext_flash_address_p1_0x40:
-	movlw	.1								; increase by 1
-	;bra	incf_ext_flash_address0_0x40	; continue
+;-----------------------------------------------------------------------------
+; increase Flash Address by one with wrap-around at 0x400000 to 0x000000
+;
+ext_flash_inc_address_0x40_p1:
+	movlw	.1								; increment by 1
+	;bra	ext_flash_inc_address_0x40_exec	; execute incrementing
 
 
-; increase flash address by value in WREG with wrap-around at 0x400000 to 0x000000
-	global	incf_ext_flash_address0_0x40
-incf_ext_flash_address0_0x40:
-	clrf	ext_flash_rollover_threshold	; set wrap-around threshold without destroying WREG to ...
-	bsf		ext_flash_rollover_threshold,6	; ... 0x40
+;-----------------------------------------------------------------------------
+; increase Flash Address by Value in WREG with wrap-around at 0x400000 to 0x000000
+;
+	global	ext_flash_inc_address_0x40_exec
+ext_flash_inc_address_0x40_exec:
+	clrf	ext_flash_address_limit			; | set wrap-around threshold to
+	bsf		ext_flash_address_limit,6		; | 0x40 without destroying WREG
 	bra		incf_ext_flash_address0_common	; continue with common part
 
 
-; increase flash address by one with wrap-around at 0x200000 to 0x000000
-incf_ext_flash_address_p1_0x20:
-	movlw	.1								; increase by one
-	;bra	incf_ext_flash_address0_0x20	; continue
+;-----------------------------------------------------------------------------
+; increase Flash Address by one with wrap-around at 0x200000 to 0x000000
+;
+ext_flash_inc_address_0x20_p1:
+	movlw	.1								; increment by one
+	;bra	ext_flash_inc_address_0x20_exec	; execute incrementing
 
 
-; increase flash address by value in WREG with wrap-around at 0x200000 to 0x000000
-	global	incf_ext_flash_address0_0x20
-incf_ext_flash_address0_0x20:
-	clrf	ext_flash_rollover_threshold	; set wrap-around threshold without destroying WREG to ...
-	bsf		ext_flash_rollover_threshold,5	; ... 0x20
+;-----------------------------------------------------------------------------
+; increase Flash Address by Value in WREG with wrap-around at 0x200000 to 0x000000
+;
+	global	ext_flash_inc_address_0x20_exec
+ext_flash_inc_address_0x20_exec:
+	clrf	ext_flash_address_limit			; | set wrap-around threshold to
+	bsf		ext_flash_address_limit,5		; | 0x20 without destroying WREG
 	;bra	incf_ext_flash_address0_common	; continue with common part
 
 
+;-----------------------------------------------------------------------------
+; common Part for Flash Address Increasing
+;
 incf_ext_flash_address0_common:
-	bcf		address_wrap_around				; clear wrap-around flag
+	bcf		flash_wrap_around				; clear wrap-around flag
 	addwf	ext_flash_address+0,F			; add WREG to address:3
 	movlw	d'0'							; ...
 	addwfc	ext_flash_address+1,F			; ...
 	addwfc	ext_flash_address+2,F			; ...
-	movf	ext_flash_rollover_threshold,W	; get wrap-around threshold
+	movf	ext_flash_address_limit,W		; get wrap-around threshold
 	cpfseq	ext_flash_address+2				; at  wrap-around threshold ?
 	bra		incf_ext_flash_address1			; NO  - no wrap-around needed
 ;	clrf	ext_flash_address+0				; YES - wrap-around to 0x000000
 ;	clrf	ext_flash_address+1				;     - ...
 	clrf	ext_flash_address+2				;     - ...
-	bsf		address_wrap_around				;     - set wrap-around flag
+	bsf		flash_wrap_around				;     - set wrap-around flag
 incf_ext_flash_address1:
 	movf	ext_flash_rw,W					; export current value of ext_flash_rw via WREG, too
 	return									; done
 
 
-; decrease flash length counter by value in WREG
-	global	decf_ext_flash_length0
-decf_ext_flash_length0:
-	subwf	ext_flash_length_counter+0,F	; decrease address by value in WREG
+;-----------------------------------------------------------------------------
+; add 0x001000 to Flash Address, no Check for wrap-around
+;
+	global	ext_flash_inc_address_4kB
+ext_flash_inc_address_4kB:
+	movlw	0x10							; add 0x10 to high byte
+	addwf	ext_flash_address+1,F			; ...
+	movlw	0x00							; propagate carry to upper byte
+	addwfc	ext_flash_address+2,F			; ...
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; decrement Length Counter by 1
+;
+	global	ext_flash_dec_length_exec
+ext_flash_dec_length_exec:
+	movlw	.1								; decrement by 1
+	subwf	ext_flash_length_counter+0,F	; ...
 	movlw	d'0'							; ...
 	subwfb	ext_flash_length_counter+1,F	; ...
 	subwfb	ext_flash_length_counter+2,F	; ...
 	return									; done
 
-; ----------------------------------------------------------------------------
-
-;	global	ext_flash_byte_read_plus_0x40	; return data read in ext_flash_rw and WREG, increase address after read with wrap-around at 0x400000
-;ext_flash_byte_read_plus_0x40:
-;	rcall	ext_flash_byte_read				; read byte into ext_flash_rw
-;	bra		incf_ext_flash_address_p1_0x40	; increase address with wrap-around at 0x400000 to 0x000000 (and return)
-
 
-	global	ext_flash_byte_read_plus_0x20	; return data read in ext_flash_rw and WREG, increase address after read with wrap-around at 0x200000
-ext_flash_byte_read_plus_0x20:
-	rcall	ext_flash_byte_read				; read byte into ext_flash_rw
-	bra		incf_ext_flash_address_p1_0x20	; increase address with roll-over at 0x200000 to 0x000000 (and return)
+;-----------------------------------------------------------------------------
+; read a Byte from Flash and increment Address with wrap-around at 0x20 / 0x40
+; returns in ext_flash_rw and WREG
+;
+	global	ext_flash_read_byte_0x40
+ext_flash_read_byte_0x40:
+	bsf		flash_wrap_around				; wrap-around at 0x400000
+	bra		ext_flash_read_byte_common		; continue with common part
 
+	global	ext_flash_read_byte_0x20
+ext_flash_read_byte_0x20:
+	bcf		flash_wrap_around				; wrap-around at 0x200000
+	;bra	ext_flash_read_byte_common		; continue with common part
 
-	global	ext_flash_byte_read				; return data read in WREG and ext_flash_rw, no address change
-ext_flash_byte_read:
-	movlw	0x03							; set up  read command
-	rcall	shift_spi						; prepare read command
+ext_flash_read_byte_common:
+	movlw	0x03							; prepare read command
+	rcall	shift_spi						; execute read command
 	rcall	ext_flash_set_address			; write 24 bit address ext_flash_address:3 via SPI
 	rcall	shift_spi						; shift the SPI to read data into WREG
 	bsf		flash_ncs						; set CS=1
-	movwf	ext_flash_rw					; return data read in WREG and ext_flash_rw
-	return									; done
+	movwf	ext_flash_rw					; copy byte read from WREG to ext_flash_rw
+	btfss	flash_wrap_around				; shall wrap-around at 0x40000 ?
+	bra		ext_flash_inc_address_0x20_p1	; NO  - increment address with wrap-around at 0x200000 and return
+	bra		ext_flash_inc_address_0x40_p1	; YES - increment address with wrap-around at 0x200000 and return
 
-; ----------------------------------------------------------------------------
-; read-range base functions
 
+;-----------------------------------------------------------------------------
+; Read-Range Base Functions - start reading
+;
 	global	ext_flash_read_block_start		; return data read in WREG
 ext_flash_read_block_start:
 	movlw	0x03							; set up  read command
@@ -107,50 +136,61 @@
 	bra		shift_spi						; shift the SPI to read data into WREG (and return)
 
 
+;-----------------------------------------------------------------------------
+; Read-Range Base Functions -  increment Address and read a Byte, wrap-around at 0x40
+;
 	global	ext_flash_read_block_0x40		; return data read in WREG
 ext_flash_read_block_0x40:
-	rcall	incf_ext_flash_address_p1_0x40	; increase address with wrap-around at 0x400000
-	btfss	address_wrap_around				; did the address wrap-around?
-	bra		shift_spi_loop_1				; NO  - shift the SPI to  read data into WREG and return
-	rcall	ext_flash_read_block_stop		; YES - do a block-stop
-	bra		ext_flash_read_block_start		;     - do a block-start, read data into WREG and return
-
-
-	global	ext_flash_read_block_0x20		; return data read in WREG
-ext_flash_read_block_0x20:
-	rcall	incf_ext_flash_address_p1_0x20	; increase address with wrap-around at 0x200000
-	btfss	address_wrap_around				; did the address wrap-around?
+	rcall	ext_flash_inc_address_0x40_p1	; increase address with wrap-around at 0x400000
+	btfss	flash_wrap_around				; did the address wrap-around?
 	bra		shift_spi_loop_1				; NO  - shift the SPI to  read data into WREG and return
 	rcall	ext_flash_read_block_stop		; YES - do a block-stop
 	bra		ext_flash_read_block_start		;     - do a block-start, read data into WREG and return
 
 
+;-----------------------------------------------------------------------------
+; Read-Range Base Functions - increment Address and read a Byte, wrap-around at 0x20
+;
+;	global	ext_flash_read_block_0x20		; return data read in WREG
+;ext_flash_read_block_0x20:
+;	rcall	ext_flash_inc_address_0x20_p1	; increase address with wrap-around at 0x200000
+;	btfss	flash_wrap_around				; did the address wrap-around?
+;	bra		shift_spi_loop_1				; NO  - shift the SPI to  read data into WREG and return
+;	rcall	ext_flash_read_block_stop		; YES - do a block-stop
+;	bra		ext_flash_read_block_start		;     - do a block-start, read data into WREG and return
+
+
+;-----------------------------------------------------------------------------
+; Read-Range Base Functions - terminate reading
+;
 	global	ext_flash_read_block_stop		; end block operation
 ext_flash_read_block_stop:
 	bsf		flash_ncs						; set CS=1
 	return									; done
 
+
 ; ----------------------------------------------------------------------------
-; read-range function, to be used through macro
+; read a Range of Bytes, to be used via Macro
 ;
 	global	ext_flash_read_range
 ext_flash_read_range:
 	movwf	eeprom_loop						; load loop counter (eeprom variable used here)
-	rcall	ext_flash_read_block_start		; read first byte from flash
+	rcall	ext_flash_read_block_start		; read first byte from FLASH to WREG
 	bra		ext_flash_read_range_loop_start	; jump into loop
 ext_flash_read_range_loop:
-	rcall	ext_flash_read_block_0x40		; read next byte from flash
+	rcall	shift_spi_loop_1				; read next  byte from FLASH to WREG
 ext_flash_read_range_loop_start:
-	movwf	POSTINC1						; write byte to memory
+	movwf	POSTINC1						; write      byte from WREG  to memory
 	decfsz	eeprom_loop,F					; decrement loop counter, all done?
 	bra		ext_flash_read_range_loop		; NO  - continue loop
 	bra		ext_flash_read_block_stop		; YES - end reading from flash (and return)
 
 
 ; ----------------------------------------------------------------------------
-; write-range base functions
-
+; Write-Range Base Functions - for use with SST26VF Chip only!
+;
 ext_flash_write_block_start:
+	movwf	ext_flash_rw					; copy byte to write from WREG to ext_flash_rw
 	bsf		flash_ncs						; set CS=1
 	movlw	0x06							; set up  WREN command
 	rcall	shift_spi						; execute WREN command
@@ -158,161 +198,182 @@
 	movlw	0x02							; set up  write (PP, Page-Program) command
 	rcall	shift_spi						; execute write
 	rcall	ext_flash_set_address			; write 24 bit address ext_flash_address:3 via SPI
-	movf	ext_flash_rw,W					; get byte to write
+	movf	ext_flash_rw,W					; get back byte to write
 	bra		shift_spi						; write the byte (and return)
 
 ext_flash_write_block:
-	movf	ext_flash_rw,W					; get byte to write
 	bra		shift_spi_loop_1				; shift the SPI to write data into FLASH (and return)
 
 ext_flash_write_block_stop:
 	bra		ext_flash_wait_write			; wait for completion (and return)
 
+
 ; ----------------------------------------------------------------------------
-; write-range function, to be used through macro
+; write a Range of Bytes, to be used via Macro
 ;
 	global	ext_flash_write_range
 ext_flash_write_range:
 	movwf	eeprom_loop						; load loop counter (eeprom variable used here)
 
-;	btfsc	flash_block_write				; does the FLASH support block-write?
-;	bra		ext_flash_write_range_block		; YES - write date via block operation
-;	;bra	ext_flash_write_range_seq		; NO  - write data via sequential single writes
+	btfsc	flash_block_write				; does the FLASH support block-write?
+	bra		ext_flash_write_range_block		; YES - write data in block      mode
+	;bra	ext_flash_write_range_seq		; NO  - write data in sequential mode
 
-ext_flash_write_range_seq:					; sequential write
-ext_flash_write_range_loop_s:
-	movff	POSTINC1,ext_flash_rw			; read  byte from     memory     to  ext_flash_rw
-	rcall	ext_flash_byte_write			; write byte from  ext_flash_rw  to     FLASH
-	rcall	incf_ext_flash_address_p1_0x40	; increase address with wrap-around at 0x400000
+	; sequential write
+ext_flash_write_range_seq:
+	bsf		flash_wait						; wait for flash writes to complete
+ext_flash_write_range_seq_loop:
+	movf	POSTINC1,W						; copy  byte from memory to WREG
+	rcall	ext_flash_byte_write_common_W	; write byte from WREG   to FLASH
+	rcall	ext_flash_inc_address_0x40_p1	; increase address with wrap-around at 0x400000
 	decfsz	eeprom_loop,F					; decrement loop counter, all done?
-	bra		ext_flash_write_range_loop_s	; NO  - continue loop
+	bra		ext_flash_write_range_seq_loop	; NO  - loop
 	return									; YES - done
 
-ext_flash_write_range_block:				; block write
-	movff	POSTINC1,ext_flash_rw			; read  first byte from memory
-	rcall	ext_flash_write_block_start		; write first byte to FLASH
+	; block write
+ext_flash_write_range_block:
+	movf	POSTINC1,W						; copy first byte from memory to WREG
+	rcall	ext_flash_write_block_start		; copy first byte from WREG   to FLASH
 	bra		ext_flash_write_range_loop_start; jump into loop
-ext_flash_write_range_loop_b:
-	movff	POSTINC1,ext_flash_rw			; read  next byte from memory
-	rcall	ext_flash_write_block			; write next byte to FLASH
+ext_flash_write_range_block_loop:
+	movf	POSTINC1,W						; copy next  byte from memory to WREG
+	rcall	ext_flash_write_block			; copy next  byte from WREG   to FLASH
 ext_flash_write_range_loop_start:
 	decfsz	eeprom_loop,F					; decrement loop counter, all done?
-	bra		ext_flash_write_range_loop_b	; NO  - continue loop
-	bra		ext_flash_write_block_stop		; YES - end writing to flash (and return)
-
-; ----------------------------------------------------------------------------
-	
-;	global	write_byte_ext_flash_plus_header
-; write_byte_ext_flash_plus_header:
-;	movwf	ext_flash_rw					; store byte to write
-;											 ; test if write is done at first byte of 4kB block, if yes delete 4kB block first
-;	tstfsz	ext_flash_address+0				; at 0x....00 ?
-;	bra		write_byte_ext_flash_plus_h1	; NO - normal write
-;	movf	ext_flash_address+1,W			; YES - get high byte
-;	andlw	0x0F							;     - mask lower nibble
-;	tstfsz	WREG							;     - at 0x..0...?
-;	bra		write_byte_ext_flash_plus_h1	;       NO  - normal write
-;	rcall	ext_flash_erase_4kB				;       YES - at beginning of 4kB block -> erases 4kB sector @ext_flash_address:3
-;write_byte_ext_flash_plus_h1:
-;	rcall	ext_flash_byte_write			; write the byte in ext_flash_rw
-;	bra		incf_ext_flash_address_p1_0x40	; increase address with wrap-around at 0x400000 and return
+	bra		ext_flash_write_range_block_loop; NO  - loop
+	rcall	ext_flash_write_block_stop		; YES - initiate FLASH write
+	clrf	ext_flash_address+0				;     - advance address to start of next block
+	infsnz	ext_flash_address+1,F			;     - ...
+	incf	ext_flash_address+2,F			;     - ...
+	return									;     - done
 
 
-	global	write_byte_ext_flash_plus_prof
-write_byte_ext_flash_plus_prof:
+;-----------------------------------------------------------------------------
+; write a Byte with wrap-around at 0x200000,
+; erase on entering new 4kB Block,
+; increment Dive Length Counter
+;
+	global	ext_flash_write_byte_0x20_incdc
+ext_flash_write_byte_0x20_incdc:
 	movwf	ext_flash_rw					; store byte to write
 	incf	ext_flash_length_counter+0,F	; increase dive length counter
 	movlw	.0								; ...
 	addwfc	ext_flash_length_counter+1,F	; ...
 	addwfc	ext_flash_length_counter+2,F	; ...
-	bra		write_byte_ext_flash_plus_nocnt1; continue with checking for begin of new page
+	bra		write_byte_ext_flash_plus_nocnt1; continue with checking for begin of new block
 
 
-	global	write_byte_ext_flash_plus_nocnt
-write_byte_ext_flash_plus_nocnt:
+;-----------------------------------------------------------------------------
+; write a Byte with wrap-around at 0x200000,
+; erase on entering new 4kB Block
+; 
+	global	ext_flash_write_byte_0x20
+ext_flash_write_byte_0x20:
 	movwf	ext_flash_rw					; store byte to write
-write_byte_ext_flash_plus_nocnt1:			; test if write is done at first byte of 4kB block, if yes delete 4kB block first
-	tstfsz	ext_flash_address+0				; at 0x....00?
-	bra		write_byte_ext_flash_plus_nodel1; NO  - execute write
-	movf	ext_flash_address+1,W			; YES - mask lower nibble
-	andlw	0x0F							;     - ...
-	tstfsz	WREG							;     - at 0x..0...?
-	bra		write_byte_ext_flash_plus_nodel1;       NO  - execute write
-											;       YES - at beginning of 4kB block -> erase first!
-	rcall	ext_flash_erase_4kB				;           - erases 4kB sector @ext_flash_address:3
+write_byte_ext_flash_plus_nocnt1:
+	; check if at 1st byte of a 4kB block,
+	; if yes the block needs to be erased
+	; before new data can be written to it
+	tstfsz	ext_flash_address+0				; is the low byte of the address = 0x00 ?
+	bra		write_byte_ext_flash_plus_nodel1; NO  - not at 1st byte, can execute write
+	movf	ext_flash_address+1,W			; YES - get high byte of the address
+	andlw	0x0F							;     - keep only the lower nibble
+	tstfsz	WREG							;     - is the lower nibble = 0x0 ?
+	bra		write_byte_ext_flash_plus_nodel1;       NO  - not at 1st byte, can execute write
+	rcall	ext_flash_erase_4kB				;       YES - at 1st byte, erase 4kB block
 	bra		write_byte_ext_flash_plus_nodel1;           - execute write
 
 
-	global	write_byte_ext_flash_plus_nodel
-write_byte_ext_flash_plus_nodel:
+;-----------------------------------------------------------------------------
+; write a Byte with wrap-around at 0x200000
+; NO erase on entering new 4kB Block
+;
+	global	ext_flash_write_byte_0x20_nodel
+ext_flash_write_byte_0x20_nodel:
 	movwf	ext_flash_rw					; store byte to write
 write_byte_ext_flash_plus_nodel1:
-	rcall	ext_flash_byte_write			; write the byte in ext_flash_rw
-	bra		incf_ext_flash_address_p1_0x20	; increase address with wrap-around at 0x200000 and return
+	bsf		flash_wait						; wait for flash write to complete
+	rcall	ext_flash_byte_write_common_F	; write the byte in ext_flash_rw
+	bra		ext_flash_inc_address_0x20_p1	; increase address with wrap-around at 0x200000 and return
 
 
-	global	write_byte_ext_flash_plus_comms	; write from WREG without wait, ~86us fixed delay due to 115200 Baud, use with caution!
-write_byte_ext_flash_plus_comms:
-	movwf	ext_flash_rw					; store byte to write
+;-----------------------------------------------------------------------------
+; write a Byte without Wait (used by comm mode)
+;
+; time budget for flash to complete a write is ~86 us at 115200 Baud on serial
+;
+	global	ext_flash_write_byte_0x40_nowait
+ext_flash_write_byte_0x40_nowait:
 	bcf		flash_wait						; do not wait on flash write to complete
-	rcall	ext_flash_byte_write_common		; write the byte in ext_flash_rw
-	bra		incf_ext_flash_address_p1_0x40	; increase address with wrap-around at 0x400000 and return
+	rcall	ext_flash_byte_write_common_W	; write the byte in WREG
+	bra		ext_flash_inc_address_0x40_p1	; increase address with wrap-around at 0x400000 and return
 
 
-ext_flash_byte_write:
-	bsf		flash_wait						; wait for flash write to complete
-ext_flash_byte_write_common:
+;-----------------------------------------------------------------------------
+; internal common Write Functions W: WREG         -> FLASH(ext_flash_address)
+;                                 F: ext_flash_rw -> FLASH(ext_flash_address)
+;
+ext_flash_byte_write_common_W:
+	movwf	ext_flash_rw					; copy byte to write from WREG to ext_flash_rw
+ext_flash_byte_write_common_F:
 	bsf		flash_ncs						; set CS=1
 	movlw	0x06							; set up  WREN command
 	rcall	shift_spi						; execute WREN command
 	bsf		flash_ncs						; set CS=1
-	movlw	0x02							; set up  write (PP, Page-Program) command
+	movlw	0x02							; prepare write (PP, Page-Program) command
 	rcall	shift_spi						; execute write
 	rcall	ext_flash_set_address			; write 24 bit address ext_flash_address:3 via SPI
-	movf	ext_flash_rw,W					; get byte to write
+	movf	ext_flash_rw,W					; get back byte to write
 	rcall	shift_spi						; write the byte
 	btfsc	flash_wait						; shall wait on flash write to complete?
 	bra		ext_flash_wait_write			; YES - wait for completion (and return)
 	bsf		flash_ncs						; NO  - set CS=1
 	return									;     - done
 
-; ----------------------------------------------------------------------------
 
+;-----------------------------------------------------------------------------
+; switch off Write-Protection
+;
 	global	ext_flash_disable_protection	; disable write protection
 ext_flash_disable_protection:
 	; unlock old memory
-	bsf		flash_ncs						; CS=1
-	movlw	0x50							; EWSR command
-	rcall	shift_spi
-	bsf		flash_ncs						; CS=1
-	movlw	0x01							; WRSR command
-	rcall	shift_spi
-	movlw	b'00000000'						; new status
-	rcall	shift_spi
-	bsf		flash_ncs						; CS=1
+	bsf		flash_ncs						; set CS=1
+	movlw	0x50							; prepare EWSR command
+	rcall	shift_spi						; execute EWSR command
+	bsf		flash_ncs						; set CS=1
+	movlw	0x01							; prepare WRSR command
+	rcall	shift_spi						; execute WRSR command
+	movlw	b'00000000'						; prepare new status
+	rcall	shift_spi						; set     new status
+
 	; unlock new memory
-	movlw	0x06							; WREN command
-	rcall	shift_spi
-	bsf		flash_ncs						; CS=1
-	movlw	0x98							; ULBPR command
-	rcall	shift_spi
-	bsf		flash_ncs						; CS=1
-	movlw	0x06							; WREN command
-	rcall	shift_spi
-	bsf		flash_ncs						; CS=1
-	movlw	0x42							; WBPR command
-	rcall	shift_spi
+	bsf		flash_ncs						; set CS=1
+	movlw	0x06							; prepare WREN command
+	rcall	shift_spi						; execute WREN command
+	bsf		flash_ncs						; set CS=1
+	movlw	0x98							; prepare ULBPR command
+	rcall	shift_spi						; execute ULBPR command
+	bsf		flash_ncs						; set CS=1
+	movlw	0x06							; prepare WREN command
+	rcall	shift_spi						; execute WREN command
+	bsf		flash_ncs						; set CS=1
+	movlw	0x42							; prepare WBPR command
+	rcall	shift_spi						; execute WBPR command
+
 	movlw	.18								; 18 bytes to do
 	movwf	lo								; initialize loop counter
 ext_flash_disable_prot_loop:
 	movlw	0x00							; prepare writing a zero
-	rcall	shift_spi						; execute write
+	rcall	shift_spi						; write a zero
 	decfsz	lo,F							; all bytes done?
 	bra		ext_flash_disable_prot_loop		; NO  - loop
 	bsf		flash_ncs						; YES - set CS=1
 	return									;     - done
 
 
+;-----------------------------------------------------------------------------
+; switch on Write-Protection
+;
 	global	ext_flash_enable_protection
 ext_flash_enable_protection:
 	; lock old memory
@@ -324,69 +385,104 @@
 	rcall	shift_spi						; execute WRSR command
 	movlw	b'00011100'						; prepare write protection on
 	rcall	shift_spi						; execute write protection on
-	bsf		flash_ncs						; set CS=1
+
 	; lock new memory
-;	movlw	0x06							; WREN command
-;	rcall	shift_spi
-;	bsf		flash_ncs						; CS=1
-;	movlw	0x8D							; LBPR command
-;	rcall	shift_spi
+	bsf		flash_ncs						; set CS=1
+;	movlw	0x06							; prepare WREN command
+;	rcall	shift_spi						; execute WREN command
+;	bsf		flash_ncs						; set CS=1
+;	movlw	0x8D							; prepare LBPR command
+;	rcall	shift_spi						; execute LBPR command
 ;	bsf		flash_ncs						; set CS=1
 	movlw	0x06							; prepare WREN command
 	rcall	shift_spi						; execute WREN command
 	bsf		flash_ncs						; set CS=1
 	movlw	0x42							; prepare WBPR command
 	rcall	shift_spi						; execute WBPR command
+
 	movlw	.18								; 18 bytes to do
 	movwf	lo								; initialize loop counter
 ext_flash_enable_prot_loop:
 	movlw	0xFF							; prepare writing 0xFF
-	rcall	shift_spi						; execute write
+	rcall	shift_spi						; write a zero
 	decfsz	lo,F							; all bytes done?
 	bra		ext_flash_enable_prot_loop		; NO  - loop
 	bsf		flash_ncs						; YES - set CS=1
 	return									;     - done
 
-; ----------------------------------------------------------------------------
 
+;-----------------------------------------------------------------------------
+; erase complete Logbook
+;
 	global	erase_complete_logbook
 erase_complete_logbook:
-	; clear logbook data in EPROM
-	CLRT	mpr								; prepare a 3 byte zero integer
-	EEPROM_II_WRITE mpr,eeprom_num_dives	; reset total number of dives
-	EEPROM_TT_WRITE mpr,eeprom_log_pointer	; reset pointer to begin of log data
-	; erase logbook data in FLASH (0x000000 -> 0x2FFFFF -> 3 MByte -> 3145728 Bytes)
-	bsf		flash_ncs						; CS=1
-	clrf	ext_flash_address+0				; set address to 0x000000
-	clrf	ext_flash_address+1				; ...
-	clrf	ext_flash_address+2				; ...
-	clrf	ext_flash_rw					; write zeros
-ext_flash_erase_logbook_loop:				; 256 * 12 kB = 3.145.728 bytes to do
-	rcall	ext_flash_erase_4kB				; erase 4kB block
-	rcall	ext_flash_add_4kB				; increase ext_flash_address:3 by 4kB
-	rcall	ext_flash_erase_4kB				; erase 4kB block
-	rcall	ext_flash_add_4kB				; increase ext_flash_address:3 by 4kB
-	rcall	ext_flash_erase_4kB				; erase 4kB block
-	rcall	ext_flash_add_4kB				; increase ext_flash_address:3 by 4kB
-	decfsz	ext_flash_rw,F					; decrement loop counter, done?
-	bra		ext_flash_erase_logbook_loop	; NO  - loop
-	return									; YES - done
+	; set address to 0x000000 / prepare a 3 byte zero integer
+	CLRT	ext_flash_address
+
+	; clear logbook data in EPROM by writing all zeros
+	EEPROM_II_WRITE ext_flash_address,eeprom_num_dives		; reset the total number of dives
+	EEPROM_TT_WRITE ext_flash_address,eeprom_log_pointer	; reset pointer to begin of profile data
+
+	; erase logbook data in FLASH from 0x000000 - 0x2FFFFF = 3 MByte = 3 * 256 blocks * 4 kB/block
+
+	clrf	WREG							; erase 256 blocks per call
+	rcall	ext_flash_erase_range			; erase 1st bunch of 256 blocks
+	rcall	ext_flash_erase_range_loop		; erase 2nd bunch of 256 blocks
+	rcall	ext_flash_erase_range_loop		; erase 3rd bunch of 256 blocks
+	return									; done
 
 
-	global	ext_flash_erase_4kB				; erase a 4kB sector
+;-----------------------------------------------------------------------------
+; erase a Number of 4kB Blocks
+;
+	global	ext_flash_erase_range
+ext_flash_erase_range:
+	movwf	eeprom_loop						; initialize loop counter
+ext_flash_erase_range_loop:
+	rcall	ext_flash_erase_4kB				; erase one block
+	rcall	ext_flash_inc_address_4kB		; increase start address by 0x1000 (4kB)
+	btfsc	ext_flash_address+2,6			; reached 0x400000 ?
+	return									; YES - reached end of address range, done anyhow
+	decfsz	eeprom_loop,F					; NO  - decrement number of blocks to do, all blocks done?
+	bra		ext_flash_erase_range_loop		;       NO  - loop
+	return									;       YES - done, back to command loop
+
+
+;-----------------------------------------------------------------------------
+; erase one 4kB Block
+;
+	global	ext_flash_erase_4kB
 ext_flash_erase_4kB:
 	bsf		flash_ncs						; set CS=1
 	movlw	0x06							; prepare WREN command
 	rcall	shift_spi						; execute WREN command
 	bsf		flash_ncs						; set CS=1
-	movlw	0x20							; prepare sector erase command
-	rcall	shift_spi						; execute sector erase command
+	movlw	0x20							; prepare block erase command
+	rcall	shift_spi						; execute block erase command
 	rcall	ext_flash_set_address			; write 24 bit address ext_flash_address:3 via SPI
 	bra		ext_flash_wait_write			; wait for write to complete and return
 
-; ----------------------------------------------------------------------------
 
-; send address
+;-----------------------------------------------------------------------------
+; read JEDEC IDs
+;
+	global	ext_flash_read_jedec
+ext_flash_read_jedec:
+	movlw	0x9F							; prepare JEDEC read command
+	rcall	shift_spi						; execute JEDEC read command
+	rcall	shift_spi						; shift the SPI to read the manufacturer ID into WREG
+	movwf	lo								; store                 the manufacturer ID in   lo
+	rcall	shift_spi						; shift the SPI to read the device type  ID into WREG
+	movwf	hi								; store                 the device type  ID in   hi
+	rcall	shift_spi						; shift the SPI to read the device model ID into WREG
+	movwf	up								; store                 the device model ID in   up
+	bsf		flash_ncs						; set CS=1
+	return									; done
+
+
+;-----------------------------------------------------------------------------
+; low level Functions - send Address
+;
 ext_flash_set_address:
 	movf	ext_flash_address+2,W			; write 24 bit address ext_flash_address:3 via SPI
 	rcall	shift_spi						; ...
@@ -395,7 +491,10 @@
 	movf	ext_flash_address+0,W			; ...
 	bra 	shift_spi						; ... and return
 
-; wait on write operation to complete
+
+;-----------------------------------------------------------------------------
+; low level Functions - wait for Completion of a Write Operation
+;
 ext_flash_wait_write:
 	bsf		flash_ncs						; set CS=1
 ;	WAITMS	d'1'							; TBE/TSE=25ms...
@@ -407,16 +506,14 @@
 	bra		ext_flash_wait_write			; YES - loop waiting
 	return									; NO  - done
 
-; add 0x001000 to flash address
-ext_flash_add_4kB:
-	movlw	0x10							; add 0x10 to high byte
-	addwf	ext_flash_address+1,F			; ...
-	movlw	d'0'							; propagate carry to upper byte
-	addwfc	ext_flash_address+2,F			; ...
-	return									; done
 
-; shift the SPI bus for a combined write/read: WREG --->\      /---> WREG
-shift_spi:                                  ;          flash chip
+;-----------------------------------------------------------------------------
+; low level functions - shift the SPI Bus for a combined Write/Read
+;
+;      WREG --> write --->\      /---> read --> WREG
+;                        flash chip
+;
+shift_spi:
 	bcf		flash_ncs						; set CS=0
 shift_spi_loop_1:
 	bcf		SSP2STAT,WCOL					; clear flag
@@ -429,4 +526,100 @@
 	movf	SSP2BUF,W						; YES - copy received data to WREG
 	return									;     - done
 
+
+ IFDEF _firmware_recovery
+
+;-----------------------------------------------------------------------------
+; copy active Firmware to Backup Storage
+;
+	global	copy_fw_active_to_backup
+copy_fw_active_to_backup:
+	; erase FLASH for recovery firmware (120 kByte = 30 * 4 kByte)
+	rcall	ext_flash_to_recovery_fw				; set ext_flash_address to 0x3C0000
+	movlw	.30										; 30 blocks to do
+	rcall	ext_flash_erase_range					; erase #WREG 4kB blocks starting at ext_flash_address
+
+	; copy firmware (120 kByte = 2 x 240 x 256 byte)
+	rcall	ext_flash_to_productive_fw				; set ext_flash_address to 0x3E0000
+	clrf	hi										; flag in 1st round
+copy_fw_active_to_backup_loop1:
+	movlw	.240									; load loop counter
+	movwf	lo										; ...
+copy_fw_active_to_backup_loop2:
+	; read active firmware
+	bsf		ext_flash_address+2,1					; switch to productive firmware
+	lfsr	FSR1,buffer								; set start address in memory
+	movlw	low(.256)								; set size of range to read
+	rcall	ext_flash_read_range					; execute range-read (ext_flash_address NOT  incremented)
+	; write to backup storage
+	bcf		ext_flash_address+2,1					; switch to backup storage
+	lfsr	FSR1,buffer								; set start address in memory
+	movlw	low(.256)								; set size of range to write
+	rcall	ext_flash_write_range					; execute range-write (ext_flash_address GETS incremented)
+	; operate loop
+	decfsz	lo,F									; decrement loop counter, done?
+	bra		copy_fw_active_to_backup_loop2			; NO  - continue copying
+	tstfsz	hi										; YES - 2nd round finished?
+	return											;       YES - done
+	setf	hi										;       NO  - flag in 2nd round now
+	bra		copy_fw_active_to_backup_loop1			;           - start 2nd round
+
+
+;-----------------------------------------------------------------------------
+; copy Backup-Firmware to Update Storage
+;
+	global	copy_fw_backup_to_active
+copy_fw_backup_to_active:
+	; erase FLASH for productive firmware (120 kByte = 30 * 4 kByte)
+	rcall	ext_flash_to_productive_fw				; set ext_flash_address to 0x3E0000
+	movlw	.30										; 30 blocks to do
+	rcall	ext_flash_erase_range					; erase #WREG 4kB blocks starting at ext_flash_address
+
+	; copy firmware (120 kByte = 2 x 240 x 256 byte)
+	rcall	ext_flash_to_recovery_fw				; set ext_flash_address to 0x3C0000
+	clrf	hi										; flag in 1st round
+copy_fw_backup_to_active_loop1:
+	movlw	.240									; load loop counter
+	movwf	lo										; ...
+copy_fw_backup_to_active_loop2:
+	; read backup firmware
+	bcf		ext_flash_address+2,1					; switch to backup firmware
+	lfsr	FSR1,buffer								; set start address in memory
+	movlw	low(.256)								; set size of range to read
+	rcall	ext_flash_read_range					; execute range-read (ext_flash_address NOT  incremented)
+	; write to update storage
+	bsf		ext_flash_address+2,1					; switch to update storage
+	lfsr	FSR1,buffer								; set start address in memory
+	movlw	low(.256)								; set size of range to write
+	rcall	ext_flash_write_range					; execute range-write (ext_flash_address GETS incremented)
+	; operate loop
+	decfsz	lo,F									; decrement loop counter, done?
+	bra		copy_fw_backup_to_active_loop2			; NO  - continue copying
+	tstfsz	hi										; YES - 2nd round finished?
+	return											;       YES - done
+	setf	hi										;       NO  - flag in 2nd round now
+	bra		copy_fw_backup_to_active_loop1			;           - start 2nd round
+
+
+;-----------------------------------------------------------------------------
+; Helper Functions - point ext_flash_address to active / backup firmware storage
+;
+ext_flash_to_recovery_fw
+	movlw	0x3C									; 0x3C|
+	bra		ext_flash_common
+
+ext_flash_to_productive_fw:
+	movlw	0x3E									; 0x3E|
+	;bra	ext_flash_common
+
+ext_flash_common:
+	movwf	ext_flash_address+2						; ....|
+	clrf	ext_flash_address+1						; ....|00|
+	clrf	ext_flash_address+0						; .......|00
+	return
+
+ ENDIF
+
+;-----------------------------------------------------------------------------
+
 	END