1 | '----------------------------------------------------------------
|
2 | ' (c) 1995-2007, MCS
|
3 | ' Bootloader.bas
|
4 | ' This sample demonstrates how you can write your own bootloader
|
5 | ' in BASCOM BASIC
|
6 | ' VERSION 2 of the BOOTLOADER. The waiting for the NAK is stretched
|
7 | ' further a bug was resolved for the M64/M128 that have a big page size
|
8 | '-----------------------------------------------------------------
|
9 | 'This sample will be extended to support other chips with bootloader
|
10 | 'The loader is supported from the IDE
|
11 |
|
12 | $crystal = 8000000
|
13 | '$crystal = 14745600
|
14 | $baud = 38400 'this loader uses serial com
|
15 | 'It is VERY IMPORTANT that the baud rate matches the one of the boot loader
|
16 | 'do not try to use buffered com as we can not use interrupts
|
17 |
|
18 | '$regfile = "m8def.dat"
|
19 |
|
20 | 'Const Loaderchip = 8
|
21 | '$regfile = "m168def.dat"
|
22 | 'Const Loaderchip = 168
|
23 |
|
24 | '$regfile = "m16def.dat"
|
25 | 'Const Loaderchip = 16
|
26 |
|
27 | $regfile = "m32def.dat"
|
28 | Const Loaderchip = 32
|
29 |
|
30 | '$regfile = "m88def.dat"
|
31 | 'Const Loaderchip = 88
|
32 |
|
33 | '$regfile = "m162def.dat"
|
34 | 'Const Loaderchip = 162
|
35 |
|
36 | '$regfile = "m8515.dat"
|
37 | 'Const Loaderchip = 8515
|
38 |
|
39 | '$regfile = "m128def.dat"
|
40 | 'Const Loaderchip = 128
|
41 |
|
42 | '$regfile = "m64def.dat"
|
43 | 'Const Loaderchip = 64
|
44 |
|
45 | '$regfile = "m2561def.dat"
|
46 | 'Const Loaderchip = 2561
|
47 |
|
48 |
|
49 | '$regfile = "m2560def.dat"
|
50 | 'Const Loaderchip = 2560
|
51 |
|
52 | '$regfile = "m329def.dat"
|
53 | 'Const Loaderchip = 329
|
54 |
|
55 | '$regfile = "m324pdef.dat"
|
56 | 'Const Loaderchip = 324
|
57 |
|
58 |
|
59 | #if Loaderchip = 88 'Mega88
|
60 | $loader = $c00 'this address you can find in the datasheet
|
61 | 'the loader address is the same as the boot vector address
|
62 | Const Maxwordbit = 5
|
63 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
64 | #endif
|
65 |
|
66 | #if Loaderchip = 168 'Mega168
|
67 | $loader = $1c00 'this address you can find in the datasheet
|
68 | 'the loader address is the same as the boot vector address
|
69 | Const Maxwordbit = 6
|
70 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
71 | #endif
|
72 |
|
73 | #if Loaderchip = 32 ' Mega32
|
74 | $loader = $3c00 ' 1024 words
|
75 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
76 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
77 | #endif
|
78 | #if Loaderchip = 8 ' Mega8
|
79 | $loader = $c00 ' 1024 words
|
80 | Const Maxwordbit = 5 'Z5 is maximum bit '
|
81 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
82 | #endif
|
83 | #if Loaderchip = 161 ' Mega161
|
84 | $loader = $1e00 ' 1024 words
|
85 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
86 | #endif
|
87 | #if Loaderchip = 162 ' Mega162
|
88 | $loader = $1c00 ' 1024 words
|
89 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
90 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
91 | #endif
|
92 |
|
93 | #if Loaderchip = 8515 ' Mega8515
|
94 | $loader = $c00 ' 1024 words
|
95 | Const Maxwordbit = 5 'Z6 is maximum bit '
|
96 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
97 | Osccal = &HB3 ' the internal osc needed a new value
|
98 | #endif
|
99 |
|
100 | #if Loaderchip = 64 ' Mega64
|
101 | $loader = $7c00 ' 1024 words
|
102 | Const Maxwordbit = 7 'Z7 is maximum bit '
|
103 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
104 | #endif
|
105 |
|
106 | #if Loaderchip = 128 ' Mega128
|
107 | $loader = &HFC00 ' 1024 words
|
108 | Const Maxwordbit = 7 'Z7 is maximum bit '
|
109 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
110 | #endif
|
111 |
|
112 | #if Loaderchip = 2561 ' Mega2561
|
113 | $loader = &H1FC00 ' 1024 words
|
114 | Const Maxwordbit = 7 'Z7 is maximum bit '
|
115 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
116 | #endif
|
117 |
|
118 |
|
119 | #if Loaderchip = 2560 ' Mega2560
|
120 | $loader = &H1FC00 ' 1024 words
|
121 | Const Maxwordbit = 7 'Z7 is maximum bit '
|
122 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
123 | #endif
|
124 |
|
125 | #if Loaderchip = 16 ' Mega16
|
126 | $loader = $1c00 ' 1024 words
|
127 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
128 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
129 | #endif
|
130 |
|
131 | #if Loaderchip = 329 ' Mega32
|
132 | $loader = $3c00 ' 1024 words
|
133 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
134 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
135 | #endif
|
136 |
|
137 | #if Loaderchip = 324 ' Mega32
|
138 | $loader = $3c00 ' 1024 words
|
139 | Const Maxwordbit = 6 'Z6 is maximum bit '
|
140 | Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
|
141 | #endif
|
142 |
|
143 |
|
144 | Const Maxword =(2 ^ Maxwordbit) * 2 '128
|
145 | Const Maxwordshift = Maxwordbit + 1
|
146 | Const Cdebug = 0 ' leave this to 0
|
147 |
|
148 | #if Cdebug
|
149 | Print Maxword
|
150 | Print Maxwordshift
|
151 | #endif
|
152 |
|
153 |
|
154 |
|
155 | 'Dim the used variables
|
156 | Dim Bstatus As Byte , Bretries As Byte , Bblock As Byte , Bblocklocal As Byte
|
157 | Dim Bcsum1 As Byte , Bcsum2 As Byte , Buf(128) As Byte , Csum As Byte
|
158 | Dim J As Byte , Spmcrval As Byte ' self program command byte value
|
159 |
|
160 | Dim Z As Long 'this is the Z pointer word
|
161 | Dim Vl As Byte , Vh As Byte ' these bytes are used for the data values
|
162 | Dim Wrd As Word , Page As Word 'these vars contain the page and word address
|
163 | Dim Bkind As Byte , Bstarted As Byte
|
164 | 'Mega 88 : 32 words, 128 pages
|
165 |
|
166 |
|
167 |
|
168 | Disable Interrupts 'we do not use ints
|
169 |
|
170 |
|
171 | 'Waitms 100 'wait 100 msec sec
|
172 | 'We start with receiving a file. The PC must send this binary file
|
173 |
|
174 | 'some constants used in serial com
|
175 | Const Nak = &H15
|
176 | Const Ack = &H06
|
177 | Const Can = &H18
|
178 |
|
179 | 'we use some leds as indication in this sample , you might want to remove it
|
180 | Config Pinb.2 = Output
|
181 | Portb.2 = 1 'the stk200 has inverted logic for the leds
|
182 | Config Pinb.3 = Output
|
183 | Portb.3 = 1
|
184 |
|
185 | $timeout = 400000 'we use a timeout
|
186 | 'When you get LOADER errors during the upload, increase the timeout value
|
187 | 'for example at 16 Mhz, use 200000
|
188 |
|
189 | Bretries = 5 'we try 5 times
|
190 | Testfor123:
|
191 | #if Cdebug
|
192 | Print "Try " ; Bretries
|
193 | Print "Wait"
|
194 | #endif
|
195 | Bstatus = Waitkey() 'wait for the loader to send a byte
|
196 | #if Cdebug
|
197 | Print "Got "
|
198 | #endif
|
199 |
|
200 | Print Chr(bstatus);
|
201 |
|
202 | If Bstatus = 123 Then 'did we received value 123 ?
|
203 | Bkind = 0 'normal flash loader
|
204 | Goto Loader
|
205 | Elseif Bstatus = 124 Then ' EEPROM
|
206 | Bkind = 1 ' EEPROM loader
|
207 | Goto Loader
|
208 | Elseif Bstatus <> 0 Then
|
209 | Decr Bretries
|
210 | If Bretries <> 0 Then Goto Testfor123 'we test again
|
211 | End If
|
212 |
|
213 | For J = 1 To 10 'this is a simple indication that we start the normal reset vector
|
214 | Toggle Portb.2 : Waitms 100
|
215 | Next
|
216 |
|
217 | #if Cdebug
|
218 | Print "RESET"
|
219 | #endif
|
220 | Goto _reset 'goto the normal reset vector at address 0
|
221 |
|
222 |
|
223 | 'this is the loader routine. It is a Xmodem-checksum reception routine
|
224 | Loader:
|
225 | #if Cdebug
|
226 | Print "Clear buffer"
|
227 | #endif
|
228 | Do
|
229 | Bstatus = Waitkey()
|
230 | Loop Until Bstatus = 0
|
231 |
|
232 |
|
233 | For J = 1 To 3 'this is a simple indication that we start the normal reset vector
|
234 | Toggle Portb.2 : Waitms 50
|
235 | Next
|
236 |
|
237 | If Bkind = 0 Then
|
238 | Spmcrval = 3 : Gosub Do_spm ' erase the first page
|
239 | Spmcrval = 17 : Gosub Do_spm ' re-enable page
|
240 | End If
|
241 |
|
242 |
|
243 | Bretries = 10 'number of retries
|
244 |
|
245 | Do
|
246 | Bstarted = 0 ' we were not started yet
|
247 | Csum = 0 'checksum is 0 when we start
|
248 | Print Chr(nak); ' firt time send a nack
|
249 | Do
|
250 |
|
251 | Bstatus = Waitkey() 'wait for statuse byte
|
252 |
|
253 | Select Case Bstatus
|
254 | Case 1: ' start of heading, PC is ready to send
|
255 | Incr Bblocklocal 'increase local block count
|
256 | Csum = 1 'checksum is 1
|
257 | Bblock = Waitkey() : Csum = Csum + Bblock 'get block
|
258 | Bcsum1 = Waitkey() : Csum = Csum + Bcsum1 'get checksum first byte
|
259 | For J = 1 To 128 'get 128 bytes
|
260 | Buf(j) = Waitkey() : Csum = Csum + Buf(j)
|
261 | Next
|
262 | Bcsum2 = Waitkey() 'get second checksum byte
|
263 | If Bblocklocal = Bblock Then 'are the blocks the same?
|
264 | If Bcsum2 = Csum Then 'is the checksum the same?
|
265 | Gosub Writepage 'yes go write the page
|
266 | Print Chr(ack); 'acknowledge
|
267 | Else 'no match so send nak
|
268 | Print Chr(nak);
|
269 | End If
|
270 | Else
|
271 | Print Chr(nak); 'blocks do not match
|
272 | End If
|
273 | Case 4: ' end of transmission , file is transmitted
|
274 | If Wrd > 0 And Bkind = 0 Then 'if there was something left in the page
|
275 | Wrd = 0 'Z pointer needs wrd to be 0
|
276 | Spmcrval = 5 : Gosub Do_spm 'write page
|
277 | Spmcrval = 17 : Gosub Do_spm ' re-enable page
|
278 | End If
|
279 | Print Chr(ack); ' send ack and ready
|
280 |
|
281 | Portb.3 = 0 ' simple indication that we are finished and ok
|
282 | Waitms 20
|
283 | Goto _reset ' start new program
|
284 | Case &H18: ' PC aborts transmission
|
285 | Goto _reset ' ready
|
286 | Case 123 : Exit Do 'was probably still in the buffer
|
287 | Case 124 : Exit Do
|
288 | Case Else
|
289 | Exit Do ' no valid data
|
290 | End Select
|
291 | Loop
|
292 | If Bretries > 0 Then 'attempte left?
|
293 | Waitms 1000
|
294 | Decr Bretries 'decrease attempts
|
295 | Else
|
296 | Goto _reset 'reset chip
|
297 | End If
|
298 | Loop
|
299 |
|
300 |
|
301 |
|
302 | 'write one or more pages
|
303 | Writepage:
|
304 | If Bkind = 0 Then
|
305 | For J = 1 To 128 Step 2 'we write 2 bytes into a page
|
306 | Vl = Buf(j) : Vh = Buf(j + 1) 'get Low and High bytes
|
307 | lds r0, {vl} 'store them into r0 and r1 registers
|
308 | lds r1, {vh}
|
309 | Spmcrval = 1 : Gosub Do_spm 'write value into page at word address
|
310 | Wrd = Wrd + 2 ' word address increases with 2 because LS bit of Z is not used
|
311 | If Wrd = Maxword Then ' page is full
|
312 | Wrd = 0 'Z pointer needs wrd to be 0
|
313 | Spmcrval = 5 : Gosub Do_spm 'write page
|
314 | Spmcrval = 17 : Gosub Do_spm ' re-enable page
|
315 |
|
316 | Page = Page + 1 'next page
|
317 | Spmcrval = 3 : Gosub Do_spm ' erase next page
|
318 | Spmcrval = 17 : Gosub Do_spm ' re-enable page
|
319 | End If
|
320 | Next
|
321 |
|
322 | Else 'eeprom
|
323 | For J = 1 To 128
|
324 | Writeeeprom Buf(j) , Wrd
|
325 | Wrd = Wrd + 1
|
326 | Next
|
327 | End If
|
328 | Toggle Portb.2 : Waitms 10 : Toggle Portb.2 'indication that we write
|
329 | Return
|
330 |
|
331 |
|
332 | Do_spm:
|
333 | Bitwait Spmcsr.0 , Reset ' check for previous SPM complete
|
334 | Bitwait Eecr.1 , Reset 'wait for eeprom
|
335 |
|
336 | Z = Page 'make equal to page
|
337 | Shift Z , Left , Maxwordshift 'shift to proper place
|
338 | Z = Z + Wrd 'add word
|
339 | lds r30,{Z}
|
340 | lds r31,{Z+1}
|
341 |
|
342 | #if _romsize > 65536
|
343 | lds r24,{Z+2}
|
344 | sts rampz,r24 ' we need to set rampz also for the M128
|
345 | #endif
|
346 |
|
347 | Spmcsr = Spmcrval 'assign register
|
348 | spm 'this is an asm instruction
|
349 | nop
|
350 | nop
|
351 | Return
|
352 |
|
353 |
|
354 | 'How you need to use this program:
|
355 | '1- compile this program
|
356 | '2- program into chip with sample elctronics programmer
|
357 | '3- select MCS Bootloader from programmers
|
358 | '4- compile a new program for example M88.bas
|
359 | '5- press F4 and reset your micro
|
360 | ' the program will now be uploaded into the chip with Xmodem Checksum
|
361 | ' you can write your own loader.too
|
362 | 'A stand alone command line loader is also available
|
363 |
|
364 |
|
365 | 'How to call the bootloader from your program without a reset ???
|
366 | 'Do
|
367 | ' Print "test"
|
368 | ' Waitms 1000
|
369 | ' If Inkey() = 27 Then
|
370 | ' Print "boot"
|
371 | ' Goto &H1C00
|
372 | ' End If
|
373 | 'Loop
|
374 |
|
375 | 'The GOTO will do the work, you need to specify the correct bootloader address
|
376 | 'this is the same as the $LOADER statement.
|