Возможно здесь есть ответы на некоторые вопросы.
CRC-16 и AES128 не вложены.
Сначала нужно добиться устойчивой работы в открытом виде, затем применить шифрование (если оно необходимо) на свой вкус. В 4КБ многое влезет...
ЕЕпром не делал, ибо у меня он не использовался.
Кстати, рекомендую скорость выбрать хотя бы 57600, на 9600 уснуть можно, читая - записывая 120кБ...
В моем варианте (500k) чтение занимает 7 секунд, запись 33 сенкунды.
; AT90CAN bootloader
; Boot exchange via USART1
; main osc 16MHz. speed - 500k
; each message format - (command byte)(page address H M L)(data 256 bytes)(crc16)
; total 262 bytes
; Possible programming space 124 kBytes for AT90CAN128
; Using AES-128 CBC Encryption/Decryprion for Read/Write Flash memory
; pavel-pervomaysk
; date 10 FEB 2015
.equ L_addr = (((FLASHEND+1)*2)-4096) ; Last programmed Block address
; Констатны для работы с бутом, на ваш вкус могут быть любыми
; Constants for managing Bootloader
.equ p_size = PAGESIZE*2 ; amount bytes in page
.equ boot_en = 0xA5 ; Enable boot command Bootin <-
.equ restart = 0xAF ; Restart bootloader Bootin <-
.equ rd_page = 0x3C ; read page command Bootin <-
.equ wr_page = 0x59 ; write page command Bootin <-
.equ st_ok = 0x85 ; Command status ok! Bootout ->
.equ st_err = 0x8A ; Command status ERROR Bootout ->
.dseg
; Boot Data RAM sedment
.dseg ;
.org 0x200 ;
;------------------------;
b_com: .byte 1 ; Bootloader command
p_ah: .byte 1 ; Page address H &1
p_am: .byte 1 ; Page address M
p_al: .byte 1 ; Page address L
bc_data: .byte 256 ; Block crypted received data
p_crch: .byte 1 ; Page CRC H-byte
p_crcl: .byte 1 ; Page CRC L-byte
;------------------------;
ack: .byte 1 ; ACK status
bmode: .byte 1 ; Bootloader mode 0 - off, 1 - on
rxch: .byte 1 ; Received bytes counteh H
rxcl: .byte 1 ; Received bytes counteh L
dummy: .byte 4 ;
aesm: .byte 1 ; AES mode 0 - decrypt 1 - encrypt
aesbc: .byte 1 ; AES128 - blocks counter!
aeskey: .byte 16 ; AES128 - key
aesdata: .byte 16 ; AES128 - data OUT
aesiv: .byte 16 ; AES128 - init vector
aesdin: .byte 16 ; AES128 - data IN
bdc_data: .byte 256 ; Block Decrypted data for writing!
.cseg ; здесь внимательно смотрим!
.org THIRDBOOTSTART ; boot size 2048words 4096 bytes 0xF800 (Dump 0x1F000)
jmp BOOTRESET ; Reset Handler
.org 0xF802 ; External Interrupt Request 0
reti
.org 0xF804 ; External Interrupt Request 1
reti
.org 0xF806 ; External Interrupt Request 2
reti
.org 0xF808 ; External Interrupt Request 3
reti
.org 0xF80A ; External Interrupt Request 4
reti
.org 0xF80C ; External Interrupt Request 5
reti
.org 0xF80E ; External Interrupt Request 6
reti
.org 0xF810 ; External Interrupt Request 7
reti
.org 0xF812 ; Timer/Counter2 Compare Match
reti
.org 0xF814 ; Timer/Counter2 Overflow
reti
.org 0xF816 ; Timer/Counter1 Capture Event
reti
.org 0xF818 ; Timer/Counter1 Compare Match A
reti
.org 0xF81A ; Timer/Counter Compare Match B
reti
.org 0xF81C ; Timer/Counter1 Compare Match C
reti
.org 0xF81E ; Timer/Counter1 Overflow
reti
.org 0xF820 ; Timer/Counter0 Compare Match
reti
.org 0xF822 ; Timer/Counter0 Overflow
jmp boot_T0_ovf ;
.org 0xF824 ; CAN Transfer Complete or Error
reti
.org 0xF826 ; CAN Timer Overrun
reti
.org 0xF828 ; SPI Serial Transfer Complete
reti
.org 0xF82A ; USART0, Rx Complete
reti
.org 0xF82C ; USART0 Data Register Empty
reti
.org 0xF82E ; USART0, Tx Complete
reti
.org 0xF830 ; Analog Comparator
reti
.org 0xF832 ; ADC Conversion Complete
reti
.org 0xF834 ; EEPROM Ready
reti
.org 0xF836 ; Timer/Counter3 Capture Event
reti
.org 0xF838 ; Timer/Counter3 Compare Match A
reti
.org 0xF83A ; Timer/Counter3 Compare Match B
reti
.org 0xF83C ; Timer/Counter3 Compare Match C
reti
.org 0xF83E ; Timer/Counter3 Overflow
jmp boot_T3_ovf ;
.org 0xF840 ; USART1, Rx Complete
jmp _b_rxd1 ; Get byte via USART1!
.org 0xF842 ; USART1, Data Register Empty
reti
.org 0xF844 ; USART1, Tx Complete
reti
.org 0xF846 ; 2-wire Serial Interface
reti
.org 0xF848 ; Store Program Memory Read
reti
BOOTRESET: ; Bootloader reset point!
;---- STACK INIT --------;
ldi tmp, low(ramend) ;
out SPL,tmp ;
ldi tmp,high(ramend) ;
out SPH,tmp ;
cli
;---- Move_interrupts ---;
in tmp,MCUCR ; Get MCUCR
mov tmp1,tmp ;
ori tmp,(1<<IVCE) ; Enable change of Interrupt Vectors
out MCUCR,tmp ;
ori tmp1,(1<<IVSEL) ; Move interrupts to Boot Flash section
out MCUCR,tmp1 ;
;------------------------;
clr zero ; ZERO - Always =0!
;---- USART1 ------------; Warning ! U2X1 = 1 Right values!
;---- 500k --------------; RXD interrupt mode!
sts UBRR1H,zero ; USART1 speed select for 16MHz!
ldi tmp,3 ; (207)-9600;(51)-38400;(16)-115200;(7)-250k;(3)-500k;(1)-1m
sts UBRR1L,tmp ;
; RXC1 TXC1 UDRE1 FE1 DOR1 UPE1 U2X1 MPCM1
ldi tmp,0b00000010 ;
sts UCSR1A,tmp ;
; RXCIE1 TXCIE1 UDRIE1 RXEN1 TXEN1 UCSZ12 RXB81 TXB81
ldi tmp,0b10011000 ; Receive bytes interrupt mode!
sts UCSR1B,tmp ;
; low 7 bits ; – UMSEL1 UPM11 UPM10 USBS1 UCSZ11 UCSZ10 UCPO1L
ldi tmp,0b00000110 ;
andi tmp,0x7f ;
sts UCSR1C,tmp ;
;---- TIMER0 ------------;
; FOC0A WGM00 COM0A1 COM0A0 WGM01 CS02 CS01 CS00
ldi tmp,0b00000001 ; (0-off),(1-F/1),(2-F/8),(3-F/64),(4-F/256),(5-F/1024),(6,7-External,f,r)
out TCCR0A,tmp ;
out TCNT0,zero ;
out OCR0A,zero ;
out TIFR0,zero ;
; – – – – – – OCIE0A TOIE0
ldi tmp,(1<<TOIE0) ;
sts TIMSK0,tmp ; Timer/Counter0 Overflow Interrupt Enable 0x01
;---- TIMER3 ------------;
; COM3A1 COM3A0 COM3B1 COM3B0 COM3C1 COM3C0 WGM31 WGM30
ldi tmp,0b00000000 ;
sts TCCR3A,tmp ;
; ICNC3 ICES3 – WGM33 WGM32 CS32 CS31 CS30
; Fclk 16MHz OVF time
ldi tmp,2 ; (1-t ~4ms);(2-t ~33ms);(3-t ~260ms);(4-t ~1s);(5-t !4.19s);
sts TCCR3B,tmp ;
; FOC3A FOC3B FOC3C – – – – –
sts TCCR3C,zero ;
sts TCNT3H,zero ; счетчик таймера_1 H
sts TCNT3L,zero ; счетчик таймера_1 L
sts ICR3H,zero ;
sts ICR3L,zero ;
sts OCR3AH,zero ;
sts OCR3AL,zero ;
sts OCR3BH,zero ;
sts OCR3BL,zero ;
; – – ICF3 – OCF3C OCF3B OCF3A TOV3
sts TIFR3,zero ;
; – – ICIE3 – OCIE3C OCIE3B OCIE3A TOIE3
ldi tmp,(1<<TOIE3) ;
sts TIMSK3,tmp ; Timer/Counter3 Overflow Interrupt Enable
;---- PORTA -------------;
ldi tmp,0x00 ; PA3 - debug led
out PORTA,tmp ; When boot started - status LED turn off!
ldi tmp,0x08 ;
out DDRA,tmp ;
;------------------------;
;---- BOOT RAM CLEAR ----; Очистка оперативной памяти от случайного мусора
ldi yl,low (SRAM_START); RAM start address
ldi yh,high(SRAM_START);
ldi xl,low (SRAM_SIZE) ; amount bytes
ldi xh,high(SRAM_SIZE) ;
ldi tmp,0xFF ; Fill RAM 0xFF
b_ram_clear: ;
st Y+,tmp ;
sbiw xl,1 ;
brne b_ram_clear ;
;------------------------;
;------------------------;
sts aesm,zero ; aesmode!
sts aesbc,zero ; Clear aes block counter
clr xh ;
clr xl ;
sts rcnt1,zero ; Ramcounter1 =0!
sts rcnt3,zero ; Ramcounter3 =0!
sts bmode,zero ; Turn ON ckecking bootloader timeout counter
sts rxch,zero ;
sts rxcl,zero ; clear RX bytes counter!
;------------------------;
; load AES128 key ;
ldi ZL, byte3(key<<1) ; Initialize Z pointer
out RAMPZ,ZL ;
ldi ZH, byte2(key<<1) ;
ldi ZL, byte1(key<<1) ;
ldi YH,high(aeskey) ;
ldi YL,low (aeskey) ;
loadaeskey: ;
elpm tmp,Z+ ;
st Y+,tmp ;
cpi YL,low(aeskey+16) ;
brne loadaeskey ;
;------------------------;
; load AES128 Init Vector from flash!
ldi ZL, byte3(Bl_ver<<1); Initialize Z pointer
out RAMPZ,ZL ;
ldi ZH, byte2(Bl_ver<<1);
ldi ZL, byte1(Bl_ver<<1);
ldi YH,high(aesiv) ;
ldi YL,low (aesiv) ;
ld_aesiv: ; cycle 16
elpm tmp,z+ ;
st y+,tmp ; store AES init vector!
cpi yl,low(aesiv+16) ;
brne ld_aesiv ;
;------------------------;
sei ; Enable interrupts!
;----------------------;
; while(tmp=!0xA5){ ;
; tmp=b_com ;
; } ;
;----------------------;
waiting_boot: ; Waiting & checking boot command 0xA5!
ldi yl,low (b_com) ;
ldi yh,high(b_com) ; RAM pointer
ld tmp,y ; load command from RAM
cpi tmp,boot_en ; compare with (0xA5)
breq run_loader ;
rjmp waiting_boot ;
;----------------------;
run_loader: ; Start bootloader main loop
ldi tmp2,st_ok ; load constanr
rcall us_tx ; Send Status_OK!
;----------------------;
ldi tmp,1 ;
sts bmode,tmp ; Turn OFF ckecking bootloader timeout counter
sts rcnt3,zero ; clear timeout counter
;************************************************************************
init_flags: ;
clr flags ; Clear flags
;----------------------;
boot_main: ;
;----------------------;
sbrc flags,0 ; Check 0-th bit
rjmp read_blockx ; Read blockX
;----------------------;
sbrc flags,1 ; Check 1-th bit
rjmp write_blockx ; write blockX
;----------------------;
sbrc flags,7 ; Check 7-th bit
rjmp check_b_com ;
;----------------------; end of boot main handler loop
rjmp boot_main ; jump to boot clear flags
;*************************************************************************
;boot_en = 0xA5 ; Enable boot command Bootin <-
;restart = 0xAF ; Restart bootloader Bootin <-
;rd_page = 0x3C ; read page command Bootin <-
;wr_page = 0x59 ; write page command Bootin <-
;st_ok = 0x80 ; Command status ok! Bootout ->
;st_err = 0x81 ; Command status ERROR Bootout ->
check_b_com: ; Checking BOOT commands!
lds tmp,b_com ; Load command
;----------------------; Check command 1
ch_n1: ; label1
cpi tmp,restart ; compare received command with (0xAF)
breq reset_boot ;
rjmp ch_n2 ; check next constant ->
reset_boot: ;
cli ;
sts bmode,zero ;
rjmp BOOTRESET ; jump to BOOTRESET
;----------------------; Check command 2
ch_n2: ; label 2
cpi tmp,rd_page ; compare received command with (0x3C)
breq set_rd_fl ;
rjmp ch_n3 ; check next constant ->
set_rd_fl: ;
ldi flags,0x01 ; set bin no.0
rjmp boot_main ;
;----------------------; Check command 3
ch_n3: ; label 3
cpi tmp,wr_page ; compare received command with (0x59)
breq set_wr_fl ;
rjmp ch_b_ok ; leave checking commands
set_wr_fl: ;
ldi flags,0x02 ; set bin no.1
rjmp ch_wr_d ; check write data
ch_b_ok: ;
rjmp init_flags ; clear flags jump to boot_main
;----------------------;
;----------------------; Load address, encrypt block, send to usart
read_blockx: ;
ldi tmp2,st_ok ;
rcall us_tx ; Send command to the USART1
;----------------------;
lds zl,p_ah ; Init RAMPZ:Z pointer
out RAMPZ,zl ; Flash address RAMPZ0
lds zh,p_am ; Flash address M
lds zl,p_al ; Flash address L
ldi yl,low (bc_data) ; Encrypted AES data
ldi yh,high(bc_data) ; RAM pointer
;----------------------; Read 256 bytes from Flash
ldi loop3,0 ; amount
read_b_c: ;
elpm tmp2,z+ ; load byte, address=+1
st y+,tmp2 ; store byte in ram
dec loop3 ;
brne read_b_c ;
;----------------------; Encrypt block
ldi tmp,1 ; load aes ecncrypt mode
sts aesm,tmp ; AES Encryption
rcall _aesB ; Encrypt stored Block
;----------------------; Send block to USART1
ldi yl,low (bdc_data) ; Encrypted AES data
ldi yh,high(bdc_data) ; RAM pointer
ldi loop3,0 ; 256 bytes!
read_b_ce: ;
ld tmp2,y+ ;
rcall us_tx ; Send data to the USART1
dec loop3 ;
brne read_b_ce ;
;----------------------;
rjmp init_flags ; clear flags jump to boot_main
;----------------------;
write_blockx: ;
clr tmp ; selecl mode Decrypt
sts aesm,tmp ; save mode
rcall _aesB ; decrypr received block 256bytes
; save result block 256 bytes in (bdc_data)
lds zl,p_ah ; Init RAMPZ:Z pointer
out RAMPZ,zl ; Flash address RAMPZ0
lds zh,p_am ; Flash address M
lds zl,p_al ; Flash address L
;----------------------;
;ldi yl,low (bc_data) ; pure received data without decrypting
;ldi yh,high(bc_data) ; RAM pointer
ldi yl,low (bdc_data) ; Decrypted AES data
ldi yh,high(bdc_data) ; RAM pointer
rcall write_page ; Write page to flash!
wr_b_end: ;
rcall us_tx ; Send command to the USART1
rjmp init_flags ; clear flags jump to boot_main
;----------------------;
ch_wr_d: ; check write data block!
; 262 bytes = 0x0106
ldi tmp,6 ; amount bytes!
mov r0,tmp ;
ldi tmp,1 ;
mov r1,tmp ; r1:r0 = 0x0106 (same 262)
;---- comparing -------;
lds xl,rxcl ;
lds xh,rxch ; Load amount received bytes!
cp xl,r0 ;
cpc xh,r1 ;
breq check_b262 ;
rjmp init_flags ; clear flags jump to boot_main
;----------------------;
check_b262: ; check crc in received ram block
rcall crc16 ; check received data block CRC
rjmp boot_main ;
crc16: ; CRC-16 POLY 0xA001
; your CRC16 code

