Код:
'-------------------------------------------------------------------------------
'IMPORTANT : Look at BOOTLOADER.BAS which is simpler
'-------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
'name : bootM8.bas
'copyright : (c) 1995-2005, MCS Electronics
'purpose : demonstration of genereric bootloader program
'micro : Mega8
'suited for demo : yes
'commercial addon needed : no
'use in simulator : not possible
'--------------------------------------------------------------------------------
'
'Include at end of regular program
'
'Bootloader Code:
'The fusebits need to be set for 128 bytes for the boot code,
'starting at $F80
'
'Fusebits: Boot Application Bootloader End of Boot Reset
'BOOTSZ1 BOOTSZ0 Size Flash Section Flash Section Application Address
' 1 1 128 $000 - $F7F $F80 - $FFF $F7F $F80
'
'Standard Intel hex file can be sent: (spaces added for readability)
'All record sizes must be even, AVR uses WORDs, not bytes
'
' :Size Address Type Data Bytes Checksum
' :10 00 00 00 26 C0 B3 C0 B3 C0 B3 C0 B3 C0 C5 C0 C5 C0 D0 C0 A4
' :10 00 10 00 DB C0 E4 C0 ED C0 30 31 32 33 34 35 36 37 38 39 E7
' -
' -
' :10 05 30 00 55 DF 08 95 57 E5 57 DF 52 E5 55 DF 54 E5 53 DF A2
' :10 05 40 00 5C E2 51 DF 53 2F 52 95 49 DF 53 2F 47 DF 01 D0 33
' :0B 05 50 00 08 95 5D E0 48 DF 5A E0 46 DF 08 95 A2 DC
' :00 00 00 01 FF
'
'--------------------------------------------------------------------------------
$regfile = "M8def.dat" 'Set the chip type to ATmega8
Const Ramend_lo = $5f 'RAM ending location to set up stack pointer
Const Ramend_hi = $04
Const Pagesize = 32 'Flash Memory Page Size, in WORDS
'Variable Definitions:
!.def Tmp_reg = R16 'Temporary register for calculations etc.
!.def Hex_reg = R17 'Hex calculation register
!.def Ser_reg = R18 'Serial character buffer register
!.def SPM_reg = R19 'Temporary register for SPM register settings
!.def Rec_size = R20 'Number of data bytes in this Hex file line
!.def Chk_sum = R21 'Checksum storage
'Dummy Start code for Simulator
jmp $f80
End 'end program
'******************************************************************************
'Start of Bootloader Code Area
'$boot = $f80 'Set boot vector to F80 - CORRECT VALUE
$boot = $f7f 'Set boot vector to F7F and add a NOP, for BASCOM Programmer
nop
Disable Interrupts 'no interrupts allowed during bootloader programming
_chk_for_bootload: 'Check for bootload, this one uses hardware, Port D.5
cbi DDRD,5 'Clear the data direction bit for input
sbi PORTD,5 'Set the pull-up
sbic PIND,5 'Skip next instruction if pin is clear
jmp $0000 'Pin must be high, run normal code
_bootloader_start: 'Otherwise, run the bootloader
ldi tmp_reg,Ramend_Hi 'Load temp reg with the top of SRAM value
!out SPH,tmp_reg 'Move out to stack pointer low byte
ldi tmp_reg,Ramend_Lo 'Load temp reg with the top of SRAM value
!out SPL,tmp_reg 'Move out to stack pointer low byte
ldi tmp_reg,$00 'Load the temp register with USART settings
!out UCSRA,tmp_reg 'Set up the USART
ldi tmp_reg,$18 'Load the temp register with USART settings
!out UCSRB,tmp_reg 'Set up the USART
ldi tmp_reg,$86 'Load the temp register with USART settings
!out UCSRC,tmp_reg 'Set up the USART
ldi tmp_reg,$00 'Load the temp register with USART baud rate high
!out UBRRH,tmp_reg 'Set up the USART
ldi tmp_reg,25 'Load the temp register with USART baud rate low
!out UBRRL,tmp_reg 'Set up the USART
clt 'Clear the T flag, used to indicate end of file
_send_boot_msg: 'Send a bootloader started message
ldi ser_reg, asc("B") 'Load "B" to show bootloader enabled
rcall _send_ser 'Call routine to send a character
_read_lines: 'Read in the lines from serial port to SRAM
rcall _receive_hex_line 'Receive a single line from the UART into SRAM
_parse_line: 'Decode the current hex line
ldi XH,$01 'Point to start of line, high byte, uses $0100
ldi XL,$00 'Point to start of line, low byte
clr chk_sum 'Clear the checksum register for this line
_read_header:
ld tmp_reg,x+ 'Get first character, should be ":"
cpi tmp_reg, asc(":") 'Compare with ":" to send as error flag
breq _header_ok 'Fine, read the next record
_header_err: 'Not ":", send error character
ldi ser_reg, asc("!") 'Header error
rcall _send_ser 'Call routine to send a character
_header_ok: 'Fine, read the next record
_read_record_size: 'Read the data byte count for this line
rcall _char_to_byte 'Call routine to convert two characters to byte
mov rec_size,hex_reg 'Save number of bytes in this line
tst rec_size 'Test if record size is zero for this line
brne _read_address 'Not the final line, continue
!set 'Set the T flag indicating write last page
rjmp _write_current_page 'Final line, write current page exit to main program
_read_address: 'Read the address high byte and low bytes into ZH/ZL
rcall _char_to_byte 'Call routine to convert two characters to byte
mov ZH,hex_reg 'Load ZH with page address high byte
rcall _char_to_byte 'Call routine to convert two characters to byte
mov ZL,hex_reg 'Load ZL with page address low byte
_read_record_type: 'Read the record type for this line
rcall _char_to_byte 'Call routine to convert two characters to byte
_read_data_pairs: 'Read the rest of the data bytes
rcall _char_to_byte 'Call routine to convert two characters to byte
mov r0,hex_reg 'Save in R0, LS Byte of page write buffer
rcall _char_to_byte 'Call routine to convert two characters to byte
mov r1,hex_reg 'Save in R1, MS Byte of page write buffer
_store_word: 'Store current R1/R0 Word in page buffer at proper address
ldi spm_reg,1 'Load SPM Enable (SPMEN)
rcall _exec_spm 'Execute current SPM, return is in exec_spm
_check_byte_count: 'Check if this was the last word of the line
subi rec_size,2 'Decrement the Record Size by two bytes
breq _read_checksum 'Done with this data, read checksum
subi ZL,$FE 'Not done, increment the low address byte by two
rjmp _read_data_pairs 'Go back and read the next two characters
_read_checksum: 'Byte count = record size, next is checksum for this line
rcall _char_to_byte 'Call routine to convert two characters to byte
breq _checksum_ok 'Must have added to zero, checksum is okay
_checksum_err: 'Checksum or other decoding error detected
ldi ser_reg, asc("!") 'Load "!" to send as error flag
rcall _send_ser 'Call routine to send a character
_checksum_ok:
'Done decoding and storing one complete input line, so check if this page is full
_chk_page_full: 'Check if this page is full
mov tmp_reg, ZL 'Load the address low byte into the temp reg
andi tmp_reg,((Pagesize - 1 )*2) 'AND with page size for this device, mask bits
cpi tmp_reg,((Pagesize - 1 )*2) 'Compare with page size for this device
brne _read_lines 'Page buffer is not full, read another line
_write_current_page: 'Write current page if the page buffer is full
_erase_page: 'Erase Page, page address is in Z12-Z6
ldi spm_reg,3 'Load Page Erase (PGERS) and SPM Enable (SPMEN)
rcall _exec_spm 'Execute current SPM
_write_page: 'Page address range is Z12-Z6 for Mega8
andi ZL,$C0 'Ensure that Z5 - Z0 are 0
ldi spm_reg,5 'Load page write (PGWRT) and SPM Enable (SPMEN)
rcall _exec_spm 'Execute current SPM
_enable_page: 'Re-enable the Read-While-Write section
rcall _wait_spm 'Check if current write is complete
ldi spm_reg,11 'Set RWWSRE and SPMEN only
rcall _exec_spm 'Execute current SPM
_check_end_of_file: 'Check if this is the end of the file
brtc _read_lines 'Not the last page, continue to read in data lines
_exit_bootloader: 'Done, exit the bootloader code
jmp $0000 'Jump to main program reset vector
'*******************************************************************************
'Send a serial character
_send_ser: 'Send a serial characater
sbis UCSRA,UDRE 'Check if USART data register is empty
rjmp _send_ser 'Not ready yet, wait
!out UDR,ser_reg 'Send serial register
ret
'*******************************************************************************
'Get one line from the serial port and store at start of SRAM
_receive_hex_line:
ldi XH,$01 'Set pointers to SRAM location $0100
ldi XL,$00 'Above all registers
ldi ser_reg, asc("?") 'No data now, so load "?" to request next character
rcall _send_ser 'Call routine to send a character
_receive_hex_line_char: 'Get a character from UART and add to buffer
sbis UCSRA,RXC 'Check UART for a serial character received
rjmp _receive_hex_line_char 'No, check again...
in tmp_reg,UDR 'Store input character in temp register
' mov ser_reg, tmp_reg 'Echo this character for troubleshooting
' rcall _send_ser 'Call routine to send a character
cpi tmp_reg,13 'Compare with <CR>, input line terminator
breq _receive_hex_line_end 'Yes, line is finished, branch to end
st x+,tmp_reg 'Otherwise store value then increment buffer and
rjmp _receive_hex_line_char 'Go back and get next character
_receive_hex_line_end: 'This input line is finished, so
ret 'Done with this line, so return
'*******************************************************************************
'Get two characters from buffer, add to checksum and return with result in hex_reg
_char_to_byte:
ld hex_reg,x+ 'Load character into hex_reg, increment X
subi hex_reg,$41 'ASCII Value minus $41, "A"
brcc _char_to_byte1 'Branch if value was greater than $41
subi hex_reg,$F9 'Not greater, subtract $F9
_char_to_byte1:
subi hex_reg,$F6 'Subtract $F6
lsl hex_reg 'Shift this data
lsl hex_reg 'Left for four bits
lsl hex_reg 'To move it into the
lsl hex_reg 'High nibble
ld tmp_reg,x+ 'Get next character,
subi tmp_reg,$41 'ASCII Value minus $41, "A"
brcc _char_to_byte2 'Branch if value was greater than $41
subi tmp_reg,$F9 'Not greater, subtract $F9
_char_to_byte2:
subi tmp_reg,$F6 'Subtract $F6
add hex_reg,tmp_reg 'Add into hex register
add chk_sum,hex_reg 'Add it into the checksum for this line
ret
'*******************************************************************************
_exec_spm: 'Execute the current SPM instruction
!out spmcr,spm_reg 'Send to SPM Control Register
spm 'Do SPM instruction
_wait_spm: 'Check if current flash write is complete
in spm_reg,spmcr 'Get the SPM control Register
sbrc spm_reg,spmen 'Check if SPM Enable flag is clear
rjmp _wait_spm 'No, go back and wait for SPMEN flag cleared
ret 'Flag cleared, Return
'*******************************************************************************
Добавлено спустя 1 минуту 14 секунд:Код:
'----------------------------------------------------------------
' (c) 1995-2007, MCS
' Bootloader.bas
' This sample demonstrates how you can write your own bootloader
' in BASCOM BASIC
' VERSION 2 of the BOOTLOADER. The waiting for the NAK is stretched
' further a bug was resolved for the M64/M128 that have a big page size
'-----------------------------------------------------------------
'This sample will be extended to support other chips with bootloader
'The loader is supported from the IDE
$crystal = 8000000
'$crystal = 14745600
$baud = 38400 'this loader uses serial com
'It is VERY IMPORTANT that the baud rate matches the one of the boot loader
'do not try to use buffered com as we can not use interrupts
'$regfile = "m8def.dat"
'Const Loaderchip = 8
'$regfile = "m168def.dat"
'Const Loaderchip = 168
'$regfile = "m16def.dat"
'Const Loaderchip = 16
'$regfile = "m32def.dat"
'Const Loaderchip = 32
'$regfile = "m88def.dat"
'Const Loaderchip = 88
'$regfile = "m162def.dat"
'Const Loaderchip = 162
'$regfile = "m128def.dat"
'Const Loaderchip = 128
'$regfile = "m64def.dat"
'Const Loaderchip = 64
'$regfile = "m2561def.dat"
'Const Loaderchip = 2561
$regfile = "m2560def.dat"
Const Loaderchip = 2560
'$regfile = "m329def.dat"
'Const Loaderchip = 329
'$regfile = "m324pdef.dat"
'Const Loaderchip = 324
#if Loaderchip = 88 'Mega88
$loader = $c00 'this address you can find in the datasheet
'the loader address is the same as the boot vector address
Const Maxwordbit = 5
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 168 'Mega168
$loader = $1c00 'this address you can find in the datasheet
'the loader address is the same as the boot vector address
Const Maxwordbit = 6
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 32 ' Mega32
$loader = $3c00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 8 ' Mega8
$loader = $c00 ' 1024 words
Const Maxwordbit = 5 'Z5 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 161 ' Mega161
$loader = $1e00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
#endif
#if Loaderchip = 162 ' Mega162
$loader = $1c00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 64 ' Mega64
$loader = $7c00 ' 1024 words
Const Maxwordbit = 7 'Z7 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 128 ' Mega128
$loader = &HFC00 ' 1024 words
Const Maxwordbit = 7 'Z7 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 2561 ' Mega2561
$loader = &H1FC00 ' 1024 words
Const Maxwordbit = 7 'Z7 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 2560 ' Mega2560
$loader = &H1FC00 ' 1024 words
Const Maxwordbit = 7 'Z7 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 16 ' Mega16
$loader = $1c00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 329 ' Mega32
$loader = $3c00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
#if Loaderchip = 324 ' Mega32
$loader = $3c00 ' 1024 words
Const Maxwordbit = 6 'Z6 is maximum bit '
Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
Const Maxword =(2 ^ Maxwordbit) * 2 '128
Const Maxwordshift = Maxwordbit + 1
Const Debug = 0 ' leave this to 0
#if Debug
Print Maxword
Print Maxwordshift
#endif
'Dim the used variables
Dim Bstatus As Byte , Bretries As Byte , Bblock As Byte , Bblocklocal As Byte
Dim Bcsum1 As Byte , Bcsum2 As Byte , Buf(128) As Byte , Csum As Byte
Dim J As Byte , Spmcrval As Byte ' self program command byte value
Dim Z As Long 'this is the Z pointer word
Dim Vl As Byte , Vh As Byte ' these bytes are used for the data values
Dim Wrd As Word , Page As Word 'these vars contain the page and word address
Dim Bkind As Byte , Bstarted As Byte
'Mega 88 : 32 words, 128 pages
Disable Interrupts 'we do not use ints
'Waitms 100 'wait 100 msec sec
'We start with receiving a file. The PC must send this binary file
'some constants used in serial com
Const Nak = &H15
Const Ack = &H06
Const Can = &H18
'we use some leds as indication in this sample , you might want to remove it
Config Pinb.2 = Output
Portb.2 = 1 'the stk200 has inverted logic for the leds
Config Pinb.3 = Output
Portb.3 = 1
$timeout = 400000 'we use a timeout
'When you get LOADER errors during the upload, increase the timeout value
'for example at 16 Mhz, use 200000
Bretries = 5 'we try 5 times
Testfor123:
#if Debug
Print "Try " ; Bretries
Print "Wait"
#endif
Bstatus = Waitkey() 'wait for the loader to send a byte
#if Debug
Print "Got "
#endif
Print Chr(bstatus);
If Bstatus = 123 Then 'did we received value 123 ?
Bkind = 0 'normal flash loader
Goto Loader
Elseif Bstatus = 124 Then ' EEPROM
Bkind = 1 ' EEPROM loader
Goto Loader
Elseif Bstatus <> 0 Then
Decr Bretries
If Bretries <> 0 Then Goto Testfor123 'we test again
End If
For J = 1 To 10 'this is a simple indication that we start the normal reset vector
Toggle Portb.2 : Waitms 100
Next
#if Debug
Print "RESET"
#endif
Goto _reset 'goto the normal reset vector at address 0
'this is the loader routine. It is a Xmodem-checksum reception routine
Loader:
#if Debug
Print "Clear buffer"
#endif
Do
Bstatus = Waitkey()
Loop Until Bstatus = 0
For J = 1 To 3 'this is a simple indication that we start the normal reset vector
Toggle Portb.2 : Waitms 50
Next
If Bkind = 0 Then
Spmcrval = 3 : Gosub Do_spm ' erase the first page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
End If
Bretries = 10 'number of retries
Do
Bstarted = 0 ' we were not started yet
Csum = 0 'checksum is 0 when we start
Print Chr(nak); ' firt time send a nack
Do
Bstatus = Waitkey() 'wait for statuse byte
Select Case Bstatus
Case 1: ' start of heading, PC is ready to send
Incr Bblocklocal 'increase local block count
Csum = 1 'checksum is 1
Bblock = Waitkey() : Csum = Csum + Bblock 'get block
Bcsum1 = Waitkey() : Csum = Csum + Bcsum1 'get checksum first byte
For J = 1 To 128 'get 128 bytes
Buf(j) = Waitkey() : Csum = Csum + Buf(j)
Next
Bcsum2 = Waitkey() 'get second checksum byte
If Bblocklocal = Bblock Then 'are the blocks the same?
If Bcsum2 = Csum Then 'is the checksum the same?
Gosub Writepage 'yes go write the page
Print Chr(ack); 'acknowledge
Else 'no match so send nak
Print Chr(nak);
End If
Else
Print Chr(nak); 'blocks do not match
End If
Case 4: ' end of transmission , file is transmitted
If Wrd > 0 And Bkind = 0 Then 'if there was something left in the page
Wrd = 0 'Z pointer needs wrd to be 0
Spmcrval = 5 : Gosub Do_spm 'write page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
End If
Print Chr(ack); ' send ack and ready
Portb.3 = 0 ' simple indication that we are finished and ok
Waitms 20
Goto _reset ' start new program
Case &H18: ' PC aborts transmission
Goto _reset ' ready
Case 123 : Exit Do 'was probably still in the buffer
Case 124 : Exit Do
Case Else
Exit Do ' no valid data
End Select
Loop
If Bretries > 0 Then 'attempte left?
Waitms 1000
Decr Bretries 'decrease attempts
Else
Goto _reset 'reset chip
End If
Loop
'write one or more pages
Writepage:
If Bkind = 0 Then
For J = 1 To 128 Step 2 'we write 2 bytes into a page
Vl = Buf(j) : Vh = Buf(j + 1) 'get Low and High bytes
lds r0, {vl} 'store them into r0 and r1 registers
lds r1, {vh}
Spmcrval = 1 : Gosub Do_spm 'write value into page at word address
Wrd = Wrd + 2 ' word address increases with 2 because LS bit of Z is not used
If Wrd = Maxword Then ' page is full
Wrd = 0 'Z pointer needs wrd to be 0
Spmcrval = 5 : Gosub Do_spm 'write page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
Page = Page + 1 'next page
Spmcrval = 3 : Gosub Do_spm ' erase next page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
End If
Next
Else 'eeprom
For J = 1 To 128
Writeeeprom Buf(j) , Wrd
Wrd = Wrd + 1
Next
End If
Toggle Portb.2 : Waitms 10 : Toggle Portb.2 'indication that we write
Return
Do_spm:
Bitwait Spmcsr.0 , Reset ' check for previous SPM complete
Bitwait Eecr.1 , Reset 'wait for eeprom
Z = Page 'make equal to page
Shift Z , Left , Maxwordshift 'shift to proper place
Z = Z + Wrd 'add word
lds r30,{Z}
lds r31,{Z+1}
#if _romsize > &HFFFF
lds r24,{Z+2}
sts rampz,r24 ' we need to set rampz also for the M128
#endif
Spmcsr = Spmcrval 'assign register
spm 'this is an asm instruction
nop
nop
Return
'How you need to use this program:
'1- compile this program
'2- program into chip with sample elctronics programmer
'3- select MCS Bootloader from programmers
'4- compile a new program for example M88.bas
'5- press F4 and reset your micro
' the program will now be uploaded into the chip with Xmodem Checksum
' you can write your own loader.too
'A stand alone command line loader is also available
'How to call the bootloader from your program without a reset ???
'Do
' Print "test"
' Waitms 1000
' If Inkey() = 27 Then
' Print "boot"
' Goto &H1C00
' End If
'Loop
'The GOTO will do the work, you need to specify the correct bootloader address
'this is the same as the $LOADER statement.