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