ret ; return
;----------------------;
us_tx: ;
lds tmp,UCSR1A ;
sbrs tmp,UDRE1 ;
rjmp us_tx ;
; Put data (data) into buffer, sends the data
sts UDR1,tmp2 ;
ret ; return
;----------------------;
;----------------------;
_b_rxd1: ; USART1 receive interrupt
; we've got (n) bytes from USART1
; (n) = X
push tmp ; store register in stack
in tmp,SREG ; store SREG
push tmp ; store register in stack
push yl ; store register in stack
push yh ; store register in stack
;----------------------;
; received bytes max length -
lds tmp,UDR1 ; tmp= RXD byte
ldi yl,low (b_com) ;
ldi yh,high(b_com) ; RAM pointer
add yl,xl ;
adc yh,xh ; RAM pointer + RXD bytes loop
st y,tmp ; save RXD byte in RAM
adiw xl,1 ; Received bytes pointer +1
out TCNT0,zero ; Clear counter Timer0
ldi tmp,2 ; FOC0A FOC0B – – WGM02 CS02 CS01 CS00
out TCCR0A,tmp ; F.clk/1024 normal mode time overflow (~ )
;----------------------;
pop yh ; restore register from stack
pop yl ; restore register from stack
pop tmp ; restore register from stack
out SREG,tmp ; restore SREG
pop tmp ; restore register from stack
reti ; Interrupt exit
;----------------------;
boot_T0_ovf: ; Timer 0 overflow in boot section
push tmp ; store register in stack
in tmp,SREG ; store SREG
push tmp ; store register in stack
sts rxch,xh ; save amount received bytes H
sts rxcl,xl ; save amount received bytes L
clr xh ; clear received bytes counter H
clr xl ; clear received bytes counter L
ldi flags,0x80 ; set 7-th bit
out TCCR0A,zero ; Stop Timer 0
out TCNT0,zero ; Clear counter Timer0
pop tmp ; Restore tmp from STACK
out SREG,tmp ; Restore SREG
pop tmp ; Restore tmp from STACK
reti ; Interrupt exit
;----------------------; For debug led blinking each 0.25 seconds
; (TCCR3B=3)
boot_T3_ovf: ; Timer 3 overflow
push tmp ; Store tmp, stack
in tmp,SREG ; read status register
push tmp ; Store tmp, stack
push tmp1 ; Store tmp1, stack
push tmp2 ; Store tmp2, stack
;----------------------;
lds tmp,bmode ; Load bootloader mode
andi tmp,1 ; mark bit.0
sbrc tmp,0 ; skip next command if bit cleared
rjmp t3_blink ;
;----------------------;
ch_mreset_time: ; Chech MainRESET time
lds tmp,rcnt3 ; amount OVF3 value
cpi tmp,2 ; bootloader without (boot_en) command working ~ 67ms!
brsh _jump_mreset ; led blink single
;----------------------;
t3_blink: ;
lds tmp1,rcnt1 ; Get Led value
mov tmp2,tmp1 ; copy data
andi tmp2,1 ; mark bit.0
tst tmp2 ; counter?0
breq boot_led_0 ; branch if equal
sbi ledp,lstat ; Led ON
rjmp boot_led_ok ; jump PC+2
boot_led_0: ;
cbi ledp,lstat ; Led OFF
boot_led_ok: ;
inc tmp ; ovf counter=+1
inc tmp1 ; blink counter=+1
sts rcnt1,tmp1 ; Store led counter
sts rcnt3,tmp ; Store OVF counter value
pop tmp2 ; restore register from stack
pop tmp1 ; restore register from stack
pop tmp ; restore register from stack
out SREG,tmp ; Restore SREG
pop tmp ; restore register from stack
reti ; Interrupt exit
_jump_mreset: ;
cli ; disable interrupts!
jmp RESET ; jump to main RESET!
; code from datasheet AT90CAN32/64/128
; Y = RAM data pointer
; RAMPZ0:Z = flash address pointer
; Edited lpm to ELPM!
; added Status wrote page!
Write_page: ; Write flash page 256 bytes
ldi tmp,(1<<PGERS)|(1<<SPMEN)
call Do_spm ; Page Erase
ldi tmp, (1<<RWWSRE)|(1<<SPMEN)
call Do_spm ; re-enable the RWW section
; transfer data from RAM to Flash page buffer
ldi xl,low (p_size) ; init loop variable
ldi xh,high(p_size) ; not required for PAGESIZEB<=256
Wrloop: ;
ld r0,Y+ ;
ld r1,Y+ ;
ldi tmp,(1<<SPMEN) ;
call Do_spm ;
adiw ZH:ZL,2 ;
sbiw xh:xl,2 ; use subi for PAGESIZEB<=256
brne Wrloop ;
;--------------------------; execute Page Write
subi ZL,low (p_size) ; restore pointer
sbci ZH,high(p_size) ; not required for PAGESIZEB<=256
ldi tmp, (1<<PGWRT) | (1<<SPMEN)
call Do_spm
; re-enable the RWW section
ldi tmp, (1<<RWWSRE) | (1<<SPMEN)
call Do_spm
; read back and check, optional
ldi xl,low (p_size) ; init loop variable
ldi xh,high(p_size) ; not required for PAGESIZEB<=256
subi YL,low (p_size) ; restore pointer
sbci YH,high(p_size) ;
;--------------------------;
Rdloop: ;
elpm r0,Z+ ; Load wrote data from flash
ld r1,Y+ ; Load right data from Ram
cpse r0,r1 ; compare and skip if equal
rjmp Loader_Error ; If not equal - STATUS ERROR!
rdl_p:
sbiw xh:xl,2 ; use subi for PAGESIZEB<=256
brne Rdloop ;
; return to RWW section
; verify that RWW section is safe to read
Return:
in tmp1,SPMCSR
sbrs tmp1,RWWSB ; If RWWSB is set, the RWW section is not ready yet
ldi tmp2,st_ok ;
ret
; re-enable the RWW section
ldi tmp,(1<<RWWSRE)|(1<<SPMEN)
call Do_spm ;
rjmp Return ;
Do_spm:
Wait_spm: ; check for previous SPM complete
in tmp1,SPMCSR
sbrc tmp1,SPMEN
rjmp Wait_spm
; input: spmcsrval determines SPM action
in tmp2,SREG ; disable interrupts if enabled, store status
cli
Wait_ee: ; check that no EEPROM write access is present
sbic EECR,EEWE ;
rjmp Wait_ee ;
out SPMCSR,tmp ; SPM timed sequence
spm
out SREG,tmp2 ; restore SREG (to enable interrupts if originally enabled)
ret ; return
loader_error: ;
ldi tmp2,st_err ; load status error
ret ; leave write_page
.include "aes128.asm"
После того, как мы выходим из бута, обязательно нужно вернуть прерывания обратно!