'****************************************************************************** ' Author : rgf, avr@myluna.de, http://avr.myluna.de ' Title : bootloader example ' Last updated: 09.02.2015 ' Protocol : v1.0 ' Description : flash and eeprom write with crc check, retry and error handling ' Tools : Uploader software "bootUploader" http://avr.myluna.de '****************************************************************************** ' Compiler : LunaAVR 2015r1 or newer '****************************************************************************** avr.device = atmega168 avr.clock = 20000000 avr.stack = 64 #library "Library/Crc8.interface" '****************************************************************************** '*** CHANGE CODE START ADDRESS TO BOOT LOADER SECTION ************************* '****************************************************************************** 'Luna Bootloader requires 2 kb bootloader section avr.CodeStartAddr = nrww_start_addr const MAX_PAGES = nrww_start_addr/pagesize '****************************************************************************** uart.baud = 19200 uart.Recv.enable uart.Send.enable #define SLED as portd.6 'status led #define WLED as portd.7 'write action led SLED.mode = output,low 'status led WLED.mode = output,low 'write led '****************************************************************************** 'luna bootloader protocol (universal) '****************************************************************************** ' input commands const PROTO_RDY = 0x01 'access bootloader and keep alive when accessed const PROTO_CBV = 0x02 'read controller base values, answer: const PROTO_EFP = 0x04 'erase flash page, command: , answer: const PROTO_WFP = 0x05 'erase and write flash page, command: , answer: const PROTO_EEP = 0x06 'erase eeprom page, command: , answer: const PROTO_WEP = 0x07 'erase and write eeprom page, command: , answer: ' long flashsize_bytes ' long bootloaderStartAddr_bytes ' word eepromSize_bytes ' word pagesizeFlash_bytes ' word pagesizeEeprom_bytes ' byte crc8 ' byte const PROTO_END = 0xff 'end of processing, reset controller ' input/output commands const PROTO_ACK = 0xfd 'acknowledge const PROTO_NAK = 0xfe 'not acknowledge ' memory types const MEMTYPE_FLASH = 0 const MEMTYPE_EEPROM = 1 ' misc values const COMMAND_TIMEOUT = 10000 'command timeout in ms const PAGE_BYTES = PageSize*2 'page size flash in bytes const PAGE_BYTES_EE = 8 'page size eeprom in bytes (do not change!) '****************************************************************************** '****************************************************************************** ' main program '****************************************************************************** dim i,cnt,cmd,buffer(PAGE_BYTES-1),type as byte dim ctcnt,page,eadr as word dim rtcnt as long main() procedure main() if CheckBootloaderAccess() then ack() do cmd=uart.GetByte if cmd then clr ctcnt select case cmd case PROTO_RDY ack() case PROTO_CBV uart.writelong avr.flashsize uart.writelong avr.CodeStartAddr*2 uart.writeword avr.eramsize uart.writeword PAGE_BYTES uart.writeword PAGE_BYTES_EE crc8.Start crc8.AddLong avr.flashsize crc8.AddLong avr.CodeStartAddr*2 crc8.AddWord avr.eramsize crc8.AddWord PAGE_BYTES crc8.AddWord PAGE_BYTES_EE uart.WriteByte crc8.value ack() case PROTO_EFP ack() type=MEMTYPE_FLASH ErasePage() case PROTO_WFP ack() type=MEMTYPE_FLASH EraseWritePage() case PROTO_EEP ack() type=MEMTYPE_EEPROM ErasePage() case PROTO_WEP ack() type=MEMTYPE_EEPROM EraseWritePage() case PROTO_END reset default clr ctcnt nak() end select end if delay(1) incr ctcnt loop until ctcnt=COMMAND_TIMEOUT end if 'jump to main program reset endproc '****************************************************************************** '****************************************************************************** 'sub routines '****************************************************************************** '****************************************************************************** procedure delay(a as byte) waitms a endproc '****************************************************************************** 'check if bootloader called function CheckBootloaderAccess() as byte for i=0 to 9 SLED.toggle if uart.GetByte=PROTO_RDY then return true end if delay(50) next SLED = 1 delay(1000) SLED = 0 return false endfunc '****************************************************************************** '****************************************************************************** 'erase/write page '****************************************************************************** '****************************************************************************** procedure ErasePage() page=uart.readword if MAX_PAGES>=page then 'prevent overwriting bootloader section decr page 'page number for writing is zero-based WLED=1 if type=MEMTYPE_FLASH then for i=0 To buffer().Ubound buffer(i) = 0xff next flash.PageWrite buffer(),page 'write the page data to flash else eadr=page*PAGE_BYTES_EE for i=0 To PAGE_BYTES_EE-1 eeprom.bytevalue(eadr) = 0xff incr eadr next endif ack() WLED=0 return end if nak() endproc procedure EraseWritePage() page=uart.readword if MAX_PAGES>=page then 'prevent overwriting bootloader section crc8.start 'initialize crc calculation crc8.AddWord page 'add page number to crc stream if type=MEMTYPE_FLASH then cnt=buffer().Ubound else cnt=PAGE_BYTES_EE-1 end if for i=0 To cnt 'read page data buffer(i) = uart.ReadByte 'add to buffer crc8.AddByte buffer(i) 'add to crc stream next if uart.ReadByte = crc8.value then 'equate received and calculated crc decr page 'page number for writing is zero-based WLED=1 'indicate write if type=MEMTYPE_FLASH then flash.PageWrite buffer(),page 'write the page data to flash else eadr=page*PAGE_BYTES_EE for i=0 To PAGE_BYTES_EE-1 eeprom.bytevalue(eadr) = buffer(i) incr eadr next endif WLED=0 ack() return end if end if nak() endproc procedure ack() uart.WriteByte PROTO_ACK 'say OK to transmitter endproc procedure nak() uart.WriteByte PROTO_NAK 'failed endproc